Merge tag 'for-linus-20191205' of git://git.kernel.dk/linux-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Dec 2019 18:08:59 +0000 (10:08 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Dec 2019 18:08:59 +0000 (10:08 -0800)
Pull more block and io_uring updates from Jens Axboe:
 "I wasn't expecting this to be so big, and if I was, I would have used
  separate branches for this. Going forward I'll be doing separate
  branches for the current tree, just like for the next kernel version
  tree. In any case, this contains:

   - Series from Christoph that fixes an inherent race condition with
     zoned devices and revalidation.

   - null_blk zone size fix (Damien)

   - Fix for a regression in this merge window that caused busy spins by
     sending empty disk uevents (Eric)

   - Fix for a regression in this merge window for bfq stats (Hou)

   - Fix for io_uring creds allocation failure handling (me)

   - io_uring -ERESTARTSYS send/recvmsg fix (me)

   - Series that fixes the need for applications to retain state across
     async request punts for io_uring. This one is a bit larger than I
     would have hoped, but I think it's important we get this fixed for
     5.5.

   - connect(2) improvement for io_uring, handling EINPROGRESS instead
     of having applications needing to poll for it (me)

   - Have io_uring use a hash for poll requests instead of an rbtree.
     This turned out to work much better in practice, so I think we
     should make the switch now. For some workloads, even with a fair
     amount of cancellations, the insertion sort is just too expensive.
     (me)

   - Various little io_uring fixes (me, Jackie, Pavel, LimingWu)

   - Fix for brd unaligned IO, and a warning for the future (Ming)

   - Fix for a bio integrity data leak (Justin)

   - bvec_iter_advance() improvement (Pavel)

   - Xen blkback page unmap fix (SeongJae)

  The major items in here are all well tested, and on the liburing side
  we continue to add regression and feature test cases. We're up to 50
  topic cases now, each with anywhere from 1 to more than 10 cases in
  each"

* tag 'for-linus-20191205' of git://git.kernel.dk/linux-block: (33 commits)
  block: fix memleak of bio integrity data
  io_uring: fix a typo in a comment
  bfq-iosched: Ensure bio->bi_blkg is valid before using it
  io_uring: hook all linked requests via link_list
  io_uring: fix error handling in io_queue_link_head
  io_uring: use hash table for poll command lookups
  io-wq: clear node->next on list deletion
  io_uring: ensure deferred timeouts copy necessary data
  io_uring: allow IO_SQE_* flags on IORING_OP_TIMEOUT
  null_blk: remove unused variable warning on !CONFIG_BLK_DEV_ZONED
  brd: warn on un-aligned buffer
  brd: remove max_hw_sectors queue limit
  xen/blkback: Avoid unmapping unmapped grant pages
  io_uring: handle connect -EINPROGRESS like -EAGAIN
  block: set the zone size in blk_revalidate_disk_zones atomically
  block: don't handle bio based drivers in blk_revalidate_disk_zones
  block: allocate the zone bitmaps lazily
  block: replace seq_zones_bitmap with conv_zones_bitmap
  block: simplify blkdev_nr_zones
  block: remove the empty line at the end of blk-zoned.c
  ...

2475 files changed:
.gitattributes
.gitignore
.mailmap
CREDITS
Documentation/ABI/stable/sysfs-driver-aspeed-vuart
Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-platform-wilco-ec
Documentation/Makefile
Documentation/admin-guide/LSM/SafeSetID.rst
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/dell_rbu.rst [new file with mode: 0644]
Documentation/admin-guide/device-mapper/dm-dust.rst [new file with mode: 0644]
Documentation/admin-guide/device-mapper/dm-dust.txt [deleted file]
Documentation/admin-guide/device-mapper/index.rst
Documentation/admin-guide/index.rst
Documentation/admin-guide/iostats.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/perf/imx-ddr.rst
Documentation/admin-guide/perf/index.rst
Documentation/admin-guide/sysctl/kernel.rst
Documentation/arm/microchip.rst
Documentation/conf.py
Documentation/core-api/genalloc.rst
Documentation/core-api/genericirq.rst
Documentation/core-api/memory-allocation.rst
Documentation/core-api/mm-api.rst
Documentation/core-api/printk-formats.rst
Documentation/core-api/refcount-vs-atomic.rst
Documentation/core-api/symbol-namespaces.rst
Documentation/dev-tools/kasan.rst
Documentation/dev-tools/kcov.rst
Documentation/dev-tools/kmemleak.rst
Documentation/devicetree/bindings/Makefile
Documentation/devicetree/bindings/arm/amlogic.yaml
Documentation/devicetree/bindings/arm/amlogic/smp-sram.txt [deleted file]
Documentation/devicetree/bindings/arm/arm,scmi.txt
Documentation/devicetree/bindings/arm/arm,scpi.txt
Documentation/devicetree/bindings/arm/atmel-at91.yaml
Documentation/devicetree/bindings/arm/axentia.txt [deleted file]
Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt [deleted file]
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt [deleted file]
Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.txt [deleted file]
Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mrvl/mrvl.txt [deleted file]
Documentation/devicetree/bindings/arm/mrvl/mrvl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt [deleted file]
Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/omap/prm-inst.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/realtek.yaml
Documentation/devicetree/bindings/arm/renesas,prr.txt [deleted file]
Documentation/devicetree/bindings/arm/renesas,prr.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/renesas.yaml
Documentation/devicetree/bindings/arm/rockchip.yaml
Documentation/devicetree/bindings/arm/samsung/exynos-chipid.txt [deleted file]
Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/samsung/pmu.txt [deleted file]
Documentation/devicetree/bindings/arm/samsung/pmu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt [deleted file]
Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/samsung/samsung-secure-firmware.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/samsung/sysreg.txt [deleted file]
Documentation/devicetree/bindings/arm/samsung/sysreg.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/sprd.txt [deleted file]
Documentation/devicetree/bindings/arm/sprd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/stm32/stm32.yaml
Documentation/devicetree/bindings/arm/sunxi.yaml
Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt [deleted file]
Documentation/devicetree/bindings/arm/sunxi/sunxi-mbus.txt
Documentation/devicetree/bindings/ata/sata_rcar.txt
Documentation/devicetree/bindings/bus/renesas,bsc.txt [deleted file]
Documentation/devicetree/bindings/bus/renesas,bsc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/bus/simple-pm-bus.txt [deleted file]
Documentation/devicetree/bindings/bus/simple-pm-bus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
Documentation/devicetree/bindings/clock/rockchip,px30-cru.txt
Documentation/devicetree/bindings/clock/ti/davinci/psc.txt
Documentation/devicetree/bindings/counter/stm32-lptimer-cnt.txt [deleted file]
Documentation/devicetree/bindings/counter/stm32-timer-cnt.txt [deleted file]
Documentation/devicetree/bindings/cpu/cpu-topology.txt
Documentation/devicetree/bindings/crypto/allwinner,sun8i-ce.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/samsung-slimsss.txt [deleted file]
Documentation/devicetree/bindings/crypto/samsung-slimsss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/samsung-sss.txt [deleted file]
Documentation/devicetree/bindings/crypto/samsung-sss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/st,stm32-crc.txt [deleted file]
Documentation/devicetree/bindings/crypto/st,stm32-crc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/st,stm32-cryp.txt [deleted file]
Documentation/devicetree/bindings/crypto/st,stm32-cryp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/st,stm32-hash.txt [deleted file]
Documentation/devicetree/bindings/crypto/st,stm32-hash.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/ddr/lpddr2-timings.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ddr/lpddr2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ddr/lpddr3-timings.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ddr/lpddr3.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
Documentation/devicetree/bindings/display/bridge/anx6345.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt
Documentation/devicetree/bindings/display/cirrus,clps711x-fb.txt
Documentation/devicetree/bindings/display/imx/fsl,imx-fb.txt
Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt [deleted file]
Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/st,stm32-dsi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/st,stm32-ltdc.txt [deleted file]
Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
Documentation/devicetree/bindings/dma/dma-common.yaml
Documentation/devicetree/bindings/dma/jz4780-dma.txt
Documentation/devicetree/bindings/dma/milbeaut-m10v-hdmac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/milbeaut-m10v-xdmac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/dma/ti-edma.txt
Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
Documentation/devicetree/bindings/eeprom/at24.txt
Documentation/devicetree/bindings/eeprom/at24.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/example-schema.yaml
Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml
Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml
Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml
Documentation/devicetree/bindings/gpu/samsung-g2d.txt [deleted file]
Documentation/devicetree/bindings/gpu/samsung-g2d.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/samsung-rotator.txt [deleted file]
Documentation/devicetree/bindings/gpu/samsung-rotator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/samsung-scaler.txt [deleted file]
Documentation/devicetree/bindings/gpu/samsung-scaler.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt [deleted file]
Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml
Documentation/devicetree/bindings/i2c/i2c-stm32.txt [deleted file]
Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt [deleted file]
Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
Documentation/devicetree/bindings/iio/pressure/bmp085.yaml
Documentation/devicetree/bindings/iio/timer/stm32-lptimer-trigger.txt [deleted file]
Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt [deleted file]
Documentation/devicetree/bindings/input/max77650-onkey.txt [deleted file]
Documentation/devicetree/bindings/input/max77650-onkey.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt [deleted file]
Documentation/devicetree/bindings/interconnect/qcom,qcs404.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt
Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt
Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt [deleted file]
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt [deleted file]
Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt [deleted file]
Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iommu/arm,smmu.txt [deleted file]
Documentation/devicetree/bindings/iommu/arm,smmu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt [deleted file]
Documentation/devicetree/bindings/iommu/samsung,sysmmu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/leds/leds-max77650.txt [deleted file]
Documentation/devicetree/bindings/leds/leds-max77650.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt [deleted file]
Documentation/devicetree/bindings/lpddr2/lpddr2.txt [deleted file]
Documentation/devicetree/bindings/mailbox/st,stm32-ipcc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt [deleted file]
Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml
Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/meson-ao-cec.txt [deleted file]
Documentation/devicetree/bindings/media/rc.yaml
Documentation/devicetree/bindings/media/st,stm32-cec.txt [deleted file]
Documentation/devicetree/bindings/media/st,stm32-cec.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/st,stm32-dcmi.txt [deleted file]
Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/exynos-srom.txt [deleted file]
Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/exynos5422-dmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt [deleted file]
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt
Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/stm32-lptimer.txt [deleted file]
Documentation/devicetree/bindings/mfd/stm32-timers.txt [deleted file]
Documentation/devicetree/bindings/mfd/syscon.txt [deleted file]
Documentation/devicetree/bindings/mfd/syscon.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/misc/allwinner,syscon.txt [deleted file]
Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml
Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt [deleted file]
Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml
Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml
Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml
Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml
Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/sun4i_can.txt [deleted file]
Documentation/devicetree/bindings/net/davinci-mdio.txt [deleted file]
Documentation/devicetree/bindings/net/ti,davinci-mdio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml
Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt
Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt
Documentation/devicetree/bindings/pci/layerscape-pci.txt
Documentation/devicetree/bindings/pci/rcar-pci.txt
Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt
Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt
Documentation/devicetree/bindings/power/pd-samsung.txt [deleted file]
Documentation/devicetree/bindings/power/pd-samsung.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/power-domain.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/power_domain.txt
Documentation/devicetree/bindings/power/qcom,rpmpd.txt
Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt
Documentation/devicetree/bindings/power/renesas,sysc-rmobile.txt
Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt [deleted file]
Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/reset/syscon-reboot.txt [deleted file]
Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/max77650-charger.txt [deleted file]
Documentation/devicetree/bindings/power/supply/max77650-charger.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/xlnx,zynqmp-genpd.txt
Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
Documentation/devicetree/bindings/pwm/atmel-pwm.txt
Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt
Documentation/devicetree/bindings/pwm/brcm,iproc-pwm.txt
Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt
Documentation/devicetree/bindings/pwm/img-pwm.txt
Documentation/devicetree/bindings/pwm/imx-pwm.txt
Documentation/devicetree/bindings/pwm/imx-tpm-pwm.txt
Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt
Documentation/devicetree/bindings/pwm/mxs-pwm.txt
Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt
Documentation/devicetree/bindings/pwm/pwm-berlin.txt
Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt
Documentation/devicetree/bindings/pwm/pwm-hibvt.txt
Documentation/devicetree/bindings/pwm/pwm-lp3943.txt
Documentation/devicetree/bindings/pwm/pwm-mediatek.txt
Documentation/devicetree/bindings/pwm/pwm-meson.txt
Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt
Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
Documentation/devicetree/bindings/pwm/pwm-samsung.txt [deleted file]
Documentation/devicetree/bindings/pwm/pwm-samsung.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-sifive.txt
Documentation/devicetree/bindings/pwm/pwm-sprd.txt
Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt [deleted file]
Documentation/devicetree/bindings/pwm/pwm-stm32.txt [deleted file]
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
Documentation/devicetree/bindings/pwm/pwm-zx.txt
Documentation/devicetree/bindings/pwm/pwm.txt
Documentation/devicetree/bindings/pwm/pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt [deleted file]
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt [deleted file]
Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/spear-pwm.txt
Documentation/devicetree/bindings/pwm/st,stmpe-pwm.txt
Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
Documentation/devicetree/bindings/regulator/fixed-regulator.yaml
Documentation/devicetree/bindings/regulator/max77650-regulator.txt [deleted file]
Documentation/devicetree/bindings/regulator/max77650-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt [deleted file]
Documentation/devicetree/bindings/reset/amlogic,meson-axg-audio-arb.txt
Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml
Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt [deleted file]
Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/qcom,pdc-global.txt [deleted file]
Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/renesas,rst.txt
Documentation/devicetree/bindings/reset/uniphier-reset.txt
Documentation/devicetree/bindings/rng/samsung,exynos4-rng.txt [deleted file]
Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rng/st,stm32-rng.txt [deleted file]
Documentation/devicetree/bindings/rng/st,stm32-rng.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/renesas,sh-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/rtc-sh.txt [deleted file]
Documentation/devicetree/bindings/rtc/s3c-rtc.txt [deleted file]
Documentation/devicetree/bindings/rtc/s3c-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/serial/8250.txt
Documentation/devicetree/bindings/serial/fsl-lpuart.txt
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
Documentation/devicetree/bindings/serial/samsung_uart.txt [deleted file]
Documentation/devicetree/bindings/serial/samsung_uart.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/serial/sprd-uart.txt [deleted file]
Documentation/devicetree/bindings/serial/sprd-uart.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt [deleted file]
Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt [deleted file]
Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.txt
Documentation/devicetree/bindings/soc/fsl/rcpm.txt
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
Documentation/devicetree/bindings/soc/rockchip/grf.txt
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
Documentation/devicetree/bindings/sram/milbeaut-smp-sram.txt [deleted file]
Documentation/devicetree/bindings/sram/renesas,smp-sram.txt [deleted file]
Documentation/devicetree/bindings/sram/rockchip-smp-sram.txt [deleted file]
Documentation/devicetree/bindings/sram/samsung-sram.txt [deleted file]
Documentation/devicetree/bindings/sram/sram.txt [deleted file]
Documentation/devicetree/bindings/sram/sram.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/submitting-patches.txt
Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/qcom-tsens.txt [deleted file]
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
Documentation/devicetree/bindings/thermal/st,stm32-thermal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/stm32-thermal.txt [deleted file]
Documentation/devicetree/bindings/timer/ingenic,tcu.txt
Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
Documentation/devicetree/bindings/timer/renesas,tmu.txt
Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt [deleted file]
Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/timer/st,stm32-timer.txt [deleted file]
Documentation/devicetree/bindings/timer/st,stm32-timer.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt [deleted file]
Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/amlogic,dwc3.txt
Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/generic-ehci.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/devicetree/bindings/watchdog/amlogic,meson-gxbb-wdt.yaml
Documentation/devicetree/bindings/watchdog/renesas,wdt.txt
Documentation/devicetree/bindings/watchdog/samsung-wdt.txt [deleted file]
Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml [new file with mode: 0644]
Documentation/devicetree/writing-schema.rst
Documentation/doc-guide/kernel-doc.rst
Documentation/dontdiff
Documentation/driver-api/dell_rbu.rst [deleted file]
Documentation/driver-api/devfreq.rst [new file with mode: 0644]
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/index.rst
Documentation/driver-api/infrastructure.rst
Documentation/driver-api/interconnect.rst
Documentation/driver-api/pti_intel_mid.rst
Documentation/driver-api/thermal/sysfs-api.rst
Documentation/features/core/tracehook/arch-support.txt
Documentation/filesystems/autofs.rst [new file with mode: 0644]
Documentation/filesystems/autofs.txt [deleted file]
Documentation/filesystems/index.rst
Documentation/filesystems/locking.rst
Documentation/hwmon/inspur-ipsps1.rst
Documentation/i2c/busses/index.rst
Documentation/i2c/index.rst
Documentation/index.rst
Documentation/ioctl/botching-up-ioctls.rst [deleted file]
Documentation/ioctl/cdrom.rst [deleted file]
Documentation/ioctl/hdio.rst [deleted file]
Documentation/ioctl/index.rst [deleted file]
Documentation/ioctl/ioctl-decoding.rst [deleted file]
Documentation/ioctl/ioctl-number.rst [deleted file]
Documentation/kbuild/makefiles.rst
Documentation/kbuild/modules.rst
Documentation/maintainer/configure-git.rst
Documentation/maintainer/index.rst
Documentation/maintainer/maintainer-entry-profile.rst [new file with mode: 0644]
Documentation/memory-barriers.txt
Documentation/mips/ingenic-tcu.rst
Documentation/misc-devices/xilinx_sdfec.rst [new file with mode: 0644]
Documentation/networking/device_drivers/mellanox/mlx5.rst
Documentation/networking/devlink-trap.rst
Documentation/networking/phy.rst
Documentation/nvdimm/maintainer-entry-profile.rst [new file with mode: 0644]
Documentation/power/pci.rst
Documentation/process/botching-up-ioctls.rst [new file with mode: 0644]
Documentation/process/embargoed-hardware-issues.rst
Documentation/process/index.rst
Documentation/process/magic-number.rst
Documentation/process/maintainers.rst [new file with mode: 0644]
Documentation/process/submitting-patches.rst
Documentation/riscv/boot-image-header.rst
Documentation/scheduler/sched-stats.rst
Documentation/scsi/scsi_mid_low_api.txt
Documentation/security/keys/core.rst
Documentation/security/lsm.rst
Documentation/sphinx-static/theme_overrides.css
Documentation/sphinx/kerneldoc.py
Documentation/sphinx/maintainers_include.py [new file with mode: 0755]
Documentation/sphinx/parallel-wrapper.sh [new file with mode: 0644]
Documentation/trace/coresight-cpu-debug.rst [deleted file]
Documentation/trace/coresight.rst [deleted file]
Documentation/trace/coresight/coresight-cpu-debug.rst [new file with mode: 0644]
Documentation/trace/coresight/coresight-etm4x-reference.rst [new file with mode: 0644]
Documentation/trace/coresight/coresight.rst [new file with mode: 0644]
Documentation/trace/coresight/index.rst [new file with mode: 0644]
Documentation/trace/index.rst
Documentation/translations/it_IT/process/magic-number.rst
Documentation/translations/it_IT/process/maintainer-pgp-guide.rst
Documentation/translations/ko_KR/howto.rst
Documentation/translations/ko_KR/index.rst
Documentation/translations/ko_KR/memory-barriers.txt
Documentation/translations/zh_CN/process/magic-number.rst
Documentation/userspace-api/index.rst
Documentation/userspace-api/ioctl/cdrom.rst [new file with mode: 0644]
Documentation/userspace-api/ioctl/hdio.rst [new file with mode: 0644]
Documentation/userspace-api/ioctl/index.rst [new file with mode: 0644]
Documentation/userspace-api/ioctl/ioctl-decoding.rst [new file with mode: 0644]
Documentation/userspace-api/ioctl/ioctl-number.rst [new file with mode: 0644]
Documentation/virt/kvm/api.txt
Documentation/w1/index.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/mmzone.h
arch/alpha/include/asm/pgalloc.h
arch/alpha/include/asm/pgtable.h
arch/alpha/kernel/pci-sysfs.c
arch/alpha/mm/init.c
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/boot/dts/axc001.dtsi
arch/arc/boot/dts/axs101.dts
arch/arc/boot/dts/axs103_idu.dts
arch/arc/boot/dts/axs10x_mb.dtsi
arch/arc/boot/dts/haps_hs.dts
arch/arc/boot/dts/haps_hs_idu.dts
arch/arc/boot/dts/nsim_700.dts
arch/arc/boot/dts/nsim_hs.dts [deleted file]
arch/arc/boot/dts/nsim_hs_idu.dts [deleted file]
arch/arc/configs/haps_hs_defconfig
arch/arc/configs/haps_hs_smp_defconfig
arch/arc/configs/nsim_700_defconfig
arch/arc/configs/nsim_hs_defconfig [deleted file]
arch/arc/configs/nsim_hs_smp_defconfig [deleted file]
arch/arc/include/asm/Kbuild
arch/arc/include/asm/cache.h
arch/arc/include/asm/entry-compact.h
arch/arc/include/asm/jump_label.h [new file with mode: 0644]
arch/arc/include/asm/mmu.h
arch/arc/include/asm/mmu_context.h
arch/arc/include/asm/pgtable.h
arch/arc/kernel/Makefile
arch/arc/kernel/jump_label.c [new file with mode: 0644]
arch/arc/mm/fault.c
arch/arc/mm/highmem.c
arch/arc/mm/tlb.c
arch/arc/mm/tlbex.S
arch/arc/plat-sim/platform.c
arch/arm/Kconfig
arch/arm/boot/compressed/libfdt_env.h
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-baltos.dtsi
arch/arm/boot/dts/am335x-bone-common.dtsi
arch/arm/boot/dts/am335x-boneblue.dts
arch/arm/boot/dts/am335x-chiliboard.dts
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-guardian.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-8100-me-t.dts
arch/arm/boot/dts/am335x-netcan-plus-1xx.dts [new file with mode: 0644]
arch/arm/boot/dts/am335x-netcom-plus-2xx.dts [new file with mode: 0644]
arch/arm/boot/dts/am335x-netcom-plus-8xx.dts [new file with mode: 0644]
arch/arm/boot/dts/am335x-osd3358-sm-red.dts
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-pocketbeagle.dts
arch/arm/boot/dts/am335x-regor.dtsi
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/am33xx-l4.dtsi
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am3517.dtsi
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am437x-l4.dtsi
arch/arm/boot/dts/armada-38x.dtsi
arch/arm/boot/dts/armada-xp-98dx3236.dtsi
arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts
arch/arm/boot/dts/armada-xp.dtsi
arch/arm/boot/dts/aspeed-ast2500-evb.dts
arch/arm/boot/dts/aspeed-ast2600-evb.dts
arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts
arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts
arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts
arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts
arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts
arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts
arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts
arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts
arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts
arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts
arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts
arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
arch/arm/boot/dts/aspeed-bmc-opp-swift.dts
arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts
arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts
arch/arm/boot/dts/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed-g5.dtsi
arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
arch/arm/boot/dts/aspeed-g6.dtsi
arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91-kizbox2-2.dts [new file with mode: 0644]
arch/arm/boot/dts/at91-kizbox2-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91-kizbox2.dts [deleted file]
arch/arm/boot/dts/at91-kizbox3-hs.dts [new file with mode: 0644]
arch/arm/boot/dts/at91-kizbox3_common.dtsi [new file with mode: 0644]
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/atlas7-evb.dts
arch/arm/boot/dts/bcm-hr2.dtsi
arch/arm/boot/dts/bcm2711-rpi-4-b.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm2711.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm2835-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm2835-rpi.dtsi
arch/arm/boot/dts/bcm2835.dtsi
arch/arm/boot/dts/bcm2836.dtsi
arch/arm/boot/dts/bcm2837.dtsi
arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm283x.dtsi
arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts [new file with mode: 0644]
arch/arm/boot/dts/dove.dtsi
arch/arm/boot/dts/dra7-l4.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/e60k02.dtsi [new file with mode: 0644]
arch/arm/boot/dts/emev2.dtsi
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/exynos4412.dtsi
arch/arm/boot/dts/exynos5.dtsi
arch/arm/boot/dts/exynos5250-arndale.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5260.dtsi
arch/arm/boot/dts/exynos5410.dtsi
arch/arm/boot/dts/exynos5420-peach-pit.dts
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/exynos5422-odroid-core.dtsi
arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
arch/arm/boot/dts/exynos54xx.dtsi
arch/arm/boot/dts/exynos5800-peach-pi.dts
arch/arm/boot/dts/exynos5800.dtsi
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx31.dtsi
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53-qsb-common.dtsi
arch/arm/boot/dts/imx53-usbarmory.dts
arch/arm/boot/dts/imx6dl-apf6dev.dts
arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
arch/arm/boot/dts/imx6dl-yapp4-common.dtsi
arch/arm/boot/dts/imx6dl-yapp4-hydra.dts
arch/arm/boot/dts/imx6dl.dtsi
arch/arm/boot/dts/imx6q-apalis-eval.dts
arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts
arch/arm/boot/dts/imx6q-apalis-ixora.dts
arch/arm/boot/dts/imx6q-apf6dev.dts
arch/arm/boot/dts/imx6q-dhcom-pdk2.dts
arch/arm/boot/dts/imx6q-dhcom-som.dtsi
arch/arm/boot/dts/imx6q-gw54xx.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/boot/dts/imx6qdl-apalis.dtsi
arch/arm/boot/dts/imx6qdl-apf6.dtsi
arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
arch/arm/boot/dts/imx6qdl-colibri.dtsi
arch/arm/boot/dts/imx6qdl-gw551x.dtsi
arch/arm/boot/dts/imx6qdl-rex.dtsi
arch/arm/boot/dts/imx6qdl-udoo.dtsi
arch/arm/boot/dts/imx6qdl-wandboard.dtsi
arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
arch/arm/boot/dts/imx6sl.dtsi
arch/arm/boot/dts/imx6sll-kobo-clarahd.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6sll.dtsi
arch/arm/boot/dts/imx6sx.dtsi
arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
arch/arm/boot/dts/imx6ul-imx6ull-opos6ul.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ul-imx6ull-opos6uldev.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts
arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi
arch/arm/boot/dts/imx6ul-kontron-n6311-s.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6ul-kontron-n6311-som.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ul-kontron-n6x1x-s.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ul-kontron-n6x1x-som-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ul-opos6ul.dtsi
arch/arm/boot/dts/imx6ul-opos6uldev.dts
arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi
arch/arm/boot/dts/imx6ul.dtsi
arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi
arch/arm/boot/dts/imx6ull-colibri-nonwifi.dtsi
arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
arch/arm/boot/dts/imx6ull-colibri.dtsi
arch/arm/boot/dts/imx6ull-kontron-n6411-s.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6ull-kontron-n6411-som.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ull-opos6ul.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6ull-opos6uldev.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
arch/arm/boot/dts/imx7-colibri.dtsi
arch/arm/boot/dts/imx7d.dtsi
arch/arm/boot/dts/imx7s.dtsi
arch/arm/boot/dts/imx7ulp-evk.dts
arch/arm/boot/dts/imx7ulp.dtsi
arch/arm/boot/dts/keystone-clocks.dtsi
arch/arm/boot/dts/keystone-k2e-clocks.dtsi
arch/arm/boot/dts/keystone-k2e-netcp.dtsi
arch/arm/boot/dts/keystone-k2hk-netcp.dtsi
arch/arm/boot/dts/keystone-k2l-netcp.dtsi
arch/arm/boot/dts/kirkwood-synology.dtsi
arch/arm/boot/dts/logicpd-torpedo-37xx-devkit-28.dts
arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
arch/arm/boot/dts/logicpd-torpedo-som.dtsi
arch/arm/boot/dts/mmp3-dell-ariel.dts [new file with mode: 0644]
arch/arm/boot/dts/mmp3.dtsi [new file with mode: 0644]
arch/arm/boot/dts/motorola-mapphone-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/mt6323.dtsi
arch/arm/boot/dts/omap3-igep0020-rev-f.dts
arch/arm/boot/dts/omap3-igep0030-rev-g.dts
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi
arch/arm/boot/dts/omap4-droid-bionic-xt875.dts [new file with mode: 0644]
arch/arm/boot/dts/omap4-droid4-xt894.dts
arch/arm/boot/dts/omap4-l4-abe.dtsi
arch/arm/boot/dts/omap4-l4.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5-l4-abe.dtsi
arch/arm/boot/dts/omap5-l4.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/openbmc-flash-layout-128.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom-ipq4019.dtsi
arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts
arch/arm/boot/dts/qcom-msm8974.dtsi
arch/arm/boot/dts/qcom-pm8941.dtsi
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/r8a7793-gose.dts
arch/arm/boot/dts/rda8810pl.dtsi
arch/arm/boot/dts/rk3036.dtsi
arch/arm/boot/dts/rk3288-rock2-som.dtsi
arch/arm/boot/dts/rk3288-tinker.dtsi
arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
arch/arm/boot/dts/rk3288-veyron-edp.dtsi
arch/arm/boot/dts/rk3288-veyron-jaq.dts
arch/arm/boot/dts/rk3288-veyron-mickey.dts
arch/arm/boot/dts/rk3288-veyron-minnie.dts
arch/arm/boot/dts/rk3288-veyron-tiger.dts
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/s3c6410-mini6410.dts
arch/arm/boot/dts/s3c6410-smdk6410.dts
arch/arm/boot/dts/sama5d2.dtsi
arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts
arch/arm/boot/dts/stm32429i-eval.dts
arch/arm/boot/dts/stm32746g-eval.dts
arch/arm/boot/dts/stm32f429-disco.dts
arch/arm/boot/dts/stm32f469-disco.dts
arch/arm/boot/dts/stm32f469.dtsi
arch/arm/boot/dts/stm32f746-disco.dts
arch/arm/boot/dts/stm32f769-disco.dts
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-avenger96.dts
arch/arm/boot/dts/stm32mp157a-dk1.dts
arch/arm/boot/dts/stm32mp157c-dk2.dts
arch/arm/boot/dts/stm32mp157c-ed1.dts
arch/arm/boot/dts/stm32mp157c-ev1.dts
arch/arm/boot/dts/stm32mp157c.dtsi
arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
arch/arm/boot/dts/sun8i-a83t.dtsi
arch/arm/boot/dts/sun8i-h3-nanopi-duo2.dts [new file with mode: 0644]
arch/arm/boot/dts/sun8i-h3.dtsi
arch/arm/boot/dts/sun8i-r40.dtsi
arch/arm/boot/dts/sun9i-a80.dtsi
arch/arm/boot/dts/sunxi-h3-h5.dtsi
arch/arm/boot/dts/tegra124-nyan-big-emc.dtsi
arch/arm/boot/dts/tegra124-venice2.dts
arch/arm/boot/dts/tegra124.dtsi
arch/arm/boot/dts/tegra20-cpu-opp-microvolt.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra20-cpu-opp.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra20-paz00.dts
arch/arm/boot/dts/tegra20-trimslice.dts
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30-apalis-v1.1.dtsi
arch/arm/boot/dts/tegra30-apalis.dtsi
arch/arm/boot/dts/tegra30-cardhu-a04.dts
arch/arm/boot/dts/tegra30-colibri.dtsi
arch/arm/boot/dts/tegra30-cpu-opp-microvolt.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra30-cpu-opp.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra30.dtsi
arch/arm/boot/dts/vf-colibri.dtsi
arch/arm/boot/dts/vf500-colibri.dtsi
arch/arm/boot/dts/vf610-bk4.dts
arch/arm/boot/dts/vf610-zii-scu4-aib.dts
arch/arm/configs/aspeed_g4_defconfig
arch/arm/configs/aspeed_g5_defconfig
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/exynos_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/keystone_defconfig
arch/arm/configs/multi_v5_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/qcom_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/configs/sunxi_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/crypto/chacha-glue.c
arch/arm/crypto/curve25519-glue.c
arch/arm/crypto/poly1305-glue.c
arch/arm/include/asm/Kbuild
arch/arm/include/asm/arch_gicv3.h
arch/arm/include/asm/hardware/cache-l2x0.h
arch/arm/include/asm/pgtable.h
arch/arm/mach-bcm/Kconfig
arch/arm/mach-bcm/Makefile
arch/arm/mach-bcm/bcm2711.c [new file with mode: 0644]
arch/arm/mach-bcm/bcm_kona_smc.c
arch/arm/mach-bcm/platsmp.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-hisi/Kconfig
arch/arm/mach-imx/anatop.c
arch/arm/mach-imx/cpu.c
arch/arm/mach-imx/hotplug.c
arch/arm/mach-mmp/Kconfig
arch/arm/mach-mmp/Makefile
arch/arm/mach-mmp/addr-map.h
arch/arm/mach-mmp/common.c
arch/arm/mach-mmp/common.h
arch/arm/mach-mmp/cputype.h [deleted file]
arch/arm/mach-mmp/devices.c
arch/arm/mach-mmp/mmp-dt.c
arch/arm/mach-mmp/mmp2-dt.c
arch/arm/mach-mmp/mmp2.c
arch/arm/mach-mmp/mmp3.c [new file with mode: 0644]
arch/arm/mach-mmp/platsmp.c [new file with mode: 0644]
arch/arm/mach-mmp/pm-mmp2.c
arch/arm/mach-mmp/pm-pxa910.c
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mmp/regs-usb.h
arch/arm/mach-mmp/time.c
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/ams-delta-fiq.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/control.c
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/omap-mpuss-lowpower.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
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_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_twl.c
arch/arm/mach-omap2/opp4xxx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm44xx.c
arch/arm/mach-omap2/pmic-cpcap.c [new file with mode: 0644]
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/vc.c
arch/arm/mach-omap2/vc.h
arch/arm/mach-s3c24xx/s3c2416.c
arch/arm/mach-s3c24xx/s3c2443.c
arch/arm/mach-s3c24xx/spi-core.h
arch/arm/mach-s3c64xx/setup-usb-phy.c
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-tegra/reset-handler.S
arch/arm/mach-tegra/sleep-tegra30.S
arch/arm/mm/Kconfig
arch/arm/mm/dma-mapping.c
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/include/plat/usb-phy.h
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/actions/s900-bubblegum-96.dts
arch/arm64/boot/dts/actions/s900.dtsi
arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
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.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
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-tanix-tx6.dts
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
arch/arm64/boot/dts/amlogic/Makefile
arch/arm64/boot/dts/amlogic/meson-a1-ad401.dts [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-a1.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
arch/arm64/boot/dts/amlogic/meson-g12.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.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-g12b-a311d-khadas-vim3.dts
arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts
arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts
arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s805x-p241.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
arch/arm64/boot/dts/amlogic/meson-gxm-vega-s96.dts
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/broadcom/Makefile
arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts [new file with mode: 0644]
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-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-ls1046a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
arch/arm64/boot/dts/freescale/imx8mm-evk.dts
arch/arm64/boot/dts/freescale/imx8mm.dtsi
arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts
arch/arm64/boot/dts/freescale/imx8mn-evk.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mn.dtsi
arch/arm64/boot/dts/freescale/imx8mq-evk.dts
arch/arm64/boot/dts/freescale/imx8mq-hummingboard-pulse.dts
arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts
arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts
arch/arm64/boot/dts/freescale/imx8mq-sr-som.dtsi
arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts
arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
arch/arm64/boot/dts/freescale/imx8qxp.dtsi
arch/arm64/boot/dts/freescale/s32v234-evb.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/s32v234.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/hisilicon/hi6220.dtsi
arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts
arch/arm64/boot/dts/lg/lg1312.dtsi
arch/arm64/boot/dts/lg/lg1313.dtsi
arch/arm64/boot/dts/marvell/Makefile
arch/arm64/boot/dts/marvell/armada-3720-espressobin-emmc.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-3720-espressobin-v7-emmc.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-3720-espressobin-v7.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
arch/arm64/boot/dts/marvell/armada-70x0.dtsi
arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
arch/arm64/boot/dts/marvell/armada-80x0.dtsi
arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
arch/arm64/boot/dts/marvell/armada-ap806.dtsi
arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-ap807.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-ap80x.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-common.dtsi
arch/arm64/boot/dts/marvell/armada-cp110.dtsi
arch/arm64/boot/dts/marvell/armada-cp115.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-cp11x.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/cn9130-db.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/cn9130.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/cn9131-db.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/cn9132-db.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8183.dtsi
arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
arch/arm64/boot/dts/nvidia/tegra186.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
arch/arm64/boot/dts/nvidia/tegra194.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
arch/arm64/boot/dts/nvidia/tegra210.dtsi
arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts
arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi
arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
arch/arm64/boot/dts/qcom/msm8998-pins.dtsi
arch/arm64/boot/dts/qcom/msm8998.dtsi
arch/arm64/boot/dts/qcom/qcs404.dtsi
arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
arch/arm64/boot/dts/qcom/sdm845-db845c.dts
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
arch/arm64/boot/dts/realtek/Makefile
arch/arm64/boot/dts/realtek/rtd1293-ds418j.dts [new file with mode: 0644]
arch/arm64/boot/dts/realtek/rtd1293.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/realtek/rtd1295-zidoo-x9s.dts
arch/arm64/boot/dts/realtek/rtd1295.dtsi
arch/arm64/boot/dts/realtek/rtd1296-ds418.dts [new file with mode: 0644]
arch/arm64/boot/dts/realtek/rtd1296.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/realtek/rtd129x.dtsi
arch/arm64/boot/dts/renesas/Makefile
arch/arm64/boot/dts/renesas/hihope-common.dtsi
arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi
arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m-ex.dts
arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m.dts
arch/arm64/boot/dts/renesas/r8a774a1.dtsi
arch/arm64/boot/dts/renesas/r8a774b1-hihope-rzg2n-ex.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774b1-hihope-rzg2n.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774b1.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774c0.dtsi
arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
arch/arm64/boot/dts/renesas/r8a7795.dtsi
arch/arm64/boot/dts/renesas/r8a7796.dtsi
arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a77961.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a77965.dtsi
arch/arm64/boot/dts/renesas/r8a77970.dtsi
arch/arm64/boot/dts/renesas/r8a77980.dtsi
arch/arm64/boot/dts/renesas/r8a77990.dtsi
arch/arm64/boot/dts/renesas/r8a77995.dtsi
arch/arm64/boot/dts/renesas/rzg2-advantech-idk-1110wr-panel.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/Makefile
arch/arm64/boot/dts/rockchip/px30-evb.dts
arch/arm64/boot/dts/rockchip/px30.dtsi
arch/arm64/boot/dts/rockchip/rk3308-evb.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3308.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3328-a1.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
arch/arm64/boot/dts/rockchip/rk3328.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi
arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dts
arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/ti/k3-am65-main.dtsi
arch/arm64/boot/dts/ti/k3-am654-base-board.dts
arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
arch/arm64/boot/dts/ti/k3-j721e.dtsi
arch/arm64/boot/dts/xilinx/zynqmp.dtsi
arch/arm64/configs/defconfig
arch/arm64/crypto/chacha-neon-glue.c
arch/arm64/crypto/poly1305-glue.c
arch/arm64/include/asm/Kbuild
arch/c6x/include/asm/pgtable.h
arch/hexagon/include/uapi/asm/bitsperlong.h [deleted file]
arch/ia64/include/asm/iommu.h
arch/ia64/include/asm/irqflags.h
arch/ia64/include/uapi/asm/errno.h [deleted file]
arch/ia64/include/uapi/asm/gcc_intrin.h
arch/ia64/include/uapi/asm/intel_intrin.h
arch/ia64/include/uapi/asm/intrinsics.h
arch/ia64/include/uapi/asm/ioctl.h [deleted file]
arch/ia64/include/uapi/asm/ioctls.h [deleted file]
arch/m68k/coldfire/entry.S
arch/m68k/include/asm/mcf_pgalloc.h
arch/m68k/include/asm/mcf_pgtable.h
arch/m68k/include/asm/mmu_context.h
arch/m68k/include/asm/motorola_pgalloc.h
arch/m68k/include/asm/motorola_pgtable.h
arch/m68k/include/asm/page.h
arch/m68k/include/asm/pgtable_mm.h
arch/m68k/include/asm/pgtable_no.h
arch/m68k/include/asm/sun3_pgalloc.h
arch/m68k/include/asm/sun3_pgtable.h
arch/m68k/kernel/sys_m68k.c
arch/m68k/mm/init.c
arch/m68k/mm/kmap.c
arch/m68k/mm/mcfmmu.c
arch/m68k/mm/motorola.c
arch/m68k/sun3x/dvma.c
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/kernel/signal.c
arch/microblaze/mm/init.c
arch/microblaze/mm/pgtable.c
arch/mips/crypto/chacha-glue.c
arch/mips/crypto/poly1305-glue.c
arch/mips/include/asm/Kbuild
arch/mips/include/uapi/asm/msgbuf.h
arch/mips/include/uapi/asm/sembuf.h
arch/mips/sgi-ip32/ip32-platform.c
arch/nds32/include/asm/page.h
arch/nds32/include/asm/pgalloc.h
arch/nds32/include/asm/pgtable.h
arch/nds32/include/asm/tlb.h
arch/nds32/kernel/pm.c
arch/nds32/mm/fault.c
arch/nds32/mm/init.c
arch/nds32/mm/mm-nds32.c
arch/nds32/mm/proc.c
arch/openrisc/Kconfig
arch/parisc/include/asm/page.h
arch/parisc/include/asm/pgalloc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/tlb.h
arch/parisc/include/uapi/asm/msgbuf.h
arch/parisc/include/uapi/asm/sembuf.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/pci-dma.c
arch/parisc/mm/fixmap.c
arch/parisc/mm/hugetlbpage.c
arch/powerpc/Kconfig
arch/powerpc/boot/libfdt_env.h
arch/powerpc/include/asm/Kbuild
arch/powerpc/include/asm/book3s/64/pgtable-4k.h
arch/powerpc/include/asm/book3s/64/pgtable-64k.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/kvm_book3s_uvmem.h [new file with mode: 0644]
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/ultravisor-api.h
arch/powerpc/include/asm/ultravisor.h
arch/powerpc/include/uapi/asm/msgbuf.h
arch/powerpc/include/uapi/asm/sembuf.h
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s_64_mmu_radix.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_uvmem.c [new file with mode: 0644]
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/riscv/Kconfig.socs
arch/riscv/configs/defconfig
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/Kbuild
arch/riscv/mm/init.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/boot/startup.c
arch/s390/include/asm/cpu_mf.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/pci_clp.h
arch/s390/include/asm/perf_event.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/stacktrace.h
arch/s390/include/asm/unwind.h
arch/s390/include/asm/vdso.h
arch/s390/include/uapi/asm/ipcbuf.h
arch/s390/kernel/Makefile
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/dumpstack.c
arch/s390/kernel/head64.S
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/stacktrace.c
arch/s390/kernel/unwind_bc.c
arch/s390/kernel/vdso.c
arch/s390/kernel/vdso32/.gitignore [deleted file]
arch/s390/kernel/vdso32/Makefile [deleted file]
arch/s390/kernel/vdso32/clock_getres.S [deleted file]
arch/s390/kernel/vdso32/clock_gettime.S [deleted file]
arch/s390/kernel/vdso32/getcpu.S [deleted file]
arch/s390/kernel/vdso32/gettimeofday.S [deleted file]
arch/s390/kernel/vdso32/note.S [deleted file]
arch/s390/kernel/vdso32/vdso32.lds.S [deleted file]
arch/s390/kernel/vdso32/vdso32_wrapper.S [deleted file]
arch/s390/kernel/vdso64/getcpu.S
arch/s390/lib/Makefile
arch/s390/lib/test_unwind.c [new file with mode: 0644]
arch/s390/mm/maccess.c
arch/s390/pci/pci.c
arch/s390/pci/pci_clp.c
arch/sh/kernel/cpu/shmobile/cpuidle.c
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/pgalloc_32.h
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/uapi/asm/ipcbuf.h
arch/sparc/include/uapi/asm/msgbuf.h
arch/sparc/include/uapi/asm/sembuf.h
arch/sparc/mm/fault_32.c
arch/sparc/mm/highmem.c
arch/sparc/mm/io-unit.c
arch/sparc/mm/iommu.c
arch/sparc/mm/srmmu.c
arch/um/Kconfig
arch/um/drivers/Kconfig
arch/um/drivers/vector_kern.c
arch/um/drivers/vector_kern.h
arch/um/drivers/vector_user.c
arch/um/drivers/vector_user.h
arch/um/drivers/virtio_uml.c
arch/um/include/asm/pgtable-2level.h
arch/um/include/asm/pgtable-3level.h
arch/um/include/asm/pgtable.h
arch/um/kernel/mem.c
arch/um/kernel/skas/mmu.c
arch/um/kernel/skas/uaccess.c
arch/um/kernel/tlb.c
arch/um/kernel/trap.c
arch/um/os-Linux/main.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/crypto/blake2s-glue.c
arch/x86/crypto/chacha_glue.c
arch/x86/crypto/curve25519-x86_64.c
arch/x86/crypto/poly1305_glue.c
arch/x86/entry/entry_32.S
arch/x86/events/core.c
arch/x86/include/asm/cpu_entry_area.h
arch/x86/include/asm/doublefault.h [new file with mode: 0644]
arch/x86/include/asm/fpu/internal.h
arch/x86/include/asm/iommu.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/pgtable_32_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/traps.h
arch/x86/include/uapi/asm/msgbuf.h
arch/x86/include/uapi/asm/sembuf.h
arch/x86/kernel/Makefile
arch/x86/kernel/cpu/common.c
arch/x86/kernel/doublefault.c [deleted file]
arch/x86/kernel/doublefault_32.c [new file with mode: 0644]
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/process.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/traps.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/lib/x86-opcode-map.txt
arch/x86/mm/cpu_entry_area.c
arch/x86/mm/fault.c
arch/x86/mm/kasan_init_64.c
arch/x86/mm/pat_interval.c
arch/x86/pci/Makefile
arch/x86/pci/common.c
arch/x86/pci/fixup.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/numachip.c
arch/xtensa/Kconfig
arch/xtensa/Kconfig.debug
arch/xtensa/Makefile
arch/xtensa/boot/Makefile
arch/xtensa/configs/xip_kc705_defconfig [new file with mode: 0644]
arch/xtensa/include/asm/Kbuild
arch/xtensa/include/asm/atomic.h
arch/xtensa/include/asm/bitops.h
arch/xtensa/include/asm/cache.h
arch/xtensa/include/asm/cmpxchg.h
arch/xtensa/include/asm/fixmap.h
arch/xtensa/include/asm/futex.h
arch/xtensa/include/asm/hw_irq.h [deleted file]
arch/xtensa/include/asm/initialize_mmu.h
arch/xtensa/include/asm/kmem_layout.h
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/processor.h
arch/xtensa/include/asm/syscall.h
arch/xtensa/include/asm/uaccess.h
arch/xtensa/include/asm/user.h [deleted file]
arch/xtensa/include/asm/vectors.h
arch/xtensa/include/uapi/asm/ipcbuf.h
arch/xtensa/include/uapi/asm/msgbuf.h
arch/xtensa/include/uapi/asm/sembuf.h
arch/xtensa/kernel/coprocessor.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/head.S
arch/xtensa/kernel/process.c
arch/xtensa/kernel/ptrace.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/signal.c
arch/xtensa/kernel/traps.c
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/mm/fault.c
arch/xtensa/mm/init.c
arch/xtensa/mm/kasan_init.c
arch/xtensa/mm/mmu.c
arch/xtensa/mm/tlb.c
drivers/acpi/Kconfig
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/osl.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/ata/pata_arasan_cf.c
drivers/ata/pata_atp867x.c
drivers/ata/sata_nv.c
drivers/auxdisplay/charlcd.c
drivers/base/Kconfig
drivers/base/memory.c
drivers/base/node.c
drivers/base/power/Makefile
drivers/base/power/qos-test.c [new file with mode: 0644]
drivers/base/power/qos.c
drivers/base/power/wakeup.c
drivers/block/rbd.c
drivers/bus/Kconfig
drivers/bus/hisi_lpc.c
drivers/bus/ti-sysc.c
drivers/clk/Kconfig
drivers/clk/mmp/Makefile
drivers/clk/qcom/clk-rpmh.c
drivers/clk/qcom/gcc-qcs404.c
drivers/clk/qcom/gcc-sdm845.c
drivers/clocksource/Kconfig
drivers/clocksource/asm9260_timer.c
drivers/clocksource/renesas-ostm.c
drivers/clocksource/timer-of.c
drivers/cpufreq/Kconfig.powerpc
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_performance.c
drivers/cpufreq/cpufreq_powersave.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpuidle/Kconfig
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/cpuidle.c
drivers/cpuidle/poll_state.c
drivers/crypto/Kconfig
drivers/crypto/hisilicon/sec2/sec_crypto.c
drivers/devfreq/devfreq.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/at_xdmac.c
drivers/dma/dma-jz4780.c
drivers/dma/dw/platform.c
drivers/dma/fsl-dpaa2-qdma/Kconfig [new file with mode: 0644]
drivers/dma/fsl-dpaa2-qdma/Makefile [new file with mode: 0644]
drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c [new file with mode: 0644]
drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h [new file with mode: 0644]
drivers/dma/fsl-dpaa2-qdma/dpdmai.c [new file with mode: 0644]
drivers/dma/fsl-dpaa2-qdma/dpdmai.h [new file with mode: 0644]
drivers/dma/fsl-qdma.c
drivers/dma/iop-adma.c
drivers/dma/k3dma.c
drivers/dma/mediatek/mtk-cqdma.c
drivers/dma/mediatek/mtk-hsdma.c
drivers/dma/mediatek/mtk-uart-apdma.c
drivers/dma/milbeaut-hdmac.c [new file with mode: 0644]
drivers/dma/milbeaut-xdmac.c [new file with mode: 0644]
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/owl-dma.c
drivers/dma/sf-pdma/Kconfig [new file with mode: 0644]
drivers/dma/sf-pdma/Makefile [new file with mode: 0644]
drivers/dma/sf-pdma/sf-pdma.c [new file with mode: 0644]
drivers/dma/sf-pdma/sf-pdma.h [new file with mode: 0644]
drivers/dma/sh/rcar-dmac.c
drivers/dma/sprd-dma.c
drivers/dma/ti/edma.c
drivers/dma/uniphier-mdmac.c
drivers/dma/xilinx/xilinx_dma.c
drivers/dma/zx_dma.c
drivers/firewire/core-cdev.c
drivers/firewire/core-iso.c
drivers/firewire/core.h
drivers/firewire/ohci.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/dmi_scan.c
drivers/firmware/imx/imx-dsp.c
drivers/firmware/imx/imx-scu-irq.c
drivers/firmware/imx/imx-scu.c
drivers/firmware/meson/meson_sm.c
drivers/firmware/qcom_scm-32.c
drivers/firmware/qcom_scm-64.c
drivers/firmware/qcom_scm.c
drivers/firmware/qcom_scm.h
drivers/firmware/tegra/bpmp.c
drivers/firmware/xilinx/zynqmp.c
drivers/gpio/gpio-104-dio-48e.c
drivers/gpio/gpio-104-idi-48.c
drivers/gpio/gpio-74x164.c
drivers/gpio/gpio-gpio-mm.c
drivers/gpio/gpio-max3191x.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pci-idio-16.c
drivers/gpio/gpio-pcie-idio-24.c
drivers/gpio/gpio-pisosr.c
drivers/gpio/gpio-uniphier.c
drivers/gpio/gpio-ws16c48.c
drivers/gpu/drm/amd/amdgpu/cik.c
drivers/gpu/drm/amd/amdgpu/si.c
drivers/gpu/drm/drm_property.c
drivers/gpu/drm/i915/Kconfig.debug
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/si.c
drivers/hv/hv_balloon.c
drivers/idle/intel_idle.c
drivers/iio/accel/cros_ec_accel_legacy.c
drivers/iio/common/cros_ec_sensors/Kconfig
drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/light/cros_ec_light_prox.c
drivers/input/keyboard/cros_ec_keyb.c
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_types.h
drivers/iommu/arm-smmu-impl.c
drivers/iommu/arm-smmu-qcom.c [new file with mode: 0644]
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c
drivers/iommu/arm-smmu.h
drivers/iommu/dma-iommu.c
drivers/iommu/dmar.c
drivers/iommu/exynos-iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/io-pgtable-arm-v7s.c
drivers/iommu/io-pgtable-arm.c
drivers/iommu/ioasid.c [new file with mode: 0644]
drivers/iommu/iommu.c
drivers/iommu/ipmmu-vmsa.c
drivers/iommu/msm_iommu.c
drivers/iommu/mtk_iommu.c
drivers/iommu/mtk_iommu.h
drivers/iommu/mtk_iommu_v1.c
drivers/iommu/of_iommu.c
drivers/iommu/omap-iommu.c
drivers/iommu/qcom_iommu.c
drivers/iommu/rockchip-iommu.c
drivers/iommu/s390-iommu.c
drivers/iommu/tegra-gart.c
drivers/iommu/tegra-smmu.c
drivers/iommu/virtio-iommu.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-bcm7038-l1.c
drivers/irqchip/irq-gic-v2m.c
drivers/irqchip/irq-gic-v3-its-pci-msi.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-ingenic.c
drivers/irqchip/irq-ls-extirq.c [new file with mode: 0644]
drivers/irqchip/irq-ti-sci-inta.c
drivers/irqchip/irq-zevio.c
drivers/irqchip/qcom-pdc.c
drivers/memory/atmel-ebi.c
drivers/memory/brcmstb_dpfe.c
drivers/memory/emif.c
drivers/memory/jedec_ddr.h
drivers/memory/mtk-smi.c
drivers/memory/of_memory.c
drivers/memory/of_memory.h
drivers/memory/samsung/Kconfig
drivers/memory/samsung/Makefile
drivers/memory/samsung/exynos5422-dmc.c [new file with mode: 0644]
drivers/memory/tegra/Kconfig
drivers/memory/tegra/Makefile
drivers/memory/tegra/mc.c
drivers/memory/tegra/mc.h
drivers/memory/tegra/tegra114.c
drivers/memory/tegra/tegra124.c
drivers/memory/tegra/tegra20-emc.c
drivers/memory/tegra/tegra30-emc.c [new file with mode: 0644]
drivers/memory/tegra/tegra30.c
drivers/memstick/host/jmb38x_ms.c
drivers/mfd/cros_ec_dev.c
drivers/misc/lkdtm/bugs.c
drivers/misc/lkdtm/core.c
drivers/misc/lkdtm/lkdtm.h
drivers/misc/pci_endpoint_test.c
drivers/misc/sram-exec.c
drivers/mtd/nand/onenand/Makefile
drivers/mtd/nand/onenand/samsung.c [deleted file]
drivers/mtd/nand/onenand/samsung_mtd.c [new file with mode: 0644]
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/fastmap-wl.c
drivers/mtd/ubi/fastmap.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/mtd/ubi/wl.h
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/emulex/benet/Kconfig
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/intel/e1000/e1000.h
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/ixgb/ixgb.h
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
drivers/net/ethernet/pensando/ionic/ionic_if.h
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
drivers/net/ethernet/synopsys/dwc-xlgmac-pci.c
drivers/net/ethernet/ti/cpsw_ale.c
drivers/net/phy/realtek.c
drivers/net/wan/z85230.h
drivers/nvme/host/core.c
drivers/nvmem/meson-efuse.c
drivers/of/address.c
drivers/of/base.c
drivers/of/fdt.c
drivers/of/of_private.h
drivers/of/overlay.c
drivers/of/property.c
drivers/of/unittest-data/testcases.dts
drivers/of/unittest-data/tests-address.dtsi [new file with mode: 0644]
drivers/of/unittest.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/access.c
drivers/pci/ats.c
drivers/pci/controller/Kconfig
drivers/pci/controller/Makefile
drivers/pci/controller/cadence/Kconfig [new file with mode: 0644]
drivers/pci/controller/cadence/Makefile [new file with mode: 0644]
drivers/pci/controller/cadence/pcie-cadence-ep.c [new file with mode: 0644]
drivers/pci/controller/cadence/pcie-cadence-host.c [new file with mode: 0644]
drivers/pci/controller/cadence/pcie-cadence-plat.c [new file with mode: 0644]
drivers/pci/controller/cadence/pcie-cadence.c [new file with mode: 0644]
drivers/pci/controller/cadence/pcie-cadence.h [new file with mode: 0644]
drivers/pci/controller/dwc/Kconfig
drivers/pci/controller/dwc/pci-dra7xx.c
drivers/pci/controller/dwc/pci-layerscape-ep.c
drivers/pci/controller/dwc/pci-layerscape.c
drivers/pci/controller/dwc/pci-meson.c
drivers/pci/controller/dwc/pcie-artpec6.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware-plat.c
drivers/pci/controller/dwc/pcie-designware.h
drivers/pci/controller/dwc/pcie-tegra194.c
drivers/pci/controller/dwc/pcie-uniphier.c
drivers/pci/controller/pci-aardvark.c
drivers/pci/controller/pci-ftpci100.c
drivers/pci/controller/pci-host-common.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/controller/pci-mvebu.c
drivers/pci/controller/pci-thunder-pem.c
drivers/pci/controller/pci-v3-semi.c
drivers/pci/controller/pci-versatile.c
drivers/pci/controller/pci-xgene.c
drivers/pci/controller/pcie-altera.c
drivers/pci/controller/pcie-cadence-ep.c [deleted file]
drivers/pci/controller/pcie-cadence-host.c [deleted file]
drivers/pci/controller/pcie-cadence.c [deleted file]
drivers/pci/controller/pcie-cadence.h [deleted file]
drivers/pci/controller/pcie-iproc-msi.c
drivers/pci/controller/pcie-iproc-platform.c
drivers/pci/controller/pcie-iproc.c
drivers/pci/controller/pcie-mediatek.c
drivers/pci/controller/pcie-mobiveil.c
drivers/pci/controller/pcie-rcar.c
drivers/pci/controller/pcie-rockchip-host.c
drivers/pci/controller/pcie-rockchip.h
drivers/pci/controller/pcie-xilinx-nwl.c
drivers/pci/controller/pcie-xilinx.c
drivers/pci/controller/vmd.c
drivers/pci/endpoint/functions/pci-epf-test.c
drivers/pci/endpoint/pci-epc-mem.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/acpiphp_glue.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/rpaphp_core.c
drivers/pci/iov.c
drivers/pci/msi.c
drivers/pci/of.c
drivers/pci/pci-bridge-emul.c
drivers/pci/pci-bridge-emul.h
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aer.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/dpc.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/pcie/ptm.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/pci/switch/switchtec.c
drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c
drivers/phy/marvell/Kconfig
drivers/phy/marvell/Makefile
drivers/phy/marvell/phy-mmp3-usb.c [new file with mode: 0644]
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-msm.h
drivers/pinctrl/qcom/pinctrl-sdm845.c
drivers/platform/chrome/Kconfig
drivers/platform/chrome/Makefile
drivers/platform/chrome/cros_ec.c
drivers/platform/chrome/cros_ec_ishtp.c
drivers/platform/chrome/cros_ec_lpc.c
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/chrome/cros_ec_rpmsg.c
drivers/platform/chrome/cros_ec_sensorhub.c [new file with mode: 0644]
drivers/platform/chrome/cros_usbpd_logger.c
drivers/platform/chrome/wilco_ec/Kconfig
drivers/platform/chrome/wilco_ec/Makefile
drivers/platform/chrome/wilco_ec/core.c
drivers/platform/chrome/wilco_ec/debugfs.c
drivers/platform/chrome/wilco_ec/keyboard_leds.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/sysfs.c
drivers/platform/chrome/wilco_ec/telemetry.c
drivers/platform/x86/Kconfig
drivers/platform/x86/dell_rbu.c
drivers/power/avs/Kconfig
drivers/pwm/pwm-stm32.c
drivers/pwm/pwm-sun4i.c
drivers/rapidio/devices/tsi721.c
drivers/rapidio/rio-access.c
drivers/rapidio/rio-driver.c
drivers/reset/Kconfig
drivers/reset/core.c
drivers/reset/hisilicon/reset-hi3660.c
drivers/reset/reset-meson-audio-arb.c
drivers/reset/reset-meson.c
drivers/reset/reset-uniphier-glue.c
drivers/reset/reset-zynqmp.c
drivers/rtc/Kconfig
drivers/rtc/interface.c
drivers/rtc/rtc-ab-b5ze-s3.c
drivers/rtc/rtc-armada38x.c
drivers/rtc/rtc-asm9260.c
drivers/rtc/rtc-aspeed.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-bd70528.c
drivers/rtc/rtc-brcmstb-waketimer.c
drivers/rtc/rtc-cadence.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-cros-ec.c
drivers/rtc/rtc-da9063.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-digicolor.c
drivers/rtc/rtc-ds1216.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-ds1343.c
drivers/rtc/rtc-ds1347.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1685.c
drivers/rtc/rtc-em3027.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-fsl-ftm-alarm.c
drivers/rtc/rtc-goldfish.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lpc24xx.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-mc146818-lib.c
drivers/rtc/rtc-meson.c
drivers/rtc/rtc-msm6242.c
drivers/rtc/rtc-mt7622.c
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-pcf2127.c
drivers/rtc/rtc-pcf8523.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pic32.c
drivers/rtc/rtc-pm8xxx.c
drivers/rtc/rtc-r7301.c
drivers/rtc/rtc-rtd119x.c
drivers/rtc/rtc-rv3028.c
drivers/rtc/rtc-rx6110.c
drivers/rtc/rtc-s35390a.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sc27xx.c
drivers/rtc/rtc-sirfsoc.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-st-lpc.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-stm32.c
drivers/rtc/rtc-sun6i.c
drivers/rtc/rtc-sunxi.c
drivers/rtc/rtc-tegra.c
drivers/rtc/rtc-tps65910.c
drivers/rtc/rtc-tx4939.c
drivers/rtc/rtc-v3020.c
drivers/rtc/rtc-vt8500.c
drivers/rtc/rtc-wilco-ec.c
drivers/rtc/rtc-xgene.c
drivers/rtc/rtc-zynqmp.c
drivers/rtc/sysfs.c
drivers/s390/crypto/zcrypt_error.h
drivers/s390/scsi/Makefile
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_diag.c [new file with mode: 0644]
drivers/s390/scsi/zfcp_diag.h [new file with mode: 0644]
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs.c
drivers/scsi/NCR5380.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/src.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/arm/acornscsi.c
drivers/scsi/atari_scsi.c
drivers/scsi/atp870u.c
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_attr.c
drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/csiostor/csio_hw.c
drivers/scsi/csiostor/csio_init.c
drivers/scsi/csiostor/csio_lnode.c
drivers/scsi/csiostor/csio_mb.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/cxlflash/main.c
drivers/scsi/esas2r/esas2r_flash.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/fnic/vnic_dev.c
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/hosts.c
drivers/scsi/ips.c
drivers/scsi/isci/port_config.c
drivers/scsi/isci/remote_device.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_logmsg.h
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/lpfc/lpfc_nvmet.c
drivers/scsi/lpfc/lpfc_nvmet.h
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/mac_scsi.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_ctl.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/nsp32.c
drivers/scsi/pcmcia/Kconfig
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pm8001/pm8001_ctl.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm8001_sas.h
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/pm8001/pm80xx_hwi.h
drivers/scsi/qedf/qedf_dbg.h
drivers/scsi/qedf/qedf_main.c
drivers/scsi/qedi/qedi_dbg.h
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_nvme.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_tmpl.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_logging.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_trace.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/smartpqi/smartpqi.h
drivers/scsi/smartpqi/smartpqi_init.c
drivers/scsi/smartpqi/smartpqi_sas_transport.c
drivers/scsi/sun3_scsi.c
drivers/scsi/ufs/Kconfig
drivers/scsi/ufs/Makefile
drivers/scsi/ufs/ti-j721e-ufs.c [new file with mode: 0644]
drivers/scsi/ufs/ufs-hisi.c
drivers/scsi/ufs/ufs-mediatek.c
drivers/scsi/ufs/ufs-qcom.c
drivers/scsi/ufs/ufs-qcom.h
drivers/scsi/ufs/ufs-sysfs.c
drivers/scsi/ufs/ufs_bsg.c
drivers/scsi/ufs/ufshcd-dwc.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/scsi/ufs/ufshci.h
drivers/scsi/zorro_esp.c
drivers/soc/amlogic/meson-gx-socinfo.c
drivers/soc/atmel/Kconfig
drivers/soc/atmel/Makefile
drivers/soc/atmel/sfr.c [new file with mode: 0644]
drivers/soc/fsl/Kconfig
drivers/soc/fsl/Makefile
drivers/soc/fsl/rcpm.c [new file with mode: 0644]
drivers/soc/imx/soc-imx-scu.c
drivers/soc/imx/soc-imx8.c
drivers/soc/mediatek/mtk-scpsys.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/llcc-qcom.c [new file with mode: 0644]
drivers/soc/qcom/llcc-sdm845.c [deleted file]
drivers/soc/qcom/llcc-slice.c [deleted file]
drivers/soc/qcom/qcom_aoss.c
drivers/soc/qcom/rpmpd.c
drivers/soc/qcom/smd-rpm.c
drivers/soc/qcom/socinfo.c
drivers/soc/renesas/Kconfig
drivers/soc/renesas/Makefile
drivers/soc/renesas/r8a7743-sysc.c
drivers/soc/renesas/r8a7745-sysc.c
drivers/soc/renesas/r8a77470-sysc.c
drivers/soc/renesas/r8a774a1-sysc.c
drivers/soc/renesas/r8a774b1-sysc.c [new file with mode: 0644]
drivers/soc/renesas/r8a774c0-sysc.c
drivers/soc/renesas/r8a7779-sysc.c
drivers/soc/renesas/r8a7790-sysc.c
drivers/soc/renesas/r8a7791-sysc.c
drivers/soc/renesas/r8a7792-sysc.c
drivers/soc/renesas/r8a7794-sysc.c
drivers/soc/renesas/r8a7795-sysc.c
drivers/soc/renesas/r8a7796-sysc.c
drivers/soc/renesas/r8a77965-sysc.c
drivers/soc/renesas/r8a77970-sysc.c
drivers/soc/renesas/r8a77980-sysc.c
drivers/soc/renesas/r8a77990-sysc.c
drivers/soc/renesas/r8a77995-sysc.c
drivers/soc/renesas/rcar-rst.c
drivers/soc/renesas/rcar-sysc.c
drivers/soc/renesas/rcar-sysc.h
drivers/soc/renesas/renesas-soc.c
drivers/soc/samsung/Kconfig
drivers/soc/samsung/Makefile
drivers/soc/samsung/exynos-asv.c [new file with mode: 0644]
drivers/soc/samsung/exynos-asv.h [new file with mode: 0644]
drivers/soc/samsung/exynos-chipid.c
drivers/soc/samsung/exynos5422-asv.c [new file with mode: 0644]
drivers/soc/samsung/exynos5422-asv.h [new file with mode: 0644]
drivers/soc/tegra/Kconfig
drivers/soc/tegra/Makefile
drivers/soc/tegra/flowctrl.c
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse-tegra30.c
drivers/soc/tegra/fuse/fuse.h
drivers/soc/tegra/pmc.c
drivers/soc/tegra/regulators-tegra20.c [new file with mode: 0644]
drivers/soc/tegra/regulators-tegra30.c [new file with mode: 0644]
drivers/soc/ti/Makefile
drivers/soc/ti/omap_prm.c [new file with mode: 0644]
drivers/soc/xilinx/zynqmp_pm_domains.c
drivers/staging/gasket/gasket_constants.h
drivers/staging/gasket/gasket_core.c
drivers/staging/gasket/gasket_core.h
drivers/target/iscsi/cxgbit/cxgbit_ddp.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_auth.h
drivers/target/iscsi/iscsi_target_parameters.h
drivers/target/target_core_fabric_lib.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/target_core_user.c
drivers/target/target_core_xcopy.c
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/amlogic_thermal.c [new file with mode: 0644]
drivers/thermal/cpu_cooling.c
drivers/thermal/intel/intel_soc_dts_iosf.c
drivers/thermal/intel/intel_soc_dts_iosf.h
drivers/thermal/qcom/tsens-8960.c
drivers/thermal/qcom/tsens-common.c
drivers/thermal/qcom/tsens-v0_1.c
drivers/thermal/qcom/tsens-v1.c
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/thermal-generic-adc.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_mmio.c
drivers/tty/Kconfig
drivers/tty/amiserial.c
drivers/tty/hvc/Kconfig
drivers/tty/hvc/hvc_dcc.c
drivers/tty/rocket.c
drivers/tty/serdev/core.c
drivers/tty/serial/8250/8250_aspeed_vuart.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_exar.c
drivers/tty/serial/8250/8250_lpss.c
drivers/tty/serial/8250/8250_mtk.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/fsl_linflexuart.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/ifx6x60.c
drivers/tty/serial/imx.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/samsung.c [deleted file]
drivers/tty/serial/samsung_tty.c [new file with mode: 0644]
drivers/tty/serial/serial-tegra.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/sirfsoc_uart.h
drivers/tty/serial/sprd_serial.c
drivers/tty/serial/stm32-usart.c
drivers/tty/serial/uartlite.c
drivers/tty/tty_io.c
drivers/tty/tty_ldisc.c
drivers/tty/vt/keyboard.c
drivers/tty/vt/vc_screen.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hub.c
drivers/usb/host/pci-quirks.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/storage/transport.c
drivers/usb/storage/uas.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_config.c
drivers/vfio/pci/vfio_pci_private.h
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/fbdev/aty/radeon_pm.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/efifb.c
drivers/video/logo/.gitignore
drivers/video/logo/Makefile
drivers/video/logo/pnmtologo.c [new file with mode: 0644]
drivers/xen/balloon.c
drivers/xen/platform-pci.c
fs/autofs/autofs_i.h
fs/autofs/expire.c
fs/autofs/root.c
fs/binfmt_elf.c
fs/buffer.c
fs/ceph/cache.c
fs/ceph/cache.h
fs/ceph/mds_client.c
fs/ceph/mdsmap.c
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/cifsfs.c
fs/compat_ioctl.c
fs/dcache.c
fs/debugfs/inode.c
fs/direct-io.c
fs/eventpoll.c
fs/exec.c
fs/fuse/Kconfig
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/readdir.c
fs/fuse/virtio_fs.c
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/inode.c
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/lops.c
fs/gfs2/lops.h
fs/gfs2/meta_io.c
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/recovery.c
fs/gfs2/super.c
fs/gfs2/sys.c
fs/gfs2/trans.c
fs/gfs2/util.c
fs/gfs2/util.h
fs/hugetlbfs/inode.c
fs/ioctl.c
fs/iomap/direct-io.c
fs/jffs2/nodelist.c
fs/kernfs/mount.c
fs/namei.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/ocfs2/acl.c
fs/overlayfs/namei.c
fs/pipe.c
fs/proc/Kconfig
fs/proc/array.c
fs/proc/generic.c
fs/proc/internal.h
fs/pstore/platform.c
fs/quota/dquot.c
fs/ubifs/debug.c
fs/ubifs/journal.c
fs/ubifs/orphan.c
fs/ubifs/sb.c
fs/ubifs/super.c
fs/ubifs/tnc_commit.c
fs/userfaultfd.c
fs/xfs/Makefile
fs/xfs/kmem.c
fs/xfs/kmem.h
fs/xfs/libxfs/xfs_ag_resv.c
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.h
fs/xfs/libxfs/xfs_alloc_btree.c
fs/xfs/libxfs/xfs_attr.c
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_attr_leaf.h
fs/xfs/libxfs/xfs_attr_remote.c
fs/xfs/libxfs/xfs_bit.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_da_btree.h
fs/xfs/libxfs/xfs_da_format.c [deleted file]
fs/xfs/libxfs/xfs_da_format.h
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2.h
fs/xfs/libxfs/xfs_dir2_block.c
fs/xfs/libxfs/xfs_dir2_data.c
fs/xfs/libxfs/xfs_dir2_leaf.c
fs/xfs/libxfs/xfs_dir2_node.c
fs/xfs/libxfs/xfs_dir2_priv.h
fs/xfs/libxfs/xfs_dir2_sf.c
fs/xfs/libxfs/xfs_dquot_buf.c
fs/xfs/libxfs/xfs_format.h
fs/xfs/libxfs/xfs_fs.h
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_iext_tree.c
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/libxfs/xfs_inode_buf.h
fs/xfs/libxfs/xfs_inode_fork.c
fs/xfs/libxfs/xfs_inode_fork.h
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/libxfs/xfs_log_recover.h
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/libxfs/xfs_rmap.c
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_trans_inode.c
fs/xfs/libxfs/xfs_trans_resv.c
fs/xfs/libxfs/xfs_types.h
fs/xfs/scrub/attr.c
fs/xfs/scrub/bitmap.c
fs/xfs/scrub/common.h
fs/xfs/scrub/dabtree.c
fs/xfs/scrub/dabtree.h
fs/xfs/scrub/dir.c
fs/xfs/scrub/fscounters.c
fs/xfs/scrub/health.c
fs/xfs/scrub/parent.c
fs/xfs/scrub/quota.c
fs/xfs/scrub/scrub.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h
fs/xfs/xfs_attr_inactive.c
fs/xfs/xfs_attr_list.c
fs/xfs/xfs_bmap_item.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_bmap_util.h
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_dir2_readdir.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_dquot_item.h
fs/xfs/xfs_error.c
fs/xfs/xfs_error.h
fs/xfs/xfs_extent_busy.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_file.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_fsmap.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icreate_item.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_ioctl.h
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_ioctl32.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iomap.h
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_iwalk.c
fs/xfs/xfs_linux.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_message.c
fs/xfs/xfs_message.h
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm.h
fs/xfs/xfs_qm_bhv.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quotaops.c
fs/xfs/xfs_refcount_item.c
fs/xfs/xfs_reflink.c
fs/xfs/xfs_reflink.h
fs/xfs/xfs_rmap_item.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_super.c
fs/xfs/xfs_super.h
fs/xfs/xfs_symlink.c
fs/xfs/xfs_symlink.h
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_dquot.c
fs/xfs/xfs_xattr.c
include/Kbuild [deleted file]
include/asm-generic/4level-fixup.h [deleted file]
include/asm-generic/5level-fixup.h
include/asm-generic/Kbuild
include/asm-generic/bitops/find.h
include/asm-generic/export.h
include/asm-generic/pgtable-nop4d.h
include/asm-generic/pgtable-nopmd.h
include/asm-generic/pgtable-nopud.h
include/asm-generic/pgtable.h
include/asm-generic/tlb.h
include/dt-bindings/dma/x1000-dma.h [new file with mode: 0644]
include/dt-bindings/pinctrl/rockchip.h
include/dt-bindings/power/qcom-rpmpd.h
include/dt-bindings/reset/amlogic,meson-a1-reset.h [new file with mode: 0644]
include/dt-bindings/reset/amlogic,meson-axg-audio-arb.h
include/dt-bindings/reset/realtek,rtd1295.h [new file with mode: 0644]
include/linux/aer.h
include/linux/bitmap.h
include/linux/bitops.h
include/linux/build_bug.h
include/linux/ceph/libceph.h
include/linux/cpu_cooling.h
include/linux/cpuidle.h
include/linux/dcache.h
include/linux/dma/sprd-dma.h
include/linux/dmar.h
include/linux/dmi.h
include/linux/energy_model.h
include/linux/export.h
include/linux/falloc.h
include/linux/firmware/meson/meson_sm.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/fs.h
include/linux/genalloc.h
include/linux/gfp.h
include/linux/hrtimer.h
include/linux/hugetlb.h
include/linux/interrupt.h
include/linux/io-pgtable.h
include/linux/ioasid.h [new file with mode: 0644]
include/linux/iommu.h
include/linux/irq.h
include/linux/irq_work.h
include/linux/irqchip/arm-gic-v3.h
include/linux/irqchip/ingenic.h [deleted file]
include/linux/irqdomain.h
include/linux/kasan.h
include/linux/kcov.h
include/linux/kernel.h
include/linux/libfdt_env.h
include/linux/license.h
include/linux/logic_pio.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/memory_hotplug.h
include/linux/mfd/stm32-timers.h
include/linux/mfd/syscon/atmel-matrix.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/module.h
include/linux/moduleloader.h
include/linux/moduleparam.h
include/linux/namei.h
include/linux/notifier.h
include/linux/of_address.h
include/linux/of_pci.h
include/linux/page-isolation.h
include/linux/pci-ats.h
include/linux/pci-epc.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/percpu-refcount.h
include/linux/platform_data/cros_ec_proto.h
include/linux/platform_data/cros_ec_sensorhub.h [new file with mode: 0644]
include/linux/platform_data/ti-prm.h [new file with mode: 0644]
include/linux/platform_data/wilco-ec.h
include/linux/pm_qos.h
include/linux/pm_wakeup.h
include/linux/proc_fs.h
include/linux/pwm.h
include/linux/qcom_scm.h
include/linux/rbtree_augmented.h
include/linux/reset-controller.h
include/linux/reset.h
include/linux/resource_ext.h
include/linux/rtc.h
include/linux/rtc/ds1685.h
include/linux/sched.h
include/linux/skmsg.h
include/linux/slab.h
include/linux/soc/mmp/cputype.h [new file with mode: 0644]
include/linux/soc/qcom/irq.h [new file with mode: 0644]
include/linux/soc/qcom/llcc-qcom.h
include/linux/string.h
include/linux/swap.h
include/linux/sysctl.h
include/linux/thermal.h
include/linux/thread_info.h
include/linux/vmalloc.h
include/linux/vmstat.h
include/net/tls.h
include/scsi/iscsi_proto.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/soc/tegra/mc.h
include/target/target_core_base.h
include/trace/events/kmem.h
include/trace/trace_events.h
include/uapi/asm-generic/ipcbuf.h
include/uapi/asm-generic/msgbuf.h
include/uapi/asm-generic/sembuf.h
include/uapi/linux/chio.h
include/uapi/linux/iommu.h
include/uapi/linux/kcov.h
include/uapi/linux/kvm.h
include/uapi/linux/pci_regs.h
include/uapi/linux/scc.h
include/uapi/linux/serial_core.h
init/Kconfig
kernel/Makefile
kernel/bpf/stackmap.c
kernel/dma/remap.c
kernel/events/uprobes.c
kernel/fork.c
kernel/gen_kheaders.sh
kernel/irq/chip.c
kernel/irq/irqdesc.c
kernel/irq_work.c
kernel/kcov.c
kernel/module.c
kernel/notifier.c
kernel/power/qos.c
kernel/printk/printk.c
kernel/profile.c
kernel/sched/cpufreq_schedutil.c
kernel/sys.c
kernel/sysctl.c
kernel/time/hrtimer.c
kernel/time/time.c
kernel/trace/Kconfig
kernel/trace/Makefile
kernel/trace/bpf_trace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_events_inject.c [new file with mode: 0644]
lib/Kconfig.debug
lib/Kconfig.kasan
lib/Makefile
lib/bitmap.c
lib/devres.c
lib/find_bit.c
lib/genalloc.c
lib/logic_pio.c
lib/math/rational.c
lib/test_bitmap.c
lib/test_kasan.c
lib/test_meminit.c
lib/ubsan.c
lib/vsprintf.c
mm/Kconfig
mm/cma.c
mm/cma_debug.c
mm/filemap.c
mm/gup.c
mm/huge_memory.c
mm/hugetlb.c
mm/hwpoison-inject.c
mm/internal.h
mm/kasan/common.c
mm/kasan/generic_report.c
mm/kasan/kasan.h
mm/khugepaged.c
mm/ksm.c
mm/madvise.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/page_alloc.c
mm/page_io.c
mm/page_isolation.c
mm/pgtable-generic.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swapfile.c
mm/userfaultfd.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
mm/workingset.c
mm/z3fold.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/core/filter.c
net/core/skmsg.c
net/ipv4/tcp_bpf.c
net/openvswitch/datapath.c
net/sched/sch_mq.c
net/sched/sch_mqprio.c
net/sched/sch_multiq.c
net/sched/sch_prio.c
net/sunrpc/rpc_pipe.c
net/tipc/socket.c
net/tls/tls_main.c
net/tls/tls_sw.c
scripts/.gitignore
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.build
scripts/Makefile.headersinst
scripts/Makefile.lib
scripts/Makefile.modpost
scripts/Makefile.package
scripts/checkpatch.pl
scripts/dtc/Makefile
scripts/dtc/dtx_diff
scripts/get_maintainer.pl
scripts/jobserver-exec [new file with mode: 0755]
scripts/kallsyms.c
scripts/kconfig/Makefile
scripts/kconfig/conf.c
scripts/kconfig/mconf-cfg.sh
scripts/kconfig/nconf-cfg.sh
scripts/kconfig/parser.y
scripts/kernel-doc
scripts/mod/modpost.c
scripts/mod/modpost.h
scripts/nsdeps
scripts/package/buildtar
scripts/pnmtologo.c [deleted file]
scripts/setlocalversion
scripts/spelling.txt
scripts/sphinx-pre-install
scripts/ver_linux
security/apparmor/Kconfig
security/apparmor/apparmorfs.c
security/apparmor/domain.c
security/apparmor/file.c
security/apparmor/include/apparmor.h
security/apparmor/include/file.h
security/apparmor/include/match.h
security/apparmor/include/path.h
security/apparmor/include/policy_unpack.h
security/apparmor/label.c
security/apparmor/lsm.c
security/apparmor/match.c
security/apparmor/mount.c
security/apparmor/policy.c
security/apparmor/policy_unpack.c
tools/arch/x86/lib/x86-opcode-map.txt
tools/build/Makefile.feature
tools/build/feature/Makefile
tools/build/feature/test-libbpf.c [new file with mode: 0644]
tools/pci/pcitest.c
tools/perf/Makefile.config
tools/perf/Makefile.perf
tools/perf/arch/arm/tests/dwarf-unwind.c
tools/perf/arch/arm64/tests/dwarf-unwind.c
tools/perf/arch/powerpc/tests/dwarf-unwind.c
tools/perf/arch/s390/annotate/instructions.c
tools/perf/arch/x86/tests/dwarf-unwind.c
tools/perf/arch/x86/tests/insn-x86-dat-32.c
tools/perf/arch/x86/tests/insn-x86-dat-64.c
tools/perf/arch/x86/tests/insn-x86-dat-src.c
tools/perf/arch/x86/util/event.c
tools/perf/builtin-diff.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/tests/Build
tools/perf/tests/builtin-test.c
tools/perf/tests/code-reading.c
tools/perf/tests/map_groups.c [deleted file]
tools/perf/tests/maps.c [new file with mode: 0644]
tools/perf/tests/tests.h
tools/perf/tests/thread-maps-share.c [new file with mode: 0644]
tools/perf/tests/thread-mg-share.c [deleted file]
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/ui/browsers/annotate.c
tools/perf/ui/stdio/hist.c
tools/perf/util/Build
tools/perf/util/affinity.c [new file with mode: 0644]
tools/perf/util/affinity.h [new file with mode: 0644]
tools/perf/util/annotate.c
tools/perf/util/bpf-event.c
tools/perf/util/callchain.c
tools/perf/util/cs-etm.c
tools/perf/util/db-export.c
tools/perf/util/event.c
tools/perf/util/fncache.c [new file with mode: 0644]
tools/perf/util/fncache.h [new file with mode: 0644]
tools/perf/util/hist.c
tools/perf/util/intel-pt.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/map_groups.h [deleted file]
tools/perf/util/map_symbol.h
tools/perf/util/maps.h [new file with mode: 0644]
tools/perf/util/perf_regs.h
tools/perf/util/pmu.c
tools/perf/util/probe-event.c
tools/perf/util/python-ext-sources
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/srccode.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/synthetic-events.c
tools/perf/util/thread-stack.c
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/unwind-libdw.c
tools/perf/util/unwind-libunwind-local.c
tools/perf/util/unwind-libunwind.c
tools/perf/util/unwind.h
tools/perf/util/vdso.c
tools/testing/selftests/Makefile
tools/testing/selftests/bpf/test_sockmap.c
tools/testing/selftests/bpf/xdping.c
tools/testing/selftests/filesystems/epoll/.gitignore [new file with mode: 0644]
tools/testing/selftests/filesystems/epoll/Makefile [new file with mode: 0644]
tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c [new file with mode: 0644]
tools/testing/selftests/memfd/memfd_test.c
tools/testing/selftests/net/forwarding/tc_common.sh
tools/testing/selftests/net/pmtu.sh
tools/testing/selftests/net/tls.c
tools/testing/selftests/vm/config
tools/testing/selftests/x86/single_step_syscall.c
usr/include/Makefile

index 89c411b..4b32eaa 100644 (file)
@@ -1,2 +1,4 @@
 *.c   diff=cpp
 *.h   diff=cpp
+*.dtsi diff=dts
+*.dts  diff=dts
index 70580bd..72ef86a 100644 (file)
@@ -32,7 +32,6 @@
 *.lzo
 *.mod
 *.mod.c
-*.ns_deps
 *.o
 *.o.*
 *.patch
@@ -61,6 +60,7 @@ modules.order
 /System.map
 /Module.markers
 /modules.builtin.modinfo
+/modules.nsdeps
 
 #
 # RPM spec file (make rpm-pkg)
index e7f0341..1fd03c7 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -156,6 +156,7 @@ Mark Brown <broonie@sirena.org.uk>
 Mark Yao <markyao0591@gmail.com> <mark.yao@rock-chips.com>
 Martin Kepplinger <martink@posteo.de> <martin.kepplinger@theobroma-systems.com>
 Martin Kepplinger <martink@posteo.de> <martin.kepplinger@ginzinger.com>
+Martin Kepplinger <martink@posteo.de> <martin.kepplinger@puri.sm>
 Mathieu Othacehe <m.othacehe@gmail.com>
 Matthew Wilcox <willy@infradead.org> <matthew.r.wilcox@intel.com>
 Matthew Wilcox <willy@infradead.org> <matthew@wil.cx>
diff --git a/CREDITS b/CREDITS
index 031605d..9602b0f 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1875,8 +1875,9 @@ S: The Netherlands
 
 N: Martin Kepplinger
 E: martink@posteo.de
-E: martin.kepplinger@ginzinger.com
+E: martin.kepplinger@puri.sm
 W: http://www.martinkepplinger.com
+P: 4096R/5AB387D3 F208 2B88 0F9E 4239 3468  6E3F 5003 98DF 5AB3 87D3
 D: mma8452 accelerators iio driver
 D: pegasus_notetaker input driver
 D: Kernel fixes and cleanups
index 8062953..950cafc 100644 (file)
@@ -6,10 +6,19 @@ Description:  Configures which IO port the host side of the UART
 Users:         OpenBMC.  Proposed changes should be mailed to
                openbmc@lists.ozlabs.org
 
-What:          /sys/bus/platform/drivers/aspeed-vuart*/sirq
+What:          /sys/bus/platform/drivers/aspeed-vuart/*/sirq
 Date:          April 2017
 Contact:       Jeremy Kerr <jk@ozlabs.org>
 Description:   Configures which interrupt number the host side of
                the UART will appear on the host <-> BMC LPC bus.
 Users:         OpenBMC.  Proposed changes should be mailed to
                openbmc@lists.ozlabs.org
+
+What:          /sys/bus/platform/drivers/aspeed-vuart/*/sirq_polarity
+Date:          July 2019
+Contact:       Oskar Senft <osk@google.com>
+Description:   Configures the polarity of the serial interrupt to the
+               host via the BMC LPC bus.
+               Set to 0 for active-low or 1 for active-high.
+Users:         OpenBMC.  Proposed changes should be mailed to
+               openbmc@lists.ozlabs.org
index 36258bc..614874e 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/bus/coresight/devices/<memory_map>.etm/enable_source
+What:          /sys/bus/coresight/devices/etm<N>/enable_source
 Date:          April 2015
 KernelVersion:  4.01
 Contact:        Mathieu Poirier <mathieu.poirier@linaro.org>
@@ -8,82 +8,82 @@ Description:  (RW) Enable/disable tracing on this specific trace entiry.
                of coresight components linking the source to the sink is
                configured and managed automatically by the coresight framework.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/cpu
+What:          /sys/bus/coresight/devices/etm<N>/cpu
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) The CPU this tracing entity is associated with.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nr_pe_cmp
+What:          /sys/bus/coresight/devices/etm<N>/nr_pe_cmp
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of PE comparator inputs that are
                available for tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nr_addr_cmp
+What:          /sys/bus/coresight/devices/etm<N>/nr_addr_cmp
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of address comparator pairs that are
                available for tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nr_cntr
+What:          /sys/bus/coresight/devices/etm<N>/nr_cntr
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of counters that are available for
                tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nr_ext_inp
+What:          /sys/bus/coresight/devices/etm<N>/nr_ext_inp
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates how many external inputs are implemented.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/numcidc
+What:          /sys/bus/coresight/devices/etm<N>/numcidc
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of Context ID comparators that are
                available for tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/numvmidc
+What:          /sys/bus/coresight/devices/etm<N>/numvmidc
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of VMID comparators that are available
                for tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nrseqstate
+What:          /sys/bus/coresight/devices/etm<N>/nrseqstate
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of sequencer states that are
                implemented.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nr_resource
+What:          /sys/bus/coresight/devices/etm<N>/nr_resource
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of resource selection pairs that are
                available for tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/nr_ss_cmp
+What:          /sys/bus/coresight/devices/etm<N>/nr_ss_cmp
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Indicates the number of single-shot comparator controls that
                are available for tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/reset
+What:          /sys/bus/coresight/devices/etm<N>/reset
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (W) Cancels all configuration on a trace unit and set it back
                to its boot configuration.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mode
+What:          /sys/bus/coresight/devices/etm<N>/mode
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
@@ -91,302 +91,349 @@ Description:      (RW) Controls various modes supported by this ETM, for example
                P0 instruction tracing, branch broadcast, cycle counting and
                context ID tracing.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/pe
+What:          /sys/bus/coresight/devices/etm<N>/pe
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls which PE to trace.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/event
+What:          /sys/bus/coresight/devices/etm<N>/event
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls the tracing of arbitrary events from bank 0 to 3.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/event_instren
+What:          /sys/bus/coresight/devices/etm<N>/event_instren
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls the behavior of the events in bank 0 to 3.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/event_ts
+What:          /sys/bus/coresight/devices/etm<N>/event_ts
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls the insertion of global timestamps in the trace
                streams.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/syncfreq
+What:          /sys/bus/coresight/devices/etm<N>/syncfreq
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls how often trace synchronization requests occur.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/cyc_threshold
+What:          /sys/bus/coresight/devices/etm<N>/cyc_threshold
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Sets the threshold value for cycle counting.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/bb_ctrl
+What:          /sys/bus/coresight/devices/etm<N>/bb_ctrl
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls which regions in the memory map are enabled to
                use branch broadcasting.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/event_vinst
+What:          /sys/bus/coresight/devices/etm<N>/event_vinst
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls instruction trace filtering.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/s_exlevel_vinst
+What:          /sys/bus/coresight/devices/etm<N>/s_exlevel_vinst
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) In Secure state, each bit controls whether instruction
                tracing is enabled for the corresponding exception level.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/ns_exlevel_vinst
+What:          /sys/bus/coresight/devices/etm<N>/ns_exlevel_vinst
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) In non-secure state, each bit controls whether instruction
                tracing is enabled for the corresponding exception level.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/addr_idx
+What:          /sys/bus/coresight/devices/etm<N>/addr_idx
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Select which address comparator or pair (of comparators) to
                work with.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/addr_instdatatype
+What:          /sys/bus/coresight/devices/etm<N>/addr_instdatatype
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls what type of comparison the trace unit performs.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/addr_single
+What:          /sys/bus/coresight/devices/etm<N>/addr_single
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Used to setup single address comparator values.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/addr_range
+What:          /sys/bus/coresight/devices/etm<N>/addr_range
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Used to setup address range comparator values.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/seq_idx
+What:          /sys/bus/coresight/devices/etm<N>/seq_idx
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Select which sequensor.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/seq_state
+What:          /sys/bus/coresight/devices/etm<N>/seq_state
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Use this to set, or read, the sequencer state.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/seq_event
+What:          /sys/bus/coresight/devices/etm<N>/seq_event
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Moves the sequencer state to a specific state.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/seq_reset_event
+What:          /sys/bus/coresight/devices/etm<N>/seq_reset_event
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Moves the sequencer to state 0 when a programmed event
                occurs.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/cntr_idx
+What:          /sys/bus/coresight/devices/etm<N>/cntr_idx
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Select which counter unit to work with.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/cntrldvr
+What:          /sys/bus/coresight/devices/etm<N>/cntrldvr
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) This sets or returns the reload count value of the
                specific counter.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/cntr_val
+What:          /sys/bus/coresight/devices/etm<N>/cntr_val
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) This sets or returns the current count value of the
                 specific counter.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/cntr_ctrl
+What:          /sys/bus/coresight/devices/etm<N>/cntr_ctrl
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls the operation of the selected counter.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/res_idx
+What:          /sys/bus/coresight/devices/etm<N>/res_idx
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Select which resource selection unit to work with.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/res_ctrl
+What:          /sys/bus/coresight/devices/etm<N>/res_ctrl
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Controls the selection of the resources in the trace unit.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/ctxid_idx
+What:          /sys/bus/coresight/devices/etm<N>/ctxid_idx
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Select which context ID comparator to work with.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/ctxid_pid
+What:          /sys/bus/coresight/devices/etm<N>/ctxid_pid
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Get/Set the context ID comparator value to trigger on.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/ctxid_masks
+What:          /sys/bus/coresight/devices/etm<N>/ctxid_masks
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Mask for all 8 context ID comparator value
                registers (if implemented).
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/vmid_idx
+What:          /sys/bus/coresight/devices/etm<N>/vmid_idx
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Select which virtual machine ID comparator to work with.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/vmid_val
+What:          /sys/bus/coresight/devices/etm<N>/vmid_val
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Get/Set the virtual machine ID comparator value to
                trigger on.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/vmid_masks
+What:          /sys/bus/coresight/devices/etm<N>/vmid_masks
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (RW) Mask for all 8 virtual machine ID comparator value
                registers (if implemented).
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcoslsr
+What:          /sys/bus/coresight/devices/etm<N>/addr_exlevel_s_ns
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (RW) Set the Exception Level matching bits for secure and
+               non-secure exception levels.
+
+What:          /sys/bus/coresight/devices/etm<N>/vinst_pe_cmp_start_stop
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (RW) Access the start stop control register for PE input
+               comparators.
+
+What:          /sys/bus/coresight/devices/etm<N>/addr_cmp_view
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (R) Print the current settings for the selected address
+               comparator.
+
+What:          /sys/bus/coresight/devices/etm<N>/sshot_idx
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (RW) Select the single shot control register to access.
+
+What:          /sys/bus/coresight/devices/etm<N>/sshot_ctrl
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (RW) Access the selected single shot control register.
+
+What:          /sys/bus/coresight/devices/etm<N>/sshot_status
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (R) Print the current value of the selected single shot
+               status register.
+
+What:          /sys/bus/coresight/devices/etm<N>/sshot_pe_ctrl
+Date:          December 2019
+KernelVersion: 5.5
+Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:   (RW) Access the selected single show PE comparator control
+               register.
+
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcoslsr
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the OS Lock Status Register (0x304).
                The value it taken directly  from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpdcr
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcpdcr
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Power Down Control Register
                (0x310).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpdsr
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcpdsr
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Power Down Status Register
                (0x314).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trclsr
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trclsr
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the SW Lock Status Register
                (0xFB4).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcauthstatus
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcauthstatus
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Authentication Status Register
                (0xFB8).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcdevid
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcdevid
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Device ID Register
                (0xFC8).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcdevtype
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcdevtype
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Device Type Register
                (0xFCC).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr0
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcpidr0
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Peripheral ID0 Register
                (0xFE0).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr1
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcpidr1
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Peripheral ID1 Register
                (0xFE4).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr2
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcpidr2
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Peripheral ID2 Register
                (0xFE8).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr3
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcpidr3
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the Peripheral ID3 Register
                (0xFEC).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcconfig
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trcconfig
 Date:          February 2016
 KernelVersion: 4.07
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the trace configuration register
                (0x010) as currently set by SW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trctraceid
+What:          /sys/bus/coresight/devices/etm<N>/mgmt/trctraceid
 Date:          February 2016
 KernelVersion: 4.07
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Print the content of the trace ID register (0x040).
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr0
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr0
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns the tracing capabilities of the trace unit (0x1E0).
                The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr1
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr1
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns the tracing capabilities of the trace unit (0x1E4).
                The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr2
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr2
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
@@ -394,7 +441,7 @@ Description:        (R) Returns the maximum size of the data value, data address,
                VMID, context ID and instuction address in the trace unit
                (0x1E8).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr3
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr3
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
@@ -403,42 +450,42 @@ Description:      (R) Returns the value associated with various resources
                architecture specification for more details (0x1E8).
                The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr4
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr4
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns how many resources the trace unit supports (0x1F0).
                The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr5
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr5
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns how many resources the trace unit supports (0x1F4).
                The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr8
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr8
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns the maximum speculation depth of the instruction
                trace stream. (0x180).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr9
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr9
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns the number of P0 right-hand keys that the trace unit
                can use (0x184).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr10
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr10
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:   (R) Returns the number of P1 right-hand keys that the trace unit
                can use (0x188).  The value is taken directly from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr11
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr11
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
@@ -446,7 +493,7 @@ Description:        (R) Returns the number of special P1 right-hand keys that the
                trace unit can use (0x18C).  The value is taken directly from
                the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr12
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr12
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
@@ -454,7 +501,7 @@ Description:        (R) Returns the number of conditional P1 right-hand keys that
                the trace unit can use (0x190).  The value is taken directly
                from the HW.
 
-What:          /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr13
+What:          /sys/bus/coresight/devices/etm<N>/trcidr/trcidr13
 Date:          April 2015
 KernelVersion: 4.01
 Contact:       Mathieu Poirier <mathieu.poirier@linaro.org>
index 8bfee55..450296c 100644 (file)
@@ -347,3 +347,16 @@ Description:
                If the device has any Peer-to-Peer memory registered, this
                file contains a '1' if the memory has been published for
                use outside the driver that owns the device.
+
+What:          /sys/bus/pci/devices/.../link/clkpm
+               /sys/bus/pci/devices/.../link/l0s_aspm
+               /sys/bus/pci/devices/.../link/l1_aspm
+               /sys/bus/pci/devices/.../link/l1_1_aspm
+               /sys/bus/pci/devices/.../link/l1_2_aspm
+               /sys/bus/pci/devices/.../link/l1_1_pcipm
+               /sys/bus/pci/devices/.../link/l1_2_pcipm
+Date:          October 2019
+Contact:       Heiner Kallweit <hkallweit1@gmail.com>
+Description:   If ASPM is supported for an endpoint, these files can be
+               used to disable or enable the individual power management
+               states. Write y/1/on to enable, n/0/off to disable.
index 8827a73..5f60b18 100644 (file)
@@ -31,6 +31,23 @@ Description:
                Output will a version string be similar to the example below:
                08B6
 
+What:          /sys/bus/platform/devices/GOOG000C\:00/usb_charge
+Date:          October 2019
+KernelVersion: 5.5
+Description:
+               Control the USB PowerShare Policy. USB PowerShare is a policy
+               which affects charging via the special USB PowerShare port
+               (marked with a small lightning bolt or battery icon) when in
+               low power states:
+               - In S0, the port will always provide power.
+               - In S0ix, if usb_charge is enabled, then power will be
+                 supplied to the port when on AC or if battery is > 50%.
+                 Else no power is supplied.
+               - In S5, if usb_charge is enabled, then power will be supplied
+                 to the port when on AC. Else no power is supplied.
+
+               Input should be either "0" or "1".
+
 What:          /sys/bus/platform/devices/GOOG000C\:00/version
 Date:          May 2019
 KernelVersion: 5.3
index e145e4d..d77bb60 100644 (file)
@@ -13,7 +13,7 @@ endif
 SPHINXBUILD   = sphinx-build
 SPHINXOPTS    =
 SPHINXDIRS    = .
-_SPHINXDIRS   = $(patsubst $(srctree)/Documentation/%/conf.py,%,$(wildcard $(srctree)/Documentation/*/conf.py))
+_SPHINXDIRS   = $(patsubst $(srctree)/Documentation/%/index.rst,%,$(wildcard $(srctree)/Documentation/*/index.rst))
 SPHINX_CONF   = conf.py
 PAPER         =
 BUILDDIR      = $(obj)/output
@@ -33,8 +33,6 @@ ifeq ($(HAVE_SPHINX),0)
 
 else # HAVE_SPHINX
 
-export SPHINXOPTS = $(shell perl -e 'open IN,"sphinx-build --version 2>&1 |"; while (<IN>) { if (m/([\d\.]+)/) { print "-jauto" if ($$1 >= "1.7") } ;} close IN')
-
 # User-friendly check for pdflatex and latexmk
 HAVE_PDFLATEX := $(shell if which $(PDFLATEX) >/dev/null 2>&1; then echo 1; else echo 0; fi)
 HAVE_LATEXMK := $(shell if which latexmk >/dev/null 2>&1; then echo 1; else echo 0; fi)
@@ -67,6 +65,8 @@ quiet_cmd_sphinx = SPHINX  $@ --> file://$(abspath $(BUILDDIR)/$3/$4)
       cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media $2 && \
        PYTHONDONTWRITEBYTECODE=1 \
        BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
+       $(PYTHON) $(srctree)/scripts/jobserver-exec \
+       $(SHELL) $(srctree)/Documentation/sphinx/parallel-wrapper.sh \
        $(SPHINXBUILD) \
        -b $2 \
        -c $(abspath $(srctree)/$(src)) \
@@ -128,8 +128,10 @@ dochelp:
        @echo  '  pdfdocs         - PDF'
        @echo  '  epubdocs        - EPUB'
        @echo  '  xmldocs         - XML'
-       @echo  '  linkcheckdocs   - check for broken external links (will connect to external hosts)'
-       @echo  '  refcheckdocs    - check for references to non-existing files under Documentation'
+       @echo  '  linkcheckdocs   - check for broken external links'
+       @echo  '                    (will connect to external hosts)'
+       @echo  '  refcheckdocs    - check for references to non-existing files under'
+       @echo  '                    Documentation'
        @echo  '  cleandocs       - clean all generated files'
        @echo
        @echo  '  make SPHINXDIRS="s1 s2" [target] Generate only docs of folder s1, s2'
index 212434e..7bff07c 100644 (file)
@@ -56,7 +56,7 @@ setid capabilities from the application completely and refactor the process
 spawning semantics in the application (e.g. by using a privileged helper program
 to do process spawning and UID/GID transitions). Unfortunately, there are a
 number of semantics around process spawning that would be affected by this, such
-as fork() calls where the program doesn???t immediately call exec() after the
+as fork() calls where the program doesn't immediately call exec() after the
 fork(), parent processes specifying custom environment variables or command line
 args for spawned child processes, or inheritance of file handles across a
 fork()/exec(). Because of this, as solution that uses a privileged helper in
@@ -72,7 +72,7 @@ own user namespace, and only approved UIDs/GIDs could be mapped back to the
 initial system user namespace, affectively preventing privilege escalation.
 Unfortunately, it is not generally feasible to use user namespaces in isolation,
 without pairing them with other namespace types, which is not always an option.
-Linux checks for capabilities based off of the user namespace that ???owns??? some
+Linux checks for capabilities based off of the user namespace that "owns" some
 entity. For example, Linux has the notion that network namespaces are owned by
 the user namespace in which they were created. A consequence of this is that
 capability checks for access to a given network namespace are done by checking
index 007ba86..0636bcb 100644 (file)
@@ -1120,8 +1120,9 @@ PAGE_SIZE multiple when read back.
 
        Best-effort memory protection.  If the memory usage of a
        cgroup is within its effective low boundary, the cgroup's
-       memory won't be reclaimed unless memory can be reclaimed
-       from unprotected cgroups.  Above the effective low boundary (or
+       memory won't be reclaimed unless there is no reclaimable
+       memory available in unprotected cgroups.
+       Above the effective low boundary (or 
        effective min boundary if it is higher), pages are reclaimed
        proportionally to the overage, reducing reclaim pressure for
        smaller overages.
@@ -1288,7 +1289,12 @@ PAGE_SIZE multiple when read back.
          inactive_anon, active_anon, inactive_file, active_file, unevictable
                Amount of memory, swap-backed and filesystem-backed,
                on the internal memory management lists used by the
-               page reclaim algorithm
+               page reclaim algorithm.
+
+               As these represent internal list state (eg. shmem pages are on anon
+               memory management lists), inactive_foo + active_foo may not be equal to
+               the value for the foo counter, since the foo counter is type-based, not
+               list-based.
 
          slab_reclaimable
                Part of "slab" that might be reclaimed, such as
@@ -1920,7 +1926,7 @@ Cpuset Interface Files
 
         It accepts only the following input values when written to.
 
-        "root"   - a paritition root
+        "root"   - a partition root
         "member" - a non-root member of a partition
 
        When set to be a partition root, the current cgroup is the
diff --git a/Documentation/admin-guide/dell_rbu.rst b/Documentation/admin-guide/dell_rbu.rst
new file mode 100644 (file)
index 0000000..8d70e1f
--- /dev/null
@@ -0,0 +1,128 @@
+=========================================
+Dell Remote BIOS Update driver (dell_rbu)
+=========================================
+
+Purpose
+=======
+
+Document demonstrating the use of the Dell Remote BIOS Update driver
+for updating BIOS images on Dell servers and desktops.
+
+Scope
+=====
+
+This document discusses the functionality of the rbu driver only.
+It does not cover the support needed from applications to enable the BIOS to
+update itself with the image downloaded in to the memory.
+
+Overview
+========
+
+This driver works with Dell OpenManage or Dell Update Packages for updating
+the BIOS on Dell servers (starting from servers sold since 1999), desktops
+and notebooks (starting from those sold in 2005).
+
+Please go to  http://support.dell.com register and you can find info on
+OpenManage and Dell Update packages (DUP).
+
+Libsmbios can also be used to update BIOS on Dell systems go to
+http://linux.dell.com/libsmbios/ for details.
+
+Dell_RBU driver supports BIOS update using the monolithic image and packetized
+image methods. In case of monolithic the driver allocates a contiguous chunk
+of physical pages having the BIOS image. In case of packetized the app
+using the driver breaks the image in to packets of fixed sizes and the driver
+would place each packet in contiguous physical memory. The driver also
+maintains a link list of packets for reading them back.
+
+If the dell_rbu driver is unloaded all the allocated memory is freed.
+
+The rbu driver needs to have an application (as mentioned above) which will
+inform the BIOS to enable the update in the next system reboot.
+
+The user should not unload the rbu driver after downloading the BIOS image
+or updating.
+
+The driver load creates the following directories under the /sys file system::
+
+       /sys/class/firmware/dell_rbu/loading
+       /sys/class/firmware/dell_rbu/data
+       /sys/devices/platform/dell_rbu/image_type
+       /sys/devices/platform/dell_rbu/data
+       /sys/devices/platform/dell_rbu/packet_size
+
+The driver supports two types of update mechanism; monolithic and packetized.
+These update mechanism depends upon the BIOS currently running on the system.
+Most of the Dell systems support a monolithic update where the BIOS image is
+copied to a single contiguous block of physical memory.
+
+In case of packet mechanism the single memory can be broken in smaller chunks
+of contiguous memory and the BIOS image is scattered in these packets.
+
+By default the driver uses monolithic memory for the update type. This can be
+changed to packets during the driver load time by specifying the load
+parameter image_type=packet.  This can also be changed later as below::
+
+       echo packet > /sys/devices/platform/dell_rbu/image_type
+
+In packet update mode the packet size has to be given before any packets can
+be downloaded. It is done as below::
+
+       echo XXXX > /sys/devices/platform/dell_rbu/packet_size
+
+In the packet update mechanism, the user needs to create a new file having
+packets of data arranged back to back. It can be done as follows:
+The user creates packets header, gets the chunk of the BIOS image and
+places it next to the packetheader; now, the packetheader + BIOS image chunk
+added together should match the specified packet_size. This makes one
+packet, the user needs to create more such packets out of the entire BIOS
+image file and then arrange all these packets back to back in to one single
+file.
+
+This file is then copied to /sys/class/firmware/dell_rbu/data.
+Once this file gets to the driver, the driver extracts packet_size data from
+the file and spreads it across the physical memory in contiguous packet_sized
+space.
+
+This method makes sure that all the packets get to the driver in a single operation.
+
+In monolithic update the user simply get the BIOS image (.hdr file) and copies
+to the data file as is without any change to the BIOS image itself.
+
+Do the steps below to download the BIOS image.
+
+1) echo 1 > /sys/class/firmware/dell_rbu/loading
+2) cp bios_image.hdr /sys/class/firmware/dell_rbu/data
+3) echo 0 > /sys/class/firmware/dell_rbu/loading
+
+The /sys/class/firmware/dell_rbu/ entries will remain till the following is
+done.
+
+::
+
+       echo -1 > /sys/class/firmware/dell_rbu/loading
+
+Until this step is completed the driver cannot be unloaded.
+
+Also echoing either mono, packet or init in to image_type will free up the
+memory allocated by the driver.
+
+If a user by accident executes steps 1 and 3 above without executing step 2;
+it will make the /sys/class/firmware/dell_rbu/ entries disappear.
+
+The entries can be recreated by doing the following::
+
+       echo init > /sys/devices/platform/dell_rbu/image_type
+
+.. note:: echoing init in image_type does not change its original value.
+
+Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to
+read back the image downloaded.
+
+.. note::
+
+   After updating the BIOS image a user mode application needs to execute
+   code which sends the BIOS update request to the BIOS. So on the next reboot
+   the BIOS knows about the new image downloaded and it updates itself.
+   Also don't unload the rbu driver if the image has to be updated.
+
diff --git a/Documentation/admin-guide/device-mapper/dm-dust.rst b/Documentation/admin-guide/device-mapper/dm-dust.rst
new file mode 100644 (file)
index 0000000..b6e7e7e
--- /dev/null
@@ -0,0 +1,287 @@
+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 not 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).
diff --git a/Documentation/admin-guide/device-mapper/dm-dust.txt b/Documentation/admin-guide/device-mapper/dm-dust.txt
deleted file mode 100644 (file)
index 954d402..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-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 c77c58b..4872fb6 100644 (file)
@@ -9,6 +9,7 @@ Device Mapper
     cache
     delay
     dm-crypt
+    dm-dust
     dm-flakey
     dm-init
     dm-integrity
index 34cc20e..4405b74 100644 (file)
@@ -57,60 +57,61 @@ configure specific aspects of kernel behavior to your liking.
 .. toctree::
    :maxdepth: 1
 
-   initrd
-   cgroup-v2
-   cgroup-v1/index
-   serial-console
-   braille-console
-   parport
-   md
-   module-signing
-   rapidio
-   sysrq
-   unicode
-   vga-softcursor
-   binfmt-misc
-   mono
-   java
-   ras
-   bcache
-   blockdev/index
-   ext4
-   binderfs
-   cifs/index
-   xfs
-   jfs
-   ufs
-   pm/index
-   thunderbolt
-   LSM/index
-   mm/index
-   namespaces/index
-   perf-security
    acpi/index
    aoe/index
+   auxdisplay/index
+   bcache
+   binderfs
+   binfmt-misc
+   blockdev/index
+   braille-console
    btmrvl
+   cgroup-v1/index
+   cgroup-v2
+   cifs/index
    clearing-warn-once
    cpu-load
    cputopology
+   dell_rbu
    device-mapper/index
    efi-stub
+   ext4
    gpio/index
    highuid
    hw_random
+   initrd
    iostats
+   java
+   jfs
    kernel-per-CPU-kthreads
    laptops/index
-   auxdisplay/index
    lcd-panel-cgram
    ldm
    lockup-watchdogs
+   LSM/index
+   md
+   mm/index
+   module-signing
+   mono
+   namespaces/index
    numastat
+   parport
+   perf-security
+   pm/index
    pnp
+   rapidio
+   ras
    rtc
+   serial-console
    svga
-   wimax/index
+   sysrq
+   thunderbolt
+   ufs
+   unicode
+   vga-softcursor
    video-output
+   wimax/index
+   xfs
 
 .. only::  subproject and html
 
index 4f0462a..df5b834 100644 (file)
@@ -46,78 +46,79 @@ each snapshot of your disk statistics.
 In 2.4, the statistics fields are those after the device name. In
 the above example, the first field of statistics would be 446216.
 By contrast, in 2.6+ if you look at ``/sys/block/hda/stat``, you'll
-find just the eleven fields, beginning with 446216.  If you look at
-``/proc/diskstats``, the eleven fields will be preceded by the major and
+find just the 15 fields, beginning with 446216.  If you look at
+``/proc/diskstats``, the 15 fields will be preceded by the major and
 minor device numbers, and device name.  Each of these formats provides
-eleven fields of statistics, each meaning exactly the same things.
+15 fields of statistics, each meaning exactly the same things.
 All fields except field 9 are cumulative since boot.  Field 9 should
 go to zero as I/Os complete; all others only increase (unless they
-overflow and wrap).  Yes, these are (32-bit or 64-bit) unsigned long
-(native word size) numbers, and on a very busy or long-lived system they
-may wrap. Applications should be prepared to deal with that; unless
-your observations are measured in large numbers of minutes or hours,
-they should not wrap twice before you notice them.
+overflow and wrap). Wrapping might eventually occur on a very busy
+or long-lived system; so applications should be prepared to deal with
+it. Regarding wrapping, the types of the fields are either unsigned
+int (32 bit) or unsigned long (32-bit or 64-bit, depending on your
+machine) as noted per-field below. Unless your observations are very
+spread in time, these fields should not wrap twice before you notice it.
 
 Each set of stats only applies to the indicated device; if you want
 system-wide stats you'll have to find all the devices and sum them all up.
 
-Field  1 -- # of reads completed
+Field  1 -- # of reads completed (unsigned long)
     This is the total number of reads completed successfully.
 
-Field  2 -- # of reads merged, field 6 -- # of writes merged
+Field  2 -- # of reads merged, field 6 -- # of writes merged (unsigned long)
     Reads and writes which are adjacent to each other may be merged for
     efficiency.  Thus two 4K reads may become one 8K read before it is
     ultimately handed to the disk, and so it will be counted (and queued)
     as only one I/O.  This field lets you know how often this was done.
 
-Field  3 -- # of sectors read
+Field  3 -- # of sectors read (unsigned long)
     This is the total number of sectors read successfully.
 
-Field  4 -- # of milliseconds spent reading
+Field  4 -- # of milliseconds spent reading (unsigned int)
     This is the total number of milliseconds spent by all reads (as
     measured from __make_request() to end_that_request_last()).
 
-Field  5 -- # of writes completed
+Field  5 -- # of writes completed (unsigned long)
     This is the total number of writes completed successfully.
 
-Field  6 -- # of writes merged
+Field  6 -- # of writes merged  (unsigned long)
     See the description of field 2.
 
-Field  7 -- # of sectors written
+Field  7 -- # of sectors written (unsigned long)
     This is the total number of sectors written successfully.
 
-Field  8 -- # of milliseconds spent writing
+Field  8 -- # of milliseconds spent writing (unsigned int)
     This is the total number of milliseconds spent by all writes (as
     measured from __make_request() to end_that_request_last()).
 
-Field  9 -- # of I/Os currently in progress
+Field  9 -- # of I/Os currently in progress (unsigned int)
     The only field that should go to zero. Incremented as requests are
     given to appropriate struct request_queue and decremented as they finish.
 
-Field 10 -- # of milliseconds spent doing I/Os
+Field 10 -- # of milliseconds spent doing I/Os (unsigned int)
     This field increases so long as field 9 is nonzero.
 
     Since 5.0 this field counts jiffies when at least one request was
     started or completed. If request runs more than 2 jiffies then some
     I/O time will not be accounted unless there are other requests.
 
-Field 11 -- weighted # of milliseconds spent doing I/Os
+Field 11 -- weighted # of milliseconds spent doing I/Os (unsigned int)
     This field is incremented at each I/O start, I/O completion, I/O
     merge, or read of these stats by the number of I/Os in progress
     (field 9) times the number of milliseconds spent doing I/O since the
     last update of this field.  This can provide an easy measure of both
     I/O completion time and the backlog that may be accumulating.
 
-Field 12 -- # of discards completed
+Field 12 -- # of discards completed (unsigned long)
     This is the total number of discards completed successfully.
 
-Field 13 -- # of discards merged
+Field 13 -- # of discards merged (unsigned long)
     See the description of field 2
 
-Field 14 -- # of sectors discarded
+Field 14 -- # of sectors discarded (unsigned long)
     This is the total number of sectors discarded successfully.
 
-Field 15 -- # of milliseconds spent discarding
+Field 15 -- # of milliseconds spent discarding (unsigned int)
     This is the total number of milliseconds spent by all discards (as
     measured from __make_request() to end_that_request_last()).
 
index b25b47a..ade4e6e 100644 (file)
                        the GPE dispatcher.
                        This facility can be used to prevent such uncontrolled
                        GPE floodings.
-                       Format: <int>
+                       Format: <byte>
 
        acpi_no_auto_serialize  [HW,ACPI]
                        Disable auto-serialization of AML methods
                        no delay (0).
                        Format: integer
 
-       bootmem_debug   [KNL] Enable bootmem allocator debug messages.
-
        bert_disable    [ACPI]
                        Disable BERT OS support on buggy BIOSes.
 
 
        earlycon=       [KNL] Output early console device and options.
 
-                       [ARM64] The early console is determined by the
-                       stdout-path property in device tree's chosen node,
-                       or determined by the ACPI SPCR table.
-
-                       [X86] When used with no options the early console is
-                       determined by the ACPI SPCR table.
+                       When used with no options, the early console is
+                       determined by stdout-path property in device tree's
+                       chosen node or the ACPI SPCR table if supported by
+                       the platform.
 
                cdns,<addr>[,options]
                        Start an early, polled-mode console on a Cadence
                        mapped with the correct attributes.
 
                linflex,<addr>
-                       Use early console provided by Freescale LinFlex UART
+                       Use early console provided by Freescale LINFlexD UART
                        serial driver for NXP S32V234 SoCs. A valid base
                        address must be provided, and the serial port must
                        already be setup and configured.
                hpiosize=nn[KMG]        The fixed amount of bus space which is
                                reserved for hotplug bridge's IO window.
                                Default size is 256 bytes.
+               hpmmiosize=nn[KMG]      The fixed amount of bus space which is
+                               reserved for hotplug bridge's MMIO window.
+                               Default size is 2 megabytes.
+               hpmmioprefsize=nn[KMG]  The fixed amount of bus space which is
+                               reserved for hotplug bridge's MMIO_PREF window.
+                               Default size is 2 megabytes.
                hpmemsize=nn[KMG]       The fixed amount of bus space which is
-                               reserved for hotplug bridge's memory window.
+                               reserved for hotplug bridge's MMIO and
+                               MMIO_PREF window.
                                Default size is 2 megabytes.
                hpbussize=nn    The minimum amount of additional bus numbers
                                reserved for buses below a hotplug bridge.
                        even if the platform doesn't give the OS permission to
                        use them.  This may cause conflicts if the platform
                        also tries to use these services.
+               dpc-native      Use native PCIe service for DPC only.  May
+                               cause conflicts if firmware uses AER or DPC.
                compat  Disable native PCIe services (PME, AER, DPC, PCIe
                        hotplug).
 
index 90056e4..3726a10 100644 (file)
@@ -19,7 +19,9 @@ devices/imx8_ddr0/format/. The "events" directory describes the events types
 hardware supported that can be used with perf tool, see /sys/bus/event_source/
 devices/imx8_ddr0/events/. The "caps" directory describes filter features implemented
 in DDR PMU, see /sys/bus/events_source/devices/imx8_ddr0/caps/.
-  e.g.::
+
+    .. code-block:: bash
+
         perf stat -a -e imx8_ddr0/cycles/ cmd
         perf stat -a -e imx8_ddr0/read/,imx8_ddr0/write/ cmd
 
@@ -35,24 +37,31 @@ value 1 for supported.
   Filter is defined with two configuration parts:
   --AXI_ID defines AxID matching value.
   --AXI_MASKING defines which bits of AxID are meaningful for the matching.
-        0:corresponding bit is masked.
-        1: corresponding bit is not masked, i.e. used to do the matching.
+
+      - 0: corresponding bit is masked.
+      - 1: corresponding bit is not masked, i.e. used to do the matching.
 
   AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance counter.
   When non-masked bits are matching corresponding AXI_ID bits then counter is
   incremented. Perf counter is incremented if
-          AxID && AXI_MASKING == AXI_ID && AXI_MASKING
+        AxID && AXI_MASKING == AXI_ID && AXI_MASKING
 
   This filter doesn't support filter different AXI ID for axid-read and axid-write
   event at the same time as this filter is shared between counters.
-  e.g.::
-        perf stat -a -e imx8_ddr0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
-        perf stat -a -e imx8_ddr0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
-
-  NOTE: axi_mask is inverted in userspace(i.e. set bits are bits to mask), and
-  it will be reverted in driver automatically. so that the user can just specify
-  axi_id to monitor a specific id, rather than having to specify axi_mask.
-  e.g.::
+
+  .. code-block:: bash
+
+      perf stat -a -e imx8_ddr0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
+      perf stat -a -e imx8_ddr0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
+
+  .. note::
+
+      axi_mask is inverted in userspace(i.e. set bits are bits to mask), and
+      it will be reverted in driver automatically. so that the user can just specify
+      axi_id to monitor a specific id, rather than having to specify axi_mask.
+
+  .. code-block:: bash
+
         perf stat -a -e imx8_ddr0/axid-read,axi_id=0x12/ cmd, which will monitor ARID=0x12
 
 * With DDR_CAP_AXI_ID_FILTER_ENHANCED quirk(filter: 1, enhanced_filter: 1).
index ee4bfd2..47c99f4 100644 (file)
@@ -8,6 +8,7 @@ Performance monitor support
    :maxdepth: 1
 
    hisi-pmu
+   imx-ddr
    qcom_l2_pmu
    qcom_l3_pmu
    arm-ccn
index 032c7cd..def0748 100644 (file)
@@ -831,8 +831,8 @@ printk_ratelimit:
 =================
 
 Some warning messages are rate limited. printk_ratelimit specifies
-the minimum length of time between these messages (in jiffies), by
-default we allow one every 5 seconds.
+the minimum length of time between these messages (in seconds).
+The default value is 5 seconds.
 
 A value of 0 will disable rate limiting.
 
@@ -845,6 +845,8 @@ seconds, we do allow a burst of messages to pass through.
 printk_ratelimit_burst specifies the number of messages we can
 send before ratelimiting kicks in.
 
+The default value is 10 messages.
+
 
 printk_devkmsg:
 ===============
@@ -1101,7 +1103,7 @@ During initialization the kernel sets this value such that even if the
 maximum number of threads is created, the thread structures occupy only
 a part (1/8th) of the available RAM pages.
 
-The minimum value that can be written to threads-max is 20.
+The minimum value that can be written to threads-max is 1.
 
 The maximum value that can be written to threads-max is given by the
 constant FUTEX_TID_MASK (0x3fffffff).
@@ -1109,10 +1111,6 @@ constant FUTEX_TID_MASK (0x3fffffff).
 If a value outside of this range is written to threads-max an error
 EINVAL occurs.
 
-The value written is checked against the available RAM pages. If the
-thread structures would occupy too much (more than 1/8th) of the
-available RAM pages threads-max is reduced accordingly.
-
 
 unknown_nmi_panic:
 ==================
index c9a44c9..1adf53d 100644 (file)
@@ -103,7 +103,7 @@ the Microchip website: http://www.microchip.com.
 
           * Datasheet
 
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet.pdf
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet_B.pdf
 
     * ARM Cortex-A5 + NEON based SoCs
       - sama5d4 family
@@ -167,7 +167,7 @@ the Microchip website: http://www.microchip.com.
 
           * Datasheet
 
-          http://ww1.microchip.com/downloads/en/DeviceDoc/60001527A.pdf
+          http://ww1.microchip.com/downloads/en/DeviceDoc/SAM-E70-S70-V70-V71-Family-Data-Sheet-DS60001527D.pdf
 
 
 Linux kernel information
index a8fe845..3c7bdf4 100644 (file)
@@ -37,7 +37,8 @@ needs_sphinx = '1.3'
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain',
-              'kfigure', 'sphinx.ext.ifconfig', 'automarkup']
+              'kfigure', 'sphinx.ext.ifconfig', 'automarkup',
+              'maintainers_include']
 
 # The name of the math extension changed on Sphinx 1.4
 if (major == 1 and minor > 3) or (major > 1):
index 6b38a39..a5af2cb 100644 (file)
@@ -23,7 +23,7 @@ begins with the creation of a pool using one of:
 .. kernel-doc:: lib/genalloc.c
    :functions: devm_gen_pool_create
 
-A call to :c:func:`gen_pool_create` will create a pool.  The granularity of
+A call to gen_pool_create() will create a pool.  The granularity of
 allocations is set with min_alloc_order; it is a log-base-2 number like
 those used by the page allocator, but it refers to bytes rather than pages.
 So, if min_alloc_order is passed as 3, then all allocations will be a
@@ -32,7 +32,7 @@ required to track the memory in the pool.  The nid parameter specifies
 which NUMA node should be used for the allocation of the housekeeping
 structures; it can be -1 if the caller doesn't care.
 
-The "managed" interface :c:func:`devm_gen_pool_create` ties the pool to a
+The "managed" interface devm_gen_pool_create() ties the pool to a
 specific device.  Among other things, it will automatically clean up the
 pool when the given device is destroyed.
 
@@ -53,32 +53,32 @@ to the pool.  That can be done with one of:
    :functions: gen_pool_add
 
 .. kernel-doc:: lib/genalloc.c
-   :functions: gen_pool_add_virt
+   :functions: gen_pool_add_owner
 
-A call to :c:func:`gen_pool_add` will place the size bytes of memory
+A call to gen_pool_add() will place the size bytes of memory
 starting at addr (in the kernel's virtual address space) into the given
 pool, once again using nid as the node ID for ancillary memory allocations.
-The :c:func:`gen_pool_add_virt` variant associates an explicit physical
+The gen_pool_add_virt() variant associates an explicit physical
 address with the memory; this is only necessary if the pool will be used
 for DMA allocations.
 
 The functions for allocating memory from the pool (and putting it back)
 are:
 
-.. kernel-doc:: lib/genalloc.c
+.. kernel-doc:: include/linux/genalloc.h
    :functions: gen_pool_alloc
 
 .. kernel-doc:: lib/genalloc.c
    :functions: gen_pool_dma_alloc
 
 .. kernel-doc:: lib/genalloc.c
-   :functions: gen_pool_free
+   :functions: gen_pool_free_owner
 
-As one would expect, :c:func:`gen_pool_alloc` will allocate size< bytes
-from the given pool.  The :c:func:`gen_pool_dma_alloc` variant allocates
+As one would expect, gen_pool_alloc() will allocate size< bytes
+from the given pool.  The gen_pool_dma_alloc() variant allocates
 memory for use with DMA operations, returning the associated physical
 address in the space pointed to by dma.  This will only work if the memory
-was added with :c:func:`gen_pool_add_virt`.  Note that this function
+was added with gen_pool_add_virt().  Note that this function
 departs from the usual genpool pattern of using unsigned long values to
 represent kernel addresses; it returns a void * instead.
 
@@ -89,14 +89,14 @@ return.  If that sort of control is needed, the following functions will be
 of interest:
 
 .. kernel-doc:: lib/genalloc.c
-   :functions: gen_pool_alloc_algo
+   :functions: gen_pool_alloc_algo_owner
 
 .. kernel-doc:: lib/genalloc.c
    :functions: gen_pool_set_algo
 
-Allocations with :c:func:`gen_pool_alloc_algo` specify an algorithm to be
+Allocations with gen_pool_alloc_algo() specify an algorithm to be
 used to choose the memory to be allocated; the default algorithm can be set
-with :c:func:`gen_pool_set_algo`.  The data value is passed to the
+with gen_pool_set_algo().  The data value is passed to the
 algorithm; most ignore it, but it is occasionally needed.  One can,
 naturally, write a special-purpose algorithm, but there is a fair set
 already available:
@@ -129,7 +129,7 @@ writing of special-purpose memory allocators in the future.
    :functions: gen_pool_for_each_chunk
 
 .. kernel-doc:: lib/genalloc.c
-   :functions: addr_in_gen_pool
+   :functions: gen_pool_has_addr
 
 .. kernel-doc:: lib/genalloc.c
    :functions: gen_pool_avail
index 4da67b6..8f06d88 100644 (file)
@@ -26,7 +26,7 @@ Rationale
 =========
 
 The original implementation of interrupt handling in Linux uses the
-:c:func:`__do_IRQ` super-handler, which is able to deal with every type of
+__do_IRQ() super-handler, which is able to deal with every type of
 interrupt logic.
 
 Originally, Russell King identified different types of handlers to build
@@ -43,7 +43,7 @@ During the implementation we identified another type:
 
 -  Fast EOI type
 
-In the SMP world of the :c:func:`__do_IRQ` super-handler another type was
+In the SMP world of the __do_IRQ() super-handler another type was
 identified:
 
 -  Per CPU type
@@ -83,7 +83,7 @@ IRQ-flow implementation for 'level type' interrupts and add a
 (sub)architecture specific 'edge type' implementation.
 
 To make the transition to the new model easier and prevent the breakage
-of existing implementations, the :c:func:`__do_IRQ` super-handler is still
+of existing implementations, the __do_IRQ() super-handler is still
 available. This leads to a kind of duality for the time being. Over time
 the new model should be used in more and more architectures, as it
 enables smaller and cleaner IRQ subsystems. It's deprecated for three
@@ -116,7 +116,7 @@ status information and pointers to the interrupt flow method and the
 interrupt chip structure which are assigned to this interrupt.
 
 Whenever an interrupt triggers, the low-level architecture code calls
-into the generic interrupt code by calling :c:func:`desc->handle_irq`. This
+into the generic interrupt code by calling desc->handle_irq(). This
 high-level IRQ handling function only uses desc->irq_data.chip
 primitives referenced by the assigned chip descriptor structure.
 
@@ -125,27 +125,29 @@ High-level Driver API
 
 The high-level Driver API consists of following functions:
 
--  :c:func:`request_irq`
+-  request_irq()
 
--  :c:func:`free_irq`
+-  request_threaded_irq()
 
--  :c:func:`disable_irq`
+-  free_irq()
 
--  :c:func:`enable_irq`
+-  disable_irq()
 
--  :c:func:`disable_irq_nosync` (SMP only)
+-  enable_irq()
 
--  :c:func:`synchronize_irq` (SMP only)
+-  disable_irq_nosync() (SMP only)
 
--  :c:func:`irq_set_irq_type`
+-  synchronize_irq() (SMP only)
 
--  :c:func:`irq_set_irq_wake`
+-  irq_set_irq_type()
 
--  :c:func:`irq_set_handler_data`
+-  irq_set_irq_wake()
 
--  :c:func:`irq_set_chip`
+-  irq_set_handler_data()
 
--  :c:func:`irq_set_chip_data`
+-  irq_set_chip()
+
+-  irq_set_chip_data()
 
 See the autogenerated function documentation for details.
 
@@ -154,19 +156,19 @@ High-level IRQ flow handlers
 
 The generic layer provides a set of pre-defined irq-flow methods:
 
--  :c:func:`handle_level_irq`
+-  handle_level_irq()
 
--  :c:func:`handle_edge_irq`
+-  handle_edge_irq()
 
--  :c:func:`handle_fasteoi_irq`
+-  handle_fasteoi_irq()
 
--  :c:func:`handle_simple_irq`
+-  handle_simple_irq()
 
--  :c:func:`handle_percpu_irq`
+-  handle_percpu_irq()
 
--  :c:func:`handle_edge_eoi_irq`
+-  handle_edge_eoi_irq()
 
--  :c:func:`handle_bad_irq`
+-  handle_bad_irq()
 
 The interrupt flow handlers (either pre-defined or architecture
 specific) are assigned to specific interrupts by the architecture either
@@ -325,14 +327,14 @@ Delayed interrupt disable
 
 This per interrupt selectable feature, which was introduced by Russell
 King in the ARM interrupt implementation, does not mask an interrupt at
-the hardware level when :c:func:`disable_irq` is called. The interrupt is kept
+the hardware level when disable_irq() is called. The interrupt is kept
 enabled and is masked in the flow handler when an interrupt event
 happens. This prevents losing edge interrupts on hardware which does not
 store an edge interrupt event while the interrupt is disabled at the
 hardware level. When an interrupt arrives while the IRQ_DISABLED flag
 is set, then the interrupt is masked at the hardware level and the
 IRQ_PENDING bit is set. When the interrupt is re-enabled by
-:c:func:`enable_irq` the pending bit is checked and if it is set, the interrupt
+enable_irq() the pending bit is checked and if it is set, the interrupt
 is resent either via hardware or by a software resend mechanism. (It's
 necessary to enable CONFIG_HARDIRQS_SW_RESEND when you want to use
 the delayed interrupt disable feature and your hardware is not capable
@@ -369,7 +371,7 @@ handler(s) to use these basic units of low-level functionality.
 __do_IRQ entry point
 ====================
 
-The original implementation :c:func:`__do_IRQ` was an alternative entry point
+The original implementation __do_IRQ() was an alternative entry point
 for all types of interrupts. It no longer exists.
 
 This handler turned out to be not suitable for all interrupt hardware
index 939e3df..4aa82dd 100644 (file)
@@ -88,10 +88,11 @@ Selecting memory allocator
 ==========================
 
 The most straightforward way to allocate memory is to use a function
-from the :c:func:`kmalloc` family. And, to be on the safe size it's
-best to use routines that set memory to zero, like
-:c:func:`kzalloc`. If you need to allocate memory for an array, there
-are :c:func:`kmalloc_array` and :c:func:`kcalloc` helpers.
+from the kmalloc() family. And, to be on the safe side it's best to use
+routines that set memory to zero, like kzalloc(). If you need to
+allocate memory for an array, there are kmalloc_array() and kcalloc()
+helpers. The helpers struct_size(), array_size() and array3_size() can
+be used to safely calculate object sizes without overflowing.
 
 The maximal size of a chunk that can be allocated with `kmalloc` is
 limited. The actual limit depends on the hardware and the kernel
@@ -102,29 +103,26 @@ The address of a chunk allocated with `kmalloc` is aligned to at least
 ARCH_KMALLOC_MINALIGN bytes.  For sizes which are a power of two, the
 alignment is also guaranteed to be at least the respective size.
 
-For large allocations you can use :c:func:`vmalloc` and
-:c:func:`vzalloc`, or directly request pages from the page
-allocator. The memory allocated by `vmalloc` and related functions is
-not physically contiguous.
+For large allocations you can use vmalloc() and vzalloc(), or directly
+request pages from the page allocator. The memory allocated by `vmalloc`
+and related functions is not physically contiguous.
 
 If you are not sure whether the allocation size is too large for
-`kmalloc`, it is possible to use :c:func:`kvmalloc` and its
-derivatives. It will try to allocate memory with `kmalloc` and if the
-allocation fails it will be retried with `vmalloc`. There are
-restrictions on which GFP flags can be used with `kvmalloc`; please
-see :c:func:`kvmalloc_node` reference documentation. Note that
-`kvmalloc` may return memory that is not physically contiguous.
+`kmalloc`, it is possible to use kvmalloc() and its derivatives. It will
+try to allocate memory with `kmalloc` and if the allocation fails it
+will be retried with `vmalloc`. There are restrictions on which GFP
+flags can be used with `kvmalloc`; please see kvmalloc_node() reference
+documentation. Note that `kvmalloc` may return memory that is not
+physically contiguous.
 
 If you need to allocate many identical objects you can use the slab
-cache allocator. The cache should be set up with
-:c:func:`kmem_cache_create` or :c:func:`kmem_cache_create_usercopy`
-before it can be used. The second function should be used if a part of
-the cache might be copied to the userspace.  After the cache is
-created :c:func:`kmem_cache_alloc` and its convenience wrappers can
-allocate memory from that cache.
-
-When the allocated memory is no longer needed it must be freed. You
-can use :c:func:`kvfree` for the memory allocated with `kmalloc`,
-`vmalloc` and `kvmalloc`. The slab caches should be freed with
-:c:func:`kmem_cache_free`. And don't forget to destroy the cache with
-:c:func:`kmem_cache_destroy`.
+cache allocator. The cache should be set up with kmem_cache_create() or
+kmem_cache_create_usercopy() before it can be used. The second function
+should be used if a part of the cache might be copied to the userspace.
+After the cache is created kmem_cache_alloc() and its convenience
+wrappers can allocate memory from that cache.
+
+When the allocated memory is no longer needed it must be freed. You can
+use kvfree() for the memory allocated with `kmalloc`, `vmalloc` and
+`kvmalloc`. The slab caches should be freed with kmem_cache_free(). And
+don't forget to destroy the cache with kmem_cache_destroy().
index 128e8a7..be72698 100644 (file)
@@ -11,7 +11,7 @@ User Space Memory Access
 .. kernel-doc:: arch/x86/lib/usercopy_32.c
    :export:
 
-.. kernel-doc:: mm/util.c
+.. kernel-doc:: mm/gup.c
    :functions: get_user_pages_fast
 
 .. _mm-api-gfp-flags:
index ea21dd4..8ebe46b 100644 (file)
@@ -137,6 +137,20 @@ equivalent to %lx (or %lu). %px is preferred because it is more uniquely
 grep'able. If in the future we need to modify the way the kernel handles
 printing pointers we will be better equipped to find the call sites.
 
+Pointer Differences
+-------------------
+
+::
+
+       %td     2560
+       %tx     a00
+
+For printing the pointer differences, use the %t modifier for ptrdiff_t.
+
+Example::
+
+       printk("test: difference between pointers: %td\n", ptr2 - ptr1);
+
 Struct Resources
 ----------------
 
index 976e85a..79a009c 100644 (file)
@@ -35,7 +35,7 @@ atomics & refcounters only provide atomicity and
 program order (po) relation (on the same CPU). It guarantees that
 each ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions
 are executed in program order on a single CPU.
-This is implemented using :c:func:`READ_ONCE`/:c:func:`WRITE_ONCE` and
+This is implemented using READ_ONCE()/WRITE_ONCE() and
 compare-and-swap primitives.
 
 A strong (full) memory ordering guarantees that all prior loads and
@@ -44,7 +44,7 @@ before any po-later instruction is executed on the same CPU.
 It also guarantees that all po-earlier stores on the same CPU
 and all propagated stores from other CPUs must propagate to all
 other CPUs before any po-later instruction is executed on the original
-CPU (A-cumulative property). This is implemented using :c:func:`smp_mb`.
+CPU (A-cumulative property). This is implemented using smp_mb().
 
 A RELEASE memory ordering guarantees that all prior loads and
 stores (all po-earlier instructions) on the same CPU are completed
@@ -52,14 +52,14 @@ before the operation. It also guarantees that all po-earlier
 stores on the same CPU and all propagated stores from other CPUs
 must propagate to all other CPUs before the release operation
 (A-cumulative property). This is implemented using
-:c:func:`smp_store_release`.
+smp_store_release().
 
 An ACQUIRE memory ordering guarantees that all post loads and
 stores (all po-later instructions) on the same CPU are
 completed after the acquire operation. It also guarantees that all
 po-later stores on the same CPU must propagate to all other CPUs
 after the acquire operation executes. This is implemented using
-:c:func:`smp_acquire__after_ctrl_dep`.
+smp_acquire__after_ctrl_dep().
 
 A control dependency (on success) for refcounters guarantees that
 if a reference for an object was successfully obtained (reference
@@ -78,8 +78,8 @@ case 1) - non-"Read/Modify/Write" (RMW) ops
 
 Function changes:
 
- * :c:func:`atomic_set` --> :c:func:`refcount_set`
- * :c:func:`atomic_read` --> :c:func:`refcount_read`
+ * atomic_set() --> refcount_set()
+ * atomic_read() --> refcount_read()
 
 Memory ordering guarantee changes:
 
@@ -91,8 +91,8 @@ case 2) - increment-based ops that return no value
 
 Function changes:
 
- * :c:func:`atomic_inc` --> :c:func:`refcount_inc`
- * :c:func:`atomic_add` --> :c:func:`refcount_add`
+ * atomic_inc() --> refcount_inc()
+ * atomic_add() --> refcount_add()
 
 Memory ordering guarantee changes:
 
@@ -103,7 +103,7 @@ case 3) - decrement-based RMW ops that return no value
 
 Function changes:
 
- * :c:func:`atomic_dec` --> :c:func:`refcount_dec`
+ * atomic_dec() --> refcount_dec()
 
 Memory ordering guarantee changes:
 
@@ -115,8 +115,8 @@ case 4) - increment-based RMW ops that return a value
 
 Function changes:
 
- * :c:func:`atomic_inc_not_zero` --> :c:func:`refcount_inc_not_zero`
- * no atomic counterpart --> :c:func:`refcount_add_not_zero`
+ * atomic_inc_not_zero() --> refcount_inc_not_zero()
+ * no atomic counterpart --> refcount_add_not_zero()
 
 Memory ordering guarantees changes:
 
@@ -131,8 +131,8 @@ case 5) - generic dec/sub decrement-based RMW ops that return a value
 
 Function changes:
 
- * :c:func:`atomic_dec_and_test` --> :c:func:`refcount_dec_and_test`
- * :c:func:`atomic_sub_and_test` --> :c:func:`refcount_sub_and_test`
+ * atomic_dec_and_test() --> refcount_dec_and_test()
+ * atomic_sub_and_test() --> refcount_sub_and_test()
 
 Memory ordering guarantees changes:
 
@@ -144,14 +144,14 @@ case 6) other decrement-based RMW ops that return a value
 
 Function changes:
 
- * no atomic counterpart --> :c:func:`refcount_dec_if_one`
+ * no atomic counterpart --> refcount_dec_if_one()
  * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)``
 
 Memory ordering guarantees changes:
 
  * fully ordered --> RELEASE ordering + control dependency
 
-.. note:: :c:func:`atomic_add_unless` only provides full order on success.
+.. note:: atomic_add_unless() only provides full order on success.
 
 
 case 7) - lock-based RMW
@@ -159,10 +159,10 @@ case 7) - lock-based RMW
 
 Function changes:
 
- * :c:func:`atomic_dec_and_lock` --> :c:func:`refcount_dec_and_lock`
- * :c:func:`atomic_dec_and_mutex_lock` --> :c:func:`refcount_dec_and_mutex_lock`
+ * atomic_dec_and_lock() --> refcount_dec_and_lock()
+ * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock()
 
 Memory ordering guarantees changes:
 
  * fully ordered --> RELEASE ordering + control dependency + hold
-   :c:func:`spin_lock` on success
+   spin_lock() on success
index 982ed7b..9b76337 100644 (file)
@@ -152,3 +152,6 @@ in-tree modules::
        - notice the warning of modpost telling about a missing import
        - run `make nsdeps` to add the import to the correct code location
 
+You can also run nsdeps for external module builds. A typical usage is::
+
+       $ make -C <path_to_kernel_src> M=$PWD nsdeps
index 5252961..e4d66e7 100644 (file)
@@ -218,3 +218,66 @@ brk handler is used to print bug reports.
 A potential expansion of this mode is a hardware tag-based mode, which would
 use hardware memory tagging support instead of compiler instrumentation and
 manual shadow memory manipulation.
+
+What memory accesses are sanitised by KASAN?
+--------------------------------------------
+
+The kernel maps memory in a number of different parts of the address
+space. This poses something of a problem for KASAN, which requires
+that all addresses accessed by instrumented code have a valid shadow
+region.
+
+The range of kernel virtual addresses is large: there is not enough
+real memory to support a real shadow region for every address that
+could be accessed by the kernel.
+
+By default
+~~~~~~~~~~
+
+By default, architectures only map real memory over the shadow region
+for the linear mapping (and potentially other small areas). For all
+other areas - such as vmalloc and vmemmap space - a single read-only
+page is mapped over the shadow area. This read-only shadow page
+declares all memory accesses as permitted.
+
+This presents a problem for modules: they do not live in the linear
+mapping, but in a dedicated module space. By hooking in to the module
+allocator, KASAN can temporarily map real shadow memory to cover
+them. This allows detection of invalid accesses to module globals, for
+example.
+
+This also creates an incompatibility with ``VMAP_STACK``: if the stack
+lives in vmalloc space, it will be shadowed by the read-only page, and
+the kernel will fault when trying to set up the shadow data for stack
+variables.
+
+CONFIG_KASAN_VMALLOC
+~~~~~~~~~~~~~~~~~~~~
+
+With ``CONFIG_KASAN_VMALLOC``, KASAN can cover vmalloc space at the
+cost of greater memory usage. Currently this is only supported on x86.
+
+This works by hooking into vmalloc and vmap, and dynamically
+allocating real shadow memory to back the mappings.
+
+Most mappings in vmalloc space are small, requiring less than a full
+page of shadow space. Allocating a full shadow page per mapping would
+therefore be wasteful. Furthermore, to ensure that different mappings
+use different shadow pages, mappings would have to be aligned to
+``KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE``.
+
+Instead, we share backing space across multiple mappings. We allocate
+a backing page when a mapping in vmalloc space uses a particular page
+of the shadow region. This page can be shared by other vmalloc
+mappings later on.
+
+We hook in to the vmap infrastructure to lazily clean up unused shadow
+memory.
+
+To avoid the difficulties around swapping mappings around, we expect
+that the part of the shadow region that covers the vmalloc space will
+not be covered by the early shadow page, but will be left
+unmapped. This will require changes in arch-specific code.
+
+This allows ``VMAP_STACK`` support on x86, and can simplify support of
+architectures that do not have a fixed module region.
index 42b6126..36890b0 100644 (file)
@@ -34,6 +34,7 @@ Profiling data will only become accessible once debugfs has been mounted::
 
 Coverage collection
 -------------------
+
 The following program demonstrates coverage collection from within a test
 program using kcov:
 
@@ -128,6 +129,7 @@ only need to enable coverage (disable happens automatically on thread end).
 
 Comparison operands collection
 ------------------------------
+
 Comparison operands collection is similar to coverage collection:
 
 .. code-block:: c
@@ -202,3 +204,130 @@ Comparison operands collection is similar to coverage collection:
 
 Note that the kcov modes (coverage collection or comparison operands) are
 mutually exclusive.
+
+Remote coverage collection
+--------------------------
+
+With KCOV_ENABLE coverage is collected only for syscalls that are issued
+from the current process. With KCOV_REMOTE_ENABLE it's possible to collect
+coverage for arbitrary parts of the kernel code, provided that those parts
+are annotated with kcov_remote_start()/kcov_remote_stop().
+
+This allows to collect coverage from two types of kernel background
+threads: the global ones, that are spawned during kernel boot in a limited
+number of instances (e.g. one USB hub_event() worker thread is spawned per
+USB HCD); and the local ones, that are spawned when a user interacts with
+some kernel interface (e.g. vhost workers).
+
+To enable collecting coverage from a global background thread, a unique
+global handle must be assigned and passed to the corresponding
+kcov_remote_start() call. Then a userspace process can pass a list of such
+handles to the KCOV_REMOTE_ENABLE ioctl in the handles array field of the
+kcov_remote_arg struct. This will attach the used kcov device to the code
+sections, that are referenced by those handles.
+
+Since there might be many local background threads spawned from different
+userspace processes, we can't use a single global handle per annotation.
+Instead, the userspace process passes a non-zero handle through the
+common_handle field of the kcov_remote_arg struct. This common handle gets
+saved to the kcov_handle field in the current task_struct and needs to be
+passed to the newly spawned threads via custom annotations. Those threads
+should in turn be annotated with kcov_remote_start()/kcov_remote_stop().
+
+Internally kcov stores handles as u64 integers. The top byte of a handle
+is used to denote the id of a subsystem that this handle belongs to, and
+the lower 4 bytes are used to denote the id of a thread instance within
+that subsystem. A reserved value 0 is used as a subsystem id for common
+handles as they don't belong to a particular subsystem. The bytes 4-7 are
+currently reserved and must be zero. In the future the number of bytes
+used for the subsystem or handle ids might be increased.
+
+When a particular userspace proccess collects coverage by via a common
+handle, kcov will collect coverage for each code section that is annotated
+to use the common handle obtained as kcov_handle from the current
+task_struct. However non common handles allow to collect coverage
+selectively from different subsystems.
+
+.. code-block:: c
+
+    struct kcov_remote_arg {
+       unsigned        trace_mode;
+       unsigned        area_size;
+       unsigned        num_handles;
+       uint64_t        common_handle;
+       uint64_t        handles[0];
+    };
+
+    #define KCOV_INIT_TRACE                    _IOR('c', 1, unsigned long)
+    #define KCOV_DISABLE                       _IO('c', 101)
+    #define KCOV_REMOTE_ENABLE         _IOW('c', 102, struct kcov_remote_arg)
+
+    #define COVER_SIZE (64 << 10)
+
+    #define KCOV_TRACE_PC      0
+
+    #define KCOV_SUBSYSTEM_COMMON      (0x00ull << 56)
+    #define KCOV_SUBSYSTEM_USB (0x01ull << 56)
+
+    #define KCOV_SUBSYSTEM_MASK        (0xffull << 56)
+    #define KCOV_INSTANCE_MASK (0xffffffffull)
+
+    static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst)
+    {
+       if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK)
+               return 0;
+       return subsys | inst;
+    }
+
+    #define KCOV_COMMON_ID     0x42
+    #define KCOV_USB_BUS_NUM   1
+
+    int main(int argc, char **argv)
+    {
+       int fd;
+       unsigned long *cover, n, i;
+       struct kcov_remote_arg *arg;
+
+       fd = open("/sys/kernel/debug/kcov", O_RDWR);
+       if (fd == -1)
+               perror("open"), exit(1);
+       if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
+               perror("ioctl"), exit(1);
+       cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
+                                    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if ((void*)cover == MAP_FAILED)
+               perror("mmap"), exit(1);
+
+       /* Enable coverage collection via common handle and from USB bus #1. */
+       arg = calloc(1, sizeof(*arg) + sizeof(uint64_t));
+       if (!arg)
+               perror("calloc"), exit(1);
+       arg->trace_mode = KCOV_TRACE_PC;
+       arg->area_size = COVER_SIZE;
+       arg->num_handles = 1;
+       arg->common_handle = kcov_remote_handle(KCOV_SUBSYSTEM_COMMON,
+                                                       KCOV_COMMON_ID);
+       arg->handles[0] = kcov_remote_handle(KCOV_SUBSYSTEM_USB,
+                                               KCOV_USB_BUS_NUM);
+       if (ioctl(fd, KCOV_REMOTE_ENABLE, arg))
+               perror("ioctl"), free(arg), exit(1);
+       free(arg);
+
+       /*
+        * Here the user needs to trigger execution of a kernel code section
+        * that is either annotated with the common handle, or to trigger some
+        * activity on USB bus #1.
+        */
+       sleep(2);
+
+       n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
+       for (i = 0; i < n; i++)
+               printf("0x%lx\n", cover[i + 1]);
+       if (ioctl(fd, KCOV_DISABLE, 0))
+               perror("ioctl"), exit(1);
+       if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
+               perror("munmap"), exit(1);
+       if (close(fd))
+               perror("close"), exit(1);
+       return 0;
+    }
index 3621cd5..3a289e8 100644 (file)
@@ -69,7 +69,7 @@ the kernel command line.
 
 Memory may be allocated or freed before kmemleak is initialised and
 these actions are stored in an early log buffer. The size of this buffer
-is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
+is configured via the CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE option.
 
 If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
 disabled by default. Passing ``kmemleak=on`` on the kernel command
index 5138a2f..646cb35 100644 (file)
@@ -12,7 +12,6 @@ $(obj)/%.example.dts: $(src)/%.yaml FORCE
        $(call if_changed,chk_binding)
 
 DT_TMP_SCHEMA := processed-schema.yaml
-extra-y += $(DT_TMP_SCHEMA)
 
 quiet_cmd_mk_schema = SCHEMA  $@
       cmd_mk_schema = $(DT_MK_SCHEMA) $(DT_MK_SCHEMA_FLAGS) -o $@ $(real-prereqs)
@@ -26,8 +25,12 @@ DT_DOCS = $(shell \
 
 DT_SCHEMA_FILES ?= $(addprefix $(src)/,$(DT_DOCS))
 
+ifeq ($(CHECK_DTBS),)
 extra-y += $(patsubst $(src)/%.yaml,%.example.dts, $(DT_SCHEMA_FILES))
 extra-y += $(patsubst $(src)/%.yaml,%.example.dt.yaml, $(DT_SCHEMA_FILES))
+endif
 
 $(obj)/$(DT_TMP_SCHEMA): $(DT_SCHEMA_FILES) FORCE
        $(call if_changed,mk_schema)
+
+extra-y += $(DT_TMP_SCHEMA)
index 99015ce..c6a4433 100644 (file)
@@ -94,7 +94,7 @@ properties:
               - amlogic,p212
               - hwacom,amazetv
               - khadas,vim
-              - libretech,cc
+              - libretech,aml-s905x-cc
               - nexbox,a95x
           - const: amlogic,s905x
           - const: amlogic,meson-gxl
@@ -147,6 +147,7 @@ properties:
           - enum:
               - hardkernel,odroid-n2
               - khadas,vim3
+              - ugoos,am6
           - const: amlogic,s922x
           - const: amlogic,g12b
 
@@ -156,4 +157,10 @@ properties:
               - seirobotics,sei610
               - khadas,vim3l
           - const: amlogic,sm1
+
+      - description: Boards with the Amlogic Meson A1 A113L SoC
+        items:
+          - enum:
+              - amlogic,ad401
+          - const: amlogic,a1
 ...
diff --git a/Documentation/devicetree/bindings/arm/amlogic/smp-sram.txt b/Documentation/devicetree/bindings/arm/amlogic/smp-sram.txt
deleted file mode 100644 (file)
index 3473dda..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-Amlogic Meson8 and Meson8b SRAM for smp bringup:
-------------------------------------------------
-
-Amlogic's SMP-capable SoCs use part of the sram for the bringup of the cores.
-Once the core gets powered up it executes the code that is residing at a
-specific location.
-
-Therefore a reserved section sub-node has to be added to the mmio-sram
-declaration.
-
-Required sub-node properties:
-- compatible : depending on the SoC this should be one of:
-               "amlogic,meson8-smp-sram"
-               "amlogic,meson8b-smp-sram"
-
-The rest of the properties should follow the generic mmio-sram discription
-found in ../../misc/sram.txt
-
-Example:
-
-       sram: sram@d9000000 {
-               compatible = "mmio-sram";
-               reg = <0xd9000000 0x20000>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0xd9000000 0x20000>;
-
-               smp-sram@1ff80 {
-                       compatible = "amlogic,meson8b-smp-sram";
-                       reg = <0x1ff80 0x8>;
-               };
-       };
index 083dbf9..f493d69 100644 (file)
@@ -100,7 +100,7 @@ Required sub-node properties:
 
 [0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] Documentation/devicetree/bindings/power/power_domain.txt
+[2] Documentation/devicetree/bindings/power/power-domain.yaml
 [3] Documentation/devicetree/bindings/thermal/thermal.txt
 [4] Documentation/devicetree/bindings/sram/sram.txt
 [5] Documentation/devicetree/bindings/reset/reset.txt
index 4018319..7b83ef4 100644 (file)
@@ -110,7 +110,7 @@ Required properties:
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/thermal/thermal.txt
 [3] Documentation/devicetree/bindings/sram/sram.txt
-[4] Documentation/devicetree/bindings/power/power_domain.txt
+[4] Documentation/devicetree/bindings/power/power-domain.yaml
 
 Example:
 
index 6e168ab..6dd8be4 100644 (file)
@@ -45,6 +45,13 @@ properties:
           - const: atmel,at91sam9x5
           - const: atmel,at91sam9
 
+      - description: Overkiz kizbox3 board
+        items:
+          - const: overkiz,kizbox3-hs
+          - const: atmel,sama5d27
+          - const: atmel,sama5d2
+          - const: atmel,sama5
+
       - items:
           - const: atmel,sama5d27
           - const: atmel,sama5d2
@@ -73,6 +80,13 @@ properties:
           - const: atmel,sama5d3
           - const: atmel,sama5
 
+      - description: Overkiz kizbox2 board with two heads
+        items:
+          - const: overkiz,kizbox2-2
+          - const: atmel,sama5d31
+          - const: atmel,sama5d3
+          - const: atmel,sama5
+
       - items:
           - enum:
               - atmel,sama5d31
diff --git a/Documentation/devicetree/bindings/arm/axentia.txt b/Documentation/devicetree/bindings/arm/axentia.txt
deleted file mode 100644 (file)
index de58f24..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-Device tree bindings for Axentia ARM devices
-============================================
-
-Linea CPU module
-----------------
-
-Required root node properties:
-compatible = "axentia,linea",
-            "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
-and following the rules from atmel-at91.txt for a sama5d31 SoC.
-
-
-Nattis v2 board with Natte v2 power board
------------------------------------------
-
-Required root node properties:
-compatible = "axentia,nattis-2", "axentia,natte-2", "axentia,linea",
-            "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
-and following the rules from above for the axentia,linea CPU module.
-
-
-TSE-850 v3 board
-----------------
-
-Required root node properties:
-compatible = "axentia,tse850v3", "axentia,linea",
-            "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
-and following the rules from above for the axentia,linea CPU module.
diff --git a/Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml b/Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml
new file mode 100644 (file)
index 0000000..dd52e29
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/bcm/bcm2835.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM2711/BCM2835 Platforms Device Tree Bindings
+
+maintainers:
+  - Eric Anholt <eric@anholt.net>
+  - Stefan Wahren <wahrenst@gmx.net>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: BCM2711 based Boards
+        items:
+          - enum:
+              - raspberrypi,4-model-b
+          - const: brcm,bcm2711
+
+      - description: BCM2835 based Boards
+        items:
+          - enum:
+              - raspberrypi,model-a
+              - raspberrypi,model-a-plus
+              - raspberrypi,model-b
+              - raspberrypi,model-b-i2c0  # Raspberry Pi Model B (no P5)
+              - raspberrypi,model-b-rev2
+              - raspberrypi,model-b-plus
+              - raspberrypi,compute-module
+              - raspberrypi,model-zero
+              - raspberrypi,model-zero-w
+          - const: brcm,bcm2835
+
+      - description: BCM2836 based Boards
+        items:
+          - enum:
+              - raspberrypi,2-model-b
+          - const: brcm,bcm2836
+
+      - description: BCM2837 based Boards
+        items:
+          - enum:
+              - raspberrypi,3-model-a-plus
+              - raspberrypi,3-model-b
+              - raspberrypi,3-model-b-plus
+              - raspberrypi,3-compute-module
+              - raspberrypi,3-compute-module-lite
+          - const: brcm,bcm2837
+
+...
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
deleted file mode 100644 (file)
index 245328f..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-Broadcom BCM2835 device tree bindings
--------------------------------------------
-
-Raspberry Pi Model A
-Required root node properties:
-compatible = "raspberrypi,model-a", "brcm,bcm2835";
-
-Raspberry Pi Model A+
-Required root node properties:
-compatible = "raspberrypi,model-a-plus", "brcm,bcm2835";
-
-Raspberry Pi Model B
-Required root node properties:
-compatible = "raspberrypi,model-b", "brcm,bcm2835";
-
-Raspberry Pi Model B (no P5)
-early model B with I2C0 rather than I2C1 routed to the expansion header
-Required root node properties:
-compatible = "raspberrypi,model-b-i2c0", "brcm,bcm2835";
-
-Raspberry Pi Model B rev2
-Required root node properties:
-compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835";
-
-Raspberry Pi Model B+
-Required root node properties:
-compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
-
-Raspberry Pi 2 Model B
-Required root node properties:
-compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
-
-Raspberry Pi 3 Model A+
-Required root node properties:
-compatible = "raspberrypi,3-model-a-plus", "brcm,bcm2837";
-
-Raspberry Pi 3 Model B
-Required root node properties:
-compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
-
-Raspberry Pi 3 Model B+
-Required root node properties:
-compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837";
-
-Raspberry Pi Compute Module
-Required root node properties:
-compatible = "raspberrypi,compute-module", "brcm,bcm2835";
-
-Raspberry Pi Compute Module 3
-Required root node properties:
-compatible = "raspberrypi,3-compute-module", "brcm,bcm2837";
-
-Raspberry Pi Compute Module 3 Lite
-Required root node properties:
-compatible = "raspberrypi,3-compute-module-lite", "brcm,bcm2837";
-
-Raspberry Pi Zero
-Required root node properties:
-compatible = "raspberrypi,model-zero", "brcm,bcm2835";
-
-Raspberry Pi Zero W
-Required root node properties:
-compatible = "raspberrypi,model-zero-w", "brcm,bcm2835";
-
-Generic BCM2835 board
-Required root node properties:
-compatible = "brcm,bcm2835";
index cb30895..c23c24f 100644 (file)
@@ -189,6 +189,7 @@ properties:
               - marvell,armada-390-smp
               - marvell,armada-xp-smp
               - marvell,98dx3236-smp
+              - marvell,mmp3-smp
               - mediatek,mt6589-smp
               - mediatek,mt81xx-tz-smp
               - qcom,gcc-msm8660
index 70c1a62..e07735a 100644 (file)
@@ -124,7 +124,7 @@ Required properties for Pinctrl sub nodes:
                        CONFIG settings.
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] Documentation/devicetree/bindings/power/power_domain.txt
+[2] Documentation/devicetree/bindings/power/power-domain.yaml
 [3] Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
 
 RTC bindings based on SCU Message Protocol
index 1b4b4e6..f79683a 100644 (file)
@@ -38,12 +38,16 @@ properties:
       - description: i.MX27 Product Development Kit
         items:
           - enum:
+              - armadeus,imx27-apf27      # APF27 SoM
+              - armadeus,imx27-apf27dev   # APF27 SoM on APF27Dev board
               - fsl,imx27-pdk
           - const: fsl,imx27
 
       - description: i.MX28 based Boards
         items:
           - enum:
+              - armadeus,imx28-apf28      # APF28 SoM
+              - armadeus,imx28-apf28dev   # APF28 SoM on APF28Dev board
               - fsl,imx28-evk
               - i2se,duckbill
               - i2se,duckbill-2
@@ -87,7 +91,8 @@ properties:
       - description: i.MX51 Babbage Board
         items:
           - enum:
-              - armadeus,imx51-apf51
+              - armadeus,imx51-apf51    # APF51 SoM
+              - armadeus,imx51-apf51dev # APF51 SoM on APF51Dev board
               - fsl,imx51-babbage
               - technologic,imx51-ts4800
           - const: fsl,imx51
@@ -106,6 +111,8 @@ properties:
       - description: i.MX6Q based Boards
         items:
           - enum:
+              - armadeus,imx6q-apf6       # APF6 (Quad/Dual) SoM
+              - armadeus,imx6q-apf6dev    # APF6 (Quad/Dual) SoM on APF6Dev board
               - emtrion,emcon-mx6         # emCON-MX6D or emCON-MX6Q SoM
               - emtrion,emcon-mx6-avari   # emCON-MX6D or emCON-MX6Q SoM on Avari Base
               - fsl,imx6q-arm2
@@ -114,6 +121,11 @@ properties:
               - fsl,imx6q-sabresd
               - technologic,imx6q-ts4900
               - technologic,imx6q-ts7970
+              - toradex,apalis_imx6q            # Apalis iMX6 Module
+              - toradex,apalis_imx6q-eval       # Apalis iMX6 Module on Apalis Evaluation Board
+              - toradex,apalis_imx6q-ixora      # Apalis iMX6 Module on Ixora
+              - toradex,apalis_imx6q-ixora-v1.1 # Apalis iMX6 Module on Ixora V1.1
+              - variscite,dt6customboard
           - const: fsl,imx6q
 
       - description: i.MX6QP based Boards
@@ -126,6 +138,8 @@ properties:
       - description: i.MX6DL based Boards
         items:
           - enum:
+              - armadeus,imx6dl-apf6      # APF6 (Solo) SoM
+              - armadeus,imx6dl-apf6dldev # APF6 (Solo) SoM on APF6Dev board
               - eckelmann,imx6dl-ci4x10
               - emtrion,emcon-mx6         # emCON-MX6S or emCON-MX6DL SoM
               - emtrion,emcon-mx6-avari   # emCON-MX6S or emCON-MX6DL SoM on Avari Base
@@ -133,6 +147,8 @@ properties:
               - fsl,imx6dl-sabresd        # i.MX6 DualLite SABRE Smart Device Board
               - technologic,imx6dl-ts4900
               - technologic,imx6dl-ts7970
+              - toradex,colibri_imx6dl          # Colibri iMX6 Module
+              - toradex,colibri_imx6dl-eval-v3  # Colibri iMX6 Module on Colibri Evaluation Board V3
               - ysoft,imx6dl-yapp4-draco  # i.MX6 DualLite Y Soft IOTA Draco board
               - ysoft,imx6dl-yapp4-hydra  # i.MX6 DualLite Y Soft IOTA Hydra board
               - ysoft,imx6dl-yapp4-ursa   # i.MX6 Solo Y Soft IOTA Ursa board
@@ -148,6 +164,7 @@ properties:
         items:
           - enum:
               - fsl,imx6sll-evk
+              - kobo,clarahd
           - const: fsl,imx6sll
 
       - description: i.MX6SX based Boards
@@ -160,8 +177,11 @@ properties:
       - description: i.MX6UL based Boards
         items:
           - enum:
+              - armadeus,imx6ul-opos6ul    # OPOS6UL (i.MX6UL) SoM
+              - armadeus,imx6ul-opos6uldev # OPOS6UL (i.MX6UL) SoM on OPOS6ULDev board
               - fsl,imx6ul-14x14-evk      # i.MX6 UltraLite 14x14 EVK Board
               - kontron,imx6ul-n6310-som  # Kontron N6310 SOM
+              - kontron,imx6ul-n6311-som  # Kontron N6311 SOM
           - const: fsl,imx6ul
 
       - description: Kontron N6310 S Board
@@ -170,6 +190,12 @@ properties:
           - const: kontron,imx6ul-n6310-som
           - const: fsl,imx6ul
 
+      - description: Kontron N6311 S Board
+        items:
+          - const: kontron,imx6ul-n6311-s
+          - const: kontron,imx6ul-n6311-som
+          - const: fsl,imx6ul
+
       - description: Kontron N6310 S 43 Board
         items:
           - const: kontron,imx6ul-n6310-s-43
@@ -180,7 +206,18 @@ properties:
       - description: i.MX6ULL based Boards
         items:
           - enum:
+              - armadeus,imx6ull-opos6ul    # OPOS6UL (i.MX6ULL) SoM
+              - armadeus,imx6ull-opos6uldev # OPOS6UL (i.MX6ULL) SoM on OPOS6ULDev board
               - fsl,imx6ull-14x14-evk     # i.MX6 UltraLiteLite 14x14 EVK Board
+              - kontron,imx6ull-n6411-som # Kontron N6411 SOM
+              - toradex,colibri-imx6ull-eval            # Colibri iMX6ULL Module on Colibri Evaluation Board
+              - toradex,colibri-imx6ull-wifi-eval       # Colibri iMX6ULL Wi-Fi / Bluetooth Module on Colibri Evaluation Board
+          - const: fsl,imx6ull
+
+      - description: Kontron N6411 S Board
+        items:
+          - const: kontron,imx6ull-n6411-s
+          - const: kontron,imx6ull-n6411-som
           - const: fsl,imx6ull
 
       - description: i.MX6ULZ based Boards
@@ -193,6 +230,8 @@ properties:
       - description: i.MX7S based Boards
         items:
           - enum:
+              - toradex,colibri-imx7s           # Colibri iMX7 Solo Module
+              - toradex,colibri-imx7s-eval-v3   # Colibri iMX7 Solo Module on Colibri Evaluation Board V3
               - tq,imx7s-mba7             # i.MX7S TQ MBa7 with TQMa7S SoM
           - const: fsl,imx7s
 
@@ -201,6 +240,10 @@ properties:
           - enum:
               - fsl,imx7d-sdb             # i.MX7 SabreSD Board
               - novtech,imx7d-meerkat96   # i.MX7 Meerkat96 Board
+              - toradex,colibri-imx7d                   # Colibri iMX7 Dual Module
+              - toradex,colibri-imx7d-emmc              # Colibri iMX7 Dual 1GB (eMMC) Module
+              - toradex,colibri-imx7d-emmc-eval-v3      # Colibri iMX7 Dual 1GB (eMMC) Module on Colibri Evaluation Board V3
+              - toradex,colibri-imx7d-eval-v3           # Colibri iMX7 Dual Module on Colibri Evaluation Board V3
               - tq,imx7d-mba7             # i.MX7D TQ MBa7 with TQMa7D SoM
               - zii,imx7d-rmu2            # ZII RMU2 Board
               - zii,imx7d-rpu2            # ZII RPU2 Board
@@ -233,6 +276,7 @@ properties:
         items:
           - enum:
               - fsl,imx8mn-ddr4-evk       # i.MX8MN DDR4 EVK Board
+              - fsl,imx8mn-evk            # i.MX8MN LPDDR4 EVK Board
           - const: fsl,imx8mn
 
       - description: i.MX8MQ based Boards
@@ -250,6 +294,8 @@ properties:
           - enum:
               - einfochips,imx8qxp-ai_ml  # i.MX8QXP AI_ML Board
               - fsl,imx8qxp-mek           # i.MX8QXP MEK Board
+              - toradex,colibri-imx8x         # Colibri iMX8X Module
+              - toradex,colibri-imx8x-eval-v3 # Colibri iMX8X Module on Colibri Evaluation Board V3
           - const: fsl,imx8qxp
 
       - description:
@@ -267,6 +313,10 @@ properties:
               - fsl,vf600
               - fsl,vf610
               - fsl,vf610m4
+              - toradex,vf500-colibri_vf50              # Colibri VF50 Module
+              - toradex,vf500-colibri_vf50-on-eval      # Colibri VF50 Module on Colibri Evaluation Board
+              - toradex,vf610-colibri_vf61              # Colibri VF61 Module
+              - toradex,vf610-colibri_vf61-on-eval      # Colibri VF61 Module on Colibri Evaluation Board
 
       - description: ZII's VF610 based Boards
         items:
@@ -335,4 +385,10 @@ properties:
               - fsl,ls2088a-rdb
           - const: fsl,ls2088a
 
+      - description: S32V234 based Boards
+        items:
+          - enum:
+              - fsl,s32v234-evb           # S32V234-EVB2 Customer Evaluation Board
+          - const: fsl,s32v234
+
 ...
diff --git a/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt
deleted file mode 100644 (file)
index 26410fb..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-Marvell Armada AP806 System Controller
-======================================
-
-The AP806 is one of the two core HW blocks of the Marvell Armada 7K/8K
-SoCs. It contains system controllers, which provide several registers
-giving access to numerous features: clocks, pin-muxing and many other
-SoC configuration items. This DT binding allows to describe these
-system controllers.
-
-For the top level node:
- - compatible: must be: "syscon", "simple-mfd";
- - reg: register area of the AP806 system controller
-
-SYSTEM CONTROLLER 0
-===================
-
-Clocks:
--------
-
-
-The Device Tree node representing the AP806/AP807 system controller
-provides a number of clocks:
-
- - 0: reference clock of CPU cluster 0
- - 1: reference clock of CPU cluster 1
- - 2: fixed PLL at 1200 Mhz
- - 3: MSS clock, derived from the fixed PLL
-
-Required properties:
-
- - compatible: must be one of:
-   * "marvell,ap806-clock"
-   * "marvell,ap807-clock"
- - #clock-cells: must be set to 1
-
-Pinctrl:
---------
-
-For common binding part and usage, refer to
-Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt.
-
-Required properties:
-- compatible must be "marvell,ap806-pinctrl",
-
-Available mpp pins/groups and functions:
-Note: brackets (x) are not part of the mpp name for marvell,function and given
-only for more detailed description in this document.
-
-name   pins    functions
-================================================================================
-mpp0   0       gpio, sdio(clk), spi0(clk)
-mpp1   1       gpio, sdio(cmd), spi0(miso)
-mpp2   2       gpio, sdio(d0), spi0(mosi)
-mpp3   3       gpio, sdio(d1), spi0(cs0n)
-mpp4   4       gpio, sdio(d2), i2c0(sda)
-mpp5   5       gpio, sdio(d3), i2c0(sdk)
-mpp6   6       gpio, sdio(ds)
-mpp7   7       gpio, sdio(d4), uart1(rxd)
-mpp8   8       gpio, sdio(d5), uart1(txd)
-mpp9   9       gpio, sdio(d6), spi0(cs1n)
-mpp10  10      gpio, sdio(d7)
-mpp11  11      gpio, uart0(txd)
-mpp12  12      gpio, sdio(pw_off), sdio(hw_rst)
-mpp13  13      gpio
-mpp14  14      gpio
-mpp15  15      gpio
-mpp16  16      gpio
-mpp17  17      gpio
-mpp18  18      gpio
-mpp19  19      gpio, uart0(rxd), sdio(pw_off)
-
-GPIO:
------
-For common binding part and usage, refer to
-Documentation/devicetree/bindings/gpio/gpio-mvebu.txt.
-
-Required properties:
-
-- compatible: "marvell,armada-8k-gpio"
-
-- offset: offset address inside the syscon block
-
-Example:
-ap_syscon: system-controller@6f4000 {
-       compatible = "syscon", "simple-mfd";
-       reg = <0x6f4000 0x1000>;
-
-       ap_clk: clock {
-               compatible = "marvell,ap806-clock";
-               #clock-cells = <1>;
-       };
-
-       ap_pinctrl: pinctrl {
-               compatible = "marvell,ap806-pinctrl";
-       };
-
-       ap_gpio: gpio {
-               compatible = "marvell,armada-8k-gpio";
-               offset = <0x1040>;
-               ngpios = <19>;
-               gpio-controller;
-               #gpio-cells = <2>;
-               gpio-ranges = <&ap_pinctrl 0 0 19>;
-       };
-};
-
-SYSTEM CONTROLLER 1
-===================
-
-Thermal:
---------
-
-For common binding part and usage, refer to
-Documentation/devicetree/bindings/thermal/thermal.txt
-
-The thermal IP can probe the temperature all around the processor. It
-may feature several channels, each of them wired to one sensor.
-
-It is possible to setup an overheat interrupt by giving at least one
-critical point to any subnode of the thermal-zone node.
-
-Required properties:
-- compatible: must be one of:
-  * marvell,armada-ap806-thermal
-- reg: register range associated with the thermal functions.
-
-Optional properties:
-- interrupts: overheat interrupt handle. Should point to line 18 of the
-  SEI irqchip. See interrupt-controller/interrupts.txt
-- #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer
-  to this IP and represents the channel ID. There is one sensor per
-  channel. O refers to the thermal IP internal channel, while positive
-  IDs refer to each CPU.
-
-Example:
-ap_syscon1: system-controller@6f8000 {
-       compatible = "syscon", "simple-mfd";
-       reg = <0x6f8000 0x1000>;
-
-       ap_thermal: thermal-sensor@80 {
-               compatible = "marvell,armada-ap806-thermal";
-               reg = <0x80 0x10>;
-               interrupt-parent = <&sei>;
-               interrupts = <18>;
-               #thermal-sensor-cells = <1>;
-       };
-};
-
-Cluster clocks:
----------------
-
-Device Tree Clock bindings for cluster clock of Marvell
-AP806/AP807. Each cluster contain up to 2 CPUs running at the same
-frequency.
-
-Required properties:
- - compatible: must be one of:
-   * "marvell,ap806-cpu-clock"
-   * "marvell,ap807-cpu-clock"
-- #clock-cells : should be set to 1.
-
-- clocks : shall be the input parent clock(s) phandle for the clock
-           (one per cluster)
-
-- reg: register range associated with the cluster clocks
-
-ap_syscon1: system-controller@6f8000 {
-       compatible = "marvell,armada-ap806-syscon1", "syscon", "simple-mfd";
-       reg = <0x6f8000 0x1000>;
-
-       cpu_clk: clock-cpu@278 {
-               compatible = "marvell,ap806-cpu-clock";
-               clocks = <&ap_clk 0>, <&ap_clk 1>;
-               #clock-cells = <1>;
-               reg = <0x278 0xa30>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt
new file mode 100644 (file)
index 0000000..098d932
--- /dev/null
@@ -0,0 +1,177 @@
+Marvell Armada AP80x System Controller
+======================================
+
+The AP806/AP807 is one of the two core HW blocks of the Marvell Armada
+7K/8K/931x SoCs. It contains system controllers, which provide several
+registers giving access to numerous features: clocks, pin-muxing and
+many other SoC configuration items. This DT binding allows to describe
+these system controllers.
+
+For the top level node:
+ - compatible: must be: "syscon", "simple-mfd";
+ - reg: register area of the AP80x system controller
+
+SYSTEM CONTROLLER 0
+===================
+
+Clocks:
+-------
+
+
+The Device Tree node representing the AP806/AP807 system controller
+provides a number of clocks:
+
+ - 0: reference clock of CPU cluster 0
+ - 1: reference clock of CPU cluster 1
+ - 2: fixed PLL at 1200 Mhz
+ - 3: MSS clock, derived from the fixed PLL
+
+Required properties:
+
+ - compatible: must be one of:
+   * "marvell,ap806-clock"
+   * "marvell,ap807-clock"
+ - #clock-cells: must be set to 1
+
+Pinctrl:
+--------
+
+For common binding part and usage, refer to
+Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt.
+
+Required properties:
+- compatible must be "marvell,ap806-pinctrl",
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name   pins    functions
+================================================================================
+mpp0   0       gpio, sdio(clk), spi0(clk)
+mpp1   1       gpio, sdio(cmd), spi0(miso)
+mpp2   2       gpio, sdio(d0), spi0(mosi)
+mpp3   3       gpio, sdio(d1), spi0(cs0n)
+mpp4   4       gpio, sdio(d2), i2c0(sda)
+mpp5   5       gpio, sdio(d3), i2c0(sdk)
+mpp6   6       gpio, sdio(ds)
+mpp7   7       gpio, sdio(d4), uart1(rxd)
+mpp8   8       gpio, sdio(d5), uart1(txd)
+mpp9   9       gpio, sdio(d6), spi0(cs1n)
+mpp10  10      gpio, sdio(d7)
+mpp11  11      gpio, uart0(txd)
+mpp12  12      gpio, sdio(pw_off), sdio(hw_rst)
+mpp13  13      gpio
+mpp14  14      gpio
+mpp15  15      gpio
+mpp16  16      gpio
+mpp17  17      gpio
+mpp18  18      gpio
+mpp19  19      gpio, uart0(rxd), sdio(pw_off)
+
+GPIO:
+-----
+For common binding part and usage, refer to
+Documentation/devicetree/bindings/gpio/gpio-mvebu.txt.
+
+Required properties:
+
+- compatible: "marvell,armada-8k-gpio"
+
+- offset: offset address inside the syscon block
+
+Example:
+ap_syscon: system-controller@6f4000 {
+       compatible = "syscon", "simple-mfd";
+       reg = <0x6f4000 0x1000>;
+
+       ap_clk: clock {
+               compatible = "marvell,ap806-clock";
+               #clock-cells = <1>;
+       };
+
+       ap_pinctrl: pinctrl {
+               compatible = "marvell,ap806-pinctrl";
+       };
+
+       ap_gpio: gpio {
+               compatible = "marvell,armada-8k-gpio";
+               offset = <0x1040>;
+               ngpios = <19>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-ranges = <&ap_pinctrl 0 0 19>;
+       };
+};
+
+SYSTEM CONTROLLER 1
+===================
+
+Thermal:
+--------
+
+For common binding part and usage, refer to
+Documentation/devicetree/bindings/thermal/thermal.txt
+
+The thermal IP can probe the temperature all around the processor. It
+may feature several channels, each of them wired to one sensor.
+
+It is possible to setup an overheat interrupt by giving at least one
+critical point to any subnode of the thermal-zone node.
+
+Required properties:
+- compatible: must be one of:
+  * marvell,armada-ap806-thermal
+- reg: register range associated with the thermal functions.
+
+Optional properties:
+- interrupts: overheat interrupt handle. Should point to line 18 of the
+  SEI irqchip. See interrupt-controller/interrupts.txt
+- #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer
+  to this IP and represents the channel ID. There is one sensor per
+  channel. O refers to the thermal IP internal channel, while positive
+  IDs refer to each CPU.
+
+Example:
+ap_syscon1: system-controller@6f8000 {
+       compatible = "syscon", "simple-mfd";
+       reg = <0x6f8000 0x1000>;
+
+       ap_thermal: thermal-sensor@80 {
+               compatible = "marvell,armada-ap806-thermal";
+               reg = <0x80 0x10>;
+               interrupt-parent = <&sei>;
+               interrupts = <18>;
+               #thermal-sensor-cells = <1>;
+       };
+};
+
+Cluster clocks:
+---------------
+
+Device Tree Clock bindings for cluster clock of Marvell
+AP806/AP807. Each cluster contain up to 2 CPUs running at the same
+frequency.
+
+Required properties:
+ - compatible: must be one of:
+   * "marvell,ap806-cpu-clock"
+   * "marvell,ap807-cpu-clock"
+- #clock-cells : should be set to 1.
+
+- clocks : shall be the input parent clock(s) phandle for the clock
+           (one per cluster)
+
+- reg: register range associated with the cluster clocks
+
+ap_syscon1: system-controller@6f8000 {
+       compatible = "marvell,armada-ap806-syscon1", "syscon", "simple-mfd";
+       reg = <0x6f8000 0x1000>;
+
+       cpu_clk: clock-cpu@278 {
+               compatible = "marvell,ap806-cpu-clock";
+               clocks = <&ap_clk 0>, <&ap_clk 1>;
+               #clock-cells = <1>;
+               reg = <0x278 0xa30>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.txt b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.txt
deleted file mode 100644 (file)
index df98a9c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Marvell Armada 7K/8K Platforms Device Tree Bindings
----------------------------------------------------
-
-Boards using a SoC of the Marvell Armada 7K or 8K families must carry
-the following root node property:
-
- - compatible, with one of the following values:
-
-   - "marvell,armada7020", "marvell,armada-ap806-dual", "marvell,armada-ap806"
-      when the SoC being used is the Armada 7020
-
-   - "marvell,armada7040", "marvell,armada-ap806-quad", "marvell,armada-ap806"
-      when the SoC being used is the Armada 7040
-
-   - "marvell,armada8020", "marvell,armada-ap806-dual", "marvell,armada-ap806"
-      when the SoC being used is the Armada 8020
-
-   - "marvell,armada8040", "marvell,armada-ap806-quad", "marvell,armada-ap806"
-      when the SoC being used is the Armada 8040
-
-Example:
-
-compatible = "marvell,armada7040-db", "marvell,armada7040",
-             "marvell,armada-ap806-quad", "marvell,armada-ap806";
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml
new file mode 100644 (file)
index 0000000..a9828c5
--- /dev/null
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR X11)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/marvell/armada-7k-8k.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Marvell Armada 7K/8K Platforms Device Tree Bindings
+
+maintainers:
+  - Gregory CLEMENT <gregory.clement@bootlin.com>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+
+      - description: Armada 7020 SoC
+        items:
+          - const: marvell,armada7020
+          - const: marvell,armada-ap806-dual
+          - const: marvell,armada-ap806
+
+      - description: Armada 7040 SoC
+        items:
+          - const: marvell,armada7040
+          - const: marvell,armada-ap806-quad
+          - const: marvell,armada-ap806
+
+      - description: Armada 8020 SoC
+        items:
+          - const: marvell,armada8020
+          - const: marvell,armada-ap806-dual
+          - const: marvell,armada-ap806
+
+      - description: Armada 8040 SoC
+        items:
+          - const: marvell,armada8040
+          - const: marvell,armada-ap806-quad
+          - const: marvell,armada-ap806
+
+      - description: Armada CN9130 SoC with no external CP
+        items:
+          - const: marvell,cn9130
+          - const: marvell,armada-ap807-quad
+          - const: marvell,armada-ap807
+
+      - description: Armada CN9131 SoC with one external CP
+        items:
+          - const: marvell,cn9131
+          - const: marvell,cn9130
+          - const: marvell,armada-ap807-quad
+          - const: marvell,armada-ap807
+
+      - description: Armada CN9132 SoC with two external CPs
+        items:
+          - const: marvell,cn9132
+          - const: marvell,cn9131
+          - const: marvell,cn9130
+          - const: marvell,armada-ap807-quad
+          - const: marvell,armada-ap807
diff --git a/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
deleted file mode 100644 (file)
index 9516875..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Marvell Platforms Device Tree Bindings
-----------------------------------------------------
-
-PXA168 Aspenite Board
-Required root node properties:
-       - compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
-
-PXA910 DKB Board
-Required root node properties:
-       - compatible = "mrvl,pxa910-dkb";
-
-MMP2 Brownstone Board
-Required root node properties:
-       - compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2";
diff --git a/Documentation/devicetree/bindings/arm/mrvl/mrvl.yaml b/Documentation/devicetree/bindings/arm/mrvl/mrvl.yaml
new file mode 100644 (file)
index 0000000..818dfe6
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/mrvl/mrvl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Marvell Platforms Device Tree Bindings
+
+maintainers:
+  - Lubomir Rintel <lkundrak@v3.sk>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: PXA168 Aspenite Board
+        items:
+          - enum:
+              - mrvl,pxa168-aspenite
+          - const: mrvl,pxa168
+      - description: PXA910 DKB Board
+        items:
+          - enum:
+              - mrvl,pxa910-dkb
+          - const: mrvl,pxa910
+      - description: MMP2 based boards
+        items:
+          - enum:
+              - mrvl,mmp2-brownstone
+          - const: mrvl,mmp2
+      - description: MMP3 based boards
+        items:
+          - const: mrvl,mmp3
+...
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
deleted file mode 100644 (file)
index eaee06b..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-== Introduction==
-
-LLCC (Last Level Cache Controller) provides last level of cache memory in SOC,
-that can be shared by multiple clients. Clients here are different cores in the
-SOC, the idea is to minimize the local caches at the clients and migrate to
-common pool of memory. Cache memory is divided into partitions called slices
-which are assigned to clients. Clients can query the slice details, activate
-and deactivate them.
-
-Properties:
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be "qcom,sdm845-llcc"
-
-- reg:
-       Usage: required
-       Value Type: <prop-encoded-array>
-       Definition: The first element specifies the llcc base start address and
-                   the size of the register region. The second element specifies
-                   the llcc broadcast base address and size of the register region.
-
-- reg-names:
-        Usage: required
-        Value Type: <stringlist>
-        Definition: Register region names. Must be "llcc_base", "llcc_broadcast_base".
-
-- interrupts:
-       Usage: required
-       Definition: The interrupt is associated with the llcc edac device.
-                       It's used for llcc cache single and double bit error detection
-                       and reporting.
-
-Example:
-
-       cache-controller@1100000 {
-               compatible = "qcom,sdm845-llcc";
-               reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
-               reg-names = "llcc_base", "llcc_broadcast_base";
-               interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml
new file mode 100644 (file)
index 0000000..5587490
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/msm/qcom,llcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Last Level Cache Controller
+
+maintainers:
+  - Rishabh Bhatnagar <rishabhb@codeaurora.org>
+  - Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
+
+description: |
+  LLCC (Last Level Cache Controller) provides last level of cache memory in SoC,
+  that can be shared by multiple clients. Clients here are different cores in the
+  SoC, the idea is to minimize the local caches at the clients and migrate to
+  common pool of memory. Cache memory is divided into partitions called slices
+  which are assigned to clients. Clients can query the slice details, activate
+  and deactivate them.
+
+properties:
+  compatible:
+    enum:
+      - qcom,sc7180-llcc
+      - qcom,sdm845-llcc
+
+  reg:
+    items:
+      - description: LLCC base register region
+      - description: LLCC broadcast base register region
+
+  reg-names:
+    items:
+      - const: llcc_base
+      - const: llcc_broadcast_base
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    cache-controller@1100000 {
+      compatible = "qcom,sdm845-llcc";
+      reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
+      reg-names = "llcc_base", "llcc_broadcast_base";
+      interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/omap/prm-inst.txt b/Documentation/devicetree/bindings/arm/omap/prm-inst.txt
new file mode 100644 (file)
index 0000000..fcd3456
--- /dev/null
@@ -0,0 +1,29 @@
+OMAP PRM instance bindings
+
+Power and Reset Manager is an IP block on OMAP family of devices which
+handle the power domains and their current state, and provide reset
+handling for the domains and/or separate IP blocks under the power domain
+hierarchy.
+
+Required properties:
+- compatible:  Must contain one of the following:
+               "ti,am3-prm-inst"
+               "ti,am4-prm-inst"
+               "ti,omap4-prm-inst"
+               "ti,omap5-prm-inst"
+               "ti,dra7-prm-inst"
+               and additionally must contain:
+               "ti,omap-prm-inst"
+- reg:         Contains PRM instance register address range
+               (base address and length)
+
+Optional properties:
+- #reset-cells:        Should be 1 if the PRM instance in question supports resets.
+
+Example:
+
+prm_dsp2: prm@1b00 {
+       compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+       reg = <0x1b00 0x40>;
+       #reset-cells = <1>;
+};
index 3528b61..ab59de1 100644 (file)
@@ -13,11 +13,24 @@ properties:
   $nodename:
     const: '/'
   compatible:
-    # RTD1295 SoC based boards
-    items:
-      - enum:
-          - mele,v9
-          - probox2,ava
-          - zidoo,x9s
-      - const: realtek,rtd1295
+    oneOf:
+      # RTD1293 SoC based boards
+      - items:
+          - enum:
+              - synology,ds418j # Synology DiskStation DS418j
+          - const: realtek,rtd1293
+
+      # RTD1295 SoC based boards
+      - items:
+          - enum:
+              - mele,v9 # MeLE V9
+              - probox2,ava # ProBox2 AVA
+              - zidoo,x9s # Zidoo X9S
+          - const: realtek,rtd1295
+
+      # RTD1296 SoC based boards
+      - items:
+          - enum:
+              - synology,ds418 # Synology DiskStation DS418
+          - const: realtek,rtd1296
 ...
diff --git a/Documentation/devicetree/bindings/arm/renesas,prr.txt b/Documentation/devicetree/bindings/arm/renesas,prr.txt
deleted file mode 100644 (file)
index 08e482e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-Renesas Product Register
-
-Most Renesas ARM SoCs have a Product Register or Boundary Scan ID Register that
-allows to retrieve SoC product and revision information.  If present, a device
-node for this register should be added.
-
-Required properties:
-  - compatible: Must be one of:
-    "renesas,prr"
-    "renesas,bsid"
-  - reg: Base address and length of the register block.
-
-
-Examples
---------
-
-       prr: chipid@ff000044 {
-               compatible = "renesas,prr";
-               reg = <0 0xff000044 0 4>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/renesas,prr.yaml b/Documentation/devicetree/bindings/arm/renesas,prr.yaml
new file mode 100644 (file)
index 0000000..7f8d17f
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/renesas,prr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas Product Register
+
+maintainers:
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+  - Magnus Damm <magnus.damm@gmail.com>
+
+description: |
+  Most Renesas ARM SoCs have a Product Register or Boundary Scan ID
+  Register that allows to retrieve SoC product and revision information.
+  If present, a device node for this register should be added.
+
+properties:
+  compatible:
+    enum:
+      - renesas,prr
+      - renesas,bsid
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    prr: chipid@ff000044 {
+        compatible = "renesas,prr";
+        reg = <0 0xff000044 0 4>;
+    };
index 28eb458..9436124 100644 (file)
@@ -116,6 +116,18 @@ properties:
           - const: hoperun,hihope-rzg2m
           - const: renesas,r8a774a1
 
+      - description: RZ/G2N (R8A774B1)
+        items:
+          - enum:
+              - hoperun,hihope-rzg2n # HopeRun HiHope RZ/G2N platform
+          - const: renesas,r8a774b1
+
+      - items:
+          - enum:
+              - hoperun,hihope-rzg2-ex # HopeRun expansion board for HiHope RZ/G2 platforms
+          - const: hoperun,hihope-rzg2n
+          - const: renesas,r8a774b1
+
       - description: RZ/G2E (R8A774C0)
         items:
           - enum:
@@ -193,15 +205,23 @@ properties:
               - renesas,salvator-xs # Salvator-XS (Salvator-X 2nd version, RTP0RC7796SIPB0012S)
           - const: renesas,r8a7796
 
+      - description: R-Car M3-W+ (R8A77961)
+        items:
+          - enum:
+              - renesas,salvator-xs # Salvator-XS (Salvator-X 2nd version, RTP0RC7796SIPB0012SA5A)
+          - const: renesas,r8a77961
+
       - description: Kingfisher (SBEV-RCAR-KF-M03)
         items:
           - const: shimafuji,kingfisher
           - enum:
               - renesas,h3ulcb
               - renesas,m3ulcb
+              - renesas,m3nulcb
           - enum:
               - renesas,r8a7795
               - renesas,r8a7796
+              - renesas,r8a77965
 
       - description: R-Car M3-N (R8A77965)
         items:
index 9c7e703..d9847b3 100644 (file)
@@ -40,6 +40,11 @@ properties:
           - const: asus,rk3288-tinker-s
           - const: rockchip,rk3288
 
+      - description: Beelink A1
+        items:
+          - const: azw,beelink-a1
+          - const: rockchip,rk3328
+
       - description: bq Curie 2 tablet
         items:
           - const: mundoreader,bq-curie2
@@ -82,6 +87,11 @@ properties:
           - const: firefly,firefly-rk3399
           - const: rockchip,rk3399
 
+      - description: Firefly ROC-RK3308-CC
+        items:
+          - const: firefly,roc-rk3308-cc
+          - const: rockchip,rk3308
+
       - description: Firefly roc-rk3328-cc
         items:
           - const: firefly,roc-rk3328-cc
@@ -89,7 +99,9 @@ properties:
 
       - description: Firefly ROC-RK3399-PC
         items:
-          - const: firefly,roc-rk3399-pc
+          - enum:
+              - firefly,roc-rk3399-pc
+              - firefly,roc-rk3399-pc-mezzanine
           - const: rockchip,rk3399
 
       - description: FriendlyElec NanoPi4 series boards
@@ -464,6 +476,11 @@ properties:
               - rockchip,rk3288-evb-rk808
           - const: rockchip,rk3288
 
+      - description: Rockchip RK3308 Evaluation board
+        items:
+          - const: rockchip,rk3308-evb
+          - const: rockchip,rk3308
+
       - description: Rockchip RK3328 Evaluation board
         items:
           - const: rockchip,rk3328-evb
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.txt
deleted file mode 100644 (file)
index 85c5dfd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-SAMSUNG Exynos SoCs Chipid driver.
-
-Required properties:
-- compatible : Should at least contain "samsung,exynos4210-chipid".
-
-- reg: offset and length of the register set
-
-Example:
-       chipid@10000000 {
-               compatible = "samsung,exynos4210-chipid";
-               reg = <0x10000000 0x100>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml b/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml
new file mode 100644 (file)
index 0000000..afcd708
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/samsung/exynos-chipid.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC series Chipid driver
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+  compatible:
+    items:
+      - const: samsung,exynos4210-chipid
+
+  reg:
+    maxItems: 1
+
+  samsung,asv-bin:
+    description:
+      Adaptive Supply Voltage bin selection. This can be used
+      to determine the ASV bin of an SoC if respective information
+      is missing in the CHIPID registers or in the OTP memory.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [ 0, 1, 2, 3 ]
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    chipid@10000000 {
+        compatible = "samsung,exynos4210-chipid";
+        reg = <0x10000000 0x100>;
+        samsung,asv-bin = <2>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
deleted file mode 100644 (file)
index 433bfd7..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-SAMSUNG Exynos SoC series PMU Registers
-
-Properties:
- - compatible : should contain two values. First value must be one from following list:
-                  - "samsung,exynos3250-pmu" - for Exynos3250 SoC,
-                  - "samsung,exynos4210-pmu" - for Exynos4210 SoC,
-                  - "samsung,exynos4412-pmu" - for Exynos4412 SoC,
-                  - "samsung,exynos5250-pmu" - for Exynos5250 SoC,
-                  - "samsung,exynos5260-pmu" - for Exynos5260 SoC.
-                  - "samsung,exynos5410-pmu" - for Exynos5410 SoC,
-                  - "samsung,exynos5420-pmu" - for Exynos5420 SoC.
-                  - "samsung,exynos5433-pmu" - for Exynos5433 SoC.
-                  - "samsung,exynos7-pmu" - for Exynos7 SoC.
-               second value must be always "syscon".
-
- - reg : offset and length of the register set.
-
- - #clock-cells : must be <1>, since PMU requires once cell as clock specifier.
-               The single specifier cell is used as index to list of clocks
-               provided by PMU, which is currently:
-                       0 : SoC clock output (CLKOUT pin)
-
- - clock-names : list of clock names for particular CLKOUT mux inputs in
-               following format:
-                       "clkoutN", where N is a decimal number corresponding to
-                       CLKOUT mux control bits value for given input, e.g.
-                               "clkout0", "clkout7", "clkout15".
-
- - clocks : list of phandles and specifiers to all input clocks listed in
-               clock-names property.
-
-Optional properties:
-
-Some PMUs are capable of behaving as an interrupt controller (mostly
-to wake up a suspended PMU). In which case, they can have the
-following properties:
-
-- interrupt-controller: indicate that said PMU is an interrupt controller
-
-- #interrupt-cells: must be identical to the that of the parent interrupt
-  controller.
-
-
-Optional nodes:
-
-- nodes defining the restart and poweroff syscon children
-
-
-Example :
-pmu_system_controller: system-controller@10040000 {
-       compatible = "samsung,exynos5250-pmu", "syscon";
-       reg = <0x10040000 0x5000>;
-       interrupt-controller;
-       #interrupt-cells = <3>;
-       interrupt-parent = <&gic>;
-       #clock-cells = <1>;
-       clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
-                       "clkout4", "clkout8", "clkout9";
-       clocks = <&clock CLK_OUT_DMC>, <&clock CLK_OUT_TOP>,
-               <&clock CLK_OUT_LEFTBUS>, <&clock CLK_OUT_RIGHTBUS>,
-               <&clock CLK_OUT_CPU>, <&clock CLK_XXTI>,
-               <&clock CLK_XUSBXTI>;
-};
-
-Example of clock consumer :
-
-usb3503: usb3503@8 {
-       /* ... */
-       clock-names = "refclk";
-       clocks = <&pmu_system_controller 0>;
-       /* ... */
-};
diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.yaml b/Documentation/devicetree/bindings/arm/samsung/pmu.yaml
new file mode 100644 (file)
index 0000000..73b56fc
--- /dev/null
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/samsung/pmu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC series Power Management Unit (PMU)
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+# Custom select to avoid matching all nodes with 'syscon'
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - samsung,exynos3250-pmu
+          - samsung,exynos4210-pmu
+          - samsung,exynos4412-pmu
+          - samsung,exynos5250-pmu
+          - samsung,exynos5260-pmu
+          - samsung,exynos5410-pmu
+          - samsung,exynos5420-pmu
+          - samsung,exynos5433-pmu
+          - samsung,exynos7-pmu
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - samsung,exynos3250-pmu
+          - samsung,exynos4210-pmu
+          - samsung,exynos4412-pmu
+          - samsung,exynos5250-pmu
+          - samsung,exynos5260-pmu
+          - samsung,exynos5410-pmu
+          - samsung,exynos5420-pmu
+          - samsung,exynos5433-pmu
+          - samsung,exynos7-pmu
+      - const: syscon
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clock-names:
+    description:
+      List of clock names for particular CLKOUT mux inputs
+    minItems: 1
+    maxItems: 32
+    items:
+      pattern: '^clkout([0-9]|[12][0-9]|3[0-1])$'
+
+  clocks:
+    minItems: 1
+    maxItems: 32
+
+  interrupt-controller:
+    description:
+      Some PMUs are capable of behaving as an interrupt controller (mostly
+      to wake up a suspended PMU).
+
+  '#interrupt-cells':
+    description:
+      Must be identical to the that of the parent interrupt controller.
+    const: 3
+
+  syscon-poweroff:
+    $ref: "../../power/reset/syscon-poweroff.yaml#"
+    type: object
+    description:
+      Node for power off method
+
+  syscon-reboot:
+    $ref: "../../power/reset/syscon-reboot.yaml#"
+    type: object
+    description:
+      Node for reboot method
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+  - clock-names
+  - clocks
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos5250.h>
+
+    pmu_system_controller: system-controller@10040000 {
+        compatible = "samsung,exynos5250-pmu", "syscon";
+        reg = <0x10040000 0x5000>;
+        interrupt-controller;
+        #interrupt-cells = <3>;
+        interrupt-parent = <&gic>;
+        #clock-cells = <1>;
+        clock-names = "clkout16";
+        clocks = <&clock CLK_FIN_PLL>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
deleted file mode 100644 (file)
index 56021bf..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-* Samsung's Exynos and S5P SoC based boards
-
-Required root node properties:
-    - compatible = should be one or more of the following.
-       - "samsung,aries"       - for S5PV210-based Samsung Aries board.
-       - "samsung,fascinate4g" - for S5PV210-based Samsung Galaxy S Fascinate 4G (SGH-T959P) board.
-       - "samsung,galaxys"     - for S5PV210-based Samsung Galaxy S (i9000)  board.
-       - "samsung,artik5"      - for Exynos3250-based Samsung ARTIK5 module.
-       - "samsung,artik5-eval" - for Exynos3250-based Samsung ARTIK5 eval board.
-       - "samsung,monk"        - for Exynos3250-based Samsung Simband board.
-       - "samsung,rinato"      - for Exynos3250-based Samsung Gear2 board.
-       - "samsung,smdkv310"    - for Exynos4210-based Samsung SMDKV310 eval board.
-       - "samsung,trats"       - for Exynos4210-based Tizen Reference board.
-       - "samsung,universal_c210" - for Exynos4210-based Samsung board.
-       - "samsung,i9300"          - for Exynos4412-based Samsung GT-I9300 board.
-       - "samsung,i9305"          - for Exynos4412-based Samsung GT-I9305 board.
-       - "samsung,midas"       - for Exynos4412-based Samsung Midas board.
-       - "samsung,smdk4412",   - for Exynos4412-based Samsung SMDK4412 eval board.
-       - "samsung,n710x"          - for Exynos4412-based Samsung GT-N7100/GT-N7105 board.
-       - "samsung,trats2"      - for Exynos4412-based Tizen Reference board.
-       - "samsung,smdk5250"    - for Exynos5250-based Samsung SMDK5250 eval board.
-       - "samsung,xyref5260"   - for Exynos5260-based Samsung board.
-       - "samsung,smdk5410"    - for Exynos5410-based Samsung SMDK5410 eval board.
-       - "samsung,smdk5420"    - for Exynos5420-based Samsung SMDK5420 eval board.
-       - "samsung,tm2"         - for Exynos5433-based Samsung TM2 board.
-       - "samsung,tm2e"        - for Exynos5433-based Samsung TM2E board.
-
-* Other companies Exynos SoC based
-  * FriendlyARM
-       - "friendlyarm,tiny4412"  - for Exynos4412-based FriendlyARM
-                                   TINY4412 board.
-  * TOPEET
-       - "topeet,itop4412-elite" - for Exynos4412-based TOPEET
-                                    Elite base board.
-
-  * Google
-       - "google,pi"           - for Exynos5800-based Google Peach Pi
-                                 Rev 10+ board,
-         also: "google,pi-rev16", "google,pi-rev15", "google,pi-rev14",
-               "google,pi-rev13", "google,pi-rev12", "google,pi-rev11",
-               "google,pi-rev10", "google,peach".
-
-       - "google,pit"          - for Exynos5420-based Google Peach Pit
-                                 Rev 6+ (Exynos5420),
-         also: "google,pit-rev16", "google,pit-rev15", "google,pit-rev14",
-               "google,pit-rev13", "google,pit-rev12", "google,pit-rev11",
-               "google,pit-rev10", "google,pit-rev9", "google,pit-rev8",
-               "google,pit-rev7", "google,pit-rev6", "google,peach".
-
-       - "google,snow-rev4"    - for Exynos5250-based Google Snow board,
-         also: "google,snow"
-       - "google,snow-rev5"    - for Exynos5250-based Google Snow
-                                 Rev 5+ board.
-       - "google,spring"       - for Exynos5250-based Google Spring board.
-
-  * Hardkernel
-       - "hardkernel,odroid-u3"  - for Exynos4412-based Hardkernel Odroid U3.
-       - "hardkernel,odroid-x"   - for Exynos4412-based Hardkernel Odroid X.
-       - "hardkernel,odroid-x2"  - for Exynos4412-based Hardkernel Odroid X2.
-       - "hardkernel,odroid-xu"  - for Exynos5410-based Hardkernel Odroid XU.
-       - "hardkernel,odroid-xu3" - for Exynos5422-based Hardkernel Odroid XU3.
-       - "hardkernel,odroid-xu3-lite" - for Exynos5422-based Hardkernel
-                                        Odroid XU3 Lite board.
-       - "hardkernel,odroid-xu4" - for Exynos5422-based Hardkernel Odroid XU4.
-       - "hardkernel,odroid-hc1" - for Exynos5422-based Hardkernel Odroid HC1.
-
-  * Insignal
-       - "insignal,arndale"      - for Exynos5250-based Insignal Arndale board.
-       - "insignal,arndale-octa" - for Exynos5420-based Insignal Arndale
-                                   Octa board.
-       - "insignal,origen"       - for Exynos4210-based Insignal Origen board.
-       - "insignal,origen4412"   - for Exynos4412-based Insignal Origen board.
-
-
-Optional nodes:
-    - firmware node, specifying presence and type of secure firmware:
-        - compatible: only "samsung,secure-firmware" is currently supported
-        - reg: address of non-secure SYSRAM used for communication with firmware
-
-       firmware@203f000 {
-               compatible = "samsung,secure-firmware";
-               reg = <0x0203F000 0x1000>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml
new file mode 100644 (file)
index 0000000..63acd57
--- /dev/null
@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/samsung/samsung-boards.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos and S5P SoC based boards
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: S5PV210 based boards
+        items:
+          - enum:
+              - aesop,torbreck                  # aESOP Torbreck based on S5PV210
+              - samsung,aquila                  # Samsung Aquila based on S5PC110
+              - samsung,goni                    # Samsung Goni based on S5PC110
+              - yic,smdkc110                    # YIC System SMDKC110 based on S5PC110
+              - yic,smdkv210                    # YIC System SMDKV210 based on S5PV210
+          - const: samsung,s5pv210
+
+      - description: S5PV210 based Aries boards
+        items:
+          - enum:
+              - samsung,fascinate4g             # Samsung Galaxy S Fascinate 4G (SGH-T959P)
+              - samsung,galaxys                 # Samsung Galaxy S (i9000)
+          - const: samsung,aries
+          - const: samsung,s5pv210
+
+      - description: Exynos3250 based boards
+        items:
+          - enum:
+              - samsung,monk                    # Samsung Simband
+              - samsung,rinato                  # Samsung Gear2
+          - const: samsung,exynos3250
+          - const: samsung,exynos3
+
+      - description: Samsung ARTIK5 boards
+        items:
+          - enum:
+              - samsung,artik5-eval             # Samsung ARTIK5 eval board
+          - const: samsung,artik5               # Samsung ARTIK5 module
+          - const: samsung,exynos3250
+          - const: samsung,exynos3
+
+      - description: Exynos4210 based boards
+        items:
+          - enum:
+              - insignal,origen                 # Insignal Origen
+              - samsung,smdkv310                # Samsung SMDKV310 eval
+              - samsung,trats                   # Samsung Tizen Reference
+              - samsung,universal_c210          # Samsung C210
+          - const: samsung,exynos4210
+          - const: samsung,exynos4
+
+      - description: Exynos4412 based boards
+        items:
+          - enum:
+              - friendlyarm,tiny4412            # FriendlyARM TINY4412
+              - hardkernel,odroid-u3            # Hardkernel Odroid U3
+              - hardkernel,odroid-x             # Hardkernel Odroid X
+              - hardkernel,odroid-x2            # Hardkernel Odroid X2
+              - insignal,origen4412             # Insignal Origen
+              - samsung,smdk4412                # Samsung SMDK4412 eval
+              - topeet,itop4412-elite           # TOPEET Elite base
+          - const: samsung,exynos4412
+          - const: samsung,exynos4
+
+      - description: Samsung Midas family boards
+        items:
+          - enum:
+              - samsung,i9300                   # Samsung GT-I9300
+              - samsung,i9305                   # Samsung GT-I9305
+              - samsung,n710x                   # Samsung GT-N7100/GT-N7105
+              - samsung,trats2                  # Samsung Tizen Reference
+          - const: samsung,midas
+          - const: samsung,exynos4412
+          - const: samsung,exynos4
+
+      - description: Exynos5250 based boards
+        items:
+          - enum:
+              - google,snow-rev5                # Google Snow Rev 5+
+              - google,spring                   # Google Spring
+              - insignal,arndale                # Insignal Arndale
+              - samsung,smdk5250                # Samsung SMDK5250 eval
+          - const: samsung,exynos5250
+          - const: samsung,exynos5
+
+      - description: Google Snow Boards (Rev 4+)
+        items:
+          - const: google,snow-rev4
+          - const: google,snow
+          - const: samsung,exynos5250
+          - const: samsung,exynos5
+
+      - description: Exynos5260 based boards
+        items:
+          - enum:
+              - samsung,xyref5260               # Samsung Xyref5260 eval
+          - const: samsung,exynos5260
+          - const: samsung,exynos5
+
+      - description: Exynos5410 based boards
+        items:
+          - enum:
+              - hardkernel,odroid-xu            # Hardkernel Odroid XU
+              - samsung,smdk5410                # Samsung SMDK5410 eval
+          - const: samsung,exynos5410
+          - const: samsung,exynos5
+
+      - description: Exynos5420 based boards
+        items:
+          - enum:
+              - insignal,arndale-octa           # Insignal Arndale Octa
+              - samsung,smdk5420                # Samsung SMDK5420 eval
+          - const: samsung,exynos5420
+          - const: samsung,exynos5
+
+      - description: Google Peach Pit Boards (Rev 6+)
+        items:
+          - const: google,pit-rev16
+          - const: google,pit-rev15
+          - const: google,pit-rev14
+          - const: google,pit-rev13
+          - const: google,pit-rev12
+          - const: google,pit-rev11
+          - const: google,pit-rev10
+          - const: google,pit-rev9
+          - const: google,pit-rev8
+          - const: google,pit-rev7
+          - const: google,pit-rev6
+          - const: google,pit
+          - const: google,peach
+          - const: samsung,exynos5420
+          - const: samsung,exynos5
+
+      - description: Exynos5800 based boards
+        items:
+          - enum:
+              - hardkernel,odroid-xu3           # Hardkernel Odroid XU3
+              - hardkernel,odroid-xu3-lite      # Hardkernel Odroid XU3 Lite
+              - hardkernel,odroid-xu4           # Hardkernel Odroid XU4
+              - hardkernel,odroid-hc1           # Hardkernel Odroid HC1
+          - const: samsung,exynos5800
+          - const: samsung,exynos5
+
+      - description: Google Peach Pi Boards (Rev 10+)
+        items:
+          - const: google,pi-rev16
+          - const: google,pi-rev15
+          - const: google,pi-rev14
+          - const: google,pi-rev13
+          - const: google,pi-rev12
+          - const: google,pi-rev11
+          - const: google,pi-rev10
+          - const: google,pi
+          - const: google,peach
+          - const: samsung,exynos5800
+          - const: samsung,exynos5
+
+      - description: Exynos5433 based boards
+        items:
+          - enum:
+              - samsung,tm2                     # Samsung TM2
+              - samsung,tm2e                    # Samsung TM2E
+          - const: samsung,exynos5433
+
+      - description: Exynos7 based boards
+        items:
+          - enum:
+              - samsung,exynos7-espresso        # Samsung Exynos7 Espresso
+          - const: samsung,exynos7
+
+required:
+  - compatible
diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-secure-firmware.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-secure-firmware.yaml
new file mode 100644 (file)
index 0000000..51d23b6
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/samsung/samsung-secure-firmware.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos Secure Firmware
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+  compatible:
+    items:
+      - const: samsung,secure-firmware
+
+  reg:
+    description:
+      Address of non-secure SYSRAM used for communication with firmware.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    firmware@203f000 {
+      compatible = "samsung,secure-firmware";
+      reg = <0x0203f000 0x1000>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/samsung/sysreg.txt b/Documentation/devicetree/bindings/arm/samsung/sysreg.txt
deleted file mode 100644 (file)
index 4fced6e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-SAMSUNG S5P/Exynos SoC series System Registers (SYSREG)
-
-Properties:
- - compatible : should contain two values. First value must be one from following list:
-               - "samsung,exynos4-sysreg" - for Exynos4 based SoCs,
-               - "samsung,exynos5-sysreg" - for Exynos5 based SoCs.
-               second value must be always "syscon".
- - reg : offset and length of the register set.
-
-Example:
-       syscon@10010000 {
-               compatible = "samsung,exynos4-sysreg", "syscon";
-               reg = <0x10010000 0x400>;
-       };
-
-       syscon@10050000 {
-               compatible = "samsung,exynos5-sysreg", "syscon";
-               reg = <0x10050000 0x5000>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/samsung/sysreg.yaml b/Documentation/devicetree/bindings/arm/samsung/sysreg.yaml
new file mode 100644 (file)
index 0000000..3b78118
--- /dev/null
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/samsung/sysreg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S5P/Exynos SoC series System Registers (SYSREG)
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+# Custom select to avoid matching all nodes with 'syscon'
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - samsung,exynos4-sysreg
+          - samsung,exynos5-sysreg
+  required:
+    - compatible
+
+properties:
+  compatible:
+    allOf:
+      - items:
+          - enum:
+              - samsung,exynos4-sysreg
+              - samsung,exynos5-sysreg
+          - const: syscon
+
+  reg:
+    maxItems: 1
+
+examples:
+  - |
+    syscon@10010000 {
+        compatible = "samsung,exynos4-sysreg", "syscon";
+        reg = <0x10010000 0x400>;
+    };
+
+    syscon@10050000 {
+        compatible = "samsung,exynos5-sysreg", "syscon";
+        reg = <0x10050000 0x5000>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/sprd.txt b/Documentation/devicetree/bindings/arm/sprd.txt
deleted file mode 100644 (file)
index 3df034b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Spreadtrum SoC Platforms Device Tree Bindings
-----------------------------------------------------
-
-SC9836 openphone Board
-Required root node properties:
-       - compatible = "sprd,sc9836-openphone", "sprd,sc9836";
-
-SC9860 SoC
-Required root node properties:
-       - compatible = "sprd,sc9860"
-
-SP9860G 3GFHD Board
-Required root node properties:
-       - compatible = "sprd,sp9860g-1h10", "sprd,sc9860";
diff --git a/Documentation/devicetree/bindings/arm/sprd.yaml b/Documentation/devicetree/bindings/arm/sprd.yaml
new file mode 100644 (file)
index 0000000..c35fb84
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2019 Unisoc Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sprd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Unisoc platforms device tree bindings
+
+maintainers:
+  - Orson Zhai <orsonzhai@gmail.com>
+  - Baolin Wang <baolin.wang7@gmail.com>
+  - Chunyan Zhang <zhang.lyra@gmail.com>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - sprd,sc9836-openphone
+          - const: sprd,sc9836
+      - items:
+          - enum:
+              - sprd,sp9860g-1h10
+          - const: sprd,sc9860
+      - items:
+          - enum:
+              - sprd,sp9863a-1h10
+          - const: sprd,sc9863a
+
+...
index 4d194f1..1fcf306 100644 (file)
@@ -13,19 +13,38 @@ properties:
   compatible:
     oneOf:
       - items:
+          - enum:
+              - st,stm32f429i-disco
+              - st,stm32429i-eval
           - const: st,stm32f429
-
       - items:
+          - enum:
+              - st,stm32f469i-disco
           - const: st,stm32f469
-
       - items:
+          - enum:
+              - st,stm32f746-disco
+              - st,stm32746g-eval
           - const: st,stm32f746
-
       - items:
+          - enum:
+              - st,stm32f769-disco
+          - const: st,stm32f769
+      - items:
+          - enum:
+              - st,stm32h743i-disco
+              - st,stm32h743i-eval
           - const: st,stm32h743
-
       - items:
           - enum:
               - arrow,stm32mp157a-avenger96 # Avenger96
+              - st,stm32mp157c-ed1
+              - st,stm32mp157a-dk1
+              - st,stm32mp157c-dk2
+
+          - const: st,stm32mp157
+      - items:
+          - const: st,stm32mp157c-ev1
+          - const: st,stm32mp157c-ed1
           - const: st,stm32mp157
 ...
index 972b1e9..8a1e38a 100644 (file)
@@ -211,6 +211,11 @@ properties:
           - const: friendlyarm,nanopi-a64
           - const: allwinner,sun50i-a64
 
+      - description: FriendlyARM NanoPi Duo2
+        items:
+          - const: friendlyarm,nanopi-duo2
+          - const: allwinner,sun8i-h3
+
       - description: FriendlyARM NanoPi M1
         items:
           - const: friendlyarm,nanopi-m1
diff --git a/Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt b/Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt
deleted file mode 100644 (file)
index 082e6a9..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Allwinner SRAM for smp bringup:
-------------------------------------------------
-
-Allwinner's A80 SoC uses part of the secure sram for hotplugging of the
-primary core (cpu0). Once the core gets powered up it checks if a magic
-value is set at a specific location. If it is then the BROM will jump
-to the software entry address, instead of executing a standard boot.
-
-Therefore a reserved section sub-node has to be added to the mmio-sram
-declaration.
-
-Note that this is separate from the Allwinner SRAM controller found in
-../../sram/sunxi-sram.txt. This SRAM is secure only and not mappable to
-any device.
-
-Also there are no "secure-only" properties. The implementation should
-check if this SRAM is usable first.
-
-Required sub-node properties:
-- compatible : depending on the SoC this should be one of:
-               "allwinner,sun9i-a80-smp-sram"
-
-The rest of the properties should follow the generic mmio-sram discription
-found in ../../misc/sram.txt
-
-Example:
-
-       sram_b: sram@20000 {
-               /* 256 KiB secure SRAM at 0x20000 */
-               compatible = "mmio-sram";
-               reg = <0x00020000 0x40000>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0x00020000 0x40000>;
-
-               smp-sram@1000 {
-                       /*
-                        * This is checked by BROM to determine if
-                        * cpu0 should jump to SMP entry vector
-                        */
-                       compatible = "allwinner,sun9i-a80-smp-sram";
-                       reg = <0x1000 0x8>;
-               };
-       };
index 1464a47..2005bb4 100644 (file)
@@ -8,6 +8,7 @@ bus.
 Required properties:
  - compatible: Must be one of:
        - allwinner,sun5i-a13-mbus
+       - allwinner,sun8i-h3-mbus
  - reg: Offset and length of the register set for the controller
  - clocks: phandle to the clock driving the controller
  - dma-ranges: See section 2.3.9 of the DeviceTree Specification
index 4268e17..a2fbdc9 100644 (file)
@@ -2,6 +2,7 @@
 
 Required properties:
 - compatible           : should contain one or more of the following:
+                         - "renesas,sata-r8a774b1" for RZ/G2N
                          - "renesas,sata-r8a7779" for R-Car H1
                          - "renesas,sata-r8a7790-es1" for R-Car H2 ES1
                          - "renesas,sata-r8a7790" for R-Car H2 other than ES1
@@ -9,8 +10,10 @@ Required properties:
                          - "renesas,sata-r8a7793" for R-Car M2-N
                          - "renesas,sata-r8a7795" for R-Car H3
                          - "renesas,sata-r8a77965" for R-Car M3-N
-                         - "renesas,rcar-gen2-sata" for a generic R-Car Gen2 compatible device
-                         - "renesas,rcar-gen3-sata" for a generic R-Car Gen3 compatible device
+                         - "renesas,rcar-gen2-sata" for a generic R-Car Gen2
+                            compatible device
+                         - "renesas,rcar-gen3-sata" for a generic R-Car Gen3 or
+                            RZ/G2 compatible device
                          - "renesas,rcar-sata" is deprecated
 
                          When compatible with the generic version nodes
diff --git a/Documentation/devicetree/bindings/bus/renesas,bsc.txt b/Documentation/devicetree/bindings/bus/renesas,bsc.txt
deleted file mode 100644 (file)
index 90e9472..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Renesas Bus State Controller (BSC)
-==================================
-
-The Renesas Bus State Controller (BSC, sometimes called "LBSC within Bus
-Bridge", or "External Bus Interface") can be found in several Renesas ARM SoCs.
-It provides an external bus for connecting multiple external devices to the
-SoC, driving several chip select lines, for e.g. NOR FLASH, Ethernet and USB.
-
-While the BSC is a fairly simple memory-mapped bus, it may be part of a PM
-domain, and may have a gateable functional clock.
-Before a device connected to the BSC can be accessed, the PM domain
-containing the BSC must be powered on, and the functional clock
-driving the BSC must be enabled.
-
-The bindings for the BSC extend the bindings for "simple-pm-bus".
-
-
-Required properties
-  - compatible: Must contain an SoC-specific value, and "renesas,bsc" and
-               "simple-pm-bus" as fallbacks.
-                SoC-specific values can be:
-               "renesas,bsc-r8a73a4" for R-Mobile APE6 (r8a73a4)
-               "renesas,bsc-sh73a0" for SH-Mobile AG5 (sh73a0)
-  - #address-cells, #size-cells, ranges: Must describe the mapping between
-               parent address and child address spaces.
-  - reg: Must contain the base address and length to access the bus controller.
-
-Optional properties:
-  - interrupts: Must contain a reference to the BSC interrupt, if available.
-  - clocks: Must contain a reference to the functional clock, if available.
-  - power-domains: Must contain a reference to the PM domain, if available.
-
-
-Example:
-
-       bsc: bus@fec10000 {
-               compatible = "renesas,bsc-sh73a0", "renesas,bsc",
-                            "simple-pm-bus";
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0 0x20000000>;
-               reg = <0xfec10000 0x400>;
-               interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&zb_clk>;
-               power-domains = <&pd_a4s>;
-       };
diff --git a/Documentation/devicetree/bindings/bus/renesas,bsc.yaml b/Documentation/devicetree/bindings/bus/renesas,bsc.yaml
new file mode 100644 (file)
index 0000000..7d10b62
--- /dev/null
@@ -0,0 +1,60 @@
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bus/renesas,bsc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas Bus State Controller (BSC)
+
+maintainers:
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+
+description: |
+  The Renesas Bus State Controller (BSC, sometimes called "LBSC within Bus
+  Bridge", or "External Bus Interface") can be found in several Renesas ARM
+  SoCs.  It provides an external bus for connecting multiple external
+  devices to the SoC, driving several chip select lines, for e.g. NOR
+  FLASH, Ethernet and USB.
+
+  While the BSC is a fairly simple memory-mapped bus, it may be part of a
+  PM domain, and may have a gateable functional clock.  Before a device
+  connected to the BSC can be accessed, the PM domain containing the BSC
+  must be powered on, and the functional clock driving the BSC must be
+  enabled.
+
+  The bindings for the BSC extend the bindings for "simple-pm-bus".
+
+allOf:
+  - $ref: simple-pm-bus.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,bsc-r8a73a4  # R-Mobile APE6 (r8a73a4)
+          - renesas,bsc-sh73a0   # SH-Mobile AG5 (sh73a0)
+      - const: renesas,bsc
+      - {} # simple-pm-bus, but not listed here to avoid false select
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - reg
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    bsc: bus@fec10000 {
+        compatible = "renesas,bsc-sh73a0", "renesas,bsc", "simple-pm-bus";
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0 0x20000000>;
+        reg = <0xfec10000 0x400>;
+        interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&zb_clk>;
+        power-domains = <&pd_a4s>;
+    };
diff --git a/Documentation/devicetree/bindings/bus/simple-pm-bus.txt b/Documentation/devicetree/bindings/bus/simple-pm-bus.txt
deleted file mode 100644 (file)
index 6f15037..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Simple Power-Managed Bus
-========================
-
-A Simple Power-Managed Bus is a transparent bus that doesn't need a real
-driver, as it's typically initialized by the boot loader.
-
-However, its bus controller is part of a PM domain, or under the control of a
-functional clock.  Hence, the bus controller's PM domain and/or clock must be
-enabled for child devices connected to the bus (either on-SoC or externally)
-to function.
-
-While "simple-pm-bus" follows the "simple-bus" set of properties, as specified
-in the Devicetree Specification, it is not an extension of "simple-bus".
-
-
-Required properties:
-  - compatible: Must contain at least "simple-pm-bus".
-               Must not contain "simple-bus".
-               It's recommended to let this be preceded by one or more
-               vendor-specific compatible values.
-  - #address-cells, #size-cells, ranges: Must describe the mapping between
-               parent address and child address spaces.
-
-Optional platform-specific properties for clock or PM domain control (at least
-one of them is required):
-  - clocks: Must contain a reference to the functional clock(s),
-  - power-domains: Must contain a reference to the PM domain.
-Please refer to the binding documentation for the clock and/or PM domain
-providers for more details.
-
-
-Example:
-
-       bsc: bus@fec10000 {
-               compatible = "renesas,bsc-sh73a0", "renesas,bsc",
-                            "simple-pm-bus";
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0 0x20000000>;
-               reg = <0xfec10000 0x400>;
-               interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&zb_clk>;
-               power-domains = <&pd_a4s>;
-       };
diff --git a/Documentation/devicetree/bindings/bus/simple-pm-bus.yaml b/Documentation/devicetree/bindings/bus/simple-pm-bus.yaml
new file mode 100644 (file)
index 0000000..33326ff
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bus/simple-pm-bus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Simple Power-Managed Bus
+
+maintainers:
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+
+description: |
+  A Simple Power-Managed Bus is a transparent bus that doesn't need a real
+  driver, as it's typically initialized by the boot loader.
+
+  However, its bus controller is part of a PM domain, or under the control
+  of a functional clock.  Hence, the bus controller's PM domain and/or
+  clock must be enabled for child devices connected to the bus (either
+  on-SoC or externally) to function.
+
+  While "simple-pm-bus" follows the "simple-bus" set of properties, as
+  specified in the Devicetree Specification, it is not an extension of
+  "simple-bus".
+
+properties:
+  $nodename:
+    pattern: "^bus(@[0-9a-f]+)?$"
+
+  compatible:
+    contains:
+      const: simple-pm-bus
+    description:
+      Shall contain "simple-pm-bus" in addition to a optional bus-specific
+      compatible strings defined in individual pm-bus bindings.
+
+  '#address-cells':
+    enum: [ 1, 2 ]
+
+  '#size-cells':
+    enum: [ 1, 2 ]
+
+  ranges: true
+
+  clocks: true
+    # Functional clocks
+    # Required if power-domains is absent, optional otherwise
+
+  power-domains:
+    # Required if clocks is absent, optional otherwise
+    minItems: 1
+
+required:
+  - compatible
+  - '#address-cells'
+  - '#size-cells'
+  - ranges
+
+anyOf:
+  - required:
+      - clocks
+  - required:
+      - power-domains
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-msm8996.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    bus {
+        power-domains = <&gcc AGGRE0_NOC_GDSC>;
+        compatible = "simple-pm-bus";
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+    };
index d67f57e..c7674d0 100644 (file)
@@ -62,7 +62,7 @@ Required Properties:
        power-managed through Module Standby should refer to the CPG device
        node in their "power-domains" property, as documented by the generic PM
        Domain bindings in
-       Documentation/devicetree/bindings/power/power_domain.txt.
+       Documentation/devicetree/bindings/power/power-domain.yaml.
 
   - #reset-cells: Must be 1
       - The single reset specifier cell must be the module number, as defined
index 39f0c1a..55e78cd 100644 (file)
@@ -10,6 +10,11 @@ Required Properties:
 - compatible: CRU should be "rockchip,px30-cru"
 - reg: physical base address of the controller and length of memory mapped
   region.
+- clocks: A list of phandle + clock-specifier pairs for the clocks listed
+          in clock-names
+- clock-names: Should contain the following:
+  - "xin24m" for both PMUCRU and CRU
+  - "gpll" for CRU (sourced from PMUCRU)
 - #clock-cells: should be 1.
 - #reset-cells: should be 1.
 
index dae4ad8..5f746eb 100644 (file)
@@ -67,5 +67,5 @@ Examples:
 
 Also see:
 - Documentation/devicetree/bindings/clock/clock-bindings.txt
-- Documentation/devicetree/bindings/power/power_domain.txt
+- Documentation/devicetree/bindings/power/power-domain.yaml
 - Documentation/devicetree/bindings/reset/reset.txt
diff --git a/Documentation/devicetree/bindings/counter/stm32-lptimer-cnt.txt b/Documentation/devicetree/bindings/counter/stm32-lptimer-cnt.txt
deleted file mode 100644 (file)
index e90bc47..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-STMicroelectronics STM32 Low-Power Timer quadrature encoder and counter
-
-STM32 Low-Power Timer provides several counter modes. It can be used as:
-- quadrature encoder to detect angular position and direction of rotary
-  elements, from IN1 and IN2 input signals.
-- simple counter from IN1 input signal.
-
-Must be a sub-node of an STM32 Low-Power Timer device tree node.
-See ../mfd/stm32-lptimer.txt for details about the parent node.
-
-Required properties:
-- compatible:          Must be "st,stm32-lptimer-counter".
-- pinctrl-names:       Set to "default". An additional "sleep" state can be
-                       defined to set pins in sleep state.
-- pinctrl-n:           List of phandles pointing to pin configuration nodes,
-                       to set IN1/IN2 pins in mode of operation for Low-Power
-                       Timer input on external pin.
-
-Example:
-       timer@40002400 {
-               compatible = "st,stm32-lptimer";
-               ...
-               counter {
-                       compatible = "st,stm32-lptimer-counter";
-                       pinctrl-names = "default", "sleep";
-                       pinctrl-0 = <&lptim1_in_pins>;
-                       pinctrl-1 = <&lptim1_sleep_in_pins>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/counter/stm32-timer-cnt.txt b/Documentation/devicetree/bindings/counter/stm32-timer-cnt.txt
deleted file mode 100644 (file)
index c52fcdd..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-STMicroelectronics STM32 Timer quadrature encoder
-
-STM32 Timer provides quadrature encoder to detect
-angular position and direction of rotary elements,
-from IN1 and IN2 input signals.
-
-Must be a sub-node of an STM32 Timer device tree node.
-See ../mfd/stm32-timers.txt for details about the parent node.
-
-Required properties:
-- compatible:          Must be "st,stm32-timer-counter".
-- pinctrl-names:       Set to "default".
-- pinctrl-0:           List of phandles pointing to pin configuration nodes,
-                       to set CH1/CH2 pins in mode of operation for STM32
-                       Timer input on external pin.
-
-Example:
-       timers@40010000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "st,stm32-timers";
-               reg = <0x40010000 0x400>;
-               clocks = <&rcc 0 160>;
-               clock-names = "int";
-
-               counter {
-                       compatible = "st,stm32-timer-counter";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&tim1_in_pins>;
-               };
-       };
index 9991818..9bd530a 100644 (file)
@@ -549,5 +549,5 @@ Example 3: HiFive Unleashed (RISC-V 64 bit, 4 core system)
 [2] Devicetree NUMA binding description
     Documentation/devicetree/bindings/numa.txt
 [3] RISC-V Linux kernel documentation
-    Documentation/devicetree/bindings/riscv/cpus.txt
+    Documentation/devicetree/bindings/riscv/cpus.yaml
 [4] https://www.devicetree.org/specifications/
diff --git a/Documentation/devicetree/bindings/crypto/allwinner,sun8i-ce.yaml b/Documentation/devicetree/bindings/crypto/allwinner,sun8i-ce.yaml
new file mode 100644 (file)
index 0000000..2c459b8
--- /dev/null
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/allwinner,sun8i-ce.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner Crypto Engine driver
+
+maintainers:
+  - Corentin Labbe <clabbe.montjoie@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - allwinner,sun8i-h3-crypto
+      - allwinner,sun8i-r40-crypto
+      - allwinner,sun50i-a64-crypto
+      - allwinner,sun50i-h5-crypto
+      - allwinner,sun50i-h6-crypto
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus clock
+      - description: Module clock
+      - description: MBus clock
+    minItems: 2
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+      - const: ram
+    minItems: 2
+    maxItems: 3
+
+  resets:
+    maxItems: 1
+
+if:
+  properties:
+    compatible:
+      items:
+        const: allwinner,sun50i-h6-crypto
+then:
+  properties:
+      clocks:
+        minItems: 3
+      clock-names:
+        minItems: 3
+else:
+  properties:
+      clocks:
+        maxItems: 2
+      clock-names:
+        maxItems: 2
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun50i-a64-ccu.h>
+    #include <dt-bindings/reset/sun50i-a64-ccu.h>
+
+    crypto: crypto@1c15000 {
+      compatible = "allwinner,sun8i-h3-crypto";
+      reg = <0x01c15000 0x1000>;
+      interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+      clock-names = "bus", "mod";
+      resets = <&ccu RST_BUS_CE>;
+    };
+
diff --git a/Documentation/devicetree/bindings/crypto/samsung-slimsss.txt b/Documentation/devicetree/bindings/crypto/samsung-slimsss.txt
deleted file mode 100644 (file)
index 7ec9a5a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Samsung SoC SlimSSS (Slim Security SubSystem) module
-
-The SlimSSS module in Exynos5433 SoC supports the following:
--- Feeder (FeedCtrl)
--- Advanced Encryption Standard (AES) with ECB,CBC,CTR,XTS and (CBC/XTS)/CTS
--- SHA-1/SHA-256 and (SHA-1/SHA-256)/HMAC
-
-Required properties:
-
-- compatible : Should contain entry for slimSSS version:
-  - "samsung,exynos5433-slim-sss" for Exynos5433 SoC.
-- reg : Offset and length of the register set for the module
-- interrupts : interrupt specifiers of SlimSSS module interrupts (one feed
-               control interrupt).
-
-- clocks : list of clock phandle and specifier pairs for all clocks listed in
-               clock-names property.
-- clock-names : list of device clock input names; should contain "pclk" and
-               "aclk" for slim-sss in Exynos5433.
diff --git a/Documentation/devicetree/bindings/crypto/samsung-slimsss.yaml b/Documentation/devicetree/bindings/crypto/samsung-slimsss.yaml
new file mode 100644 (file)
index 0000000..04fe5df
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/samsung-slimsss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC SlimSSS (Slim Security SubSystem) module
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+  - Kamil Konieczny <k.konieczny@partner.samsung.com>
+
+description: |+
+  The SlimSSS module in Exynos5433 SoC supports the following:
+  -- Feeder (FeedCtrl)
+  -- Advanced Encryption Standard (AES) with ECB,CBC,CTR,XTS and (CBC/XTS)/CTS
+  -- SHA-1/SHA-256 and (SHA-1/SHA-256)/HMAC
+
+properties:
+  compatible:
+    items:
+      - const: samsung,exynos5433-slim-ss
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 2
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: aclk
+
+  interrupts:
+    description: One feed control interrupt.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clock-names
+  - clocks
+  - interrupts
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/crypto/samsung-sss.txt b/Documentation/devicetree/bindings/crypto/samsung-sss.txt
deleted file mode 100644 (file)
index 7a5ca56..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-Samsung SoC SSS (Security SubSystem) module
-
-The SSS module in S5PV210 SoC supports the following:
--- Feeder (FeedCtrl)
--- Advanced Encryption Standard (AES)
--- Data Encryption Standard (DES)/3DES
--- Public Key Accelerator (PKA)
--- SHA-1/SHA-256/MD5/HMAC (SHA-1/SHA-256/MD5)/PRNG
--- PRNG: Pseudo Random Number Generator
-
-The SSS module in Exynos4 (Exynos4210) and
-Exynos5 (Exynos5420 and Exynos5250) SoCs
-supports the following also:
--- ARCFOUR (ARC4)
--- True Random Number Generator (TRNG)
--- Secure Key Manager
-
-Required properties:
-
-- compatible : Should contain entries for this and backward compatible
-  SSS versions:
-  - "samsung,s5pv210-secss" for S5PV210 SoC.
-  - "samsung,exynos4210-secss" for Exynos4210, Exynos4212, Exynos4412, Exynos5250,
-               Exynos5260 and Exynos5420 SoCs.
-- reg : Offset and length of the register set for the module
-- interrupts : interrupt specifiers of SSS module interrupts (one feed
-               control interrupt).
-
-- clocks : list of clock phandle and specifier pairs for all clocks  listed in
-               clock-names property.
-- clock-names : list of device clock input names; should contain one entry
-               "secss".
diff --git a/Documentation/devicetree/bindings/crypto/samsung-sss.yaml b/Documentation/devicetree/bindings/crypto/samsung-sss.yaml
new file mode 100644 (file)
index 0000000..cf1c47a
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/samsung-sss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC SSS (Security SubSystem) module
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+  - Kamil Konieczny <k.konieczny@partner.samsung.com>
+
+description: |+
+  The SSS module in S5PV210 SoC supports the following:
+  -- Feeder (FeedCtrl)
+  -- Advanced Encryption Standard (AES)
+  -- Data Encryption Standard (DES)/3DES
+  -- Public Key Accelerator (PKA)
+  -- SHA-1/SHA-256/MD5/HMAC (SHA-1/SHA-256/MD5)/PRNG
+  -- PRNG: Pseudo Random Number Generator
+
+  The SSS module in Exynos4 (Exynos4210) and Exynos5 (Exynos5420 and Exynos5250)
+  SoCs supports the following also:
+  -- ARCFOUR (ARC4)
+  -- True Random Number Generator (TRNG)
+  -- Secure Key Manager
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - samsung,s5pv210-secss           # for S5PV210
+          - samsung,exynos4210-secss        # for Exynos4210, Exynos4212,
+                                            # Exynos4412, Exynos5250,
+                                            # Exynos5260 and Exynos5420
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: secss
+
+  interrupts:
+    description: One feed control interrupt.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clock-names
+  - clocks
+  - interrupts
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-crc.txt b/Documentation/devicetree/bindings/crypto/st,stm32-crc.txt
deleted file mode 100644 (file)
index 3ba92a5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-* STMicroelectronics STM32 CRC
-
-Required properties:
-- compatible: Should be "st,stm32f7-crc".
-- reg: The address and length of the peripheral registers space
-- clocks: The input clock of the CRC instance
-
-Optional properties: none
-
-Example:
-
-crc: crc@40023000 {
-       compatible = "st,stm32f7-crc";
-       reg = <0x40023000 0x400>;
-       clocks = <&rcc 0 12>;
-};
diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-crc.yaml b/Documentation/devicetree/bindings/crypto/st,stm32-crc.yaml
new file mode 100644 (file)
index 0000000..cee624c
--- /dev/null
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/st,stm32-crc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 CRC bindings
+
+maintainers:
+  - Lionel Debieve <lionel.debieve@st.com>
+
+properties:
+  compatible:
+    const: st,stm32f7-crc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    crc@40023000 {
+      compatible = "st,stm32f7-crc";
+      reg = <0x40023000 0x400>;
+      clocks = <&rcc 0 12>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-cryp.txt b/Documentation/devicetree/bindings/crypto/st,stm32-cryp.txt
deleted file mode 100644 (file)
index 970487f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-* STMicroelectronics STM32 CRYP
-
-Required properties:
-- compatible: Should be "st,stm32f756-cryp".
-- reg: The address and length of the peripheral registers space
-- clocks: The input clock of the CRYP instance
-- interrupts: The CRYP interrupt
-
-Optional properties:
-- resets: The input reset of the CRYP instance
-
-Example:
-crypto@50060000 {
-       compatible = "st,stm32f756-cryp";
-       reg = <0x50060000 0x400>;
-       interrupts = <79>;
-       clocks = <&rcc 0 STM32F7_AHB2_CLOCK(CRYP)>;
-       resets = <&rcc STM32F7_AHB2_RESET(CRYP)>;
-};
diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-cryp.yaml b/Documentation/devicetree/bindings/crypto/st,stm32-cryp.yaml
new file mode 100644 (file)
index 0000000..a457455
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/st,stm32-cryp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 CRYP bindings
+
+maintainers:
+  - Lionel Debieve <lionel.debieve@st.com>
+
+properties:
+  compatible:
+    enum:
+      - st,stm32f756-cryp
+      - st,stm32mp1-cryp
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    cryp@54001000 {
+      compatible = "st,stm32mp1-cryp";
+      reg = <0x54001000 0x400>;
+      interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&rcc CRYP1>;
+      resets = <&rcc CRYP1_R>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-hash.txt b/Documentation/devicetree/bindings/crypto/st,stm32-hash.txt
deleted file mode 100644 (file)
index 04fc246..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-* STMicroelectronics STM32 HASH
-
-Required properties:
-- compatible: Should contain entries for this and backward compatible
-  HASH versions:
-  - "st,stm32f456-hash" for stm32 F456.
-  - "st,stm32f756-hash" for stm32 F756.
-- reg: The address and length of the peripheral registers space
-- interrupts: the interrupt specifier for the HASH
-- clocks: The input clock of the HASH instance
-
-Optional properties:
-- resets: The input reset of the HASH instance
-- dmas: DMA specifiers for the HASH. See the DMA client binding,
-        Documentation/devicetree/bindings/dma/dma.txt
-- dma-names: DMA request name. Should be "in" if a dma is present.
-- dma-maxburst: Set number of maximum dma burst supported
-
-Example:
-
-hash1: hash@50060400 {
-       compatible = "st,stm32f756-hash";
-       reg = <0x50060400 0x400>;
-       interrupts = <80>;
-       clocks = <&rcc 0 STM32F7_AHB2_CLOCK(HASH)>;
-       resets = <&rcc STM32F7_AHB2_RESET(HASH)>;
-       dmas = <&dma2 7 2 0x400 0x0>;
-       dma-names = "in";
-       dma-maxburst = <0>;
-};
diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-hash.yaml b/Documentation/devicetree/bindings/crypto/st,stm32-hash.yaml
new file mode 100644 (file)
index 0000000..57ae1c0
--- /dev/null
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/st,stm32-hash.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 HASH bindings
+
+maintainers:
+  - Lionel Debieve <lionel.debieve@st.com>
+
+properties:
+  compatible:
+    enum:
+      - st,stm32f456-hash
+      - st,stm32f756-hash
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  dmas:
+    maxItems: 1
+
+  dma-names:
+    items:
+      - const: in
+
+  dma-maxburst:
+    description: Set number of maximum dma burst supported
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 2
+      - default: 0
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    hash@54002000 {
+      compatible = "st,stm32f756-hash";
+      reg = <0x54002000 0x400>;
+      interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&rcc HASH1>;
+      resets = <&rcc HASH1_R>;
+      dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0>;
+      dma-names = "in";
+      dma-maxburst = <2>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/ddr/lpddr2-timings.txt b/Documentation/devicetree/bindings/ddr/lpddr2-timings.txt
new file mode 100644 (file)
index 0000000..9ceb19e
--- /dev/null
@@ -0,0 +1,52 @@
+* AC timing parameters of LPDDR2(JESD209-2) memories for a given speed-bin
+
+Required properties:
+- compatible : Should be "jedec,lpddr2-timings"
+- min-freq : minimum DDR clock frequency for the speed-bin. Type is <u32>
+- max-freq : maximum DDR clock frequency for the speed-bin. Type is <u32>
+
+Optional properties:
+
+The following properties represent AC timing parameters from the memory
+data-sheet of the device for a given speed-bin. All these properties are
+of type <u32> and the default unit is ps (pico seconds). Parameters with
+a different unit have a suffix indicating the unit such as 'tRAS-max-ns'
+- tRCD
+- tWR
+- tRAS-min
+- tRRD
+- tWTR
+- tXP
+- tRTP
+- tDQSCK-max
+- tFAW
+- tZQCS
+- tZQinit
+- tRPab
+- tZQCL
+- tCKESR
+- tRAS-max-ns
+- tDQSCK-max-derated
+
+Example:
+
+timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 {
+       compatible      = "jedec,lpddr2-timings";
+       min-freq        = <10000000>;
+       max-freq        = <400000000>;
+       tRPab           = <21000>;
+       tRCD            = <18000>;
+       tWR             = <15000>;
+       tRAS-min        = <42000>;
+       tRRD            = <10000>;
+       tWTR            = <7500>;
+       tXP             = <7500>;
+       tRTP            = <7500>;
+       tCKESR          = <15000>;
+       tDQSCK-max      = <5500>;
+       tFAW            = <50000>;
+       tZQCS           = <90000>;
+       tZQCL           = <360000>;
+       tZQinit         = <1000000>;
+       tRAS-max-ns     = <70000>;
+};
diff --git a/Documentation/devicetree/bindings/ddr/lpddr2.txt b/Documentation/devicetree/bindings/ddr/lpddr2.txt
new file mode 100644 (file)
index 0000000..ddd4012
--- /dev/null
@@ -0,0 +1,102 @@
+* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2
+
+Required properties:
+- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2",
+  "jedec,lpddr2-s4"
+
+  "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type
+
+  "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type
+
+  "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type
+
+- density  : <u32> representing density in Mb (Mega bits)
+
+- io-width : <u32> representing bus width. Possible values are 8, 16, and 32
+
+Optional properties:
+
+The following optional properties represent the minimum value of some AC
+timing parameters of the DDR device in terms of number of clock cycles.
+These values shall be obtained from the device data-sheet.
+- tRRD-min-tck
+- tWTR-min-tck
+- tXP-min-tck
+- tRTP-min-tck
+- tCKE-min-tck
+- tRPab-min-tck
+- tRCD-min-tck
+- tWR-min-tck
+- tRASmin-min-tck
+- tCKESR-min-tck
+- tFAW-min-tck
+
+Child nodes:
+- The lpddr2 node may have one or more child nodes of type "lpddr2-timings".
+  "lpddr2-timings" provides AC timing parameters of the device for
+  a given speed-bin. The user may provide the timings for as many
+  speed-bins as is required. Please see Documentation/devicetree/
+  bindings/ddr/lpddr2-timings.txt for more information on "lpddr2-timings"
+
+Example:
+
+elpida_ECB240ABACN : lpddr2 {
+       compatible      = "Elpida,ECB240ABACN","jedec,lpddr2-s4";
+       density         = <2048>;
+       io-width        = <32>;
+
+       tRPab-min-tck   = <3>;
+       tRCD-min-tck    = <3>;
+       tWR-min-tck     = <3>;
+       tRASmin-min-tck = <3>;
+       tRRD-min-tck    = <2>;
+       tWTR-min-tck    = <2>;
+       tXP-min-tck     = <2>;
+       tRTP-min-tck    = <2>;
+       tCKE-min-tck    = <3>;
+       tCKESR-min-tck  = <3>;
+       tFAW-min-tck    = <8>;
+
+       timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 {
+               compatible      = "jedec,lpddr2-timings";
+               min-freq        = <10000000>;
+               max-freq        = <400000000>;
+               tRPab           = <21000>;
+               tRCD            = <18000>;
+               tWR             = <15000>;
+               tRAS-min        = <42000>;
+               tRRD            = <10000>;
+               tWTR            = <7500>;
+               tXP             = <7500>;
+               tRTP            = <7500>;
+               tCKESR          = <15000>;
+               tDQSCK-max      = <5500>;
+               tFAW            = <50000>;
+               tZQCS           = <90000>;
+               tZQCL           = <360000>;
+               tZQinit         = <1000000>;
+               tRAS-max-ns     = <70000>;
+       };
+
+       timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 {
+               compatible      = "jedec,lpddr2-timings";
+               min-freq        = <10000000>;
+               max-freq        = <200000000>;
+               tRPab           = <21000>;
+               tRCD            = <18000>;
+               tWR             = <15000>;
+               tRAS-min        = <42000>;
+               tRRD            = <10000>;
+               tWTR            = <10000>;
+               tXP             = <7500>;
+               tRTP            = <7500>;
+               tCKESR          = <15000>;
+               tDQSCK-max      = <5500>;
+               tFAW            = <50000>;
+               tZQCS           = <90000>;
+               tZQCL           = <360000>;
+               tZQinit         = <1000000>;
+               tRAS-max-ns     = <70000>;
+       };
+
+}
diff --git a/Documentation/devicetree/bindings/ddr/lpddr3-timings.txt b/Documentation/devicetree/bindings/ddr/lpddr3-timings.txt
new file mode 100644 (file)
index 0000000..84705e5
--- /dev/null
@@ -0,0 +1,58 @@
+* AC timing parameters of LPDDR3 memories for a given speed-bin.
+
+The structures are based on LPDDR2 and extended where needed.
+
+Required properties:
+- compatible : Should be "jedec,lpddr3-timings"
+- min-freq : minimum DDR clock frequency for the speed-bin. Type is <u32>
+- reg : maximum DDR clock frequency for the speed-bin. Type is <u32>
+
+Optional properties:
+
+The following properties represent AC timing parameters from the memory
+data-sheet of the device for a given speed-bin. All these properties are
+of type <u32> and the default unit is ps (pico seconds).
+- tRFC
+- tRRD
+- tRPab
+- tRPpb
+- tRCD
+- tRC
+- tRAS
+- tWTR
+- tWR
+- tRTP
+- tW2W-C2C
+- tR2R-C2C
+- tFAW
+- tXSR
+- tXP
+- tCKE
+- tCKESR
+- tMRD
+
+Example:
+
+timings_samsung_K3QF2F20DB_800mhz: lpddr3-timings@800000000 {
+       compatible      = "jedec,lpddr3-timings";
+       reg             = <800000000>; /* workaround: it shows max-freq */
+       min-freq        = <100000000>;
+       tRFC            = <65000>;
+       tRRD            = <6000>;
+       tRPab           = <12000>;
+       tRPpb           = <12000>;
+       tRCD            = <10000>;
+       tRC             = <33750>;
+       tRAS            = <23000>;
+       tWTR            = <3750>;
+       tWR             = <7500>;
+       tRTP            = <3750>;
+       tW2W-C2C        = <0>;
+       tR2R-C2C        = <0>;
+       tFAW            = <25000>;
+       tXSR            = <70000>;
+       tXP             = <3750>;
+       tCKE            = <3750>;
+       tCKESR          = <3750>;
+       tMRD            = <7000>;
+};
diff --git a/Documentation/devicetree/bindings/ddr/lpddr3.txt b/Documentation/devicetree/bindings/ddr/lpddr3.txt
new file mode 100644 (file)
index 0000000..a0eda35
--- /dev/null
@@ -0,0 +1,101 @@
+* LPDDR3 SDRAM memories compliant to JEDEC JESD209-3C
+
+Required properties:
+- compatible : Should be "<vendor>,<type>", and generic value "jedec,lpddr3".
+  Example "<vendor>,<type>" values:
+    "samsung,K3QF2F20DB"
+
+- density  : <u32> representing density in Mb (Mega bits)
+- io-width : <u32> representing bus width. Possible values are 8, 16, 32, 64
+- #address-cells: Must be set to 1
+- #size-cells: Must be set to 0
+
+Optional properties:
+
+The following optional properties represent the minimum value of some AC
+timing parameters of the DDR device in terms of number of clock cycles.
+These values shall be obtained from the device data-sheet.
+- tRFC-min-tck
+- tRRD-min-tck
+- tRPab-min-tck
+- tRPpb-min-tck
+- tRCD-min-tck
+- tRC-min-tck
+- tRAS-min-tck
+- tWTR-min-tck
+- tWR-min-tck
+- tRTP-min-tck
+- tW2W-C2C-min-tck
+- tR2R-C2C-min-tck
+- tWL-min-tck
+- tDQSCK-min-tck
+- tRL-min-tck
+- tFAW-min-tck
+- tXSR-min-tck
+- tXP-min-tck
+- tCKE-min-tck
+- tCKESR-min-tck
+- tMRD-min-tck
+
+Child nodes:
+- The lpddr3 node may have one or more child nodes of type "lpddr3-timings".
+  "lpddr3-timings" provides AC timing parameters of the device for
+  a given speed-bin. Please see Documentation/devicetree/
+  bindings/ddr/lpddr3-timings.txt for more information on "lpddr3-timings"
+
+Example:
+
+samsung_K3QF2F20DB: lpddr3 {
+       compatible      = "samsung,K3QF2F20DB", "jedec,lpddr3";
+       density         = <16384>;
+       io-width        = <32>;
+       #address-cells  = <1>;
+       #size-cells     = <0>;
+
+       tRFC-min-tck            = <17>;
+       tRRD-min-tck            = <2>;
+       tRPab-min-tck           = <2>;
+       tRPpb-min-tck           = <2>;
+       tRCD-min-tck            = <3>;
+       tRC-min-tck             = <6>;
+       tRAS-min-tck            = <5>;
+       tWTR-min-tck            = <2>;
+       tWR-min-tck             = <7>;
+       tRTP-min-tck            = <2>;
+       tW2W-C2C-min-tck        = <0>;
+       tR2R-C2C-min-tck        = <0>;
+       tWL-min-tck             = <8>;
+       tDQSCK-min-tck          = <5>;
+       tRL-min-tck             = <14>;
+       tFAW-min-tck            = <5>;
+       tXSR-min-tck            = <12>;
+       tXP-min-tck             = <2>;
+       tCKE-min-tck            = <2>;
+       tCKESR-min-tck          = <2>;
+       tMRD-min-tck            = <5>;
+
+       timings_samsung_K3QF2F20DB_800mhz: lpddr3-timings@800000000 {
+               compatible      = "jedec,lpddr3-timings";
+               /* workaround: 'reg' shows max-freq */
+               reg             = <800000000>;
+               min-freq        = <100000000>;
+               tRFC            = <65000>;
+               tRRD            = <6000>;
+               tRPab           = <12000>;
+               tRPpb           = <12000>;
+               tRCD            = <10000>;
+               tRC             = <33750>;
+               tRAS            = <23000>;
+               tWTR            = <3750>;
+               tWR             = <7500>;
+               tRTP            = <3750>;
+               tW2W-C2C        = <0>;
+               tR2R-C2C        = <0>;
+               tFAW            = <25000>;
+               tXSR            = <70000>;
+               tXP             = <3750>;
+               tCKE            = <3750>;
+               tCKESR          = <3750>;
+               tMRD            = <7000>;
+       };
+}
index fb74768..0da42ab 100644 (file)
@@ -79,8 +79,6 @@ properties:
 
   hdmi-supply:
     description: phandle to an external 5V regulator to power the HDMI logic
-    allOf:
-      - $ref: /schemas/types.yaml#/definitions/phandle
 
   port@0:
     type: object
diff --git a/Documentation/devicetree/bindings/display/bridge/anx6345.yaml b/Documentation/devicetree/bindings/display/bridge/anx6345.yaml
new file mode 100644 (file)
index 0000000..6d72b3d
--- /dev/null
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/anx6345.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analogix ANX6345 eDP Transmitter Device Tree Bindings
+
+maintainers:
+  - Torsten Duwe <duwe@lst.de>
+
+description: |
+  The ANX6345 is an ultra-low power Full-HD eDP transmitter designed for
+  portable devices.
+
+properties:
+  compatible:
+    const: analogix,anx6345
+
+  reg:
+    maxItems: 1
+    description: base I2C address of the device
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset
+
+  dvdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  dvdd25-supply:
+    maxItems: 1
+    description: Regulator for 2.5V digital core power.
+
+  ports:
+    type: object
+
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for LVTTL input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+          May be omitted if EDID works reliably.
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - reset-gpios
+  - dvdd12-supply
+  - dvdd25-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c0 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      anx6345: anx6345@38 {
+        compatible = "analogix,anx6345";
+        reg = <0x38>;
+        reset-gpios = <&pio42 1 /* GPIO_ACTIVE_LOW */>;
+        dvdd25-supply = <&reg_dldo2>;
+        dvdd12-supply = <&reg_fldo1>;
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          anx6345_in: port@0 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            reg = <0>;
+            anx6345_in_tcon0: endpoint@0 {
+              reg = <0>;
+              remote-endpoint = <&tcon0_out_anx6345>;
+            };
+          };
+
+          anx6345_out: port@1 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            reg = <1>;
+            anx6345_out_panel: endpoint@0 {
+              reg = <0>;
+              remote-endpoint = <&panel_in_edp>;
+            };
+          };
+        };
+      };
+    };
index 0a3fbb5..8ec4a7f 100644 (file)
@@ -21,7 +21,7 @@ Optional properties:
 - #gpio-cells    : Should be two. The first cell is the pin number and
                    the second cell is used to specify flags.
                    See ../../gpio/gpio.txt for more information.
-- #pwm-cells : Should be one. See ../../pwm/pwm.txt for description of
+- #pwm-cells : Should be one. See ../../pwm/pwm.yaml for description of
                the cell formats.
 
 - clock-names: should be "refclk"
index b0e5066..0ab5f06 100644 (file)
@@ -27,11 +27,11 @@ Example:
 
        display: display {
                model = "320x240x4";
-               native-mode = <&timing0>;
                bits-per-pixel = <4>;
                ac-prescale = <17>;
 
                display-timings {
+                       native-mode = <&timing0>;
                        timing0: 320x240 {
                                hactive = <320>;
                                hback-porch = <0>;
index e5a8b36..f4df9e8 100644 (file)
@@ -38,10 +38,10 @@ Example:
 
        display0: display0 {
                model = "Primeview-PD050VL1";
-               native-mode = <&timing_disp0>;
                bits-per-pixel = <16>;
                fsl,pcr = <0xf0c88080>; /* non-standard but required */
                display-timings {
+                       native-mode = <&timing_disp0>;
                        timing_disp0: 640x480 {
                                hactive = <640>;
                                vactive = <480>;
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt b/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt
deleted file mode 100644 (file)
index fd9cf39..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Sharp LD-D5116Z01B 12.3" WUXGA+ eDP panel
-
-Required properties:
-- compatible: should be "sharp,ld-d5116z01b"
-- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
-
-This binding is compatible with the simple-panel binding.
-
-The device node can contain one 'port' child node with one child
-'endpoint' node, according to the bindings defined in [1]. This
-node should describe panel's video bus.
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-       panel: panel {
-               compatible = "sharp,ld-d5116z01b";
-               power-supply = <&vlcd_3v3>;
-
-               port {
-                       panel_ep: endpoint {
-                               remote-endpoint = <&bridge_out_ep>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.yaml b/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.yaml
new file mode 100644 (file)
index 0000000..fbb647e
--- /dev/null
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/sharp,ld-d5116z01b.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sharp LD-D5116Z01B 12.3" WUXGA+ eDP panel
+
+maintainers:
+  - Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    const: sharp,ld-d5116z01b
+
+  power-supply: true
+  backlight: true
+  port: true
+  no-hpd: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - power-supply
+
+...
diff --git a/Documentation/devicetree/bindings/display/st,stm32-dsi.yaml b/Documentation/devicetree/bindings/display/st,stm32-dsi.yaml
new file mode 100644 (file)
index 0000000..3be76d1
--- /dev/null
@@ -0,0 +1,150 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/st,stm32-dsi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 DSI host controller
+
+maintainers:
+  - Philippe Cornu <philippe.cornu@st.com>
+  - Yannick Fertre <yannick.fertre@st.com>
+
+description:
+  The STMicroelectronics STM32 DSI controller uses the Synopsys DesignWare MIPI-DSI host controller.
+
+properties:
+  compatible:
+    const: st,stm32-dsi
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Module Clock
+      - description: DSI bus clock
+      - description: Pixel clock
+    minItems: 2
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: ref
+      - const: px_clk
+    minItems: 2
+    maxItems: 3
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: apb
+
+  phy-dsi-supply:
+    description:
+        Phandle of the regulator that provides the supply voltage.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description:
+          DSI input port node, connected to the ltdc rgb output port.
+
+      port@1:
+        type: object
+        description:
+          DSI output port node, connected to a panel or a bridge input port"
+
+patternProperties:
+  "^(panel|panel-dsi)@[0-9]$":
+    type: object
+    description:
+      A node containing the panel or bridge description as documented in
+      Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
+    properties:
+      port:
+        type: object
+        description:
+          Panel or bridge port node, connected to the DSI output port (port@1)
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+required:
+  - "#address-cells"
+  - "#size-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    #include <dt-bindings/gpio/gpio.h>
+    dsi: dsi@5a000000 {
+        compatible = "st,stm32-dsi";
+        reg = <0x5a000000 0x800>;
+        clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>;
+        clock-names = "pclk", "ref", "px_clk";
+        resets = <&rcc DSI_R>;
+        reset-names = "apb";
+        phy-dsi-supply = <&reg18>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        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-dsi@0 {
+              compatible = "orisetech,otm8009a";
+              reg = <0>;
+              reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>;
+              power-supply = <&v3v3>;
+
+              port {
+                    panel_in: endpoint {
+                        remote-endpoint = <&dsi_out>;
+                    };
+              };
+        };
+    };
+
+...
+
+
diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
deleted file mode 100644 (file)
index 60c54da..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-* STMicroelectronics STM32 lcd-tft display controller
-
-- ltdc: lcd-tft display controller host
-  Required properties:
-  - compatible: "st,stm32-ltdc"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - clocks: A list of phandle + clock-specifier pairs, one for each
-    entry in 'clock-names'.
-  - clock-names: A list of clock names. For ltdc it should contain:
-      - "lcd" for the clock feeding the output pixel clock & IP clock.
-  - resets: reset to be used by the device (defined by use of RCC macro).
-  Required nodes:
-  - Video port for DPI RGB output: ltdc has one video port with up to 2
-    endpoints:
-      - for external dpi rgb panel or bridge, using gpios.
-      - for internal dpi input of the MIPI DSI host controller.
-      Note: These 2 endpoints cannot be activated simultaneously.
-
-* STMicroelectronics STM32 DSI controller specific extensions to Synopsys
-  DesignWare MIPI DSI host controller
-
-The STMicroelectronics STM32 DSI controller uses the Synopsys DesignWare MIPI
-DSI host controller. For all mandatory properties & nodes, please refer
-to the related documentation in [5].
-
-Mandatory properties specific to STM32 DSI:
-- #address-cells: Should be <1>.
-- #size-cells: Should be <0>.
-- compatible: "st,stm32-dsi".
-- clock-names:
-  - phy pll reference clock string name, must be "ref".
-- resets: see [5].
-- reset-names: see [5].
-
-Mandatory nodes specific to STM32 DSI:
-- ports: A node containing DSI input & output port nodes with endpoint
-  definitions as documented in [3] & [4].
-  - port@0: DSI input port node, connected to the ltdc rgb output port.
-  - port@1: DSI output port node, connected to a panel or a bridge input port.
-- panel or bridge node: A node containing the panel or bridge description as
-  documented in [6].
-  - port: panel or bridge port node, connected to the DSI output port (port@1).
-Optional properties:
-- phy-dsi-supply: phandle of the regulator that provides the supply voltage.
-
-Note: You can find more documentation in the following references
-[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] Documentation/devicetree/bindings/reset/reset.txt
-[3] Documentation/devicetree/bindings/media/video-interfaces.txt
-[4] Documentation/devicetree/bindings/graph.txt
-[5] Documentation/devicetree/bindings/display/bridge/dw_mipi_dsi.txt
-[6] Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
-
-Example 1: RGB panel
-/ {
-       ...
-       soc {
-       ...
-               ltdc: display-controller@40016800 {
-                       compatible = "st,stm32-ltdc";
-                       reg = <0x40016800 0x200>;
-                       interrupts = <88>, <89>;
-                       resets = <&rcc STM32F4_APB2_RESET(LTDC)>;
-                       clocks = <&rcc 1 CLK_LCD>;
-                       clock-names = "lcd";
-
-                       port {
-                               ltdc_out_rgb: endpoint {
-                               };
-                       };
-               };
-       };
-};
-
-Example 2: DSI panel
-
-/ {
-       ...
-       soc {
-       ...
-               ltdc: display-controller@40016800 {
-                       compatible = "st,stm32-ltdc";
-                       reg = <0x40016800 0x200>;
-                       interrupts = <88>, <89>;
-                       resets = <&rcc STM32F4_APB2_RESET(LTDC)>;
-                       clocks = <&rcc 1 CLK_LCD>;
-                       clock-names = "lcd";
-
-                       port {
-                               ltdc_out_dsi: endpoint {
-                                       remote-endpoint = <&dsi_in>;
-                               };
-                       };
-               };
-
-
-               dsi: dsi@40016c00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "st,stm32-dsi";
-                       reg = <0x40016c00 0x800>;
-                       clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>;
-                       clock-names = "pclk", "ref";
-                       resets = <&rcc STM32F4_APB2_RESET(DSI)>;
-                       reset-names = "apb";
-                       phy-dsi-supply = <&reg18>;
-
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
-                               port@0 {
-                                       reg = <0>;
-                                       dsi_in: endpoint {
-                                               remote-endpoint = <&ltdc_out_dsi>;
-                                       };
-                               };
-
-                               port@1 {
-                                       reg = <1>;
-                                       dsi_out: endpoint {
-                                               remote-endpoint = <&dsi_in_panel>;
-                                       };
-                               };
-
-                       };
-
-                       panel-dsi@0 {
-                               reg = <0>; /* dsi virtual channel (0..3) */
-                               compatible = ...;
-                               enable-gpios = ...;
-
-                               port {
-                                       dsi_in_panel: endpoint {
-                                               remote-endpoint = <&dsi_out>;
-                                       };
-                               };
-
-                       };
-
-               };
-
-       };
-};
diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml b/Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml
new file mode 100644 (file)
index 0000000..bf8ad91
--- /dev/null
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/st,stm32-ltdc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 lcd-tft display controller
+
+maintainers:
+  - Philippe Cornu <philippe.cornu@st.com>
+  - Yannick Fertre <yannick.fertre@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-ltdc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: events interrupt line.
+      - description: errors interrupt line.
+    minItems: 1
+    maxItems: 2
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: lcd
+
+  resets:
+    maxItems: 1
+
+  port:
+    type: object
+    description:
+      "Video port for DPI RGB output.
+      ltdc has one video port with up to 2 endpoints:
+      - for external dpi rgb panel or bridge, using gpios.
+      - for internal dpi input of the MIPI DSI host controller.
+      Note: These 2 endpoints cannot be activated simultaneously.
+      Please refer to the bindings defined in
+      Documentation/devicetree/bindings/media/video-interfaces.txt."
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    ltdc: display-controller@40016800 {
+        compatible = "st,stm32-ltdc";
+        reg = <0x5a001000 0x400>;
+        interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&rcc LTDC_PX>;
+        clock-names = "lcd";
+        resets = <&rcc LTDC_R>;
+
+        port {
+             ltdc_out_dsi: endpoint {
+                     remote-endpoint = <&dsi_in>;
+             };
+        };
+    };
+
+...
+
index 4cb9d6b..387d599 100644 (file)
@@ -68,9 +68,7 @@ else:
     clocks:
       maxItems: 1
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index ed0a49a..02a34ba 100644 (file)
@@ -25,11 +25,18 @@ properties:
       Used to provide DMA controller specific information.
 
   dma-channel-mask:
-    $ref: /schemas/types.yaml#definitions/uint32
     description:
       Bitmask of available DMA channels in ascending order that are
       not reserved by firmware and are available to the
       kernel. i.e. first channel corresponds to LSB.
+      The first item in the array is for channels 0-31, the second is for
+      channels 32-63, etc.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+    items:
+      minItems: 1
+      # Should be enough
+      maxItems: 255
 
   dma-channels:
     $ref: /schemas/types.yaml#definitions/uint32
index 636fcb2..ec89782 100644 (file)
@@ -7,10 +7,11 @@ Required properties:
   * ingenic,jz4725b-dma
   * ingenic,jz4770-dma
   * ingenic,jz4780-dma
+  * ingenic,x1000-dma
 - reg: Should contain the DMA channel registers location and length, followed
   by the DMA controller registers location and length.
 - interrupts: Should contain the interrupt specifier of the DMA controller.
-- clocks: Should contain a clock specifier for the JZ4780 PDMA clock.
+- clocks: Should contain a clock specifier for the JZ4780/X1000 PDMA clock.
 - #dma-cells: Must be <2>. Number of integer cells in the dmas property of
   DMA clients (see below).
 
diff --git a/Documentation/devicetree/bindings/dma/milbeaut-m10v-hdmac.txt b/Documentation/devicetree/bindings/dma/milbeaut-m10v-hdmac.txt
new file mode 100644 (file)
index 0000000..1f0875b
--- /dev/null
@@ -0,0 +1,32 @@
+* Milbeaut AHB DMA Controller
+
+Milbeaut AHB DMA controller has transfer capability below.
+ - device to memory transfer
+ - memory to device transfer
+
+Required property:
+- compatible:       Should be  "socionext,milbeaut-m10v-hdmac"
+- reg:              Should contain DMA registers location and length.
+- interrupts:       Should contain all of the per-channel DMA interrupts.
+                     Number of channels is configurable - 2, 4 or 8, so
+                     the number of interrupts specified should be {2,4,8}.
+- #dma-cells:       Should be 1. Specify the ID of the slave.
+- clocks:           Phandle to the clock used by the HDMAC module.
+
+
+Example:
+
+       hdmac1: dma-controller@1e110000 {
+               compatible = "socionext,milbeaut-m10v-hdmac";
+               reg = <0x1e110000 0x10000>;
+               interrupts = <0 132 4>,
+                            <0 133 4>,
+                            <0 134 4>,
+                            <0 135 4>,
+                            <0 136 4>,
+                            <0 137 4>,
+                            <0 138 4>,
+                            <0 139 4>;
+               #dma-cells = <1>;
+               clocks = <&dummy_clk>;
+       };
diff --git a/Documentation/devicetree/bindings/dma/milbeaut-m10v-xdmac.txt b/Documentation/devicetree/bindings/dma/milbeaut-m10v-xdmac.txt
new file mode 100644 (file)
index 0000000..3057918
--- /dev/null
@@ -0,0 +1,24 @@
+* Milbeaut AXI DMA Controller
+
+Milbeaut AXI DMA controller has only memory to memory transfer capability.
+
+* DMA controller
+
+Required property:
+- compatible:  Should be  "socionext,milbeaut-m10v-xdmac"
+- reg:         Should contain DMA registers location and length.
+- interrupts:  Should contain all of the per-channel DMA interrupts.
+                Number of channels is configurable - 2, 4 or 8, so
+                the number of interrupts specified should be {2,4,8}.
+- #dma-cells:  Should be 1.
+
+Example:
+       xdmac0: dma-controller@1c250000 {
+               compatible = "socionext,milbeaut-m10v-xdmac";
+               reg = <0x1c250000 0x1000>;
+               interrupts = <0 17 0x4>,
+                            <0 18 0x4>,
+                            <0 19 0x4>,
+                            <0 20 0x4>;
+               #dma-cells = <1>;
+       };
index 5a512c5..5551e92 100644 (file)
@@ -21,6 +21,7 @@ Required Properties:
                - "renesas,dmac-r8a7745" (RZ/G1E)
                - "renesas,dmac-r8a77470" (RZ/G1C)
                - "renesas,dmac-r8a774a1" (RZ/G2M)
+               - "renesas,dmac-r8a774b1" (RZ/G2N)
                - "renesas,dmac-r8a774c0" (RZ/G2E)
                - "renesas,dmac-r8a7790" (R-Car H2)
                - "renesas,dmac-r8a7791" (R-Car M2-W)
diff --git a/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml b/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
new file mode 100644 (file)
index 0000000..2ca3ddb
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/sifive,fu540-c000-pdma.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SiFive Unleashed Rev C000 Platform DMA
+
+maintainers:
+  - Green Wan <green.wan@sifive.com>
+  - Palmer Debbelt <palmer@sifive.com>
+  - Paul Walmsley <paul.walmsley@sifive.com>
+
+description: |
+  Platform DMA is a DMA engine of SiFive Unleashed. It supports 4
+  channels. Each channel has 2 interrupts. One is for DMA done and
+  the other is for DME error.
+
+  In different SoC, DMA could be attached to different IRQ line.
+  DT file need to be changed to meet the difference. For technical
+  doc,
+
+  https://static.dev.sifive.com/FU540-C000-v1.0.pdf
+
+properties:
+  compatible:
+    items:
+      - const: sifive,fu540-c000-pdma
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 8
+
+  '#dma-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - '#dma-cells'
+
+examples:
+  - |
+    dma@3000000 {
+      compatible = "sifive,fu540-c000-pdma";
+      reg = <0x0 0x3000000 0x0 0x8000>;
+      interrupts = <23 24 25 26 27 28 29 30>;
+      #dma-cells = <1>;
+    };
+
+...
index 4bbc94d..0e1398f 100644 (file)
@@ -42,6 +42,11 @@ Optional properties:
 - ti,edma-reserved-slot-ranges: PaRAM slot ranges which should not be used by
                the driver, they are allocated to be used by for example the
                DSP. See example.
+- dma-channel-mask: Mask of usable channels.
+               Single uint32 for EDMA with 32 channels, array of two uint32 for
+               EDMA with 64 channels. See example and
+               Documentation/devicetree/bindings/dma/dma-common.yaml
+
 
 ------------------------------------------------------------------------------
 eDMA3 Transfer Controller
@@ -91,6 +96,9 @@ edma: edma@49000000 {
        ti,edma-memcpy-channels = <20 21>;
        /* The following PaRAM slots are reserved: 35-44 and 100-109 */
        ti,edma-reserved-slot-ranges = <35 10>, <100 10>;
+       /* The following channels are reserved: 35-44 */
+       dma-channel-mask = <0xffffffff /* Channel 0-31 */
+                           0xffffe007>; /* Channel 32-63 */
 };
 
 edma_tptc0: tptc@49800000 {
index 93b6d96..325aca5 100644 (file)
@@ -11,9 +11,16 @@ is to receive from the device.
 Xilinx AXI CDMA engine, it does transfers between memory-mapped source
 address and a memory-mapped destination address.
 
+Xilinx AXI MCDMA engine, it does transfer between memory and AXI4 stream
+target devices. It can be configured to have up to 16 independent transmit
+and receive channels.
+
 Required properties:
-- compatible: Should be "xlnx,axi-vdma-1.00.a" or "xlnx,axi-dma-1.00.a" or
-             "xlnx,axi-cdma-1.00.a""
+- compatible: Should be one of-
+               "xlnx,axi-vdma-1.00.a"
+               "xlnx,axi-dma-1.00.a"
+               "xlnx,axi-cdma-1.00.a"
+               "xlnx,axi-mcdma-1.00.a"
 - #dma-cells: Should be <1>, see "dmas" property below
 - reg: Should contain VDMA registers location and length.
 - xlnx,addrwidth: Should be the vdma addressing size in bits(ex: 32 bits).
@@ -29,7 +36,7 @@ Required properties:
                           "m_axis_mm2s_aclk", "s_axis_s2mm_aclk"
        For CDMA:
        Required elements: "s_axi_lite_aclk", "m_axi_aclk"
-       FOR AXIDMA:
+       For AXIDMA and MCDMA:
        Required elements: "s_axi_lite_aclk"
        Optional elements: "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
                           "m_axi_sg_aclk"
@@ -37,12 +44,11 @@ Required properties:
 Required properties for VDMA:
 - xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
 
-Optional properties for AXI DMA:
+Optional properties for AXI DMA and MCDMA:
 - xlnx,sg-length-width: Should be set to the width in bits of the length
        register as configured in h/w. Takes values {8...26}. If the property
        is missing or invalid then the default value 23 is used. This is the
        maximum value that is supported by all IP versions.
-- xlnx,mcdma: Tells whether configured for multi-channel mode in the hardware.
 Optional properties for VDMA:
 - xlnx,flush-fsync: Tells which channel to Flush on Frame sync.
        It takes following values:
@@ -55,8 +61,8 @@ Required child node properties:
        For VDMA: It should be either "xlnx,axi-vdma-mm2s-channel" or
        "xlnx,axi-vdma-s2mm-channel".
        For CDMA: It should be "xlnx,axi-cdma-channel".
-       For AXIDMA: It should be either "xlnx,axi-dma-mm2s-channel" or
-       "xlnx,axi-dma-s2mm-channel".
+       For AXIDMA and MCDMA: It should be either "xlnx,axi-dma-mm2s-channel"
+       or "xlnx,axi-dma-s2mm-channel".
 - interrupts: Should contain per channel VDMA interrupts.
 - xlnx,datawidth: Should contain the stream data width, take values
        {32,64...1024}.
@@ -69,8 +75,8 @@ Optional child node properties for VDMA:
        enabled/disabled in hardware.
 - xlnx,enable-vert-flip: Tells vertical flip is
        enabled/disabled in hardware(S2MM path).
-Optional child node properties for AXI DMA:
--dma-channels: Number of dma channels in child node.
+Optional child node properties for MCDMA:
+- dma-channels: Number of dma channels in child node.
 
 Example:
 ++++++++
index 22aead8..c94acbb 100644 (file)
@@ -1,89 +1 @@
-EEPROMs (I2C)
-
-Required properties:
-
-  - compatible: Must be a "<manufacturer>,<model>" pair. The following <model>
-                values are supported (assuming "atmel" as manufacturer):
-
-                "atmel,24c00",
-                "atmel,24c01",
-                "atmel,24cs01",
-                "atmel,24c02",
-                "atmel,24cs02",
-                "atmel,24mac402",
-                "atmel,24mac602",
-                "atmel,spd",
-                "atmel,24c04",
-                "atmel,24cs04",
-                "atmel,24c08",
-                "atmel,24cs08",
-                "atmel,24c16",
-                "atmel,24cs16",
-                "atmel,24c32",
-                "atmel,24cs32",
-                "atmel,24c64",
-                "atmel,24cs64",
-                "atmel,24c128",
-                "atmel,24c256",
-                "atmel,24c512",
-                "atmel,24c1024",
-                "atmel,24c2048",
-
-                If <manufacturer> is not "atmel", then a fallback must be used
-                with the same <model> and "atmel" as manufacturer.
-
-                Example:
-                        compatible = "microchip,24c128", "atmel,24c128";
-
-                Supported manufacturers are:
-
-                "catalyst",
-                "microchip",
-                "nxp",
-                "ramtron",
-                "renesas",
-                "rohm",
-                "st",
-
-                Some vendors use different model names for chips which are just
-                variants of the above. Known such exceptions are listed below:
-
-                "nxp,se97b" - the fallback is "atmel,24c02",
-                "renesas,r1ex24002" - the fallback is "atmel,24c02"
-                "renesas,r1ex24016" - the fallback is "atmel,24c16"
-                "renesas,r1ex24128" - the fallback is "atmel,24c128"
-                "rohm,br24t01" - the fallback is "atmel,24c01"
-
-  - reg: The I2C address of the EEPROM.
-
-Optional properties:
-
-  - pagesize: The length of the pagesize for writing. Please consult the
-              manual of your device, that value varies a lot. A wrong value
-              may result in data loss! If not specified, a safety value of
-              '1' is used which will be very slow.
-
-  - read-only: This parameterless property disables writes to the eeprom.
-
-  - size: Total eeprom size in bytes.
-
-  - no-read-rollover: This parameterless property indicates that the
-                      multi-address eeprom does not automatically roll over
-                      reads to the next slave address. Please consult the
-                      manual of your device.
-
-  - wp-gpios: GPIO to which the write-protect pin of the chip is connected.
-
-  - address-width: number of address bits (one of 8, 16).
-
-  - num-addresses: total number of i2c slave addresses this device takes
-
-Example:
-
-eeprom@52 {
-       compatible = "atmel,24c32";
-       reg = <0x52>;
-       pagesize = <32>;
-       wp-gpios = <&gpio1 3 0>;
-       num-addresses = <8>;
-};
+This file has been moved to at24.yaml.
diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml
new file mode 100644 (file)
index 0000000..e877856
--- /dev/null
@@ -0,0 +1,188 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright 2019 BayLibre SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/eeprom/at24.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: I2C EEPROMs compatible with Atmel's AT24
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+select:
+  properties:
+    compatible:
+      contains:
+        pattern: "^atmel,(24(c|cs|mac)[0-9]+|spd)$"
+  required:
+    - compatible
+
+properties:
+  $nodename:
+    pattern: "^eeprom@[0-9a-f]{1,2}$"
+
+  # There are multiple known vendors who manufacture EEPROM chips compatible
+  # with Atmel's AT24. The compatible string requires either a single item
+  # if the memory comes from Atmel (in which case the vendor part must be
+  # 'atmel') or two items with the same 'model' part where the vendor part of
+  # the first one is the actual manufacturer and the second item is the
+  # corresponding 'atmel,<model>' from Atmel.
+  compatible:
+    oneOf:
+      - allOf:
+          - minItems: 1
+            maxItems: 2
+            items:
+              - pattern: "^(atmel|catalyst|microchip|nxp|ramtron|renesas|rohm|st),(24(c|cs|mac)[0-9]+|spd)$"
+              - pattern: "^atmel,(24(c|cs|mac)[0-9]+|spd)$"
+          - oneOf:
+              - items:
+                  pattern: c00$
+              - items:
+                  pattern: c01$
+              - items:
+                  pattern: cs01$
+              - items:
+                  pattern: c02$
+              - items:
+                  pattern: cs02$
+              - items:
+                  pattern: mac402$
+              - items:
+                  pattern: mac602$
+              - items:
+                  pattern: c04$
+              - items:
+                  pattern: cs04$
+              - items:
+                  pattern: c08$
+              - items:
+                  pattern: cs08$
+              - items:
+                  pattern: c16$
+              - items:
+                  pattern: cs16$
+              - items:
+                  pattern: c32$
+              - items:
+                  pattern: cs32$
+              - items:
+                  pattern: c64$
+              - items:
+                  pattern: cs64$
+              - items:
+                  pattern: c128$
+              - items:
+                  pattern: cs128$
+              - items:
+                  pattern: c256$
+              - items:
+                  pattern: cs256$
+              - items:
+                  pattern: c512$
+              - items:
+                  pattern: cs512$
+              - items:
+                  pattern: c1024$
+              - items:
+                  pattern: cs1024$
+              - items:
+                  pattern: c2048$
+              - items:
+                  pattern: cs2048$
+              - items:
+                  pattern: spd$
+      # These are special cases that don't conform to the above pattern.
+      # Each requires a standard at24 model as fallback.
+      - items:
+          - const: rohm,br24t01
+          - const: atmel,24c01
+      - items:
+          - const: nxp,se97b
+          - const: atmel,24c02
+      - items:
+          - const: renesas,r1ex24002
+          - const: atmel,24c02
+      - items:
+          - const: renesas,r1ex24016
+          - const: atmel,24c16
+      - items:
+          - const: giantec,gt24c32a
+          - const: atmel,24c32
+      - items:
+          - const: renesas,r1ex24128
+          - const: atmel,24c128
+
+  reg:
+    maxItems: 1
+
+  pagesize:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The length of the pagesize for writing. Please consult the
+      manual of your device, that value varies a lot. A wrong value
+      may result in data loss! If not specified, a safety value of
+      '1' is used which will be very slow.
+    enum: [ 1, 8, 16, 32, 64, 128, 258 ]
+    default: 1
+
+  read-only:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Disables writes to the eeprom.
+
+  size:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Total eeprom size in bytes.
+
+  no-read-rollover:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Indicates that the multi-address eeprom does not automatically roll
+      over reads to the next slave address. Please consult the manual of
+      your device.
+
+  wp-gpios:
+    description:
+      GPIO to which the write-protect pin of the chip is connected.
+    maxItems: 1
+
+  address-width:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Number of address bits.
+    default: 8
+    enum: [ 8, 16 ]
+
+  num-addresses:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Total number of i2c slave addresses this device takes.
+    default: 1
+    minimum: 1
+    maximum: 8
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      eeprom@52 {
+          compatible = "microchip,24c32", "atmel,24c32";
+          reg = <0x52>;
+          pagesize = <32>;
+          wp-gpios = <&gpio1 3 0>;
+          num-addresses = <8>;
+      };
+    };
+...
index c43819c..4ddcf70 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 # Copyright 2018 Linaro Ltd.
 %YAML 1.2
 ---
@@ -71,7 +71,7 @@ properties:
     # minItems/maxItems equal to 2 is implied
 
   reg-names:
-    # The core schema enforces this is a string array
+    # The core schema enforces this (*-names) is a string array
     items:
       - const: core
       - const: aux
@@ -79,7 +79,8 @@ properties:
   clocks:
     # Cases that have only a single entry just need to express that with maxItems
     maxItems: 1
-    description: bus clock
+    description: bus clock. A description is only needed for a single item if
+      there's something unique to add.
 
   clock-names:
     items:
@@ -127,6 +128,14 @@ properties:
     maxItems: 1
     description: A connection of the 'foo' gpio line.
 
+  # *-supply is always a single phandle, so nothing more to define.
+  foo-supply: true
+
+  # Vendor specific properties
+  #
+  # Vendor specific properties have slightly different schema requirements than
+  # common properties. They must have at least a type definition and
+  # 'description'.
   vendor,int-property:
     description: Vendor specific properties must have a description
     # 'allOf' is the json-schema way of subclassing a schema. Here the base
@@ -137,9 +146,9 @@ properties:
       - enum: [2, 4, 6, 8, 10]
 
   vendor,bool-property:
-    description: Vendor specific properties must have a description
-    # boolean properties is one case where the json-schema 'type' keyword
-    # can be used directly
+    description: Vendor specific properties must have a description. Boolean
+      properties are one case where the json-schema 'type' keyword can be used
+      directly.
     type: boolean
 
   vendor,string-array-property:
@@ -151,14 +160,72 @@ properties:
           - enum: [ foo, bar ]
           - enum: [ baz, boo ]
 
+  vendor,property-in-standard-units-microvolt:
+    description: Vendor specific properties having a standard unit suffix
+      don't need a type.
+    enum: [ 100, 200, 300 ]
+
+  child-node:
+    description: Child nodes are just another property from a json-schema
+      perspective.
+    type: object  # DT nodes are json objects
+    properties:
+      vendor,a-child-node-property:
+        description: Child node properties have all the same schema
+          requirements.
+        type: boolean
+
+    required:
+      - vendor,a-child-node-property
+
+# Describe the relationship between different properties
+dependencies:
+  # 'vendor,bool-property' is only allowed when 'vendor,string-array-property'
+  # is present
+  vendor,bool-property: [ vendor,string-array-property ]
+  # Expressing 2 properties in both orders means all of the set of properties
+  # must be present or none of them.
+  vendor,string-array-property: [ vendor,bool-property ]
+
 required:
   - compatible
   - reg
   - interrupts
   - interrupt-controller
 
+# if/then schema can be used to handle conditions on a property affecting
+# another property. A typical case is a specific 'compatible' value changes the
+# constraints on other properties.
+#
+# For multiple 'if' schema, group them under an 'allOf'.
+#
+# If the conditionals become too unweldy, then it may be better to just split
+# the binding into separate schema documents.
+if:
+  properties:
+    compatible:
+      contains:
+        const: vendor,soc2-ip
+then:
+  required:
+    - foo-supply
+
+# Ideally, the schema should have this line otherwise any other properties
+# present are allowed. There's a few common properties such as 'status' and
+# 'pinctrl-*' which are added automatically by the tooling.
+#
+# This can't be used in cases where another schema is referenced
+# (i.e. allOf: [{$ref: ...}]).
+additionalProperties: false
+
 examples:
-  # Examples are now compiled with dtc
+  # Examples are now compiled with dtc and validated against the schemas
+  #
+  # Examples have a default #address-cells and #size-cells value of 1. This can
+  # be overridden or an appropriate parent bus node should be shown (such as on
+  # i2c buses).
+  #
+  # Any includes used have to be explicitly included.
   - |
     node@1000 {
           compatible = "vendor,soc4-ip", "vendor,soc1-ip";
index 4f0db8e..878a207 100644 (file)
@@ -25,8 +25,6 @@ properties:
           - const: intel,ixp4xx-network-processing-engine
 
   reg:
-    minItems: 3
-    maxItems: 3
     items:
       - description: NPE0 register range
       - description: NPE1 register range
index ff380da..e44a13b 100644 (file)
@@ -32,7 +32,7 @@ implemented by this node:
 
 - .../clock/clock-bindings.txt
 - <dt-bindings/clock/tegra186-clock.h>
-- ../power/power_domain.txt
+- ../power/power-domain.yaml
 - <dt-bindings/power/tegra186-powergate.h>
 - .../reset/reset.txt
 - <dt-bindings/reset/tegra186-reset.h>
index a4fe136..18c3aea 100644 (file)
@@ -11,7 +11,9 @@ power management service, FPGA service and other platform management
 services.
 
 Required properties:
- - compatible: Must contain:   "xlnx,zynqmp-firmware"
+ - compatible: Must contain any of below:
+               "xlnx,zynqmp-firmware" for Zynq Ultrascale+ MPSoC
+               "xlnx,versal-firmware" for Versal
  - method:     The method of calling the PM-API firmware layer.
                Permitted values are:
                  - "smc" : SMC #0, following the SMCCC
@@ -21,6 +23,8 @@ Required properties:
 Example
 -------
 
+Zynq Ultrascale+ MPSoC
+----------------------
 firmware {
        zynqmp_firmware: zynqmp-firmware {
                compatible = "xlnx,zynqmp-firmware";
@@ -28,3 +32,13 @@ firmware {
                ...
        };
 };
+
+Versal
+------
+firmware {
+       versal_firmware: versal-firmware {
+               compatible = "xlnx,versal-firmware";
+               method = "smc";
+               ...
+       };
+};
index 5f1fd6d..0c426e3 100644 (file)
@@ -17,6 +17,7 @@ properties:
     items:
       - enum:
           - amlogic,meson-g12a-mali
+          - realtek,rtd1619-mali
       - const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable
 
   reg:
@@ -37,8 +38,7 @@ properties:
   clocks:
     maxItems: 1
 
-  mali-supply:
-    maxItems: 1
+  mali-supply: true
 
   operating-points-v2: true
 
index 47bc1ac..36f59b3 100644 (file)
@@ -14,6 +14,14 @@ properties:
     pattern: '^gpu@[a-f0-9]+$'
   compatible:
     oneOf:
+      - items:
+          - enum:
+             - samsung,exynos5250-mali
+          - const: arm,mali-t604
+      - items:
+          - enum:
+             - samsung,exynos5420-mali
+          - const: arm,mali-t628
       - items:
           - enum:
              - allwinner,sun50i-h6-mali
@@ -21,26 +29,22 @@ properties:
       - items:
           - enum:
              - amlogic,meson-gxm-mali
+             - realtek,rtd1295-mali
           - const: arm,mali-t820
+      - items:
+          - enum:
+             - arm,juno-mali
+          - const: arm,mali-t624
       - items:
           - enum:
              - rockchip,rk3288-mali
+             - samsung,exynos5433-mali
           - const: arm,mali-t760
       - items:
           - enum:
              - rockchip,rk3399-mali
           - const: arm,mali-t860
-      - items:
-          - enum:
-             - samsung,exynos5250-mali
-          - const: arm,mali-t604
-      - items:
-          - enum:
-             - samsung,exynos5433-mali
-          - const: arm,mali-t760
 
-          # "arm,mali-t624"
-          # "arm,mali-t628"
           # "arm,mali-t830"
           # "arm,mali-t880"
 
@@ -69,8 +73,7 @@ properties:
       - const: core
       - const: bus
 
-  mali-supply:
-    maxItems: 1
+  mali-supply: true
 
   resets:
     minItems: 1
index c5d93c5..afde81b 100644 (file)
@@ -97,8 +97,7 @@ properties:
 
   memory-region: true
 
-  mali-supply:
-    maxItems: 1
+  mali-supply: true
 
   power-domains:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.txt b/Documentation/devicetree/bindings/gpu/samsung-g2d.txt
deleted file mode 100644 (file)
index 1e79593..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* Samsung 2D Graphics Accelerator
-
-Required properties:
-  - compatible : value should be one among the following:
-       (a) "samsung,s5pv210-g2d" for G2D IP present in S5PV210 & Exynos4210 SoC
-       (b) "samsung,exynos4212-g2d" for G2D IP present in Exynos4x12 SoCs
-       (c) "samsung,exynos5250-g2d" for G2D IP present in Exynos5250 SoC
-
-  - reg : Physical base address of the IP registers and length of memory
-         mapped region.
-
-  - interrupts : G2D interrupt number to the CPU.
-  - clocks : from common clock binding: handle to G2D clocks.
-  - clock-names : names of clocks listed in clocks property, in the same
-                 order, depending on SoC type:
-                 - for S5PV210 and Exynos4 based SoCs: "fimg2d" and
-                   "sclk_fimg2d"
-                 - for Exynos5250 SoC: "fimg2d".
-
-Example:
-       g2d@12800000 {
-               compatible = "samsung,s5pv210-g2d";
-               reg = <0x12800000 0x1000>;
-               interrupts = <0 89 0>;
-               clocks = <&clock 177>, <&clock 277>;
-               clock-names = "sclk_fimg2d", "fimg2d";
-       };
diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml
new file mode 100644 (file)
index 0000000..e7daae8
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpu/samsung-g2d.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC 2D Graphics Accelerator
+
+maintainers:
+  - Inki Dae <inki.dae@samsung.com>
+
+properties:
+  compatible:
+    enum:
+      - samsung,s5pv210-g2d    # in S5PV210 & Exynos4210 SoC
+      - samsung,exynos4212-g2d # in Exynos4x12 SoCs
+      - samsung,exynos5250-g2d
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks: {}
+  clock-names: {}
+  iommus: {}
+  power-domains: {}
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: samsung,exynos5250-g2d
+
+then:
+  properties:
+    clocks:
+      items:
+        - description: fimg2d clock
+    clock-names:
+      items:
+        - const: fimg2d
+
+else:
+  properties:
+    clocks:
+      items:
+        - description: sclk_fimg2d clock
+        - description: fimg2d clock
+    clock-names:
+      items:
+        - const: sclk_fimg2d
+        - const: fimg2d
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    g2d@12800000 {
+        compatible = "samsung,s5pv210-g2d";
+        reg = <0x12800000 0x1000>;
+        interrupts = <0 89 0>;
+        clocks = <&clock 177>, <&clock 277>;
+        clock-names = "sclk_fimg2d", "fimg2d";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/gpu/samsung-rotator.txt b/Documentation/devicetree/bindings/gpu/samsung-rotator.txt
deleted file mode 100644 (file)
index 3aca257..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-* Samsung Image Rotator
-
-Required properties:
-  - compatible : value should be one of the following:
-       * "samsung,s5pv210-rotator" for Rotator IP in S5PV210
-       * "samsung,exynos4210-rotator" for Rotator IP in Exynos4210
-       * "samsung,exynos4212-rotator" for Rotator IP in Exynos4212/4412
-       * "samsung,exynos5250-rotator" for Rotator IP in Exynos5250
-
-  - reg : Physical base address of the IP registers and length of memory
-         mapped region.
-
-  - interrupts : Interrupt specifier for rotator interrupt, according to format
-                specific to interrupt parent.
-
-  - clocks : Clock specifier for rotator clock, according to generic clock
-            bindings. (See Documentation/devicetree/bindings/clock/exynos*.txt)
-
-  - clock-names : Names of clocks. For exynos rotator, it should be "rotator".
-
-Example:
-       rotator@12810000 {
-               compatible = "samsung,exynos4210-rotator";
-               reg = <0x12810000 0x1000>;
-               interrupts = <0 83 0>;
-               clocks = <&clock 278>;
-               clock-names = "rotator";
-       };
diff --git a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml
new file mode 100644 (file)
index 0000000..f4dfa6f
--- /dev/null
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpu/samsung-rotator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC Image Rotator
+
+maintainers:
+  - Inki Dae <inki.dae@samsung.com>
+
+properties:
+  compatible:
+    enum:
+      - "samsung,s5pv210-rotator"
+      - "samsung,exynos4210-rotator"
+      - "samsung,exynos4212-rotator"
+      - "samsung,exynos5250-rotator"
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: rotator
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    rotator@12810000 {
+        compatible = "samsung,exynos4210-rotator";
+        reg = <0x12810000 0x1000>;
+        interrupts = <0 83 0>;
+        clocks = <&clock 278>;
+        clock-names = "rotator";
+    };
+
diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.txt b/Documentation/devicetree/bindings/gpu/samsung-scaler.txt
deleted file mode 100644 (file)
index 9c3d981..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* Samsung Exynos Image Scaler
-
-Required properties:
-  - compatible : value should be one of the following:
-       (a) "samsung,exynos5420-scaler" for Scaler IP in Exynos5420
-       (b) "samsung,exynos5433-scaler" for Scaler IP in Exynos5433
-
-  - reg : Physical base address of the IP registers and length of memory
-         mapped region.
-
-  - interrupts : Interrupt specifier for scaler interrupt, according to format
-                specific to interrupt parent.
-
-  - clocks : Clock specifier for scaler clock, according to generic clock
-            bindings. (See Documentation/devicetree/bindings/clock/exynos*.txt)
-
-  - clock-names : Names of clocks. For exynos scaler, it should be "mscl"
-                 on 5420 and "pclk", "aclk" and "aclk_xiu" on 5433.
-
-Example:
-       scaler@12800000 {
-               compatible = "samsung,exynos5420-scaler";
-               reg = <0x12800000 0x1294>;
-               interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&clock CLK_MSCL0>;
-               clock-names = "mscl";
-       };
diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml
new file mode 100644 (file)
index 0000000..5317ac6
--- /dev/null
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpu/samsung-scaler.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC Image Scaler
+
+maintainers:
+  - Inki Dae <inki.dae@samsung.com>
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos5420-scaler
+      - samsung,exynos5433-scaler
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks: {}
+  clock-names: {}
+  iommus: {}
+  power-domains: {}
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: samsung,exynos5420-scaler
+
+then:
+  properties:
+    clocks:
+      items:
+        - description: mscl clock
+
+    clock-names:
+      items:
+        - const: mscl
+
+else:
+  properties:
+    clocks:
+      items:
+        - description: pclk clock
+        - description: aclk clock
+        - description: aclk_xiu clock
+
+    clock-names:
+      items:
+        - const: pclk
+        - const: aclk
+        - const: aclk_xiu
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos5420.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    scaler@12800000 {
+        compatible = "samsung,exynos5420-scaler";
+        reg = <0x12800000 0x1294>;
+        interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clock CLK_MSCL0>;
+        clock-names = "mscl";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt
deleted file mode 100644 (file)
index adf4f00..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-STM32 Hardware Spinlock Device Binding
--------------------------------------
-
-Required properties :
-- compatible : should be "st,stm32-hwspinlock".
-- reg : the register address of hwspinlock.
-- #hwlock-cells : hwlock users only use the hwlock id to represent a specific
-       hwlock, so the number of cells should be <1> here.
-- clock-names : Must contain "hsem".
-- clocks : Must contain a phandle entry for the clock in clock-names, see the
-       common clock bindings.
-
-Please look at the generic hwlock binding for usage information for consumers,
-"Documentation/devicetree/bindings/hwlock/hwlock.txt"
-
-Example of hwlock provider:
-       hwspinlock@4c000000 {
-               compatible = "st,stm32-hwspinlock";
-               #hwlock-cells = <1>;
-               reg = <0x4c000000 0x400>;
-               clocks = <&rcc HSEM>;
-               clock-names = "hsem";
-       };
diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml
new file mode 100644 (file)
index 0000000..47cf9c8
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwlock/st,stm32-hwspinlock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Hardware Spinlock bindings
+
+maintainers:
+  - Benjamin Gaignard <benjamin.gaignard@st.com>
+  - Fabien Dessenne <fabien.dessenne@st.com>
+
+properties:
+  "#hwlock-cells":
+    const: 1
+
+  compatible:
+    const: st,stm32-hwspinlock
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: hsem
+
+required:
+  - "#hwlock-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    hwspinlock@4c000000 {
+        compatible = "st,stm32-hwspinlock";
+        #hwlock-cells = <1>;
+        reg = <0x4c000000 0x400>;
+        clocks = <&rcc HSEM>;
+        clock-names = "hsem";
+    };
+
+...
index f9d526b..9346ef6 100644 (file)
@@ -40,9 +40,7 @@ required:
   - clocks
   - resets
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
deleted file mode 100644 (file)
index ce3df2f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-* I2C controller embedded in STMicroelectronics STM32 I2C platform
-
-Required properties:
-- compatible: Must be one of the following
-  - "st,stm32f4-i2c"
-  - "st,stm32f7-i2c"
-- reg: Offset and length of the register set for the device
-- interrupts: Must contain the interrupt id for I2C event and then the
-  interrupt id for I2C error.
-- resets: Must contain the phandle to the reset controller.
-- clocks: Must contain the input clock of the I2C instance.
-- A pinctrl state named "default" must be defined to set pins in mode of
-  operation for I2C transfer
-- #address-cells = <1>;
-- #size-cells = <0>;
-
-Optional properties:
-- clock-frequency: Desired I2C bus clock frequency in Hz. If not specified,
-  the default 100 kHz frequency will be used.
-  For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are
-  100000 and 400000.
-  For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode, Fast-mode and Fast-mode
-  Plus are supported, possible values are 100000, 400000 and 1000000.
-- dmas: List of phandles to rx and tx DMA channels. Refer to stm32-dma.txt.
-- dma-names: List of dma names. Valid names are: "rx" and "tx".
-- i2c-scl-rising-time-ns: I2C SCL Rising time for the board (default: 25)
-  For STM32F7, STM32H7 and STM32MP1 only.
-- i2c-scl-falling-time-ns: I2C SCL Falling time for the board (default: 10)
-  For STM32F7, STM32H7 and STM32MP1 only.
-  I2C Timings are derived from these 2 values
-- st,syscfg-fmp: Use to set Fast Mode Plus bit within SYSCFG when Fast Mode
-  Plus speed is selected by slave.
-       1st cell: phandle to syscfg
-       2nd cell: register offset within SYSCFG
-       3rd cell: register bitmask for FMP bit
-  For STM32F7, STM32H7 and STM32MP1 only.
-
-Example:
-
-       i2c@40005400 {
-               compatible = "st,stm32f4-i2c";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <0x40005400 0x400>;
-               interrupts = <31>,
-                            <32>;
-               resets = <&rcc 277>;
-               clocks = <&rcc 0 149>;
-               pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
-               pinctrl-names = "default";
-       };
-
-       i2c@40005400 {
-               compatible = "st,stm32f7-i2c";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <0x40005400 0x400>;
-               interrupts = <31>,
-                            <32>;
-               resets = <&rcc STM32F7_APB1_RESET(I2C1)>;
-               clocks = <&rcc 1 CLK_I2C1>;
-               pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
-               pinctrl-names = "default";
-               st,syscfg-fmp = <&syscfg 0x4 0x1>;
-       };
index c779000..2ceb05b 100644 (file)
@@ -93,9 +93,7 @@ allOf:
       required:
         - resets
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml
new file mode 100644 (file)
index 0000000..900ec1a
--- /dev/null
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/st,stm32-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: I2C controller embedded in STMicroelectronics STM32 I2C platform
+
+maintainers:
+  - Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
+
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - st,stm32f7-i2c
+    then:
+      properties:
+        i2c-scl-rising-time-ns:
+          default: 25
+
+        i2c-scl-falling-time-ns:
+          default: 10
+
+        st,syscfg-fmp:
+          description: Use to set Fast Mode Plus bit within SYSCFG when
+                       Fast Mode Plus speed is selected by slave.
+                       Format is phandle to syscfg / register offset within
+                       syscfg / register bitmask for FMP bit.
+          allOf:
+            - $ref: "/schemas/types.yaml#/definitions/phandle-array"
+            - items:
+                minItems: 3
+                maxItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - st,stm32f4-i2c
+    then:
+      properties:
+        clock-frequency:
+          enum: [100000, 400000]
+
+properties:
+  compatible:
+    enum:
+      - st,stm32f4-i2c
+      - st,stm32f7-i2c
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: interrupt ID for I2C event
+      - description: interrupt ID for I2C error
+
+  resets:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  dmas:
+    items:
+      - description: RX DMA Channel phandle
+      - description: TX DMA Channel phandle
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  clock-frequency:
+    description: Desired I2C bus clock frequency in Hz. If not specified,
+                 the default 100 kHz frequency will be used.
+                 For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode,
+                 Fast-mode and Fast-mode Plus are supported, possible
+                 values are 100000, 400000 and 1000000.
+    default: 100000
+    enum: [100000, 400000, 1000000]
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - resets
+  - clocks
+
+examples:
+  - |
+    #include <dt-bindings/mfd/stm32f7-rcc.h>
+    #include <dt-bindings/clock/stm32fx-clock.h>
+    //Example 1 (with st,stm32f4-i2c compatible)
+      i2c@40005400 {
+          compatible = "st,stm32f4-i2c";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          reg = <0x40005400 0x400>;
+          interrupts = <31>,
+                       <32>;
+          resets = <&rcc 277>;
+          clocks = <&rcc 0 149>;
+      };
+
+    //Example 2 (with st,stm32f7-i2c compatible)
+      i2c@40005800 {
+          compatible = "st,stm32f7-i2c";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          reg = <0x40005800 0x400>;
+          interrupts = <31>,
+                       <32>;
+          resets = <&rcc STM32F7_APB1_RESET(I2C1)>;
+          clocks = <&rcc 1 CLK_I2C1>;
+      };
+
+    //Example 3 (with st,stm32f7-i2c compatible on stm32mp)
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+      i2c@40013000 {
+          compatible = "st,stm32f7-i2c";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          reg = <0x40013000 0x400>;
+          interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+          clocks = <&rcc I2C2_K>;
+          resets = <&rcc I2C2_R>;
+          i2c-scl-rising-time-ns = <185>;
+          i2c-scl-falling-time-ns = <20>;
+          st,syscfg-fmp = <&syscfg 0x4 0x2>;
+      };
+...
index 9692b7f..e932d5a 100644 (file)
@@ -45,15 +45,12 @@ properties:
 
   refin1-supply:
     description: refin1 supply can be used as reference for conversion.
-    maxItems: 1
 
   refin2-supply:
     description: refin2 supply can be used as reference for conversion.
-    maxItems: 1
 
   avdd-supply:
     description: avdd supply can be used as reference for conversion.
-    maxItems: 1
 
 required:
   - compatible
index cc544fd..6eb3320 100644 (file)
@@ -31,10 +31,7 @@ properties:
 
   spi-cpha: true
 
-  avcc-supply:
-    description:
-      Phandle to the Avcc power supply
-    maxItems: 1
+  avcc-supply: true
 
   interrupts:
     maxItems: 1
index d110941..9acde6d 100644 (file)
@@ -39,7 +39,6 @@ properties:
   avdd-supply:
     description:
       The regulator supply for the ADC reference voltage.
-    maxItems: 1
 
   powerdown-gpios:
     description:
index d76ece9..91ab9c8 100644 (file)
@@ -41,7 +41,6 @@ properties:
   avdd-supply:
     description:
       Definition of the regulator used as analog supply
-    maxItems: 1
 
   clock-frequency:
     minimum: 20000
diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt
deleted file mode 100644 (file)
index e1fe02f..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-Samsung Exynos Analog to Digital Converter bindings
-
-The devicetree bindings are for the new ADC driver written for
-Exynos4 and upward SoCs from Samsung.
-
-New driver handles the following
-1. Supports ADC IF found on EXYNOS4412/EXYNOS5250
-   and future SoCs from Samsung
-2. Add ADC driver under iio/adc framework
-3. Also adds the Documentation for device tree bindings
-
-Required properties:
-- compatible:          Must be "samsung,exynos-adc-v1"
-                               for Exynos5250 controllers.
-                       Must be "samsung,exynos-adc-v2" for
-                               future controllers.
-                       Must be "samsung,exynos3250-adc" for
-                               controllers compatible with ADC of Exynos3250.
-                       Must be "samsung,exynos4212-adc" for
-                               controllers compatible with ADC of Exynos4212 and Exynos4412.
-                       Must be "samsung,exynos7-adc" for
-                               the ADC in Exynos7 and compatibles
-                       Must be "samsung,s3c2410-adc" for
-                               the ADC in s3c2410 and compatibles
-                       Must be "samsung,s3c2416-adc" for
-                               the ADC in s3c2416 and compatibles
-                       Must be "samsung,s3c2440-adc" for
-                               the ADC in s3c2440 and compatibles
-                       Must be "samsung,s3c2443-adc" for
-                               the ADC in s3c2443 and compatibles
-                       Must be "samsung,s3c6410-adc" for
-                               the ADC in s3c6410 and compatibles
-                       Must be "samsung,s5pv210-adc" for
-                               the ADC in s5pv210 and compatibles
-- reg:                 List of ADC register address range
-                       - The base address and range of ADC register
-                       - The base address and range of ADC_PHY register (every
-                         SoC except for s3c24xx/s3c64xx ADC)
-- interrupts:          Contains the interrupt information for the timer. The
-                       format is being dependent on which interrupt controller
-                       the Samsung device uses.
-- #io-channel-cells = <1>; As ADC has multiple outputs
-- clocks               From common clock bindings: handles to clocks specified
-                       in "clock-names" property, in the same order.
-- clock-names          From common clock bindings: list of clock input names
-                       used by ADC block:
-                       - "adc" : ADC bus clock
-                       - "sclk" : ADC special clock (only for Exynos3250 and
-                                  compatible ADC block)
-- vdd-supply           VDD input supply.
-
-- samsung,syscon-phandle Contains the PMU system controller node
-                       (To access the ADC_PHY register on Exynos5250/5420/5800/3250)
-Optional properties:
-- has-touchscreen:     If present, indicates that a touchscreen is
-                       connected an usable.
-
-Note: child nodes can be added for auto probing from device tree.
-
-Example: adding device info in dtsi file
-
-adc: adc@12d10000 {
-       compatible = "samsung,exynos-adc-v1";
-       reg = <0x12D10000 0x100>;
-       interrupts = <0 106 0>;
-       #io-channel-cells = <1>;
-       io-channel-ranges;
-
-       clocks = <&clock 303>;
-       clock-names = "adc";
-
-       vdd-supply = <&buck5_reg>;
-       samsung,syscon-phandle = <&pmu_system_controller>;
-};
-
-Example: adding device info in dtsi file for Exynos3250 with additional sclk
-
-adc: adc@126c0000 {
-       compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
-       reg = <0x126C0000 0x100>;
-       interrupts = <0 137 0>;
-       #io-channel-cells = <1>;
-       io-channel-ranges;
-
-       clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
-       clock-names = "adc", "sclk";
-
-       vdd-supply = <&buck5_reg>;
-       samsung,syscon-phandle = <&pmu_system_controller>;
-};
-
-Example: Adding child nodes in dts file
-
-adc@12d10000 {
-
-       /* NTC thermistor is a hwmon device */
-       ncp15wb473@0 {
-               compatible = "murata,ncp15wb473";
-               pullup-uv = <1800000>;
-               pullup-ohm = <47000>;
-               pulldown-ohm = <0>;
-               io-channels = <&adc 4>;
-       };
-};
-
-Note: Does not apply to ADC driver under arch/arm/plat-samsung/
-Note: The child node can be added under the adc node or separately.
diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml
new file mode 100644 (file)
index 0000000..f46de17
--- /dev/null
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/samsung,exynos-adc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos Analog to Digital Converter (ADC)
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos-adc-v1                 # Exynos5250
+      - samsung,exynos-adc-v2
+      - samsung,exynos3250-adc
+      - samsung,exynos4212-adc                # Exynos4212 and Exynos4412
+      - samsung,exynos7-adc
+      - samsung,s3c2410-adc
+      - samsung,s3c2416-adc
+      - samsung,s3c2440-adc
+      - samsung,s3c2443-adc
+      - samsung,s3c6410-adc
+      - samsung,s5pv210-adc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description:
+      Phandle to ADC bus clock. For Exynos3250 additional clock is needed.
+    minItems: 1
+    maxItems: 2
+
+  clock-names:
+    description:
+      Must contain clock names (adc, sclk) matching phandles in clocks
+      property.
+    minItems: 1
+    maxItems: 2
+
+  interrupts:
+    maxItems: 1
+
+  "#io-channel-cells":
+    const: 1
+
+  vdd-supply: true
+
+  samsung,syscon-phandle:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description:
+      Phandle to the PMU system controller node (to access the ADC_PHY
+      register on Exynos3250/4x12/5250/5420/5800).
+
+  has-touchscreen:
+    description:
+      If present, indicates that a touchscreen is connected and usable.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - interrupts
+  - "#io-channel-cells"
+  - vdd-supply
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos-adc-v1
+              - samsung,exynos-adc-v2
+              - samsung,exynos3250-adc
+              - samsung,exynos4212-adc
+              - samsung,s5pv210-adc
+    then:
+      required:
+        - samsung,syscon-phandle
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos3250-adc
+    then:
+      properties:
+        clocks:
+          minItems: 2
+          maxItems: 2
+        clock-names:
+          items:
+            - const: adc
+            - const: sclk
+    else:
+      properties:
+        clocks:
+          minItems: 1
+          maxItems: 1
+        clock-names:
+          items:
+            - const: adc
+
+examples:
+  - |
+    adc: adc@12d10000 {
+        compatible = "samsung,exynos-adc-v1";
+        reg = <0x12d10000 0x100>;
+        interrupts = <0 106 0>;
+        #io-channel-cells = <1>;
+        io-channel-ranges;
+
+        clocks = <&clock 303>;
+        clock-names = "adc";
+
+        vdd-supply = <&buck5_reg>;
+        samsung,syscon-phandle = <&pmu_system_controller>;
+
+        /* NTC thermistor is a hwmon device */
+        ncp15wb473@0 {
+            compatible = "murata,ncp15wb473";
+            pullup-uv = <1800000>;
+            pullup-ohm = <47000>;
+            pulldown-ohm = <0>;
+            io-channels = <&adc 4>;
+          };
+    };
+
+  - |
+    #include <dt-bindings/clock/exynos3250.h>
+
+    adc@126c0000 {
+        compatible = "samsung,exynos3250-adc";
+        reg = <0x126C0000 0x100>;
+        interrupts = <0 137 0>;
+        #io-channel-cells = <1>;
+        io-channel-ranges;
+
+        clocks = <&cmu CLK_TSADC>,
+                 <&cmu CLK_SCLK_TSADC>;
+        clock-names = "adc", "sclk";
+
+        vdd-supply = <&buck5_reg>;
+        samsung,syscon-phandle = <&pmu_system_controller>;
+    };
index a551d31..19e5393 100644 (file)
@@ -25,7 +25,6 @@ properties:
 
   vcc-supply:
     description: regulator that provides power to the sensor
-    maxItems: 1
 
   plantower,set-gpios:
     description: GPIO connected to the SET line
index c6721a7..519137e 100644 (file)
@@ -28,12 +28,10 @@ properties:
   vddd-supply:
     description:
       digital voltage regulator (see regulator/regulator.txt)
-    maxItems: 1
 
   vdda-supply:
     description:
       analog voltage regulator (see regulator/regulator.txt)
-    maxItems: 1
 
   reset-gpios:
     description:
diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-lptimer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-lptimer-trigger.txt
deleted file mode 100644 (file)
index 85e6806..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-STMicroelectronics STM32 Low-Power Timer Trigger
-
-STM32 Low-Power Timer provides trigger source (LPTIM output) that can be used
-by STM32 internal ADC and/or DAC.
-
-Must be a sub-node of an STM32 Low-Power Timer device tree node.
-See ../mfd/stm32-lptimer.txt for details about the parent node.
-
-Required properties:
-- compatible:          Must be "st,stm32-lptimer-trigger".
-- reg:                 Identify trigger hardware block. Must be 0, 1 or 2
-                       respectively for lptimer1, lptimer2 or lptimer3
-                       trigger output.
-
-Example:
-       timer@40002400 {
-               compatible = "st,stm32-lptimer";
-               ...
-               trigger@0 {
-                       compatible = "st,stm32-lptimer-trigger";
-                       reg = <0>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
deleted file mode 100644 (file)
index b8e8c76..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-STMicroelectronics STM32 Timers IIO timer bindings
-
-Must be a sub-node of an STM32 Timers device tree node.
-See ../mfd/stm32-timers.txt for details about the parent node.
-
-Required parameters:
-- compatible:  Must be one of:
-               "st,stm32-timer-trigger"
-               "st,stm32h7-timer-trigger"
-- reg:         Identify trigger hardware block.
-
-Example:
-       timers@40010000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "st,stm32-timers";
-               reg = <0x40010000 0x400>;
-               clocks = <&rcc 0 160>;
-               clock-names = "int";
-
-               timer@0 {
-                       compatible = "st,stm32-timer-trigger";
-                       reg = <0>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/input/max77650-onkey.txt b/Documentation/devicetree/bindings/input/max77650-onkey.txt
deleted file mode 100644 (file)
index 477dc74..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-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/max77650-onkey.yaml b/Documentation/devicetree/bindings/input/max77650-onkey.yaml
new file mode 100644 (file)
index 0000000..2f2e0b6
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/max77650-onkey.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Onkey driver for MAX77650 PMIC from Maxim Integrated.
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+description: |
+  This module is part of the MAX77650 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/max77650.yaml.
+
+  The onkey controller is represented as a sub-node of the PMIC node on
+  the device tree.
+
+properties:
+  compatible:
+    const: maxim,max77650-onkey
+
+  linux,code:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The key-code to be reported when the key is pressed. Defaults
+      to KEY_POWER.
+
+  maxim,onkey-slide:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      The system's button is a slide switch, not the default push button.
+
+required:
+  - compatible
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt b/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt
deleted file mode 100644 (file)
index c07d898..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-Qualcomm QCS404 Network-On-Chip interconnect driver binding
------------------------------------------------------------
-
-Required properties :
-- compatible : shall contain only one of the following:
-                       "qcom,qcs404-bimc"
-                       "qcom,qcs404-pcnoc"
-                       "qcom,qcs404-snoc"
-- #interconnect-cells : should contain 1
-
-reg : specifies the physical base address and size of registers
-clocks : list of phandles and specifiers to all interconnect bus clocks
-clock-names : clock names should include both "bus" and "bus_a"
-
-Example:
-
-soc {
-       ...
-       bimc: interconnect@400000 {
-               reg = <0x00400000 0x80000>;
-               compatible = "qcom,qcs404-bimc";
-               #interconnect-cells = <1>;
-               clock-names = "bus", "bus_a";
-               clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
-                       <&rpmcc RPM_SMD_BIMC_A_CLK>;
-       };
-
-       pnoc: interconnect@500000 {
-               reg = <0x00500000 0x15080>;
-               compatible = "qcom,qcs404-pcnoc";
-               #interconnect-cells = <1>;
-               clock-names = "bus", "bus_a";
-               clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
-                       <&rpmcc RPM_SMD_PNOC_A_CLK>;
-       };
-
-       snoc: interconnect@580000 {
-               reg = <0x00580000 0x23080>;
-               compatible = "qcom,qcs404-snoc";
-               #interconnect-cells = <1>;
-               clock-names = "bus", "bus_a";
-               clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
-                       <&rpmcc RPM_SMD_SNOC_A_CLK>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcs404.yaml b/Documentation/devicetree/bindings/interconnect/qcom,qcs404.yaml
new file mode 100644 (file)
index 0000000..8d65c5f
--- /dev/null
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,qcs404.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QCS404 Network-On-Chip interconnect
+
+maintainers:
+  - Georgi Djakov <georgi.djakov@linaro.org>
+
+description: |
+   The Qualcomm QCS404 interconnect providers support adjusting the
+   bandwidth requirements between the various NoC fabrics.
+
+properties:
+  reg:
+    maxItems: 1
+
+  compatible:
+    enum:
+      - qcom,qcs404-bimc
+      - qcom,qcs404-pcnoc
+      - qcom,qcs404-snoc
+
+  '#interconnect-cells':
+    const: 1
+
+  clock-names:
+    items:
+      - const: bus
+      - const: bus_a
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Bus A Clock
+
+required:
+  - compatible
+  - reg
+  - '#interconnect-cells'
+  - clock-names
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+      #include <dt-bindings/clock/qcom,rpmcc.h>
+
+      bimc: interconnect@400000 {
+              reg = <0x00400000 0x80000>;
+              compatible = "qcom,qcs404-bimc";
+              #interconnect-cells = <1>;
+              clock-names = "bus", "bus_a";
+              clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+                       <&rpmcc RPM_SMD_BIMC_A_CLK>;
+      };
+
+      pnoc: interconnect@500000 {
+             reg = <0x00500000 0x15080>;
+             compatible = "qcom,qcs404-pcnoc";
+             #interconnect-cells = <1>;
+             clock-names = "bus", "bus_a";
+             clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
+                      <&rpmcc RPM_SMD_PNOC_A_CLK>;
+      };
+
+      snoc: interconnect@580000 {
+            reg = <0x00580000 0x23080>;
+            compatible = "qcom,qcs404-snoc";
+            #interconnect-cells = <1>;
+            clock-names = "bus", "bus_a";
+            clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+                     <&rpmcc RPM_SMD_SNOC_A_CLK>;
+      };
index 0eccf55..8cd08cf 100644 (file)
@@ -52,9 +52,7 @@ required:
   - interrupts
   - interrupt-controller
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 1fe147d..66aacd1 100644 (file)
@@ -138,6 +138,7 @@ properties:
       containing a set of sub-nodes.
     patternProperties:
       "^interrupt-partition-[0-9]+$":
+        type: object
         properties:
           affinity:
             $ref: /schemas/types.yaml#/definitions/phandle-array
index 2117d4a..5ddef1d 100644 (file)
@@ -31,6 +31,17 @@ Required properties:
 - interrupts: specifies the interrupt line(s) in the interrupt-parent controller
   node; valid values depend on the type of parent interrupt controller
 
+Optional properties:
+
+- brcm,irq-can-wake: If present, this means the L1 controller can be used as a
+  wakeup source for system suspend/resume.
+
+Optional properties:
+
+- brcm,int-fwd-mask: if present, a bit mask to indicate which interrupts
+  have already been configured by the firmware and should be left unmanaged.
+  This should have one 32-bit word per status/set/clear/mask group.
+
 If multiple reg ranges and interrupt-parent entries are present on an SMP
 system, the driver will allow IRQ SMP affinity to be set up through the
 /proc/irq/ interface.  In the simplest possible configuration, only one
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt
new file mode 100644 (file)
index 0000000..f0ad780
--- /dev/null
@@ -0,0 +1,49 @@
+* Freescale Layerscape external IRQs
+
+Some Layerscape SOCs (LS1021A, LS1043A, LS1046A) support inverting
+the polarity of certain external interrupt lines.
+
+The device node must be a child of the node representing the
+Supplemental Configuration Unit (SCFG).
+
+Required properties:
+- compatible: should be "fsl,<soc-name>-extirq", e.g. "fsl,ls1021a-extirq".
+- #interrupt-cells: Must be 2. The first element is the index of the
+  external interrupt line. The second element is the trigger type.
+- #address-cells: Must be 0.
+- interrupt-controller: Identifies the node as an interrupt controller
+- reg: Specifies the Interrupt Polarity Control Register (INTPCR) in
+  the SCFG.
+- interrupt-map: Specifies the mapping from external interrupts to GIC
+  interrupts.
+- interrupt-map-mask: Must be <0xffffffff 0>.
+
+Example:
+       scfg: scfg@1570000 {
+               compatible = "fsl,ls1021a-scfg", "syscon";
+               reg = <0x0 0x1570000 0x0 0x10000>;
+               big-endian;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x1570000 0x10000>;
+
+               extirq: interrupt-controller@1ac {
+                       compatible = "fsl,ls1021a-extirq";
+                       #interrupt-cells = <2>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x1ac 4>;
+                       interrupt-map =
+                               <0 0 &gic GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+                               <1 0 &gic GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
+                               <2 0 &gic GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
+                               <3 0 &gic GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
+                               <4 0 &gic GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+                               <5 0 &gic GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-map-mask = <0xffffffff 0x0>;
+               };
+       };
+
+
+       interrupts-extended = <&gic GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+                             <&extirq 1 IRQ_TYPE_LEVEL_LOW>;
index 4a3ee25..4ebfa00 100644 (file)
@@ -108,3 +108,15 @@ commonly used:
                        sensitivity = <7>;
                };
        };
+
+3) Interrupt wakeup parent
+--------------------------
+
+Some interrupt controllers in a SoC, are always powered on and have a select
+interrupts routed to them, so that they can wakeup the SoC from suspend. These
+interrupt controllers do not fall into the category of a parent interrupt
+controller and can be specified by the "wakeup-parent" property and contain a
+single phandle referring to the wakeup capable interrupt controller.
+
+   Example:
+       wakeup-parent = <&pdc_intc>;
index 608fee1..a0ed027 100644 (file)
@@ -1,13 +1,17 @@
 * Marvell MMP Interrupt controller
 
 Required properties:
-- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
-  "mrvl,mmp2-mux-intc"
+- compatible : Should be
+               "mrvl,mmp-intc" on Marvel MMP,
+               "mrvl,mmp2-intc" along with "mrvl,mmp2-mux-intc" on MMP2 or
+               "marvell,mmp3-intc" with "mrvl,mmp2-mux-intc" on MMP3
 - reg : Address and length of the register set of the interrupt controller.
   If the interrupt controller is intc, address and length means the range
-  of the whole interrupt controller. If the interrupt controller is mux-intc,
-  address and length means one register. Since address of mux-intc is in the
-  range of intc. mux-intc is secondary interrupt controller.
+  of the whole interrupt controller. The "marvell,mmp3-intc" controller
+  also has a secondary range for the second CPU core.  If the interrupt
+  controller is mux-intc, address and length means one register. Since
+  address of mux-intc is in the range of intc. mux-intc is secondary
+  interrupt controller.
 - reg-names : Name of the register set of the interrupt controller. It's
   only required in mux-intc interrupt controller.
 - interrupts : Should be the port interrupt shared by mux interrupts. It's
index 8e0797c..1df2939 100644 (file)
@@ -17,7 +17,8 @@ Properties:
 - compatible:
        Usage: required
        Value type: <string>
-       Definition: Should contain "qcom,<soc>-pdc"
+       Definition: Should contain "qcom,<soc>-pdc" and "qcom,pdc"
+                   - "qcom,sc7180-pdc": For SC7180
                    - "qcom,sdm845-pdc": For SDM845
 
 - reg:
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
deleted file mode 100644 (file)
index f977ea7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-DT bindings for the R-Mobile/R-Car/RZ/G interrupt controller
-
-Required properties:
-
-- compatible: must be "renesas,irqc-<soctype>" or "renesas,intc-ex-<soctype>",
-             and "renesas,irqc" as fallback.
-  Examples with soctypes are:
-    - "renesas,irqc-r8a73a4" (R-Mobile APE6)
-    - "renesas,irqc-r8a7743" (RZ/G1M)
-    - "renesas,irqc-r8a7744" (RZ/G1N)
-    - "renesas,irqc-r8a7745" (RZ/G1E)
-    - "renesas,irqc-r8a77470" (RZ/G1C)
-    - "renesas,irqc-r8a7790" (R-Car H2)
-    - "renesas,irqc-r8a7791" (R-Car M2-W)
-    - "renesas,irqc-r8a7792" (R-Car V2H)
-    - "renesas,irqc-r8a7793" (R-Car M2-N)
-    - "renesas,irqc-r8a7794" (R-Car E2)
-    - "renesas,intc-ex-r8a774a1" (RZ/G2M)
-    - "renesas,intc-ex-r8a774c0" (RZ/G2E)
-    - "renesas,intc-ex-r8a7795" (R-Car H3)
-    - "renesas,intc-ex-r8a7796" (R-Car M3-W)
-    - "renesas,intc-ex-r8a77965" (R-Car M3-N)
-    - "renesas,intc-ex-r8a77970" (R-Car V3M)
-    - "renesas,intc-ex-r8a77980" (R-Car V3H)
-    - "renesas,intc-ex-r8a77990" (R-Car E3)
-    - "renesas,intc-ex-r8a77995" (R-Car D3)
-- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
-  interrupts.txt in this directory
-- clocks: Must contain a reference to the functional clock.
-
-Optional properties:
-
-- any properties, listed in interrupts.txt, and any standard resource allocation
-  properties
-
-Example:
-
-       irqc0: interrupt-controller@e61c0000 {
-               compatible = "renesas,irqc-r8a7790", "renesas,irqc";
-               #interrupt-cells = <2>;
-               interrupt-controller;
-               reg = <0 0xe61c0000 0 0x200>;
-               interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>,
-                            <0 1 IRQ_TYPE_LEVEL_HIGH>,
-                            <0 2 IRQ_TYPE_LEVEL_HIGH>,
-                            <0 3 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&mstp4_clks R8A7790_CLK_IRQC>;
-       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml
new file mode 100644 (file)
index 0000000..ee5273b
--- /dev/null
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/renesas,irqc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DT bindings for the R-Mobile/R-Car/RZ/G interrupt controller
+
+maintainers:
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,irqc-r8a73a4        # R-Mobile APE6
+          - renesas,irqc-r8a7743        # RZ/G1M
+          - renesas,irqc-r8a7744        # RZ/G1N
+          - renesas,irqc-r8a7745        # RZ/G1E
+          - renesas,irqc-r8a77470       # RZ/G1C
+          - renesas,irqc-r8a7790        # R-Car H2
+          - renesas,irqc-r8a7791        # R-Car M2-W
+          - renesas,irqc-r8a7792        # R-Car V2H
+          - renesas,irqc-r8a7793        # R-Car M2-N
+          - renesas,irqc-r8a7794        # R-Car E2
+          - renesas,intc-ex-r8a774a1    # RZ/G2M
+          - renesas,intc-ex-r8a774b1    # RZ/G2N
+          - renesas,intc-ex-r8a774c0    # RZ/G2E
+          - renesas,intc-ex-r8a7795     # R-Car H3
+          - renesas,intc-ex-r8a7796     # R-Car M3-W
+          - renesas,intc-ex-r8a77965    # R-Car M3-N
+          - renesas,intc-ex-r8a77970    # R-Car V3M
+          - renesas,intc-ex-r8a77980    # R-Car V3H
+          - renesas,intc-ex-r8a77990    # R-Car E3
+          - renesas,intc-ex-r8a77995    # R-Car D3
+      - const: renesas,irqc
+
+  '#interrupt-cells':
+    # an interrupt index and flags, as defined in interrupts.txt in
+    # this directory
+    const: 2
+
+  interrupt-controller: true
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 32
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - '#interrupt-cells'
+  - interrupt-controller
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a7790-cpg-mssr.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    irqc0: interrupt-controller@e61c0000 {
+        compatible = "renesas,irqc-r8a7790", "renesas,irqc";
+        #interrupt-cells = <2>;
+        interrupt-controller;
+        reg = <0 0xe61c0000 0 0x200>;
+        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&cpg CPG_MOD 407>;
+    };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
deleted file mode 100644 (file)
index cd01b22..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-STM32 External Interrupt Controller
-
-Required properties:
-
-- compatible: Should be:
-    "st,stm32-exti"
-    "st,stm32h7-exti"
-    "st,stm32mp1-exti"
-- reg: Specifies base physical address and size of the registers
-- interrupt-controller: Indentifies the node as an interrupt controller
-- #interrupt-cells: Specifies the number of cells to encode an interrupt
-  specifier, shall be 2
-- interrupts: interrupts references to primary interrupt controller
-  (only needed for exti controller with multiple exti under
-  same parent interrupt: st,stm32-exti and st,stm32h7-exti)
-
-Optional properties:
-
-- hwlocks: reference to a phandle of a hardware spinlock provider node.
-
-Example:
-
-exti: interrupt-controller@40013c00 {
-       compatible = "st,stm32-exti";
-       interrupt-controller;
-       #interrupt-cells = <2>;
-       reg = <0x40013C00 0x400>;
-       interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>;
-};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml
new file mode 100644 (file)
index 0000000..9e5c660
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/st,stm32-exti.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32 External Interrupt Controller Device Tree Bindings
+
+maintainers:
+  - Alexandre Torgue <alexandre.torgue@st.com>
+  - Ludovic Barre <ludovic.barre@st.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+        - enum:
+          - st,stm32-exti
+          - st,stm32h7-exti
+      - items:
+        - enum:
+          - st,stm32mp1-exti
+        - const: syscon
+
+  "#interrupt-cells":
+    const: 2
+
+  reg:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  hwlocks:
+    maxItems: 1
+    description:
+      Reference to a phandle of a hardware spinlock provider node.
+
+  interrupts:
+    description:
+      Interrupts references to primary interrupt controller
+
+required:
+  - "#interrupt-cells"
+  - compatible
+  - reg
+  - interrupt-controller
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - st,stm32-exti
+    then:
+      properties:
+        interrupts:
+          minItems: 1
+          maxItems: 32
+      required:
+        - interrupts
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - st,stm32h7-exti
+    then:
+      properties:
+        interrupts:
+          minItems: 1
+          maxItems: 96
+      required:
+        - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    //Example 1
+    exti1: interrupt-controller@5000d000 {
+        compatible = "st,stm32mp1-exti", "syscon";
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        reg = <0x5000d000 0x400>;
+    };
+
+    //Example 2
+    exti2: interrupt-controller@40013c00 {
+        compatible = "st,stm32-exti";
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        reg = <0x40013C00 0x400>;
+        interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
deleted file mode 100644 (file)
index c9abbf3..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-* ARM SMMUv3 Architecture Implementation
-
-The SMMUv3 architecture is a significant departure from previous
-revisions, replacing the MMIO register interface with in-memory command
-and event queues and adding support for the ATS and PRI components of
-the PCIe specification.
-
-** SMMUv3 required properties:
-
-- compatible        : Should include:
-
-                      * "arm,smmu-v3" for any SMMUv3 compliant
-                        implementation. This entry should be last in the
-                        compatible list.
-
-- reg               : Base address and size of the SMMU.
-
-- interrupts        : Non-secure interrupt list describing the wired
-                      interrupt sources corresponding to entries in
-                      interrupt-names. If no wired interrupts are
-                      present then this property may be omitted.
-
-- interrupt-names   : When the interrupts property is present, should
-                      include the following:
-                      * "eventq"    - Event Queue not empty
-                      * "priq"      - PRI Queue not empty
-                      * "cmdq-sync" - CMD_SYNC complete
-                      * "gerror"    - Global Error activated
-                      * "combined"  - The combined interrupt is optional,
-                                     and should only be provided if the
-                                     hardware supports just a single,
-                                     combined interrupt line.
-                                     If provided, then the combined interrupt
-                                     will be used in preference to any others.
-
-- #iommu-cells      : See the generic IOMMU binding described in
-                        devicetree/bindings/pci/pci-iommu.txt
-                      for details. For SMMUv3, must be 1, with each cell
-                      describing a single stream ID. All possible stream
-                      IDs which a device may emit must be described.
-
-** SMMUv3 optional properties:
-
-- dma-coherent      : Present if DMA operations made by the SMMU (page
-                      table walks, stream table accesses etc) are cache
-                      coherent with the CPU.
-
-                      NOTE: this only applies to the SMMU itself, not
-                      masters connected upstream of the SMMU.
-
-- msi-parent        : See the generic MSI binding described in
-                        devicetree/bindings/interrupt-controller/msi.txt
-                      for a description of the msi-parent property.
-
-- hisilicon,broken-prefetch-cmd
-                    : Avoid sending CMD_PREFETCH_* commands to the SMMU.
-
-- cavium,cn9900-broken-page1-regspace
-                    : Replaces all page 1 offsets used for EVTQ_PROD/CONS,
-                     PRIQ_PROD/CONS register access with page 0 offsets.
-                     Set for Cavium ThunderX2 silicon that doesn't support
-                     SMMU page1 register space.
-
-** Example
-
-        smmu@2b400000 {
-                compatible = "arm,smmu-v3";
-                reg = <0x0 0x2b400000 0x0 0x20000>;
-                interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
-                             <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
-                             <GIC_SPI 77 IRQ_TYPE_EDGE_RISING>,
-                             <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>;
-                interrupt-names = "eventq", "priq", "cmdq-sync", "gerror";
-                dma-coherent;
-                #iommu-cells = <1>;
-                msi-parent = <&its 0xff0000>;
-        };
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
new file mode 100644 (file)
index 0000000..5951c6f
--- /dev/null
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/arm,smmu-v3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM SMMUv3 Architecture Implementation
+
+maintainers:
+  - Will Deacon <will@kernel.org>
+  - Robin Murphy <Robin.Murphy@arm.com>
+
+description: |+
+  The SMMUv3 architecture is a significant departure from previous
+  revisions, replacing the MMIO register interface with in-memory command
+  and event queues and adding support for the ATS and PRI components of
+  the PCIe specification.
+
+properties:
+  $nodename:
+    pattern: "^iommu@[0-9a-f]*"
+  compatible:
+    const: arm,smmu-v3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 4
+
+  interrupt-names:
+    oneOf:
+      - const: combined
+        description:
+          The combined interrupt is optional, and should only be provided if the
+          hardware supports just a single, combined interrupt line.
+          If provided, then the combined interrupt will be used in preference to
+          any others.
+      - minItems: 2
+        maxItems: 4
+        items:
+          - const: eventq     # Event Queue not empty
+          - const: gerror     # Global Error activated
+          - const: priq       # PRI Queue not empty
+          - const: cmdq-sync  # CMD_SYNC complete
+
+  '#iommu-cells':
+    const: 1
+
+  dma-coherent:
+    description: |
+      Present if page table walks made by the SMMU are cache coherent with the
+      CPU.
+
+      NOTE: this only applies to the SMMU itself, not masters connected
+      upstream of the SMMU.
+
+  msi-parent: true
+
+  hisilicon,broken-prefetch-cmd:
+    type: boolean
+    description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
+
+  cavium,cn9900-broken-page1-regspace:
+    type: boolean
+    description:
+      Replaces all page 1 offsets used for EVTQ_PROD/CONS, PRIQ_PROD/CONS
+      register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
+      doesn't support SMMU page1 register space.
+
+required:
+  - compatible
+  - reg
+  - '#iommu-cells'
+
+additionalProperties: false
+
+examples:
+  - |+
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    iommu@2b400000 {
+            compatible = "arm,smmu-v3";
+            reg = <0x2b400000 0x20000>;
+            interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
+                         <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
+                         <GIC_SPI 77 IRQ_TYPE_EDGE_RISING>,
+                         <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>;
+            interrupt-names = "eventq", "gerror", "priq", "cmdq-sync";
+            dma-coherent;
+            #iommu-cells = <1>;
+            msi-parent = <&its 0xff0000>;
+    };
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
deleted file mode 100644 (file)
index 3133f3b..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-* ARM System MMU Architecture Implementation
-
-ARM SoCs may contain an implementation of the ARM System Memory
-Management Unit Architecture, which can be used to provide 1 or 2 stages
-of address translation to bus masters external to the CPU.
-
-The SMMU may also raise interrupts in response to various fault
-conditions.
-
-** System MMU required properties:
-
-- compatible    : Should be one of:
-
-                        "arm,smmu-v1"
-                        "arm,smmu-v2"
-                        "arm,mmu-400"
-                        "arm,mmu-401"
-                        "arm,mmu-500"
-                        "cavium,smmu-v2"
-                        "qcom,smmu-v2"
-
-                  depending on the particular implementation and/or the
-                  version of the architecture implemented.
-
-                  Qcom SoCs must contain, as below, SoC-specific compatibles
-                  along with "qcom,smmu-v2":
-                  "qcom,msm8996-smmu-v2", "qcom,smmu-v2",
-                  "qcom,sdm845-smmu-v2", "qcom,smmu-v2".
-
-                  Qcom SoCs implementing "arm,mmu-500" must also include,
-                  as below, SoC-specific compatibles:
-                  "qcom,sdm845-smmu-500", "arm,mmu-500"
-
-- reg           : Base address and size of the SMMU.
-
-- #global-interrupts : The number of global interrupts exposed by the
-                       device.
-
-- interrupts    : Interrupt list, with the first #global-irqs entries
-                  corresponding to the global interrupts and any
-                  following entries corresponding to context interrupts,
-                  specified in order of their indexing by the SMMU.
-
-                  For SMMUv2 implementations, there must be exactly one
-                  interrupt per context bank. In the case of a single,
-                  combined interrupt, it must be listed multiple times.
-
-- #iommu-cells  : See Documentation/devicetree/bindings/iommu/iommu.txt
-                  for details. With a value of 1, each IOMMU specifier
-                  represents a distinct stream ID emitted by that device
-                  into the relevant SMMU.
-
-                  SMMUs with stream matching support and complex masters
-                  may use a value of 2, where the second cell of the
-                  IOMMU specifier represents an SMR mask to combine with
-                  the ID in the first cell.  Care must be taken to ensure
-                  the set of matched IDs does not result in conflicts.
-
-** System MMU optional properties:
-
-- dma-coherent  : Present if page table walks made by the SMMU are
-                  cache coherent with the CPU.
-
-                  NOTE: this only applies to the SMMU itself, not
-                  masters connected upstream of the SMMU.
-
-- calxeda,smmu-secure-config-access : Enable proper handling of buggy
-                  implementations that always use secure access to
-                  SMMU configuration registers. In this case non-secure
-                  aliases of secure registers have to be used during
-                  SMMU configuration.
-
-- stream-match-mask : For SMMUs supporting stream matching and using
-                  #iommu-cells = <1>, specifies a mask of bits to ignore
-                 when matching stream IDs (e.g. this may be programmed
-                 into the SMRn.MASK field of every stream match register
-                 used). For cases where it is desirable to ignore some
-                  portion of every Stream ID (e.g. for certain MMU-500
-                  configurations given globally unique input IDs). This
-                  property is not valid for SMMUs using stream indexing,
-                  or using stream matching with #iommu-cells = <2>, and
-                  may be ignored if present in such cases.
-
-- clock-names:    List of the names of clocks input to the device. The
-                  required list depends on particular implementation and
-                  is as follows:
-                  - for "qcom,smmu-v2":
-                    - "bus": clock required for downstream bus access and
-                             for the smmu ptw,
-                    - "iface": clock required to access smmu's registers
-                               through the TCU's programming interface.
-                  - unspecified for other implementations.
-
-- clocks:         Specifiers for all clocks listed in the clock-names property,
-                  as per generic clock bindings.
-
-- power-domains:  Specifiers for power domains required to be powered on for
-                  the SMMU to operate, as per generic power domain bindings.
-
-** Deprecated properties:
-
-- mmu-masters (deprecated in favour of the generic "iommus" binding) :
-                  A list of phandles to device nodes representing bus
-                  masters for which the SMMU can provide a translation
-                  and their corresponding Stream IDs. Each device node
-                  linked from this list must have a "#stream-id-cells"
-                  property, indicating the number of Stream ID
-                  arguments associated with its phandle.
-
-** Examples:
-
-        /* SMMU with stream matching or stream indexing */
-        smmu1: iommu {
-                compatible = "arm,smmu-v1";
-                reg = <0xba5e0000 0x10000>;
-                #global-interrupts = <2>;
-                interrupts = <0 32 4>,
-                             <0 33 4>,
-                             <0 34 4>, /* This is the first context interrupt */
-                             <0 35 4>,
-                             <0 36 4>,
-                             <0 37 4>;
-                #iommu-cells = <1>;
-        };
-
-        /* device with two stream IDs, 0 and 7 */
-        master1 {
-                iommus = <&smmu1 0>,
-                         <&smmu1 7>;
-        };
-
-
-        /* SMMU with stream matching */
-        smmu2: iommu {
-                ...
-                #iommu-cells = <2>;
-        };
-
-        /* device with stream IDs 0 and 7 */
-        master2 {
-                iommus = <&smmu2 0 0>,
-                         <&smmu2 7 0>;
-        };
-
-        /* device with stream IDs 1, 17, 33 and 49 */
-        master3 {
-                iommus = <&smmu2 1 0x30>;
-        };
-
-
-        /* ARM MMU-500 with 10-bit stream ID input configuration */
-        smmu3: iommu {
-                compatible = "arm,mmu-500", "arm,smmu-v2";
-                ...
-                #iommu-cells = <1>;
-                /* always ignore appended 5-bit TBU number */
-                stream-match-mask = 0x7c00;
-        };
-
-        bus {
-                /* bus whose child devices emit one unique 10-bit stream
-                   ID each, but may master through multiple SMMU TBUs */
-                iommu-map = <0 &smmu3 0 0x400>;
-                ...
-        };
-
-       /* Qcom's arm,smmu-v2 implementation */
-       smmu4: iommu@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>;
-               power-domains = <&mmcc MDSS_GDSC>;
-
-               clocks = <&mmcc SMMU_MDP_AXI_CLK>,
-                        <&mmcc SMMU_MDP_AHB_CLK>;
-               clock-names = "bus", "iface";
-       };
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
new file mode 100644 (file)
index 0000000..6515dbe
--- /dev/null
@@ -0,0 +1,230 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/arm,smmu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM System MMU Architecture Implementation
+
+maintainers:
+  - Will Deacon <will@kernel.org>
+  - Robin Murphy <Robin.Murphy@arm.com>
+
+description: |+
+  ARM SoCs may contain an implementation of the ARM System Memory
+  Management Unit Architecture, which can be used to provide 1 or 2 stages
+  of address translation to bus masters external to the CPU.
+
+  The SMMU may also raise interrupts in response to various fault
+  conditions.
+
+properties:
+  $nodename:
+    pattern: "^iommu@[0-9a-f]*"
+  compatible:
+    oneOf:
+      - description: Qcom SoCs implementing "arm,smmu-v2"
+        items:
+          - enum:
+              - qcom,msm8996-smmu-v2
+              - qcom,msm8998-smmu-v2
+              - qcom,sdm845-smmu-v2
+          - const: qcom,smmu-v2
+
+      - description: Qcom SoCs implementing "arm,mmu-500"
+        items:
+          - enum:
+              - qcom,sc7180-smmu-500
+              - qcom,sdm845-smmu-500
+          - const: arm,mmu-500
+      - items:
+          - const: arm,mmu-500
+          - const: arm,smmu-v2
+      - items:
+          - const: arm,mmu-401
+          - const: arm,smmu-v1
+      - enum:
+          - arm,smmu-v1
+          - arm,smmu-v2
+          - arm,mmu-400
+          - arm,mmu-401
+          - arm,mmu-500
+          - cavium,smmu-v2
+
+  reg:
+    maxItems: 1
+
+  '#global-interrupts':
+    description: The number of global interrupts exposed by the device.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 260   # 2 secure, 2 non-secure, and up to 256 perf counters
+
+  '#iommu-cells':
+    enum: [ 1, 2 ]
+    description: |
+      See Documentation/devicetree/bindings/iommu/iommu.txt for details. With a
+      value of 1, each IOMMU specifier represents a distinct stream ID emitted
+      by that device into the relevant SMMU.
+
+      SMMUs with stream matching support and complex masters may use a value of
+      2, where the second cell of the IOMMU specifier represents an SMR mask to
+      combine with the ID in the first cell.  Care must be taken to ensure the
+      set of matched IDs does not result in conflicts.
+
+  interrupts:
+    minItems: 1
+    maxItems: 388   # 260 plus 128 contexts
+    description: |
+      Interrupt list, with the first #global-interrupts entries corresponding to
+      the global interrupts and any following entries corresponding to context
+      interrupts, specified in order of their indexing by the SMMU.
+
+      For SMMUv2 implementations, there must be exactly one interrupt per
+      context bank. In the case of a single, combined interrupt, it must be
+      listed multiple times.
+
+  dma-coherent:
+    description: |
+      Present if page table walks made by the SMMU are cache coherent with the
+      CPU.
+
+      NOTE: this only applies to the SMMU itself, not masters connected
+      upstream of the SMMU.
+
+  calxeda,smmu-secure-config-access:
+    type: boolean
+    description:
+      Enable proper handling of buggy implementations that always use secure
+      access to SMMU configuration registers. In this case non-secure aliases of
+      secure registers have to be used during SMMU configuration.
+
+  stream-match-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      For SMMUs supporting stream matching and using #iommu-cells = <1>,
+      specifies a mask of bits to ignore when matching stream IDs (e.g. this may
+      be programmed into the SMRn.MASK field of every stream match register
+      used). For cases where it is desirable to ignore some portion of every
+      Stream ID (e.g. for certain MMU-500 configurations given globally unique
+      input IDs). This property is not valid for SMMUs using stream indexing, or
+      using stream matching with #iommu-cells = <2>, and may be ignored if
+      present in such cases.
+
+  clock-names:
+    items:
+      - const: bus
+      - const: iface
+
+  clocks:
+    items:
+      - description: bus clock required for downstream bus access and for the
+          smmu ptw
+      - description: interface clock required to access smmu's registers
+          through the TCU's programming interface.
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - '#global-interrupts'
+  - '#iommu-cells'
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |+
+    /* SMMU with stream matching or stream indexing */
+    smmu1: iommu@ba5e0000 {
+            compatible = "arm,smmu-v1";
+            reg = <0xba5e0000 0x10000>;
+            #global-interrupts = <2>;
+            interrupts = <0 32 4>,
+                         <0 33 4>,
+                         <0 34 4>, /* This is the first context interrupt */
+                         <0 35 4>,
+                         <0 36 4>,
+                         <0 37 4>;
+            #iommu-cells = <1>;
+    };
+
+    /* device with two stream IDs, 0 and 7 */
+    master1 {
+            iommus = <&smmu1 0>,
+                     <&smmu1 7>;
+    };
+
+
+    /* SMMU with stream matching */
+    smmu2: iommu@ba5f0000 {
+            compatible = "arm,smmu-v1";
+            reg = <0xba5f0000 0x10000>;
+            #global-interrupts = <2>;
+            interrupts = <0 38 4>,
+                         <0 39 4>,
+                         <0 40 4>, /* This is the first context interrupt */
+                         <0 41 4>,
+                         <0 42 4>,
+                         <0 43 4>;
+            #iommu-cells = <2>;
+    };
+
+    /* device with stream IDs 0 and 7 */
+    master2 {
+            iommus = <&smmu2 0 0>,
+                     <&smmu2 7 0>;
+    };
+
+    /* device with stream IDs 1, 17, 33 and 49 */
+    master3 {
+            iommus = <&smmu2 1 0x30>;
+    };
+
+
+    /* ARM MMU-500 with 10-bit stream ID input configuration */
+    smmu3: iommu@ba600000 {
+            compatible = "arm,mmu-500", "arm,smmu-v2";
+            reg = <0xba600000 0x10000>;
+            #global-interrupts = <2>;
+            interrupts = <0 44 4>,
+                         <0 45 4>,
+                         <0 46 4>, /* This is the first context interrupt */
+                         <0 47 4>,
+                         <0 48 4>,
+                         <0 49 4>;
+            #iommu-cells = <1>;
+            /* always ignore appended 5-bit TBU number */
+            stream-match-mask = <0x7c00>;
+    };
+
+    bus {
+            /* bus whose child devices emit one unique 10-bit stream
+               ID each, but may master through multiple SMMU TBUs */
+            iommu-map = <0 &smmu3 0 0x400>;
+
+
+    };
+
+  - |+
+    /* Qcom's arm,smmu-v2 implementation */
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    smmu4: iommu@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>;
+      power-domains = <&mmcc 0>;
+
+      clocks = <&mmcc 123>,
+        <&mmcc 124>;
+      clock-names = "bus", "iface";
+    };
index b6bfbec..020d6f2 100644 (file)
@@ -15,6 +15,7 @@ Required Properties:
     - "renesas,ipmmu-r8a7744" for the R8A7744 (RZ/G1N) IPMMU.
     - "renesas,ipmmu-r8a7745" for the R8A7745 (RZ/G1E) IPMMU.
     - "renesas,ipmmu-r8a774a1" for the R8A774A1 (RZ/G2M) IPMMU.
+    - "renesas,ipmmu-r8a774b1" for the R8A774B1 (RZ/G2N) IPMMU.
     - "renesas,ipmmu-r8a774c0" for the R8A774C0 (RZ/G2E) IPMMU.
     - "renesas,ipmmu-r8a7790" for the R8A7790 (R-Car H2) IPMMU.
     - "renesas,ipmmu-r8a7791" for the R8A7791 (R-Car M2-W) IPMMU.
diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
deleted file mode 100644 (file)
index 525ec82..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-Samsung Exynos IOMMU H/W, System MMU (System Memory Management Unit)
-
-Samsung's Exynos architecture contains System MMUs that enables scattered
-physical memory chunks visible as a contiguous region to DMA-capable peripheral
-devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth.
-
-System MMU is an IOMMU and supports identical translation table format to
-ARMv7 translation tables with minimum set of page properties including access
-permissions, shareability and security protection. In addition, System MMU has
-another capabilities like L2 TLB or block-fetch buffers to minimize translation
-latency.
-
-System MMUs are in many to one relation with peripheral devices, i.e. single
-peripheral device might have multiple System MMUs (usually one for each bus
-master), but one System MMU can handle transactions from only one peripheral
-device. The relation between a System MMU and the peripheral device needs to be
-defined in device node of the peripheral device.
-
-MFC in all Exynos SoCs and FIMD, M2M Scalers and G2D in Exynos5420 has 2 System
-MMUs.
-* MFC has one System MMU on its left and right bus.
-* FIMD in Exynos5420 has one System MMU for window 0 and 4, the other system MMU
-  for window 1, 2 and 3.
-* M2M Scalers and G2D in Exynos5420 has one System MMU on the read channel and
-  the other System MMU on the write channel.
-
-For information on assigning System MMU controller to its peripheral devices,
-see generic IOMMU bindings.
-
-Required properties:
-- compatible: Should be "samsung,exynos-sysmmu"
-- reg: A tuple of base address and size of System MMU registers.
-- #iommu-cells: Should be <0>.
-- interrupts: An interrupt specifier for interrupt signal of System MMU,
-             according to the format defined by a particular interrupt
-             controller.
-- clock-names: Should be "sysmmu" or a pair of "aclk" and "pclk" to gate
-              SYSMMU core clocks.
-              Optional "master" if the clock to the System MMU is gated by
-              another gate clock other core  (usually main gate clock
-              of peripheral device this SYSMMU belongs to).
-- clocks: Phandles for respective clocks described by clock-names.
-- power-domains: Required if the System MMU is needed to gate its power.
-         Please refer to the following document:
-         Documentation/devicetree/bindings/power/pd-samsung.txt
-
-Examples:
-       gsc_0: gsc@13e00000 {
-               compatible = "samsung,exynos5-gsc";
-               reg = <0x13e00000 0x1000>;
-               interrupts = <0 85 0>;
-               power-domains = <&pd_gsc>;
-               clocks = <&clock CLK_GSCL0>;
-               clock-names = "gscl";
-               iommus = <&sysmmu_gsc0>;
-       };
-
-       sysmmu_gsc0: sysmmu@13e80000 {
-               compatible = "samsung,exynos-sysmmu";
-               reg = <0x13E80000 0x1000>;
-               interrupt-parent = <&combiner>;
-               interrupts = <2 0>;
-               clock-names = "sysmmu", "master";
-               clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>;
-               power-domains = <&pd_gsc>;
-               #iommu-cells = <0>;
-       };
diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.yaml b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.yaml
new file mode 100644 (file)
index 0000000..7cdd3aa
--- /dev/null
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/samsung,sysmmu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos IOMMU H/W, System MMU (System Memory Management Unit)
+
+maintainers:
+  - Marek Szyprowski <m.szyprowski@samsung.com>
+
+description: |+
+  Samsung's Exynos architecture contains System MMUs that enables scattered
+  physical memory chunks visible as a contiguous region to DMA-capable peripheral
+  devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth.
+
+  System MMU is an IOMMU and supports identical translation table format to
+  ARMv7 translation tables with minimum set of page properties including access
+  permissions, shareability and security protection. In addition, System MMU has
+  another capabilities like L2 TLB or block-fetch buffers to minimize translation
+  latency.
+
+  System MMUs are in many to one relation with peripheral devices, i.e. single
+  peripheral device might have multiple System MMUs (usually one for each bus
+  master), but one System MMU can handle transactions from only one peripheral
+  device. The relation between a System MMU and the peripheral device needs to be
+  defined in device node of the peripheral device.
+
+  MFC in all Exynos SoCs and FIMD, M2M Scalers and G2D in Exynos5420 has 2 System
+  MMUs.
+  * MFC has one System MMU on its left and right bus.
+  * FIMD in Exynos5420 has one System MMU for window 0 and 4, the other system MMU
+    for window 1, 2 and 3.
+  * M2M Scalers and G2D in Exynos5420 has one System MMU on the read channel and
+    the other System MMU on the write channel.
+
+  For information on assigning System MMU controller to its peripheral devices,
+  see generic IOMMU bindings.
+
+properties:
+  compatible:
+    const: samsung,exynos-sysmmu
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+
+  clock-names:
+    oneOf:
+      - items:
+        - const: sysmmu
+      - items:
+        - const: sysmmu
+        - const: master
+      - items:
+        - const: aclk
+        - const: pclk
+
+  "#iommu-cells":
+    const: 0
+
+  power-domains:
+    description: |
+      Required if the System MMU is needed to gate its power.
+      Please refer to the following document:
+      Documentation/devicetree/bindings/power/pd-samsung.yaml
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - "#iommu-cells"
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos5250.h>
+
+    gsc_0: scaler@13e00000 {
+      compatible = "samsung,exynos5-gsc";
+      reg = <0x13e00000 0x1000>;
+      interrupts = <0 85 0>;
+      power-domains = <&pd_gsc>;
+      clocks = <&clock CLK_GSCL0>;
+      clock-names = "gscl";
+      iommus = <&sysmmu_gsc0>;
+    };
+
+    sysmmu_gsc0: iommu@13e80000 {
+      compatible = "samsung,exynos-sysmmu";
+      reg = <0x13E80000 0x1000>;
+      interrupt-parent = <&combiner>;
+      interrupts = <2 0>;
+      clock-names = "sysmmu", "master";
+      clocks = <&clock CLK_SMMU_GSCL0>,
+               <&clock CLK_GSCL0>;
+      power-domains = <&pd_gsc>;
+      #iommu-cells = <0>;
+    };
+
diff --git a/Documentation/devicetree/bindings/leds/leds-max77650.txt b/Documentation/devicetree/bindings/leds/leds-max77650.txt
deleted file mode 100644 (file)
index 3a67115..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-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/leds/leds-max77650.yaml b/Documentation/devicetree/bindings/leds/leds-max77650.yaml
new file mode 100644 (file)
index 0000000..8c43f1e
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/leds-max77650.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LED driver for MAX77650 PMIC from Maxim Integrated.
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+description: |
+  This module is part of the MAX77650 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/max77650.yaml.
+
+  The LED controller is represented as a sub-node of the PMIC node on
+  the device tree.
+
+  This device has three current sinks.
+
+properties:
+  compatible:
+    const: maxim,max77650-led
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^led@[0-2]$":
+    type: object
+    description: |
+      Properties for a single LED.
+
+    properties:
+      reg:
+        description:
+          Index of the LED.
+        minimum: 0
+        maximum: 2
+
+      label: true
+
+      linux,default-trigger: true
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
diff --git a/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt b/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt
deleted file mode 100644 (file)
index 9ceb19e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-* AC timing parameters of LPDDR2(JESD209-2) memories for a given speed-bin
-
-Required properties:
-- compatible : Should be "jedec,lpddr2-timings"
-- min-freq : minimum DDR clock frequency for the speed-bin. Type is <u32>
-- max-freq : maximum DDR clock frequency for the speed-bin. Type is <u32>
-
-Optional properties:
-
-The following properties represent AC timing parameters from the memory
-data-sheet of the device for a given speed-bin. All these properties are
-of type <u32> and the default unit is ps (pico seconds). Parameters with
-a different unit have a suffix indicating the unit such as 'tRAS-max-ns'
-- tRCD
-- tWR
-- tRAS-min
-- tRRD
-- tWTR
-- tXP
-- tRTP
-- tDQSCK-max
-- tFAW
-- tZQCS
-- tZQinit
-- tRPab
-- tZQCL
-- tCKESR
-- tRAS-max-ns
-- tDQSCK-max-derated
-
-Example:
-
-timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 {
-       compatible      = "jedec,lpddr2-timings";
-       min-freq        = <10000000>;
-       max-freq        = <400000000>;
-       tRPab           = <21000>;
-       tRCD            = <18000>;
-       tWR             = <15000>;
-       tRAS-min        = <42000>;
-       tRRD            = <10000>;
-       tWTR            = <7500>;
-       tXP             = <7500>;
-       tRTP            = <7500>;
-       tCKESR          = <15000>;
-       tDQSCK-max      = <5500>;
-       tFAW            = <50000>;
-       tZQCS           = <90000>;
-       tZQCL           = <360000>;
-       tZQinit         = <1000000>;
-       tRAS-max-ns     = <70000>;
-};
diff --git a/Documentation/devicetree/bindings/lpddr2/lpddr2.txt b/Documentation/devicetree/bindings/lpddr2/lpddr2.txt
deleted file mode 100644 (file)
index 58354a0..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2
-
-Required properties:
-- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2",
-  "jedec,lpddr2-s4"
-
-  "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type
-
-  "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type
-
-  "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type
-
-- density  : <u32> representing density in Mb (Mega bits)
-
-- io-width : <u32> representing bus width. Possible values are 8, 16, and 32
-
-Optional properties:
-
-The following optional properties represent the minimum value of some AC
-timing parameters of the DDR device in terms of number of clock cycles.
-These values shall be obtained from the device data-sheet.
-- tRRD-min-tck
-- tWTR-min-tck
-- tXP-min-tck
-- tRTP-min-tck
-- tCKE-min-tck
-- tRPab-min-tck
-- tRCD-min-tck
-- tWR-min-tck
-- tRASmin-min-tck
-- tCKESR-min-tck
-- tFAW-min-tck
-
-Child nodes:
-- The lpddr2 node may have one or more child nodes of type "lpddr2-timings".
-  "lpddr2-timings" provides AC timing parameters of the device for
-  a given speed-bin. The user may provide the timings for as many
-  speed-bins as is required. Please see Documentation/devicetree/
-  bindings/lpddr2/lpddr2-timings.txt for more information on "lpddr2-timings"
-
-Example:
-
-elpida_ECB240ABACN : lpddr2 {
-       compatible      = "Elpida,ECB240ABACN","jedec,lpddr2-s4";
-       density         = <2048>;
-       io-width        = <32>;
-
-       tRPab-min-tck   = <3>;
-       tRCD-min-tck    = <3>;
-       tWR-min-tck     = <3>;
-       tRASmin-min-tck = <3>;
-       tRRD-min-tck    = <2>;
-       tWTR-min-tck    = <2>;
-       tXP-min-tck     = <2>;
-       tRTP-min-tck    = <2>;
-       tCKE-min-tck    = <3>;
-       tCKESR-min-tck  = <3>;
-       tFAW-min-tck    = <8>;
-
-       timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 {
-               compatible      = "jedec,lpddr2-timings";
-               min-freq        = <10000000>;
-               max-freq        = <400000000>;
-               tRPab           = <21000>;
-               tRCD            = <18000>;
-               tWR             = <15000>;
-               tRAS-min        = <42000>;
-               tRRD            = <10000>;
-               tWTR            = <7500>;
-               tXP             = <7500>;
-               tRTP            = <7500>;
-               tCKESR          = <15000>;
-               tDQSCK-max      = <5500>;
-               tFAW            = <50000>;
-               tZQCS           = <90000>;
-               tZQCL           = <360000>;
-               tZQinit         = <1000000>;
-               tRAS-max-ns     = <70000>;
-       };
-
-       timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 {
-               compatible      = "jedec,lpddr2-timings";
-               min-freq        = <10000000>;
-               max-freq        = <200000000>;
-               tRPab           = <21000>;
-               tRCD            = <18000>;
-               tWR             = <15000>;
-               tRAS-min        = <42000>;
-               tRRD            = <10000>;
-               tWTR            = <10000>;
-               tXP             = <7500>;
-               tRTP            = <7500>;
-               tCKESR          = <15000>;
-               tDQSCK-max      = <5500>;
-               tFAW            = <50000>;
-               tZQCS           = <90000>;
-               tZQCL           = <360000>;
-               tZQinit         = <1000000>;
-               tRAS-max-ns     = <70000>;
-       };
-
-}
diff --git a/Documentation/devicetree/bindings/mailbox/st,stm32-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/st,stm32-ipcc.yaml
new file mode 100644 (file)
index 0000000..5b13d66
--- /dev/null
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/mailbox/st,stm32-ipcc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: STMicroelectronics STM32 IPC controller bindings
+
+description:
+  The IPCC block provides a non blocking signaling mechanism to post and
+  retrieve messages in an atomic way between two processors.
+  It provides the signaling for N bidirectionnal channels. The number of
+  channels (N) can be read from a dedicated register.
+
+maintainers:
+  - Fabien Dessenne <fabien.dessenne@st.com>
+  - Arnaud Pouliquen <arnaud.pouliquen@st.com>
+
+properties:
+  compatible:
+    const: st,stm32mp1-ipcc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+     maxItems: 1
+
+  interrupts:
+    items:
+      - description: rx channel occupied
+      - description: tx channel free
+      - description: wakeup source
+    minItems: 2
+    maxItems: 3
+
+  interrupt-names:
+    items:
+      - const: rx
+      - const: tx
+      - const: wakeup
+    minItems: 2
+    maxItems: 3
+
+  wakeup-source: true
+
+  "#mbox-cells":
+    const: 1
+
+  st,proc-id:
+    description: Processor id using the mailbox (0 or 1)
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [ 0, 1 ]
+
+required:
+  - compatible
+  - reg
+  - st,proc-id
+  - clocks
+  - interrupt-names
+  - "#mbox-cells"
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    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_NONE>,
+                     <&intc GIC_SPI 101 IRQ_TYPE_NONE>,
+                     <&aiec 62 1>;
+      interrupt-names = "rx", "tx", "wakeup";
+      clocks = <&rcc_clk IPCC>;
+      wakeup-source;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt
deleted file mode 100644 (file)
index 1d2b7fe..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-* STMicroelectronics STM32 IPCC (Inter-Processor Communication Controller)
-
-The IPCC block provides a non blocking signaling mechanism to post and
-retrieve messages in an atomic way between two processors.
-It provides the signaling for N bidirectionnal channels. The number of channels
-(N) can be read from a dedicated register.
-
-Required properties:
-- compatible:   Must be "st,stm32mp1-ipcc"
-- reg:          Register address range (base address and length)
-- st,proc-id:   Processor id using the mailbox (0 or 1)
-- clocks:       Input clock
-- interrupt-names: List of names for the interrupts described by the interrupt
-                   property. Must contain the following entries:
-                   - "rx"
-                   - "tx"
-                   - "wakeup"
-- interrupts:   Interrupt specifiers for "rx channel occupied", "tx channel
-                free" and "system wakeup".
-- #mbox-cells:  Number of cells required for the mailbox specifier. Must be 1.
-                The data contained in the mbox specifier of the "mboxes"
-                property in the client node is the mailbox channel index.
-
-Optional properties:
-- wakeup-source: Flag to indicate whether this device can wake up the system
-
-
-
-Example:
-       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_NONE>,
-                                     <&intc GIC_SPI 101 IRQ_TYPE_NONE>,
-                                     <&aiec 62 1>;
-               interrupt-names = "rx", "tx", "wakeup";
-               clocks = <&rcc_clk IPCC>;
-               wakeup-source;
-       }
-
-Client:
-       mbox_test {
-               ...
-               mboxes = <&ipcc 0>, <&ipcc 1>;
-       };
index 98c1bdd..dea36d6 100644 (file)
@@ -60,9 +60,7 @@ required:
   - clocks
   - clock-names
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml b/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
new file mode 100644 (file)
index 0000000..4119757
--- /dev/null
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/amlogic,meson-gx-ao-cec.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Meson AO-CEC Controller
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+
+description: |
+  The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is
+  to handle communication between HDMI connected devices over the CEC bus.
+
+properties:
+  compatible:
+    enum:
+      - amlogic,meson-gx-ao-cec # GXBB, GXL, GXM, G12A and SM1 AO_CEC_A module
+      - amlogic,meson-g12a-ao-cec # G12A AO_CEC_B module
+      - amlogic,meson-sm1-ao-cec # SM1 AO_CEC_B module
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  hdmi-phandle:
+    description: phandle to the HDMI controller
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - amlogic,meson-gx-ao-cec
+
+    then:
+      properties:
+        clocks:
+          items:
+            - description: AO-CEC clock
+
+        clock-names:
+          maxItems: 1
+          items:
+            - const: core
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - amlogic,meson-g12a-ao-cec
+              - amlogic,meson-sm1-ao-cec
+
+    then:
+      properties:
+        clocks:
+          items:
+            - description: AO-CEC clock generator source
+
+        clock-names:
+          maxItems: 1
+          items:
+            - const: oscin
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - hdmi-phandle
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    cec_AO: cec@100 {
+        compatible = "amlogic,meson-gx-ao-cec";
+        reg = <0x0 0x00100 0x0 0x14>;
+        interrupts = <199>;
+        clocks = <&clkc_cec>;
+        clock-names = "core";
+        hdmi-phandle = <&hdmi_tx>;
+    };
+
diff --git a/Documentation/devicetree/bindings/media/meson-ao-cec.txt b/Documentation/devicetree/bindings/media/meson-ao-cec.txt
deleted file mode 100644 (file)
index ad92ee4..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-* Amlogic Meson AO-CEC driver
-
-The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is
-to handle communication between HDMI connected devices over the CEC bus.
-
-Required properties:
-  - compatible : value should be following depending on the SoC :
-       For GXBB, GXL, GXM, G12A and SM1 (AO_CEC_A module) :
-       "amlogic,meson-gx-ao-cec"
-       For G12A (AO_CEC_B module) :
-       "amlogic,meson-g12a-ao-cec"
-       For SM1 (AO_CEC_B module) :
-       "amlogic,meson-sm1-ao-cec"
-
-  - reg : Physical base address of the IP registers and length of memory
-         mapped region.
-
-  - interrupts : AO-CEC interrupt number to the CPU.
-  - clocks : from common clock binding: handle to AO-CEC clock.
-  - clock-names : from common clock binding, must contain :
-               For GXBB, GXL, GXM, G12A and SM1 (AO_CEC_A module) :
-               - "core"
-               For G12A, SM1 (AO_CEC_B module) :
-               - "oscin"
-               corresponding to entry in the clocks property.
-  - hdmi-phandle: phandle to the HDMI controller
-
-Example:
-
-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_32K>;
-       clock-names = "core";
-       hdmi-phandle = <&hdmi_tx>;
-};
index cdfc8ee..d113807 100644 (file)
@@ -83,6 +83,7 @@ properties:
           - rc-it913x-v1
           - rc-it913x-v2
           - rc-kaiomy
+          - rc-khadas
           - rc-kworld-315u
           - rc-kworld-pc150u
           - rc-kworld-plus-tv-analog
@@ -100,6 +101,7 @@ properties:
           - rc-nec-terratec-cinergy-xs
           - rc-norwood
           - rc-npgtech
+          - rc-odroid
           - rc-pctv-sedna
           - rc-pinnacle-color
           - rc-pinnacle-grey
@@ -120,6 +122,7 @@ properties:
           - rc-streamzap
           - rc-su3000
           - rc-tango
+          - rc-tanix-tx3mini
           - rc-tbs-nec
           - rc-technisat-ts35
           - rc-technisat-usb2
@@ -139,7 +142,10 @@ properties:
           - rc-videomate-k100
           - rc-videomate-s350
           - rc-videomate-tv-pvr
+          - rc-wetek-hub
+          - rc-wetek-play2
           - rc-winfast
           - rc-winfast-usbii-deluxe
+          - rc-x96max
           - rc-xbox-dvd
           - rc-zx-irdec
diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.txt b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
deleted file mode 100644 (file)
index 6be2381..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-STMicroelectronics STM32 CEC driver
-
-Required properties:
- - compatible : value should be "st,stm32-cec"
- - reg : Physical base address of the IP registers and length of memory
-        mapped region.
- - clocks : from common clock binding: handle to CEC clocks
- - clock-names : from common clock binding: must be "cec" and "hdmi-cec".
- - interrupts : CEC interrupt number to the CPU.
-
-Example for stm32f746:
-
-cec: cec@40006c00 {
-       compatible = "st,stm32-cec";
-       reg = <0x40006C00 0x400>;
-       interrupts = <94>;
-       clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>;
-       clock-names = "cec", "hdmi-cec";
-};
diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.yaml b/Documentation/devicetree/bindings/media/st,stm32-cec.yaml
new file mode 100644 (file)
index 0000000..d75019c
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/st,stm32-cec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 CEC bindings
+
+maintainers:
+  - Benjamin Gaignard <benjamin.gaignard@st.com>
+  - Yannick Fertre <yannick.fertre@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-cec
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Module Clock
+      - description: Bus Clock
+
+  clock-names:
+    items:
+      - const: cec
+      - const: hdmi-cec
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    cec: cec@40006c00 {
+        compatible = "st,stm32-cec";
+        reg = <0x40006c00 0x400>;
+        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&rcc CEC_K>, <&clk_lse>;
+        clock-names = "cec", "hdmi-cec";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.txt b/Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
deleted file mode 100644 (file)
index 3122ded..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-STMicroelectronics STM32 Digital Camera Memory Interface (DCMI)
-
-Required properties:
-- compatible: "st,stm32-dcmi"
-- reg: physical base address and length of the registers set for the device
-- interrupts: should contain IRQ line for the DCMI
-- resets: reference to a reset controller,
-          see Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
-- clocks: list of clock specifiers, corresponding to entries in
-          the clock-names property
-- clock-names: must contain "mclk", which is the DCMI peripherial clock
-- pinctrl: the pincontrol settings to configure muxing properly
-           for pins that connect to DCMI device.
-           See Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml.
-- dmas: phandle to DMA controller node,
-        see Documentation/devicetree/bindings/dma/stm32-dma.txt
-- dma-names: must contain "tx", which is the transmit channel from DCMI to DMA
-
-DCMI supports a single port node with parallel bus. It should contain one
-'port' child node with child 'endpoint' node. Please refer to the bindings
-defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-Example:
-
-       dcmi: dcmi@50050000 {
-               compatible = "st,stm32-dcmi";
-               reg = <0x50050000 0x400>;
-               interrupts = <78>;
-               resets = <&rcc STM32F4_AHB2_RESET(DCMI)>;
-               clocks = <&rcc 0 STM32F4_AHB2_CLOCK(DCMI)>;
-               clock-names = "mclk";
-               pinctrl-names = "default";
-               pinctrl-0 = <&dcmi_pins>;
-               dmas = <&dma2 1 1 0x414 0x3>;
-               dma-names = "tx";
-               port {
-                       dcmi_0: endpoint {
-                               remote-endpoint = <...>;
-                               bus-width = <8>;
-                               hsync-active = <0>;
-                               vsync-active = <0>;
-                               pclk-sample = <1>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
new file mode 100644 (file)
index 0000000..3fe778c
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/st,stm32-dcmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Digital Camera Memory Interface (DCMI) binding
+
+maintainers:
+  - Hugues Fruchet <hugues.fruchet@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-dcmi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: mclk
+
+  dmas:
+    maxItems: 1
+
+  dma-names:
+    items:
+      - const: tx
+
+  resets:
+    maxItems: 1
+
+  port:
+    type: object
+    description:
+      DCMI supports a single port node with parallel bus. It should contain
+      one 'port' child node with child 'endpoint' node. Please refer to the
+      bindings defined in
+      Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - dmas
+  - dma-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    dcmi: dcmi@4c006000 {
+        compatible = "st,stm32-dcmi";
+        reg = <0x4c006000 0x400>;
+        interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+        resets = <&rcc CAMITF_R>;
+        clocks = <&rcc DCMI>;
+        clock-names = "mclk";
+        dmas = <&dmamux1 75 0x400 0x0d>;
+        dma-names = "tx";
+
+        port {
+             dcmi_0: endpoint {
+                   remote-endpoint = <&ov5640_0>;
+                   bus-width = <8>;
+                   hsync-active = <0>;
+                   vsync-active = <0>;
+                   pclk-sample = <1>;
+             };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/memory-controllers/exynos-srom.txt b/Documentation/devicetree/bindings/memory-controllers/exynos-srom.txt
deleted file mode 100644 (file)
index f633b5d..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-SAMSUNG Exynos SoCs SROM Controller driver.
-
-Required properties:
-- compatible : Should contain "samsung,exynos4210-srom".
-
-- reg: offset and length of the register set
-
-Optional properties:
-The SROM controller can be used to attach external peripherals. In this case
-extra properties, describing the bus behind it, should be specified as below:
-
-- #address-cells: Must be set to 2 to allow device address translation.
-                 Address is specified as (bank#, offset).
-
-- #size-cells: Must be set to 1 to allow device size passing
-
-- ranges: Must be set up to reflect the memory layout with four integer values
-         per bank:
-               <bank-number> 0 <parent address of bank> <size>
-
-Sub-nodes:
-The actual device nodes should be added as subnodes to the SROMc node. These
-subnodes, in addition to regular device specification, should contain the following
-properties, describing configuration of the relevant SROM bank:
-
-Required properties:
-- reg: bank number, base address (relative to start of the bank) and size of
-       the memory mapped for the device. Note that base address will be
-       typically 0 as this is the start of the bank.
-
-- samsung,srom-timing : array of 6 integers, specifying bank timings in the
-                        following order: Tacp, Tcah, Tcoh, Tacc, Tcos, Tacs.
-                        Each value is specified in cycles and has the following
-                        meaning and valid range:
-                        Tacp : Page mode access cycle at Page mode (0 - 15)
-                        Tcah : Address holding time after CSn (0 - 15)
-                        Tcoh : Chip selection hold on OEn (0 - 15)
-                        Tacc : Access cycle (0 - 31, the actual time is N + 1)
-                        Tcos : Chip selection set-up before OEn (0 - 15)
-                        Tacs : Address set-up before CSn (0 - 15)
-
-Optional properties:
-- reg-io-width : data width in bytes (1 or 2). If omitted, default of 1 is used.
-
-- samsung,srom-page-mode : if page mode is set, 4 data page mode will be configured,
-                          else normal (1 data) page mode will be set.
-
-Example: basic definition, no banks are configured
-       memory-controller@12570000 {
-               compatible = "samsung,exynos4210-srom";
-               reg = <0x12570000 0x14>;
-       };
-
-Example: SROMc with SMSC911x ethernet chip on bank 3
-       memory-controller@12570000 {
-               #address-cells = <2>;
-               #size-cells = <1>;
-               ranges = <0 0 0x04000000 0x20000   // Bank0
-                         1 0 0x05000000 0x20000   // Bank1
-                         2 0 0x06000000 0x20000   // Bank2
-                         3 0 0x07000000 0x20000>; // Bank3
-
-               compatible = "samsung,exynos4210-srom";
-               reg = <0x12570000 0x14>;
-
-               ethernet@3,0 {
-                       compatible = "smsc,lan9115";
-                       reg = <3 0 0x10000>;       // Bank 3, offset = 0
-                       phy-mode = "mii";
-                       interrupt-parent = <&gpx0>;
-                       interrupts = <5 8>;
-                       reg-io-width = <2>;
-                       smsc,irq-push-pull;
-                       smsc,force-internal-phy;
-
-                       samsung,srom-page-mode;
-                       samsung,srom-timing = <9 12 1 9 1 1>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml b/Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml
new file mode 100644 (file)
index 0000000..cdfe3f7
--- /dev/null
@@ -0,0 +1,128 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/exynos-srom.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC SROM Controller driver
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |+
+  The SROM controller can be used to attach external peripherals. In this case
+  extra properties, describing the bus behind it, should be specified.
+
+properties:
+  compatible:
+    items:
+      - const: samsung,exynos4210-srom
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 1
+
+  ranges:
+    description: |
+      Reflects the memory layout with four integer values per bank. Format:
+      <bank-number> 0 <parent address of bank> <size>
+      Up to four banks are supported.
+
+patternProperties:
+  "^.*@[0-3],[a-f0-9]+$":
+    type: object
+    description:
+      The actual device nodes should be added as subnodes to the SROMc node.
+      These subnodes, in addition to regular device specification, should
+      contain the following properties, describing configuration
+      of the relevant SROM bank.
+
+    properties:
+      reg:
+        description:
+          Bank number, base address (relative to start of the bank) and size
+          of the memory mapped for the device. Note that base address will be
+          typically 0 as this is the start of the bank.
+        maxItems: 1
+
+      reg-io-width:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [1, 2]
+        description:
+          Data width in bytes (1 or 2). If omitted, default of 1 is used.
+
+      samsung,srom-page-mode:
+        description:
+          If page mode is set, 4 data page mode will be configured,
+          else normal (1 data) page mode will be set.
+        type: boolean
+
+      samsung,srom-timing:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+          - items:
+              minItems: 6
+              maxItems: 6
+        description: |
+          Array of 6 integers, specifying bank timings in the following order:
+          Tacp, Tcah, Tcoh, Tacc, Tcos, Tacs.
+          Each value is specified in cycles and has the following meaning
+          and valid range:
+          Tacp: Page mode access cycle at Page mode (0 - 15)
+          Tcah: Address holding time after CSn (0 - 15)
+          Tcoh: Chip selection hold on OEn (0 - 15)
+          Tacc: Access cycle (0 - 31, the actual time is N + 1)
+          Tcos: Chip selection set-up before OEn (0 - 15)
+          Tacs: Address set-up before CSn (0 - 15)
+
+    required:
+      - reg
+      - samsung,srom-timing
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    // Example: basic definition, no banks are configured
+    memory-controller@12560000 {
+        compatible = "samsung,exynos4210-srom";
+        reg = <0x12560000 0x14>;
+    };
+
+  - |
+    // Example: SROMc with SMSC911x ethernet chip on bank 3
+    memory-controller@12570000 {
+        #address-cells = <2>;
+        #size-cells = <1>;
+        ranges = <0 0 0x04000000 0x20000   // Bank0
+                  1 0 0x05000000 0x20000   // Bank1
+                  2 0 0x06000000 0x20000   // Bank2
+                  3 0 0x07000000 0x20000>; // Bank3
+
+        compatible = "samsung,exynos4210-srom";
+        reg = <0x12570000 0x14>;
+
+        ethernet@3,0 {
+            compatible = "smsc,lan9115";
+            reg = <3 0 0x10000>;     // Bank 3, offset = 0
+            phy-mode = "mii";
+            interrupt-parent = <&gpx0>;
+            interrupts = <5 8>;
+            reg-io-width = <2>;
+            smsc,irq-push-pull;
+            smsc,force-internal-phy;
+
+            samsung,srom-page-mode;
+            samsung,srom-timing = <9 12 1 9 1 1>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/memory-controllers/exynos5422-dmc.txt b/Documentation/devicetree/bindings/memory-controllers/exynos5422-dmc.txt
new file mode 100644 (file)
index 0000000..02e4a1f
--- /dev/null
@@ -0,0 +1,84 @@
+* Exynos5422 frequency and voltage scaling for Dynamic Memory Controller device
+
+The Samsung Exynos5422 SoC has DMC (Dynamic Memory Controller) to which the DRAM
+memory chips are connected. The driver is to monitor the controller in runtime
+and switch frequency and voltage. To monitor the usage of the controller in
+runtime, the driver uses the PPMU (Platform Performance Monitoring Unit), which
+is able to measure the current load of the memory.
+When 'userspace' governor is used for the driver, an application is able to
+switch the DMC and memory frequency.
+
+Required properties for DMC device for Exynos5422:
+- compatible: Should be "samsung,exynos5422-dmc".
+- clocks : list of clock specifiers, must contain an entry for each
+  required entry in clock-names for CLK_FOUT_SPLL, CLK_MOUT_SCLK_SPLL,
+  CLK_FF_DOUT_SPLL2, CLK_FOUT_BPLL, CLK_MOUT_BPLL, CLK_SCLK_BPLL,
+  CLK_MOUT_MX_MSPLL_CCORE, CLK_MOUT_MX_MSPLL_CCORE_PHY, CLK_MOUT_MCLK_CDREX,
+- clock-names : should include "fout_spll", "mout_sclk_spll", "ff_dout_spll2",
+  "fout_bpll", "mout_bpll", "sclk_bpll", "mout_mx_mspll_ccore",
+  "mout_mclk_cdrex"  entries
+- devfreq-events : phandles for PPMU devices connected to this DMC.
+- vdd-supply : phandle for voltage regulator which is connected.
+- reg : registers of two CDREX controllers.
+- operating-points-v2 : phandle for OPPs described in v2 definition.
+- device-handle : phandle of the connected DRAM memory device. For more
+       information please refer to documentation file:
+       Documentation/devicetree/bindings/ddr/lpddr3.txt
+- devfreq-events : phandles of the PPMU events used by the controller.
+- samsung,syscon-clk : phandle of the clock register set used by the controller,
+       these registers are used for enabling a 'pause' feature and are not
+       exposed by clock framework but they must be used in a safe way.
+       The register offsets are in the driver code and specyfic for this SoC
+       type.
+
+Optional properties for DMC device for Exynos5422:
+- interrupt-parent : The parent interrupt controller.
+- interrupts : Contains the IRQ line numbers for the DMC internal performance
+  event counters in DREX0 and DREX1 channels. Align with specification of the
+  interrupt line(s) in the interrupt-parent controller.
+- interrupt-names : IRQ names "drex_0" and "drex_1", the order should be the
+  same as in the 'interrupts' list above.
+
+Example:
+
+       ppmu_dmc0_0: ppmu@10d00000 {
+               compatible = "samsung,exynos-ppmu";
+               reg = <0x10d00000 0x2000>;
+               clocks = <&clock CLK_PCLK_PPMU_DREX0_0>;
+               clock-names = "ppmu";
+               events {
+                       ppmu_event_dmc0_0: ppmu-event3-dmc0_0 {
+                               event-name = "ppmu-event3-dmc0_0";
+                       };
+               };
+       };
+
+       dmc: memory-controller@10c20000 {
+               compatible = "samsung,exynos5422-dmc";
+               reg = <0x10c20000 0x10000>, <0x10c30000 0x10000>;
+               clocks = <&clock CLK_FOUT_SPLL>,
+                        <&clock CLK_MOUT_SCLK_SPLL>,
+                        <&clock CLK_FF_DOUT_SPLL2>,
+                        <&clock CLK_FOUT_BPLL>,
+                        <&clock CLK_MOUT_BPLL>,
+                        <&clock CLK_SCLK_BPLL>,
+                        <&clock CLK_MOUT_MX_MSPLL_CCORE>,
+                        <&clock CLK_MOUT_MCLK_CDREX>;
+               clock-names = "fout_spll",
+                             "mout_sclk_spll",
+                             "ff_dout_spll2",
+                             "fout_bpll",
+                             "mout_bpll",
+                             "sclk_bpll",
+                             "mout_mx_mspll_ccore",
+                             "mout_mclk_cdrex";
+               operating-points-v2 = <&dmc_opp_table>;
+               devfreq-events = <&ppmu_event3_dmc0_0>, <&ppmu_event3_dmc0_1>,
+                                <&ppmu_event3_dmc1_0>, <&ppmu_event3_dmc1_1>;
+               device-handle = <&samsung_K3QF2F20DB>;
+               vdd-supply = <&buck1_reg>;
+               samsung,syscon-clk = <&clock>;
+               interrupt-parent = <&combiner>;
+               interrupts = <16 0>, <16 1>;
+               interrupt-names = "drex_0", "drex_1";
+       };
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml
new file mode 100644 (file)
index 0000000..30d9fb1
--- /dev/null
@@ -0,0 +1,152 @@
+# SPDX-License-Identifier: (GPL-2.0)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/nvidia,tegra124-mc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra124 SoC Memory Controller
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Thierry Reding <thierry.reding@gmail.com>
+
+description: |
+  Tegra124 SoC features a hybrid 2x32-bit / 1x64-bit memory controller.
+  These are interleaved to provide high performance with the load shared across
+  two memory channels. The Tegra124 Memory Controller handles memory requests
+  from internal clients and arbitrates among them to allocate memory bandwidth
+  for DDR3L and LPDDR3 SDRAMs.
+
+properties:
+  compatible:
+    const: nvidia,tegra124-mc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: mc
+
+  interrupts:
+    maxItems: 1
+
+  "#reset-cells":
+    const: 1
+
+  "#iommu-cells":
+    const: 1
+
+patternProperties:
+  "^emc-timings-[0-9]+$":
+    type: object
+    properties:
+      nvidia,ram-code:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          Value of RAM_CODE this timing set is used for.
+
+    patternProperties:
+      "^timing-[0-9]+$":
+        type: object
+        properties:
+          clock-frequency:
+            description:
+              Memory clock rate in Hz.
+            minimum: 1000000
+            maximum: 1066000000
+
+          nvidia,emem-configuration:
+            $ref: /schemas/types.yaml#/definitions/uint32-array
+            description: |
+              Values to be written to the EMEM register block. See section
+              "15.6.1 MC Registers" in the TRM.
+            items:
+              - description: MC_EMEM_ARB_CFG
+              - description: MC_EMEM_ARB_OUTSTANDING_REQ
+              - description: MC_EMEM_ARB_TIMING_RCD
+              - description: MC_EMEM_ARB_TIMING_RP
+              - description: MC_EMEM_ARB_TIMING_RC
+              - description: MC_EMEM_ARB_TIMING_RAS
+              - description: MC_EMEM_ARB_TIMING_FAW
+              - description: MC_EMEM_ARB_TIMING_RRD
+              - description: MC_EMEM_ARB_TIMING_RAP2PRE
+              - description: MC_EMEM_ARB_TIMING_WAP2PRE
+              - description: MC_EMEM_ARB_TIMING_R2R
+              - description: MC_EMEM_ARB_TIMING_W2W
+              - description: MC_EMEM_ARB_TIMING_R2W
+              - description: MC_EMEM_ARB_TIMING_W2R
+              - description: MC_EMEM_ARB_DA_TURNS
+              - description: MC_EMEM_ARB_DA_COVERS
+              - description: MC_EMEM_ARB_MISC0
+              - description: MC_EMEM_ARB_MISC1
+              - description: MC_EMEM_ARB_RING1_THROTTLE
+
+        required:
+          - clock-frequency
+          - nvidia,emem-configuration
+
+        additionalProperties: false
+
+    required:
+      - nvidia,ram-code
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - "#reset-cells"
+  - "#iommu-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    memory-controller@70019000 {
+        compatible = "nvidia,tegra124-mc";
+        reg = <0x0 0x70019000 0x0 0x1000>;
+        clocks = <&tegra_car 32>;
+        clock-names = "mc";
+
+        interrupts = <0 77 4>;
+
+        #iommu-cells = <1>;
+        #reset-cells = <1>;
+
+        emc-timings-3 {
+            nvidia,ram-code = <3>;
+
+            timing-12750000 {
+                clock-frequency = <12750000>;
+
+                nvidia,emem-configuration = <
+                    0x40040001 /* MC_EMEM_ARB_CFG */
+                    0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                    0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                    0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                    0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                    0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                    0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                    0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                    0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                    0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                    0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                    0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                    0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                    0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                    0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                    0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                    0x77e30303 /* MC_EMEM_ARB_MISC0 */
+                    0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                    0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                >;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml
new file mode 100644 (file)
index 0000000..7fe0ca1
--- /dev/null
@@ -0,0 +1,336 @@
+# SPDX-License-Identifier: (GPL-2.0)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/nvidia,tegra30-emc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra30 SoC External Memory Controller
+
+maintainers:
+  - Dmitry Osipenko <digetx@gmail.com>
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Thierry Reding <thierry.reding@gmail.com>
+
+description: |
+  The EMC interfaces with the off-chip SDRAM to service the request stream
+  sent from Memory Controller. The EMC also has various performance-affecting
+  settings beyond the obvious SDRAM configuration parameters and initialization
+  settings. Tegra30 EMC supports multiple JEDEC standard protocols: LPDDR2,
+  LPDDR3, and DDR3.
+
+properties:
+  compatible:
+    const: nvidia,tegra30-emc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  nvidia,memory-controller:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle of the Memory Controller node.
+
+patternProperties:
+  "^emc-timings-[0-9]+$":
+    type: object
+    properties:
+      nvidia,ram-code:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          Value of RAM_CODE this timing set is used for.
+
+    patternProperties:
+      "^timing-[0-9]+$":
+        type: object
+        properties:
+          clock-frequency:
+            description:
+              Memory clock rate in Hz.
+            minimum: 1000000
+            maximum: 900000000
+
+          nvidia,emc-auto-cal-interval:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description:
+              Pad calibration interval in microseconds.
+            minimum: 0
+            maximum: 2097151
+
+          nvidia,emc-mode-1:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description:
+              Mode Register 1.
+
+          nvidia,emc-mode-2:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description:
+              Mode Register 2.
+
+          nvidia,emc-mode-reset:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description:
+              Mode Register 0.
+
+          nvidia,emc-zcal-cnt-long:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description:
+              Number of EMC clocks to wait before issuing any commands after
+              sending ZCAL_MRW_CMD.
+            minimum: 0
+            maximum: 1023
+
+          nvidia,emc-cfg-dyn-self-ref:
+            type: boolean
+            description:
+              Dynamic self-refresh enabled.
+
+          nvidia,emc-cfg-periodic-qrst:
+            type: boolean
+            description:
+              FBIO "read" FIFO periodic resetting enabled.
+
+          nvidia,emc-configuration:
+            $ref: /schemas/types.yaml#/definitions/uint32-array
+            description:
+              EMC timing characterization data. These are the registers
+              (see section "18.13.2 EMC Registers" in the TRM) whose values
+              need to be specified, according to the board documentation.
+            items:
+              - description: EMC_RC
+              - description: EMC_RFC
+              - description: EMC_RAS
+              - description: EMC_RP
+              - description: EMC_R2W
+              - description: EMC_W2R
+              - description: EMC_R2P
+              - description: EMC_W2P
+              - description: EMC_RD_RCD
+              - description: EMC_WR_RCD
+              - description: EMC_RRD
+              - description: EMC_REXT
+              - description: EMC_WEXT
+              - description: EMC_WDV
+              - description: EMC_QUSE
+              - description: EMC_QRST
+              - description: EMC_QSAFE
+              - description: EMC_RDV
+              - description: EMC_REFRESH
+              - description: EMC_BURST_REFRESH_NUM
+              - description: EMC_PRE_REFRESH_REQ_CNT
+              - description: EMC_PDEX2WR
+              - description: EMC_PDEX2RD
+              - description: EMC_PCHG2PDEN
+              - description: EMC_ACT2PDEN
+              - description: EMC_AR2PDEN
+              - description: EMC_RW2PDEN
+              - description: EMC_TXSR
+              - description: EMC_TXSRDLL
+              - description: EMC_TCKE
+              - description: EMC_TFAW
+              - description: EMC_TRPAB
+              - description: EMC_TCLKSTABLE
+              - description: EMC_TCLKSTOP
+              - description: EMC_TREFBW
+              - description: EMC_QUSE_EXTRA
+              - description: EMC_FBIO_CFG6
+              - description: EMC_ODT_WRITE
+              - description: EMC_ODT_READ
+              - description: EMC_FBIO_CFG5
+              - description: EMC_CFG_DIG_DLL
+              - description: EMC_CFG_DIG_DLL_PERIOD
+              - description: EMC_DLL_XFORM_DQS0
+              - description: EMC_DLL_XFORM_DQS1
+              - description: EMC_DLL_XFORM_DQS2
+              - description: EMC_DLL_XFORM_DQS3
+              - description: EMC_DLL_XFORM_DQS4
+              - description: EMC_DLL_XFORM_DQS5
+              - description: EMC_DLL_XFORM_DQS6
+              - description: EMC_DLL_XFORM_DQS7
+              - description: EMC_DLL_XFORM_QUSE0
+              - description: EMC_DLL_XFORM_QUSE1
+              - description: EMC_DLL_XFORM_QUSE2
+              - description: EMC_DLL_XFORM_QUSE3
+              - description: EMC_DLL_XFORM_QUSE4
+              - description: EMC_DLL_XFORM_QUSE5
+              - description: EMC_DLL_XFORM_QUSE6
+              - description: EMC_DLL_XFORM_QUSE7
+              - description: EMC_DLI_TRIM_TXDQS0
+              - description: EMC_DLI_TRIM_TXDQS1
+              - description: EMC_DLI_TRIM_TXDQS2
+              - description: EMC_DLI_TRIM_TXDQS3
+              - description: EMC_DLI_TRIM_TXDQS4
+              - description: EMC_DLI_TRIM_TXDQS5
+              - description: EMC_DLI_TRIM_TXDQS6
+              - description: EMC_DLI_TRIM_TXDQS7
+              - description: EMC_DLL_XFORM_DQ0
+              - description: EMC_DLL_XFORM_DQ1
+              - description: EMC_DLL_XFORM_DQ2
+              - description: EMC_DLL_XFORM_DQ3
+              - description: EMC_XM2CMDPADCTRL
+              - description: EMC_XM2DQSPADCTRL2
+              - description: EMC_XM2DQPADCTRL2
+              - description: EMC_XM2CLKPADCTRL
+              - description: EMC_XM2COMPPADCTRL
+              - description: EMC_XM2VTTGENPADCTRL
+              - description: EMC_XM2VTTGENPADCTRL2
+              - description: EMC_XM2QUSEPADCTRL
+              - description: EMC_XM2DQSPADCTRL3
+              - description: EMC_CTT_TERM_CTRL
+              - description: EMC_ZCAL_INTERVAL
+              - description: EMC_ZCAL_WAIT_CNT
+              - description: EMC_MRS_WAIT_CNT
+              - description: EMC_AUTO_CAL_CONFIG
+              - description: EMC_CTT
+              - description: EMC_CTT_DURATION
+              - description: EMC_DYN_SELF_REF_CONTROL
+              - description: EMC_FBIO_SPARE
+              - description: EMC_CFG_RSV
+
+        required:
+          - clock-frequency
+          - nvidia,emc-auto-cal-interval
+          - nvidia,emc-mode-1
+          - nvidia,emc-mode-2
+          - nvidia,emc-mode-reset
+          - nvidia,emc-zcal-cnt-long
+          - nvidia,emc-configuration
+
+        additionalProperties: false
+
+    required:
+      - nvidia,ram-code
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - nvidia,memory-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    external-memory-controller@7000f400 {
+        compatible = "nvidia,tegra30-emc";
+        reg = <0x7000f400 0x400>;
+        interrupts = <0 78 4>;
+        clocks = <&tegra_car 57>;
+
+        nvidia,memory-controller = <&mc>;
+
+        emc-timings-1 {
+            nvidia,ram-code = <1>;
+
+            timing-667000000 {
+                clock-frequency = <667000000>;
+
+                nvidia,emc-auto-cal-interval = <0x001fffff>;
+                nvidia,emc-mode-1 = <0x80100002>;
+                nvidia,emc-mode-2 = <0x80200018>;
+                nvidia,emc-mode-reset = <0x80000b71>;
+                nvidia,emc-zcal-cnt-long = <0x00000040>;
+                nvidia,emc-cfg-periodic-qrst;
+
+                nvidia,emc-configuration = <
+                    0x00000020 /* EMC_RC */
+                    0x0000006a /* EMC_RFC */
+                    0x00000017 /* EMC_RAS */
+                    0x00000007 /* EMC_RP */
+                    0x00000005 /* EMC_R2W */
+                    0x0000000c /* EMC_W2R */
+                    0x00000003 /* EMC_R2P */
+                    0x00000011 /* EMC_W2P */
+                    0x00000007 /* EMC_RD_RCD */
+                    0x00000007 /* EMC_WR_RCD */
+                    0x00000002 /* EMC_RRD */
+                    0x00000001 /* EMC_REXT */
+                    0x00000000 /* EMC_WEXT */
+                    0x00000007 /* EMC_WDV */
+                    0x0000000a /* EMC_QUSE */
+                    0x00000009 /* EMC_QRST */
+                    0x0000000b /* EMC_QSAFE */
+                    0x00000011 /* EMC_RDV */
+                    0x00001412 /* EMC_REFRESH */
+                    0x00000000 /* EMC_BURST_REFRESH_NUM */
+                    0x00000504 /* EMC_PRE_REFRESH_REQ_CNT */
+                    0x00000002 /* EMC_PDEX2WR */
+                    0x0000000e /* EMC_PDEX2RD */
+                    0x00000001 /* EMC_PCHG2PDEN */
+                    0x00000000 /* EMC_ACT2PDEN */
+                    0x0000000c /* EMC_AR2PDEN */
+                    0x00000016 /* EMC_RW2PDEN */
+                    0x00000072 /* EMC_TXSR */
+                    0x00000200 /* EMC_TXSRDLL */
+                    0x00000005 /* EMC_TCKE */
+                    0x00000015 /* EMC_TFAW */
+                    0x00000000 /* EMC_TRPAB */
+                    0x00000006 /* EMC_TCLKSTABLE */
+                    0x00000007 /* EMC_TCLKSTOP */
+                    0x00001453 /* EMC_TREFBW */
+                    0x0000000b /* EMC_QUSE_EXTRA */
+                    0x00000006 /* EMC_FBIO_CFG6 */
+                    0x00000000 /* EMC_ODT_WRITE */
+                    0x00000000 /* EMC_ODT_READ */
+                    0x00005088 /* EMC_FBIO_CFG5 */
+                    0xf00b0191 /* EMC_CFG_DIG_DLL */
+                    0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                    0x00000008 /* EMC_DLL_XFORM_DQS0 */
+                    0x00000008 /* EMC_DLL_XFORM_DQS1 */
+                    0x00000008 /* EMC_DLL_XFORM_DQS2 */
+                    0x00000008 /* EMC_DLL_XFORM_DQS3 */
+                    0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                    0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                    0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                    0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                    0x00018000 /* EMC_DLL_XFORM_QUSE0 */
+                    0x00018000 /* EMC_DLL_XFORM_QUSE1 */
+                    0x00018000 /* EMC_DLL_XFORM_QUSE2 */
+                    0x00018000 /* EMC_DLL_XFORM_QUSE3 */
+                    0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                    0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                    0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                    0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                    0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                    0x0000000a /* EMC_DLL_XFORM_DQ0 */
+                    0x0000000a /* EMC_DLL_XFORM_DQ1 */
+                    0x0000000a /* EMC_DLL_XFORM_DQ2 */
+                    0x0000000a /* EMC_DLL_XFORM_DQ3 */
+                    0x000002a0 /* EMC_XM2CMDPADCTRL */
+                    0x0800013d /* EMC_XM2DQSPADCTRL2 */
+                    0x22220000 /* EMC_XM2DQPADCTRL2 */
+                    0x77fff884 /* EMC_XM2CLKPADCTRL */
+                    0x01f1f501 /* EMC_XM2COMPPADCTRL */
+                    0x07077404 /* EMC_XM2VTTGENPADCTRL */
+                    0x54000000 /* EMC_XM2VTTGENPADCTRL2 */
+                    0x080001e8 /* EMC_XM2QUSEPADCTRL */
+                    0x0c000021 /* EMC_XM2DQSPADCTRL3 */
+                    0x00000802 /* EMC_CTT_TERM_CTRL */
+                    0x00020000 /* EMC_ZCAL_INTERVAL */
+                    0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                    0x0155000c /* EMC_MRS_WAIT_CNT */
+                    0xa0f10000 /* EMC_AUTO_CAL_CONFIG */
+                    0x00000000 /* EMC_CTT */
+                    0x00000000 /* EMC_CTT_DURATION */
+                    0x800028a5 /* EMC_DYN_SELF_REF_CONTROL */
+                    0xe8000000 /* EMC_FBIO_SPARE */
+                    0xff00ff49 /* EMC_CFG_RSV */
+                >;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt
deleted file mode 100644 (file)
index a878b59..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-NVIDIA Tegra Memory Controller device tree bindings
-===================================================
-
-memory-controller node
-----------------------
-
-Required properties:
-- compatible: Should be "nvidia,tegra<chip>-mc"
-- reg: Physical base address and length of the controller's registers.
-- clocks: Must contain an entry for each entry in clock-names.
-  See ../clocks/clock-bindings.txt for details.
-- clock-names: Must include the following entries:
-  - mc: the module's clock input
-- interrupts: The interrupt outputs from the controller.
-- #reset-cells : Should be 1. This cell represents memory client module ID.
-  The assignments may be found in header file <dt-bindings/memory/tegra30-mc.h>
-  or in the TRM documentation.
-
-Required properties for Tegra30, Tegra114, Tegra124, Tegra132 and Tegra210:
-- #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines
-  the SWGROUP of the master.
-
-This device implements an IOMMU that complies with the generic IOMMU binding.
-See ../iommu/iommu.txt for details.
-
-emc-timings subnode
--------------------
-
-The node should contain a "emc-timings" subnode for each supported RAM type (see field RAM_CODE in
-register PMC_STRAPPING_OPT_A).
-
-Required properties for "emc-timings" nodes :
-- nvidia,ram-code : Should contain the value of RAM_CODE this timing set is used for.
-
-timing subnode
---------------
-
-Each "emc-timings" node should contain a subnode for every supported EMC clock rate.
-
-Required properties for timing nodes :
-- clock-frequency : Should contain the memory clock rate in Hz.
-- nvidia,emem-configuration : Values to be written to the EMEM register block. For the Tegra124 SoC
-(see section "15.6.1 MC Registers" in the TRM), these are the registers whose values need to be
-specified, according to the board documentation:
-
-       MC_EMEM_ARB_CFG
-       MC_EMEM_ARB_OUTSTANDING_REQ
-       MC_EMEM_ARB_TIMING_RCD
-       MC_EMEM_ARB_TIMING_RP
-       MC_EMEM_ARB_TIMING_RC
-       MC_EMEM_ARB_TIMING_RAS
-       MC_EMEM_ARB_TIMING_FAW
-       MC_EMEM_ARB_TIMING_RRD
-       MC_EMEM_ARB_TIMING_RAP2PRE
-       MC_EMEM_ARB_TIMING_WAP2PRE
-       MC_EMEM_ARB_TIMING_R2R
-       MC_EMEM_ARB_TIMING_W2W
-       MC_EMEM_ARB_TIMING_R2W
-       MC_EMEM_ARB_TIMING_W2R
-       MC_EMEM_ARB_DA_TURNS
-       MC_EMEM_ARB_DA_COVERS
-       MC_EMEM_ARB_MISC0
-       MC_EMEM_ARB_MISC1
-       MC_EMEM_ARB_RING1_THROTTLE
-
-Example SoC include file:
-
-/ {
-       mc: memory-controller@70019000 {
-               compatible = "nvidia,tegra124-mc";
-               reg = <0x0 0x70019000 0x0 0x1000>;
-               clocks = <&tegra_car TEGRA124_CLK_MC>;
-               clock-names = "mc";
-
-               interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
-
-               #iommu-cells = <1>;
-               #reset-cells = <1>;
-       };
-
-       sdhci@700b0000 {
-               compatible = "nvidia,tegra124-sdhci";
-               ...
-               iommus = <&mc TEGRA_SWGROUP_SDMMC1A>;
-               resets = <&mc TEGRA124_MC_RESET_SDMMC1>;
-       };
-};
-
-Example board file:
-
-/ {
-       memory-controller@70019000 {
-               emc-timings-3 {
-                       nvidia,ram-code = <3>;
-
-                       timing-12750000 {
-                               clock-frequency = <12750000>;
-
-                               nvidia,emem-configuration = <
-                                       0x40040001 /* MC_EMEM_ARB_CFG */
-                                       0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */
-                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
-                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
-                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
-                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
-                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
-                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
-                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
-                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
-                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
-                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
-                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
-                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
-                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
-                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
-                                       0x77e30303 /* MC_EMEM_ARB_MISC0 */
-                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
-                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
-                               >;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml
new file mode 100644 (file)
index 0000000..84fd57b
--- /dev/null
@@ -0,0 +1,167 @@
+# SPDX-License-Identifier: (GPL-2.0)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/nvidia,tegra30-mc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra30 SoC Memory Controller
+
+maintainers:
+  - Dmitry Osipenko <digetx@gmail.com>
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Thierry Reding <thierry.reding@gmail.com>
+
+description: |
+  Tegra30 Memory Controller architecturally consists of the following parts:
+
+    Arbitration Domains, which can handle a single request or response per
+    clock from a group of clients. Typically, a system has a single Arbitration
+    Domain, but an implementation may divide the client space into multiple
+    Arbitration Domains to increase the effective system bandwidth.
+
+    Protocol Arbiter, which manage a related pool of memory devices. A system
+    may have a single Protocol Arbiter or multiple Protocol Arbiters.
+
+    Memory Crossbar, which routes request and responses between Arbitration
+    Domains and Protocol Arbiters. In the simplest version of the system, the
+    Memory Crossbar is just a pass through between a single Arbitration Domain
+    and a single Protocol Arbiter.
+
+    Global Resources, which include things like configuration registers which
+    are shared across the Memory Subsystem.
+
+  The Tegra30 Memory Controller handles memory requests from internal clients
+  and arbitrates among them to allocate memory bandwidth for DDR3L and LPDDR2
+  SDRAMs.
+
+properties:
+  compatible:
+    const: nvidia,tegra30-mc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: mc
+
+  interrupts:
+    maxItems: 1
+
+  "#reset-cells":
+    const: 1
+
+  "#iommu-cells":
+    const: 1
+
+patternProperties:
+  "^emc-timings-[0-9]+$":
+    type: object
+    properties:
+      nvidia,ram-code:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          Value of RAM_CODE this timing set is used for.
+
+    patternProperties:
+      "^timing-[0-9]+$":
+        type: object
+        properties:
+          clock-frequency:
+            description:
+              Memory clock rate in Hz.
+            minimum: 1000000
+            maximum: 900000000
+
+          nvidia,emem-configuration:
+            $ref: /schemas/types.yaml#/definitions/uint32-array
+            description: |
+              Values to be written to the EMEM register block. See section
+              "18.13.1 MC Registers" in the TRM.
+            items:
+              - description: MC_EMEM_ARB_CFG
+              - description: MC_EMEM_ARB_OUTSTANDING_REQ
+              - description: MC_EMEM_ARB_TIMING_RCD
+              - description: MC_EMEM_ARB_TIMING_RP
+              - description: MC_EMEM_ARB_TIMING_RC
+              - description: MC_EMEM_ARB_TIMING_RAS
+              - description: MC_EMEM_ARB_TIMING_FAW
+              - description: MC_EMEM_ARB_TIMING_RRD
+              - description: MC_EMEM_ARB_TIMING_RAP2PRE
+              - description: MC_EMEM_ARB_TIMING_WAP2PRE
+              - description: MC_EMEM_ARB_TIMING_R2R
+              - description: MC_EMEM_ARB_TIMING_W2W
+              - description: MC_EMEM_ARB_TIMING_R2W
+              - description: MC_EMEM_ARB_TIMING_W2R
+              - description: MC_EMEM_ARB_DA_TURNS
+              - description: MC_EMEM_ARB_DA_COVERS
+              - description: MC_EMEM_ARB_MISC0
+              - description: MC_EMEM_ARB_RING1_THROTTLE
+
+        required:
+          - clock-frequency
+          - nvidia,emem-configuration
+
+        additionalProperties: false
+
+    required:
+      - nvidia,ram-code
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - "#reset-cells"
+  - "#iommu-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    memory-controller@7000f000 {
+        compatible = "nvidia,tegra30-mc";
+        reg = <0x7000f000 0x400>;
+        clocks = <&tegra_car 32>;
+        clock-names = "mc";
+
+        interrupts = <0 77 4>;
+
+        #iommu-cells = <1>;
+        #reset-cells = <1>;
+
+        emc-timings-1 {
+            nvidia,ram-code = <1>;
+
+            timing-667000000 {
+                clock-frequency = <667000000>;
+
+                nvidia,emem-configuration = <
+                    0x0000000a /* MC_EMEM_ARB_CFG */
+                    0xc0000079 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                    0x00000003 /* MC_EMEM_ARB_TIMING_RCD */
+                    0x00000004 /* MC_EMEM_ARB_TIMING_RP */
+                    0x00000010 /* MC_EMEM_ARB_TIMING_RC */
+                    0x0000000b /* MC_EMEM_ARB_TIMING_RAS */
+                    0x0000000a /* MC_EMEM_ARB_TIMING_FAW */
+                    0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                    0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                    0x0000000b /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                    0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                    0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                    0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                    0x00000008 /* MC_EMEM_ARB_TIMING_W2R */
+                    0x08040202 /* MC_EMEM_ARB_DA_TURNS */
+                    0x00130b10 /* MC_EMEM_ARB_DA_COVERS */
+                    0x70ea1f11 /* MC_EMEM_ARB_MISC0 */
+                    0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                >;
+            };
+        };
+    };
index d759da6..30ea27c 100644 (file)
@@ -18,7 +18,7 @@ an optional sub-node. For "samsung,exynos5433-lpass" compatible this includes:
 UART, SLIMBUS, PCM, I2S, DMAC, Timers 0...4, VIC, WDT 0...1 devices.
 
 Bindings of the sub-nodes are described in:
-  ../serial/samsung_uart.txt
+  ../serial/samsung_uart.yaml
   ../sound/samsung-i2s.txt
   ../dma/arm-pl330.txt
 
diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
new file mode 100644 (file)
index 0000000..1a4cc5f
--- /dev/null
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/st,stm32-lptimer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Low-Power Timers bindings
+
+description: |
+  The STM32 Low-Power Timer (LPTIM) is a 16-bit timer that provides several
+  functions
+   - PWM output (with programmable prescaler, configurable polarity)
+   - Trigger source for STM32 ADC/DAC (LPTIM_OUT)
+   - Several counter modes:
+     - quadrature encoder to detect angular position and direction of rotary
+       elements, from IN1 and IN2 input signals.
+     - simple counter from IN1 input signal.
+
+maintainers:
+  - Fabrice Gasnier <fabrice.gasnier@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-lptimer
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: mux
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  pwm:
+    type: object
+
+    properties:
+      compatible:
+        const: st,stm32-pwm-lp
+
+      "#pwm-cells":
+        const: 3
+
+    required:
+      - "#pwm-cells"
+      - compatible
+
+patternProperties:
+  "^trigger@[0-9]+$":
+    type: object
+
+    properties:
+      compatible:
+        const: st,stm32-lptimer-trigger
+
+      reg:
+        description: Identify trigger hardware block.
+        items:
+         minimum: 0
+         maximum: 2
+
+    required:
+      - compatible
+      - reg
+
+  counter:
+    type: object
+
+    properties:
+      compatible:
+        const: st,stm32-lptimer-counter
+
+    required:
+      - compatible
+
+required:
+  - "#address-cells"
+  - "#size-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    timer@40002400 {
+      compatible = "st,stm32-lptimer";
+      reg = <0x40002400 0x400>;
+      clocks = <&timer_clk>;
+      clock-names = "mux";
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      pwm {
+        compatible = "st,stm32-pwm-lp";
+        #pwm-cells = <3>;
+      };
+
+      trigger@0 {
+        compatible = "st,stm32-lptimer-trigger";
+        reg = <0>;
+      };
+
+      counter {
+        compatible = "st,stm32-lptimer-counter";
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml b/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml
new file mode 100644 (file)
index 0000000..590849e
--- /dev/null
@@ -0,0 +1,162 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/st,stm32-timers.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Timers bindings
+
+description: |
+  This hardware block provides 3 types of timer along with PWM functionality:
+    - advanced-control timers consist of a 16-bit auto-reload counter driven
+      by a programmable prescaler, break input feature, PWM outputs and
+      complementary PWM outputs channels.
+    - general-purpose timers consist of a 16-bit or 32-bit auto-reload counter
+      driven by a programmable prescaler and PWM outputs.
+    - basic timers consist of a 16-bit auto-reload counter driven by a
+      programmable prescaler.
+
+maintainers:
+  - Benjamin Gaignard <benjamin.gaignard@st.com>
+  - Fabrice Gasnier <fabrice.gasnier@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-timers
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: int
+
+  reset:
+    maxItems: 1
+
+  dmas:
+    minItems: 1
+    maxItems: 7
+
+  dma-names:
+    items:
+      enum: [ ch1, ch2, ch3, ch4, up, trig, com ]
+    minItems: 1
+    maxItems: 7
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  pwm:
+    type: object
+
+    properties:
+      compatible:
+        const: st,stm32-pwm
+
+      "#pwm-cells":
+        const: 3
+
+      st,breakinput:
+        description:
+          One or two <index level filter> to describe break input
+          configurations.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-matrix
+          - items:
+              items:
+                - description: |
+                    "index" indicates on which break input (0 or 1) the
+                    configuration should be applied.
+                  enum: [ 0 , 1]
+                - description: |
+                    "level" gives the active level (0=low or 1=high) of the
+                    input signal for this configuration
+                  enum: [ 0, 1 ]
+                - description: |
+                    "filter" gives the filtering value (up to 15) to be applied.
+                  maximum: 15
+            minItems: 1
+            maxItems: 2
+
+    required:
+      - "#pwm-cells"
+      - compatible
+
+patternProperties:
+  "^timer@[0-9]+$":
+    type: object
+
+    properties:
+      compatible:
+        enum:
+          - st,stm32-timer-trigger
+          - st,stm32h7-timer-trigger
+
+      reg:
+        description: Identify trigger hardware block.
+        items:
+         minimum: 0
+         maximum: 16
+
+    required:
+      - compatible
+      - reg
+
+  counter:
+    type: object
+
+    properties:
+      compatible:
+        const: st,stm32-timer-counter
+
+    required:
+      - compatible
+
+required:
+  - "#address-cells"
+  - "#size-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    timers2: timers@40000000 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      compatible = "st,stm32-timers";
+      reg = <0x40000000 0x400>;
+      clocks = <&rcc TIM2_K>;
+      clock-names = "int";
+      dmas = <&dmamux1 18 0x400 0x1>,
+             <&dmamux1 19 0x400 0x1>,
+             <&dmamux1 20 0x400 0x1>,
+             <&dmamux1 21 0x400 0x1>,
+             <&dmamux1 22 0x400 0x1>;
+      dma-names = "ch1", "ch2", "ch3", "ch4", "up";
+      pwm {
+        compatible = "st,stm32-pwm";
+        #pwm-cells = <3>;
+        st,breakinput = <0 1 5>;
+      };
+      timer@0 {
+        compatible = "st,stm32-timer-trigger";
+        reg = <0>;
+      };
+      counter {
+        compatible = "st,stm32-timer-counter";
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt b/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt
deleted file mode 100644 (file)
index fb54e4d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-STMicroelectronics STM32 Low-Power Timer
-
-The STM32 Low-Power Timer (LPTIM) is a 16-bit timer that provides several
-functions:
-- PWM output (with programmable prescaler, configurable polarity)
-- Quadrature encoder, counter
-- Trigger source for STM32 ADC/DAC (LPTIM_OUT)
-
-Required properties:
-- compatible:          Must be "st,stm32-lptimer".
-- reg:                 Offset and length of the device's register set.
-- clocks:              Phandle to the clock used by the LP Timer module.
-- clock-names:         Must be "mux".
-- #address-cells:      Should be '<1>'.
-- #size-cells:         Should be '<0>'.
-
-Optional subnodes:
-- pwm:                 See ../pwm/pwm-stm32-lp.txt
-- counter:             See ../counter/stm32-lptimer-cnt.txt
-- trigger:             See ../iio/timer/stm32-lptimer-trigger.txt
-
-Example:
-
-       timer@40002400 {
-               compatible = "st,stm32-lptimer";
-               reg = <0x40002400 0x400>;
-               clocks = <&timer_clk>;
-               clock-names = "mux";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               pwm {
-                       compatible = "st,stm32-pwm-lp";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&lppwm1_pins>;
-               };
-
-               trigger@0 {
-                       compatible = "st,stm32-lptimer-trigger";
-                       reg = <0>;
-               };
-
-               counter {
-                       compatible = "st,stm32-lptimer-counter";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&lptim1_in_pins>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/mfd/stm32-timers.txt b/Documentation/devicetree/bindings/mfd/stm32-timers.txt
deleted file mode 100644 (file)
index 15c3b87..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-STM32 Timers driver bindings
-
-This IP provides 3 types of timer along with PWM functionality:
-- advanced-control timers consist of a 16-bit auto-reload counter driven by a programmable
-  prescaler, break input feature, PWM outputs and complementary PWM ouputs channels.
-- general-purpose timers consist of a 16-bit or 32-bit auto-reload counter driven by a
-  programmable prescaler and PWM outputs.
-- basic timers consist of a 16-bit auto-reload counter driven by a programmable prescaler.
-
-Required parameters:
-- compatible: must be "st,stm32-timers"
-
-- reg:                 Physical base address and length of the controller's
-                       registers.
-- clock-names:         Set to "int".
-- clocks:              Phandle to the clock used by the timer module.
-                       For Clk properties, please refer to ../clock/clock-bindings.txt
-
-Optional parameters:
-- resets:              Phandle to the parent reset controller.
-                       See ../reset/st,stm32-rcc.txt
-- dmas:                        List of phandle to dma channels that can be used for
-                       this timer instance. There may be up to 7 dma channels.
-- dma-names:           List of dma names. Must match 'dmas' property. Valid
-                       names are: "ch1", "ch2", "ch3", "ch4", "up", "trig",
-                       "com".
-
-Optional subnodes:
-- pwm:                 See ../pwm/pwm-stm32.txt
-- timer:               See ../iio/timer/stm32-timer-trigger.txt
-- counter:             See ../counter/stm32-timer-cnt.txt
-
-Example:
-       timers@40010000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "st,stm32-timers";
-               reg = <0x40010000 0x400>;
-               clocks = <&rcc 0 160>;
-               clock-names = "int";
-
-               pwm {
-                       compatible = "st,stm32-pwm";
-                       pinctrl-0       = <&pwm1_pins>;
-                       pinctrl-names   = "default";
-               };
-
-               timer@0 {
-                       compatible = "st,stm32-timer-trigger";
-                       reg = <0>;
-               };
-
-               counter {
-                       compatible = "st,stm32-timer-counter";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&tim1_in_pins>;
-               };
-       };
-
-Example with all dmas:
-       timer@40010000 {
-               ...
-               dmas = <&dmamux1 11 0x400 0x0>,
-                      <&dmamux1 12 0x400 0x0>,
-                      <&dmamux1 13 0x400 0x0>,
-                      <&dmamux1 14 0x400 0x0>,
-                      <&dmamux1 15 0x400 0x0>,
-                      <&dmamux1 16 0x400 0x0>,
-                      <&dmamux1 17 0x400 0x0>;
-               dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig", "com";
-               ...
-               child nodes...
-       };
diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt
deleted file mode 100644 (file)
index 25d9e9c..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-* System Controller Registers R/W driver
-
-System controller node represents a register region containing a set
-of miscellaneous registers. The registers are not cohesive enough to
-represent as any specific type of device. The typical use-case is for
-some other node's driver, or platform-specific code, to acquire a
-reference to the syscon node (e.g. by phandle, node path, or search
-using a specific compatible value), interrogate the node (or associated
-OS driver) to determine the location of the registers, and access the
-registers directly.
-
-Required properties:
-- compatible: Should contain "syscon".
-- reg: the register region can be accessed from syscon
-
-Optional property:
-- reg-io-width: the size (in bytes) of the IO accesses that should be
-  performed on the device.
-- hwlocks: reference to a phandle of a hardware spinlock provider node.
-
-Examples:
-gpr: iomuxc-gpr@20e0000 {
-       compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
-       reg = <0x020e0000 0x38>;
-       hwlocks = <&hwlock1 1>;
-};
-
-hwlock1: hwspinlock@40500000 {
-       ...
-       reg = <0x40500000 0x1000>;
-       #hwlock-cells = <1>;
-};
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
new file mode 100644 (file)
index 0000000..39375e4
--- /dev/null
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/syscon.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: System Controller Registers R/W Device Tree Bindings
+
+description: |
+  System controller node represents a register region containing a set
+  of miscellaneous registers. The registers are not cohesive enough to
+  represent as any specific type of device. The typical use-case is
+  for some other node's driver, or platform-specific code, to acquire
+  a reference to the syscon node (e.g. by phandle, node path, or
+  search using a specific compatible value), interrogate the node (or
+  associated OS driver) to determine the location of the registers,
+  and access the registers directly.
+
+maintainers:
+  - Lee Jones <lee.jones@linaro.org>
+
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - syscon
+
+  required:
+    - compatible
+
+properties:
+  compatible:
+    anyOf:
+      - items:
+        - enum:
+          - allwinner,sun8i-a83t-system-controller
+          - allwinner,sun8i-h3-system-controller
+          - allwinner,sun8i-v3s-system-controller
+          - allwinner,sun50i-a64-system-controller
+
+        - const: syscon
+
+      - contains:
+          const: syscon
+        additionalItems: true
+
+  reg:
+    maxItems: 1
+
+  reg-io-width:
+    description: |
+      The size (in bytes) of the IO accesses that should be performed
+      on the device.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [ 1, 2, 4, 8 ]
+
+  hwlocks:
+    maxItems: 1
+    description:
+      Reference to a phandle of a hardware spinlock provider node.
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    syscon: syscon@1c00000 {
+        compatible = "allwinner,sun8i-h3-system-controller", "syscon";
+        reg = <0x01c00000 0x1000>;
+    };
+
+  - |
+    gpr: iomuxc-gpr@20e0000 {
+        compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
+        reg = <0x020e0000 0x38>;
+        hwlocks = <&hwlock1 1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/misc/allwinner,syscon.txt b/Documentation/devicetree/bindings/misc/allwinner,syscon.txt
deleted file mode 100644 (file)
index 31494a2..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-* Allwinner sun8i system controller
-
-This file describes the bindings for the system controller present in
-Allwinner SoC H3, A83T and A64.
-The principal function of this syscon is to control EMAC PHY choice and
-config.
-
-Required properties for the system controller:
-- reg: address and length of the register for the device.
-- compatible: should be "syscon" and one of the following string:
-               "allwinner,sun8i-h3-system-controller"
-               "allwinner,sun8i-v3s-system-controller"
-               "allwinner,sun50i-a64-system-controller"
-               "allwinner,sun8i-a83t-system-controller"
-
-Example:
-syscon: syscon@1c00000 {
-       compatible = "allwinner,sun8i-h3-system-controller", "syscon";
-       reg = <0x01c00000 0x1000>;
-};
index d2d4308..64bca41 100644 (file)
@@ -85,6 +85,8 @@ required:
   - clocks
   - clock-names
 
+unevaluatedProperties: false
+
 examples:
   - |
     mmc0: mmc@1c0f000 {
@@ -97,8 +99,4 @@ examples:
         cd-gpios = <&pio 7 1 0>;
     };
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
-
 ...
diff --git a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml
new file mode 100644 (file)
index 0000000..b059267
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/st,stm32-fmc2-nand.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings
+
+maintainers:
+  - Christophe Kerello <christophe.kerello@st.com>
+
+allOf:
+  - $ref: "nand-controller.yaml#"
+
+properties:
+  compatible:
+    const: st,stm32mp15-fmc2
+
+  reg:
+    items:
+      - description: Registers
+      - description: Chip select 0 data
+      - description: Chip select 0 command
+      - description: Chip select 0 address space
+      - description: Chip select 1 data
+      - description: Chip select 1 command
+      - description: Chip select 1 address space
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  dmas:
+    items:
+      - description: tx DMA channel
+      - description: rx DMA channel
+      - description: ecc DMA channel
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+      - const: ecc
+
+patternProperties:
+  "^nand@[a-f0-9]$":
+    type: object
+    properties:
+      nand-ecc-step-size:
+        const: 512
+
+      nand-ecc-strength:
+        enum: [1, 4 ,8 ]
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    nand-controller@58002000 {
+      compatible = "st,stm32mp15-fmc2";
+      reg = <0x58002000 0x1000>,
+            <0x80000000 0x1000>,
+            <0x88010000 0x1000>,
+            <0x88020000 0x1000>,
+            <0x81000000 0x1000>,
+            <0x89010000 0x1000>,
+            <0x89020000 0x1000>;
+            interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+            dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>,
+                   <&mdma1 20 0x10 0x12000a08 0x0 0x0>,
+                   <&mdma1 21 0x10 0x12000a0a 0x0 0x0>;
+            dma-names = "tx", "rx", "ecc";
+            clocks = <&rcc FMC_K>;
+            resets = <&rcc FMC_R>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      nand@0 {
+        reg = <0>;
+        nand-on-flash-bbt;
+        #address-cells = <1>;
+        #size-cells = <1>;
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt b/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt
deleted file mode 100644 (file)
index e55895e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-STMicroelectronics Flexible Memory Controller 2 (FMC2)
-NAND Interface
-
-Required properties:
-- compatible: Should be one of:
-              * st,stm32mp15-fmc2
-- reg: NAND flash controller memory areas.
-       First region contains the register location.
-       Regions 2 to 4 respectively contain the data, command,
-       and address space for CS0.
-       Regions 5 to 7 contain the same areas for CS1.
-- interrupts: The interrupt number
-- pinctrl-0: Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt)
-- clocks: The clock needed by the NAND flash controller
-
-Optional properties:
-- resets: Reference to a reset controller asserting the FMC controller
-- dmas: DMA specifiers (see: dma/stm32-mdma.txt)
-- dma-names: Must be "tx", "rx" and "ecc"
-
-* NAND device bindings:
-
-Required properties:
-- reg: describes the CS lines assigned to the NAND device.
-
-Optional properties:
-- nand-on-flash-bbt: see nand-controller.yaml
-- nand-ecc-strength: see nand-controller.yaml
-- nand-ecc-step-size: see nand-controller.yaml
-
-The following ECC strength and step size are currently supported:
- - nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Hamming)
- - nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4)
- - nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) (default)
-
-Example:
-
-       fmc: nand-controller@58002000 {
-               compatible = "st,stm32mp15-fmc2";
-               reg = <0x58002000 0x1000>,
-                     <0x80000000 0x1000>,
-                     <0x88010000 0x1000>,
-                     <0x88020000 0x1000>,
-                     <0x81000000 0x1000>,
-                     <0x89010000 0x1000>,
-                     <0x89020000 0x1000>;
-               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&rcc FMC_K>;
-               resets = <&rcc FMC_R>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&fmc_pins_a>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               nand@0 {
-                       reg = <0>;
-                       nand-on-flash-bbt;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-               };
-       };
index 792196b..ae4796e 100644 (file)
@@ -38,6 +38,8 @@ required:
   - phy-handle
   - allwinner,sram
 
+unevaluatedProperties: false
+
 examples:
   - |
     emac: ethernet@1c0b000 {
@@ -49,8 +51,4 @@ examples:
         allwinner,sram = <&emac_sram 1>;
     };
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
-
 ...
index df24d9d..e5562c5 100644 (file)
@@ -49,6 +49,8 @@ required:
   - compatible
   - reg
 
+unevaluatedProperties: false
+
 examples:
   - |
     mdio@1c0b080 {
@@ -63,8 +65,4 @@ examples:
         };
     };
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
-
 ...
index ef446ae..f683b71 100644 (file)
@@ -49,6 +49,8 @@ required:
   - clock-names
   - phy-mode
 
+unevaluatedProperties: false
+
 examples:
   - |
     gmac: ethernet@1c50000 {
@@ -61,8 +63,4 @@ examples:
         phy-mode = "mii";
     };
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
-
 ...
index 3fb0714..11654d4 100644 (file)
@@ -184,6 +184,8 @@ allOf:
             - mdio-parent-bus
             - mdio@1
 
+unevaluatedProperties: false
+
 examples:
   - |
     ethernet@1c0b000 {
@@ -314,8 +316,4 @@ examples:
         };
     };
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
-
 ...
diff --git a/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml b/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml
new file mode 100644 (file)
index 0000000..770af7c
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/can/allwinner,sun4i-a10-can.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 CAN Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - const: allwinner,sun7i-a20-can
+          - const: allwinner,sun4i-a10-can
+      - const: allwinner,sun4i-a10-can
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun7i-a20-ccu.h>
+
+    can0: can@1c2bc00 {
+        compatible = "allwinner,sun7i-a20-can",
+                     "allwinner,sun4i-a10-can";
+        reg = <0x01c2bc00 0x400>;
+        interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&ccu CLK_APB1_CAN>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/net/can/sun4i_can.txt b/Documentation/devicetree/bindings/net/can/sun4i_can.txt
deleted file mode 100644 (file)
index f69845e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-Allwinner A10/A20 CAN controller Device Tree Bindings
------------------------------------------------------
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-can"
-- reg: physical base address and size of the Allwinner A10/A20 CAN register map.
-- interrupts: interrupt specifier for the sole interrupt.
-- clock: phandle and clock specifier.
-
-Example
--------
-
-SoC common .dtsi file:
-
-       can0_pins_a: can0@0 {
-               allwinner,pins = "PH20","PH21";
-               allwinner,function = "can";
-               allwinner,drive = <0>;
-               allwinner,pull = <0>;
-       };
-...
-       can0: can@1c2bc00 {
-               compatible = "allwinner,sun4i-a10-can";
-               reg = <0x01c2bc00 0x400>;
-               interrupts = <0 26 4>;
-               clocks = <&apb1_gates 4>;
-               status = "disabled";
-       };
-
-Board specific .dts file:
-
-       can0: can@1c2bc00 {
-               pinctrl-names = "default";
-               pinctrl-0 = <&can0_pins_a>;
-               status = "okay";
-       };
diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt
deleted file mode 100644 (file)
index e6527de..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-TI SoC Davinci/Keystone2 MDIO Controller Device Tree Bindings
----------------------------------------------------
-
-Required properties:
-- compatible           : Should be "ti,davinci_mdio"
-                         and "ti,keystone_mdio" for Keystone 2 SoCs
-                         and "ti,cpsw-mdio" for am335x, am472x, am57xx/dra7, dm814x SoCs
-                         and "ti,am4372-mdio" for am472x SoC
-- reg                  : physical base address and size of the davinci mdio
-                         registers map
-- bus_freq             : Mdio Bus frequency
-
-Optional properties:
-- ti,hwmods            : Must be "davinci_mdio"
-
-Note: "ti,hwmods" field is used to fetch the base address and irq
-resources from TI, omap hwmod data base during device registration.
-Future plan is to migrate hwmod data base contents into device tree
-blob so that, all the required data will be used from device tree dts
-file.
-
-Examples:
-
-       mdio: davinci_mdio@4a101000 {
-               compatible = "ti,davinci_mdio";
-               reg = <0x4A101000 0x1000>;
-               bus_freq = <1000000>;
-       };
-
-(or)
-
-       mdio: davinci_mdio@4a101000 {
-               compatible = "ti,davinci_mdio";
-               ti,hwmods = "davinci_mdio";
-               bus_freq = <1000000>;
-       };
diff --git a/Documentation/devicetree/bindings/net/ti,davinci-mdio.yaml b/Documentation/devicetree/bindings/net/ti,davinci-mdio.yaml
new file mode 100644 (file)
index 0000000..242ac49
--- /dev/null
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/ti,davinci-mdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI SoC Davinci/Keystone2 MDIO Controller
+
+maintainers:
+  - Grygorii Strashko <grygorii.strashko@ti.com>
+
+description:
+  TI SoC Davinci/Keystone2 MDIO Controller
+
+allOf:
+  - $ref: "mdio.yaml#"
+
+properties:
+  compatible:
+    oneOf:
+       - const: ti,davinci_mdio
+       - items:
+         - const: ti,keystone_mdio
+         - const: ti,davinci_mdio
+       - items:
+         - const: ti,cpsw-mdio
+         - const: ti,davinci_mdio
+       - items:
+         - const: ti,am4372-mdio
+         - const: ti,cpsw-mdio
+         - const: ti,davinci_mdio
+
+  reg:
+    maxItems: 1
+
+  bus_freq:
+      maximum: 2500000
+      description:
+        MDIO Bus frequency
+
+  ti,hwmods:
+    description: TI hwmod name
+    deprecated: true
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string-array
+      - items:
+          const: davinci_mdio
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: ti,davinci_mdio
+  required:
+    - bus_freq
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+examples:
+  - |
+    davinci_mdio: mdio@4a101000 {
+         compatible = "ti,davinci_mdio";
+         #address-cells = <1>;
+         #size-cells = <0>;
+         reg = <0x4a101000 0x1000>;
+         bus_freq = <1000000>;
+    };
index 1084e9d..659b020 100644 (file)
@@ -31,9 +31,7 @@ required:
   - compatible
   - reg
 
-# FIXME: We should set it, but it would report all the generic
-# properties as additional properties.
-# additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 2e0723a..f7b3ed7 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
 - compatible: should be "amlogic,meson-gxbb-efuse"
 - clocks: phandle to the efuse peripheral clock provided by the
          clock controller.
+- secure-monitor: phandle to the secure-monitor node
 
 = Data cells =
 Are child nodes of eFuse, bindings of which as described in
@@ -16,6 +17,7 @@ Example:
                clocks = <&clkc CLKID_EFUSE>;
                #address-cells = <1>;
                #size-cells = <1>;
+               secure-monitor = <&sm>;
 
                sn: sn@14 {
                        reg = <0x14 0x10>;
@@ -30,6 +32,10 @@ Example:
                };
        };
 
+       sm: secure-monitor {
+               compatible = "amlogic,meson-gxbb-sm";
+       };
+
 = Data consumers =
 Are device nodes which consume nvmem data cells.
 
index efa2c8b..84fdc42 100644 (file)
@@ -9,13 +9,16 @@ Additional properties are described here:
 
 Required properties:
 - compatible:
-       should contain "amlogic,axg-pcie" to identify the core.
+       should contain :
+       - "amlogic,axg-pcie" for AXG SoC Family
+       - "amlogic,g12a-pcie" for G12A SoC Family
+       to identify the core.
 - reg:
        should contain the configuration address space.
 - reg-names: Must be
        - "elbi"        External local bus interface registers
        - "cfg"         Meson specific registers
-       - "phy"         Meson PCIE PHY registers
+       - "phy"         Meson PCIE PHY registers for AXG SoC Family
        - "config"      PCIe configuration space
 - reset-gpios: The GPIO to generate PCIe PERST# assert and deassert signal.
 - clocks: Must contain an entry for each entry in clock-names.
@@ -23,12 +26,13 @@ Required properties:
        - "pclk"       PCIe GEN 100M PLL clock
        - "port"       PCIe_x(A or B) RC clock gate
        - "general"    PCIe Phy clock
-       - "mipi"       PCIe_x(A or B) 100M ref clock gate
+       - "mipi"       PCIe_x(A or B) 100M ref clock gate for AXG SoC Family
 - resets: phandle to the reset lines.
 - reset-names: must contain "phy" "port" and "apb"
-       - "phy"         Share PHY reset
+       - "phy"         Share PHY reset for AXG SoC Family
        - "port"        Port A or B reset
        - "apb"         Share APB reset
+- phys: should contain a phandle to the shared phy for G12A SoC Family
 - device_type:
        should be "pci". As specified in designware-pcie.txt
 
index e20ceaa..99a386e 100644 (file)
@@ -21,6 +21,7 @@ Required properties:
         "fsl,ls1046a-pcie"
         "fsl,ls1043a-pcie"
         "fsl,ls1012a-pcie"
+        "fsl,ls1028a-pcie"
   EP mode:
        "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"
 - reg: base addresses and lengths of the PCIe controller register blocks.
index 45bba9f..12702c8 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
 compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC;
            "renesas,pcie-r8a7744" for the R8A7744 SoC;
            "renesas,pcie-r8a774a1" for the R8A774A1 SoC;
+           "renesas,pcie-r8a774b1" for the R8A774B1 SoC;
            "renesas,pcie-r8a774c0" for the R8A774C0 SoC;
            "renesas,pcie-r8a7779" for the R8A7779 SoC;
            "renesas,pcie-r8a7790" for the R8A7790 SoC;
index 51254b4..57d8603 100644 (file)
@@ -36,7 +36,6 @@ properties:
     const: 0
 
   phy-supply:
-     maxItems: 1
      description:
        Phandle to a regulator that provides power to the PHY. This
        regulator will be managed during the PHY power on/off sequence.
diff --git a/Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt b/Documentation/devicetree/bindings/phy/phy-mmp3-usb.txt
new file mode 100644 (file)
index 0000000..7183b91
--- /dev/null
@@ -0,0 +1,13 @@
+Marvell MMP3 USB PHY
+--------------------
+
+Required properties:
+- compatible: must be "marvell,mmp3-usb-phy"
+- #phy-cells: must be 0
+
+Example:
+       usb-phy: usb-phy@d4207000 {
+               compatible = "marvell,mmp3-usb-phy";
+               reg = <0xd4207000 0x40>;
+               #phy-cells = <0>;
+       };
index 400df2d..754ea7a 100644 (file)
@@ -40,10 +40,9 @@ properties:
     allOf:
       - $ref: "/schemas/types.yaml#/definitions/phandle-array"
     description: Should be phandle/offset/mask
-    items:
-      - description: Phandle to the syscon node which includes IRQ mux selection.
-      - description: The offset of the IRQ mux selection register.
-      - description: The field mask of IRQ mux, needed if different of 0xf.
+      - Phandle to the syscon node which includes IRQ mux selection.
+      - The offset of the IRQ mux selection register.
+      - The field mask of IRQ mux, needed if different of 0xf.
 
   st,package:
     allOf:
index 0fdc3dd..99b5b10 100644 (file)
@@ -10,7 +10,7 @@ The Video Processing Unit power domain is controlled by this power controller,
 but the domain requires some external resources to meet the correct power
 sequences.
 The bindings must respect the power domain bindings as described in the file
-power_domain.txt
+power-domain.yaml
 
 Device Tree Bindings:
 ---------------------
index 726ec28..f0f5553 100644 (file)
@@ -19,7 +19,7 @@ Required properties:
   - ipg
 
 The power domains are generic power domain providers as documented in
-Documentation/devicetree/bindings/power/power_domain.txt. They are described as
+Documentation/devicetree/bindings/power/power-domain.yaml. They are described as
 subnodes of the power gating controller 'pgc' node of the GPC and should
 contain the following:
 
index 7c7e972..6164920 100644 (file)
@@ -17,7 +17,7 @@ Required properties:
 
 Power domains contained within GPC node are generic power domain
 providers, documented in
-Documentation/devicetree/bindings/power/power_domain.txt, which are
+Documentation/devicetree/bindings/power/power-domain.yaml, which are
 described as subnodes of the power gating controller 'pgc' node,
 which, in turn, is expected to contain the following:
 
diff --git a/Documentation/devicetree/bindings/power/pd-samsung.txt b/Documentation/devicetree/bindings/power/pd-samsung.txt
deleted file mode 100644 (file)
index 92ef355..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-* Samsung Exynos Power Domains
-
-Exynos processors include support for multiple power domains which are used
-to gate power to one or more peripherals on the processor.
-
-Required Properties:
-- compatible: should be one of the following.
-    * samsung,exynos4210-pd - for exynos4210 type power domain.
-    * samsung,exynos5433-pd - for exynos5433 type power domain.
-- reg: physical base address of the controller and length of memory mapped
-    region.
-- #power-domain-cells: number of cells in power domain specifier;
-    must be 0.
-
-Optional Properties:
-- label: Human readable string with domain name. Will be visible in userspace
-       to let user to distinguish between multiple domains in SoC.
-- power-domains: phandle pointing to the parent power domain, for more details
-                see Documentation/devicetree/bindings/power/power_domain.txt
-
-Deprecated Properties:
-- clocks
-- clock-names
-
-Node of a device using power domains must have a power-domains property
-defined with a phandle to respective power domain.
-
-Example:
-
-       lcd0: power-domain-lcd0 {
-               compatible = "samsung,exynos4210-pd";
-               reg = <0x10023C00 0x10>;
-               #power-domain-cells = <0>;
-               label = "LCD0";
-       };
-
-       mfc_pd: power-domain@10044060 {
-               compatible = "samsung,exynos4210-pd";
-               reg = <0x10044060 0x20>;
-               #power-domain-cells = <0>;
-               label = "MFC";
-       };
-
-See Documentation/devicetree/bindings/power/power_domain.txt for description
-of consumer-side bindings.
diff --git a/Documentation/devicetree/bindings/power/pd-samsung.yaml b/Documentation/devicetree/bindings/power/pd-samsung.yaml
new file mode 100644 (file)
index 0000000..09bdd96
--- /dev/null
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/pd-samsung.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC Power Domains
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |+
+  Exynos processors include support for multiple power domains which are used
+  to gate power to one or more peripherals on the processor.
+
+allOf:
+  - $ref: power-domain.yaml#
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos4210-pd
+      - samsung,exynos5433-pd
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    deprecated: true
+    maxItems: 1
+
+  clock-names:
+    deprecated: true
+    maxItems: 1
+
+  label:
+    description:
+      Human readable string with domain name. Will be visible in userspace
+      to let user to distinguish between multiple domains in SoC.
+
+  "#power-domain-cells":
+    const: 0
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - "#power-domain-cells"
+  - reg
+
+examples:
+  - |
+    lcd0_pd: power-domain@10023c80 {
+        compatible = "samsung,exynos4210-pd";
+        reg = <0x10023c80 0x20>;
+        #power-domain-cells = <0>;
+        label = "LCD0";
+    };
+
+    mfc_pd: power-domain@10044060 {
+        compatible = "samsung,exynos4210-pd";
+        reg = <0x10044060 0x20>;
+        #power-domain-cells = <0>;
+        label = "MFC";
+    };
diff --git a/Documentation/devicetree/bindings/power/power-domain.yaml b/Documentation/devicetree/bindings/power/power-domain.yaml
new file mode 100644 (file)
index 0000000..455b573
--- /dev/null
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/power-domain.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic PM domains
+
+maintainers:
+  - Rafael J. Wysocki <rjw@rjwysocki.net>
+  - Kevin Hilman <khilman@kernel.org>
+  - Ulf Hansson <ulf.hansson@linaro.org>
+
+description: |+
+  System on chip designs are often divided into multiple PM domains that can be
+  used for power gating of selected IP blocks for power saving by reduced leakage
+  current.
+
+  This device tree binding can be used to bind PM domain consumer devices with
+  their PM domains provided by PM domain providers. A PM domain provider can be
+  represented by any node in the device tree and can provide one or more PM
+  domains. A consumer node can refer to the provider by a phandle and a set of
+  phandle arguments (so called PM domain specifiers) of length specified by the
+  \#power-domain-cells property in the PM domain provider node.
+
+properties:
+  $nodename:
+    pattern: "^(power-controller|power-domain)(@.*)?$"
+
+  domain-idle-states:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description:
+      A phandle of an idle-state that shall be soaked into a generic domain
+      power state. The idle state definitions are compatible with
+      domain-idle-state specified in
+      Documentation/devicetree/bindings/power/domain-idle-state.txt
+      phandles that are not compatible with domain-idle-state will be ignored.
+      The domain-idle-state property reflects the idle state of this PM domain
+      and not the idle states of the devices or sub-domains in the PM domain.
+      Devices and sub-domains have their own idle-states independent
+      of the parent domain's idle states. In the absence of this property,
+      the domain would be considered as capable of being powered-on
+      or powered-off.
+
+  operating-points-v2:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description:
+      Phandles to the OPP tables of power domains provided by a power domain
+      provider. If the provider provides a single power domain only or all
+      the power domains provided by the provider have identical OPP tables,
+      then this shall contain a single phandle. Refer to ../opp/opp.txt
+      for more information.
+
+  "#power-domain-cells":
+    description:
+      Number of cells in a PM domain specifier. Typically 0 for nodes
+      representing a single PM domain and 1 for nodes providing multiple PM
+      domains (e.g. power controllers), but can be any value as specified
+      by device tree binding documentation of particular provider.
+
+  power-domains:
+    description:
+       A phandle and PM domain specifier as defined by bindings of the power
+       controller specified by phandle. Some power domains might be powered
+       from another power domain (or have other hardware specific
+       dependencies). For representing such dependency a standard PM domain
+       consumer binding is used. When provided, all domains created
+       by the given provider should be subdomains of the domain specified
+       by this binding.
+
+required:
+  - "#power-domain-cells"
+
+examples:
+  - |
+    power: power-controller@12340000 {
+        compatible = "foo,power-controller";
+        reg = <0x12340000 0x1000>;
+        #power-domain-cells = <1>;
+    };
+
+    // The node above defines a power controller that is a PM domain provider and
+    // expects one cell as its phandle argument.
+
+  - |
+    parent2: power-controller@12340000 {
+        compatible = "foo,power-controller";
+        reg = <0x12340000 0x1000>;
+        #power-domain-cells = <1>;
+    };
+
+    child2: power-controller@12341000 {
+        compatible = "foo,power-controller";
+        reg = <0x12341000 0x1000>;
+        power-domains = <&parent2 0>;
+        #power-domain-cells = <1>;
+    };
+
+    // The nodes above define two power controllers: 'parent' and 'child'.
+    // Domains created by the 'child' power controller are subdomains of '0' power
+    // domain provided by the 'parent' power controller.
+
+  - |
+    parent3: power-controller@12340000 {
+        compatible = "foo,power-controller";
+        reg = <0x12340000 0x1000>;
+        #power-domain-cells = <0>;
+        domain-idle-states = <&DOMAIN_RET>, <&DOMAIN_PWR_DN>;
+    };
+
+    child3: power-controller@12341000 {
+        compatible = "foo,power-controller";
+        reg = <0x12341000 0x1000>;
+        power-domains = <&parent3>;
+        #power-domain-cells = <0>;
+        domain-idle-states = <&DOMAIN_PWR_DN>;
+    };
+
+    DOMAIN_RET: state@0 {
+        compatible = "domain-idle-state";
+        reg = <0x0 0x0>;
+        entry-latency-us = <1000>;
+        exit-latency-us = <2000>;
+        min-residency-us = <10000>;
+    };
+
+    DOMAIN_PWR_DN: state@1 {
+        compatible = "domain-idle-state";
+        reg = <0x1 0x0>;
+        entry-latency-us = <5000>;
+        exit-latency-us = <8000>;
+        min-residency-us = <7000>;
+    };
index 8f8b25a..5b09b2d 100644 (file)
@@ -13,100 +13,7 @@ phandle arguments (so called PM domain specifiers) of length specified by the
 
 ==PM domain providers==
 
-Required properties:
- - #power-domain-cells : Number of cells in a PM domain specifier;
-   Typically 0 for nodes representing a single PM domain and 1 for nodes
-   providing multiple PM domains (e.g. power controllers), but can be any value
-   as specified by device tree binding documentation of particular provider.
-
-Optional properties:
- - power-domains : A phandle and PM domain specifier as defined by bindings of
-                   the power controller specified by phandle.
-   Some power domains might be powered from another power domain (or have
-   other hardware specific dependencies). For representing such dependency
-   a standard PM domain consumer binding is used. When provided, all domains
-   created by the given provider should be subdomains of the domain
-   specified by this binding. More details about power domain specifier are
-   available in the next section.
-
-- domain-idle-states : A phandle of an idle-state that shall be soaked into a
-                generic domain power state. The idle state definitions are
-                compatible with domain-idle-state specified in [1]. phandles
-                that are not compatible with domain-idle-state will be
-                ignored.
-  The domain-idle-state property reflects the idle state of this PM domain and
-  not the idle states of the devices or sub-domains in the PM domain. Devices
-  and sub-domains have their own idle-states independent of the parent
-  domain's idle states. In the absence of this property, the domain would be
-  considered as capable of being powered-on or powered-off.
-
-- operating-points-v2 : Phandles to the OPP tables of power domains provided by
-  a power domain provider. If the provider provides a single power domain only
-  or all the power domains provided by the provider have identical OPP tables,
-  then this shall contain a single phandle. Refer to ../opp/opp.txt for more
-  information.
-
-Example:
-
-       power: power-controller@12340000 {
-               compatible = "foo,power-controller";
-               reg = <0x12340000 0x1000>;
-               #power-domain-cells = <1>;
-       };
-
-The node above defines a power controller that is a PM domain provider and
-expects one cell as its phandle argument.
-
-Example 2:
-
-       parent: power-controller@12340000 {
-               compatible = "foo,power-controller";
-               reg = <0x12340000 0x1000>;
-               #power-domain-cells = <1>;
-       };
-
-       child: power-controller@12341000 {
-               compatible = "foo,power-controller";
-               reg = <0x12341000 0x1000>;
-               power-domains = <&parent 0>;
-               #power-domain-cells = <1>;
-       };
-
-The nodes above define two power controllers: 'parent' and 'child'.
-Domains created by the 'child' power controller are subdomains of '0' power
-domain provided by the 'parent' power controller.
-
-Example 3:
-       parent: power-controller@12340000 {
-               compatible = "foo,power-controller";
-               reg = <0x12340000 0x1000>;
-               #power-domain-cells = <0>;
-               domain-idle-states = <&DOMAIN_RET>, <&DOMAIN_PWR_DN>;
-       };
-
-       child: power-controller@12341000 {
-               compatible = "foo,power-controller";
-               reg = <0x12341000 0x1000>;
-               power-domains = <&parent>;
-               #power-domain-cells = <0>;
-               domain-idle-states = <&DOMAIN_PWR_DN>;
-       };
-
-       DOMAIN_RET: state@0 {
-               compatible = "domain-idle-state";
-               reg = <0x0>;
-               entry-latency-us = <1000>;
-               exit-latency-us = <2000>;
-               min-residency-us = <10000>;
-       };
-
-       DOMAIN_PWR_DN: state@1 {
-               compatible = "domain-idle-state";
-               reg = <0x1>;
-               entry-latency-us = <5000>;
-               exit-latency-us = <8000>;
-               min-residency-us = <7000>;
-       };
+See power-domain.yaml.
 
 ==PM domain consumers==
 
index eb35b22..bc75bf4 100644 (file)
@@ -5,6 +5,7 @@ which then translates it into a corresponding voltage on a rail
 
 Required Properties:
  - compatible: Should be one of the following
+       * qcom,msm8976-rpmpd: RPM Power domain for the msm8976 family of SoC
        * qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC
        * qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC
        * qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC
index eae2a88..acb41fa 100644 (file)
@@ -12,6 +12,7 @@ Required properties:
       - "renesas,r8a7745-sysc" (RZ/G1E)
       - "renesas,r8a77470-sysc" (RZ/G1C)
       - "renesas,r8a774a1-sysc" (RZ/G2M)
+      - "renesas,r8a774b1-sysc" (RZ/G2N)
       - "renesas,r8a774c0-sysc" (RZ/G2E)
       - "renesas,r8a7779-sysc" (R-Car H1)
       - "renesas,r8a7790-sysc" (R-Car H2)
@@ -21,6 +22,7 @@ Required properties:
       - "renesas,r8a7794-sysc" (R-Car E2)
       - "renesas,r8a7795-sysc" (R-Car H3)
       - "renesas,r8a7796-sysc" (R-Car M3-W)
+      - "renesas,r8a77961-sysc" (R-Car M3-W+)
       - "renesas,r8a77965-sysc" (R-Car M3-N)
       - "renesas,r8a77970-sysc" (R-Car V3M)
       - "renesas,r8a77980-sysc" (R-Car V3H)
index beda7d2..49aba15 100644 (file)
@@ -29,7 +29,7 @@ Optional nodes:
 
 Each of the PM domain nodes represents a PM domain, as documented by the
 generic PM domain bindings in
-Documentation/devicetree/bindings/power/power_domain.txt.
+Documentation/devicetree/bindings/power/power-domain.yaml.
 
 The nodes should be named by the real power area names, and thus their names
 should be unique.
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt b/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt
deleted file mode 100644 (file)
index 022ed1f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Generic SYSCON mapped register poweroff driver
-
-This is a generic poweroff driver using syscon to map the poweroff register.
-The poweroff is generally performed with a write to the poweroff register
-defined by the register map pointed by syscon reference plus the offset
-with the value and mask defined in the poweroff node.
-
-Required properties:
-- compatible: should contain "syscon-poweroff"
-- regmap: this is phandle to the register map node
-- offset: offset in the register map for the poweroff register (in bytes)
-- value: the poweroff value written to the poweroff 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.
-
-Examples:
-
-       poweroff {
-          compatible = "syscon-poweroff";
-          regmap = <&regmapnode>;
-          offset = <0x0>;
-          mask = <0x7a>;
-       };
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml b/Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml
new file mode 100644 (file)
index 0000000..520e07e
--- /dev/null
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/reset/syscon-poweroff.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic SYSCON mapped register poweroff driver
+
+maintainers:
+  - Sebastian Reichel <sre@kernel.org>
+
+description: |+
+  This is a generic poweroff driver using syscon to map the poweroff register.
+  The poweroff is generally performed with a write to the poweroff register
+  defined by the register map pointed by syscon reference plus the offset
+  with the value and mask defined in the poweroff node.
+  Default will be little endian mode, 32 bit access only.
+
+properties:
+  compatible:
+    const: syscon-poweroff
+
+  mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Update only the register bits defined by the mask (32 bit).
+
+  offset:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset in the register map for the poweroff register (in bytes).
+
+  regmap:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the register map node.
+
+  value:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: The poweroff value written to the poweroff register (32 bit access).
+
+required:
+  - compatible
+  - regmap
+  - offset
+
+allOf:
+  - if:
+      not:
+        required:
+          - mask
+    then:
+      required:
+        - value
+
+examples:
+  - |
+    poweroff {
+        compatible = "syscon-poweroff";
+        regmap = <&regmapnode>;
+        offset = <0x0>;
+        mask = <0x7a>;
+    };
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt b/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt
deleted file mode 100644 (file)
index e23dea8..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-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 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)
-- 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.
-
-Examples:
-
-       reboot {
-          compatible = "syscon-reboot";
-          regmap = <&regmapnode>;
-          offset = <0x0>;
-          mask = <0x1>;
-       };
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml b/Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml
new file mode 100644 (file)
index 0000000..d38006b
--- /dev/null
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/reset/syscon-reboot.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic SYSCON mapped register reset driver
+
+maintainers:
+  - Sebastian Reichel <sre@kernel.org>
+
+description: |+
+  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 value and mask defined in the reboot node.
+  Default will be little endian mode, 32 bit access only.
+
+properties:
+  compatible:
+    const: syscon-reboot
+
+  mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Update only the register bits defined by the mask (32 bit).
+
+  offset:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset in the register map for the reboot register (in bytes).
+
+  regmap:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the register map node.
+
+  value:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: The reset value written to the reboot register (32 bit access).
+
+required:
+  - compatible
+  - regmap
+  - offset
+
+allOf:
+  - if:
+      not:
+        required:
+          - mask
+    then:
+      required:
+        - value
+
+examples:
+  - |
+    reboot {
+        compatible = "syscon-reboot";
+        regmap = <&regmapnode>;
+        offset = <0x0>;
+        mask = <0x1>;
+    };
diff --git a/Documentation/devicetree/bindings/power/supply/max77650-charger.txt b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt
deleted file mode 100644 (file)
index e6d0fb6..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-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/max77650-charger.yaml b/Documentation/devicetree/bindings/power/supply/max77650-charger.yaml
new file mode 100644 (file)
index 0000000..deef010
--- /dev/null
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/max77650-charger.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Battery charger driver for MAX77650 PMIC from Maxim Integrated.
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+description: |
+  This module is part of the MAX77650 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/max77650.yaml.
+
+  The charger is represented as a sub-node of the PMIC node on the device tree.
+
+properties:
+  compatible:
+    const: maxim,max77650-charger
+
+  input-voltage-min-microvolt:
+    description:
+      Minimum CHGIN regulation voltage.
+    enum: [ 4000000, 4100000, 4200000, 4300000,
+            4400000, 4500000, 4600000, 4700000 ]
+
+  input-current-limit-microamp:
+    description:
+      CHGIN input current limit (in microamps).
+    enum: [ 95000, 190000, 285000, 380000, 475000 ]
+
+required:
+  - compatible
index 8d1b820..54b9f9d 100644 (file)
@@ -4,7 +4,7 @@ Device Tree Bindings for the Xilinx Zynq MPSoC PM domains
 The binding for zynqmp-power-controller follow the common
 generic PM domain binding[1].
 
-[1] Documentation/devicetree/bindings/power/power_domain.txt
+[1] Documentation/devicetree/bindings/power/power-domain.yaml
 
 == Zynq MPSoC Generic PM Domain Node ==
 
index cfda0d5..afa501b 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
  - pinctrl-0: should contain the pinctrl states described by pinctrl
    default.
  - #pwm-cells: should be set to 3. This PWM chip use the default 3 cells
-   bindings defined in pwm.txt in this directory.
+   bindings defined in pwm.yaml in this directory.
 
 Example:
 
index 591ecdd..fbb5325 100644 (file)
@@ -7,7 +7,7 @@ Required properties:
     - "atmel,sama5d2-pwm"
     - "microchip,sam9x60-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
+  - #pwm-cells: Should be 3. See pwm.yaml in this directory for a
     description of the cells format.
 
 Example:
index 8031148..985fcc6 100644 (file)
@@ -2,7 +2,7 @@ Atmel TCB PWM controller
 
 Required properties:
 - compatible: should be "atmel,tcb-pwm"
-- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
 - tc-block: The Timer Counter block to use as a PWM chip.
index d9254a6..0e662d7 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 
 - compatible: must be "brcm,bcm7038-pwm"
 - reg: physical base address and length for this controller
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description
   of the cells format
 - clocks: a phandle to the reference clock for this block which is fed through
   its internal variable clock frequency generator
index 21f75bb..655f6cd 100644 (file)
@@ -6,7 +6,7 @@ Required Properties :
 - compatible: must be "brcm,iproc-pwm"
 - reg: physical base address and length of the controller's registers
 - clocks: phandle + clock specifier pair for the external clock
-- #pwm-cells: Should be 3. See pwm.txt in this directory for a
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a
   description of the cells format.
 
 Refer to clocks/clock-bindings.txt for generic clock consumer properties.
index 8eae9fe..c42eecf 100644 (file)
@@ -6,7 +6,7 @@ Required Properties :
 - compatible: should contain "brcm,kona-pwm"
 - reg: physical base address and length of the controller's registers
 - clocks: phandle + clock specifier pair for the external clock
-- #pwm-cells: Should be 3. See pwm.txt in this directory for a
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a
   description of the cells format.
 
 Refer to clocks/clock-bindings.txt for generic clock consumer properties.
index fade5f2..9db6de9 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
   - clock-names: Must include the following entries.
     - pwm: PWM operating clock.
     - sys: PWM system interface clock.
-  - #pwm-cells: Should be 2. See pwm.txt in this directory for the
+  - #pwm-cells: Should be 2. See pwm.yaml in this directory for the
        description of the cells format.
   - img,cr-periph: Must contain a phandle to the peripheral control
        syscon node which contains PWM control registers.
index c61bdf8..22f1c3d 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
   - "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1
   - "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: 2 for i.MX1 and 3 for i.MX27 and newer SoCs. See pwm.txt
+- #pwm-cells: 2 for i.MX1 and 3 for i.MX27 and newer SoCs. See pwm.yaml
   in this directory for a description of the cells format.
 - clocks : Clock specifiers for both ipg and per clocks.
 - clock-names : Clock names should include both "ipg" and "per"
index 3ba958d..5bf2095 100644 (file)
@@ -3,7 +3,7 @@ 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.
+- #pwm-cells: Should be 3. See pwm.yaml 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.
 
index 36e49d4..43d9f4f 100644 (file)
@@ -7,7 +7,7 @@ Required properties:
     See ../clock/clock-bindings.txt for details.
   - clock-names: Must include the following entries.
     - pwm: PWM operating clock.
-  - #pwm-cells: Should be 3. See pwm.txt in this directory for the description
+  - #pwm-cells: Should be 3. See pwm.yaml in this directory for the description
     of the cells format.
 
 Example:
index 96cdde5..1b06f86 100644 (file)
@@ -3,7 +3,7 @@ Freescale MXS PWM controller
 Required properties:
 - compatible: should be "fsl,imx23-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 - fsl,pwm-number: the number of PWM devices
 
index c57e11b..0a69ead 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
   - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210
   - "nvidia,tegra186-pwm": for Tegra186
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 - clocks: Must contain one entry, for the module clock.
   See ../clocks/clock-bindings.txt for details.
index f84ec9d..f21b55c 100644 (file)
@@ -3,7 +3,7 @@ NXP PCA9685 16-channel 12-bit PWM LED controller
 
 Required properties:
   - compatible: "nxp,pca9685-pwm"
-  - #pwm-cells: Should be 2. See pwm.txt in this directory for a description of
+  - #pwm-cells: Should be 2. See pwm.yaml in this directory for a description of
     the cells format.
     The index 16 is the ALLCALL channel, that sets all PWM channels at the same
     time.
index 8cf87d1..f5753b3 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
 - clocks: This clock defines the base clock frequency of the PWM hardware
   system, the period and the duty_cycle of the PWM signal is a multiple of
   the base period.
-- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
   the cells format.
 
 Examples:
index 82cbe16..f01e993 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible: should be "marvell,berlin-pwm"
 - reg: physical base address and length of the controller's registers
 - clocks: phandle to the input clock
-- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
   the cells format.
 
 Example:
index 576ad00..36532cd 100644 (file)
@@ -21,7 +21,7 @@ Required properties:
   - "fsl,vf610-ftm-pwm" for PWM compatible with the one integrated on VF610
   - "fsl,imx8qm-ftm-pwm" for PWM compatible with the one integrated on i.MX8QM
 - 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
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
   the cells format.
 - clock-names: Should include the following module clock source entries:
     "ftm_sys" (module clock, also can be used as counter clock),
index daedfef..54dbc2a 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
 - reg: physical base address and length of the controller's registers.
 - clocks: phandle and clock specifier of the PWM reference clock.
 - resets: phandle and reset specifier for the PWM controller reset.
-- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
   the cells format.
 
 Example:
index 7bd9d3b..f214305 100644 (file)
@@ -2,7 +2,7 @@ TI/National Semiconductor LP3943 PWM controller
 
 Required properties:
   - compatible: "ti,lp3943-pwm"
-  - #pwm-cells: Should be 2. See pwm.txt in this directory for a
+  - #pwm-cells: Should be 2. See pwm.yaml in this directory for a
                 description of the cells format.
                 Note that this hardware limits the period length to the
                 range 6250~1600000.
index c850153..95536d8 100644 (file)
@@ -6,10 +6,10 @@ Required properties:
    - "mediatek,mt7622-pwm": found on mt7622 SoC.
    - "mediatek,mt7623-pwm": found on mt7623 SoC.
    - "mediatek,mt7628-pwm": found on mt7628 SoC.
-   - "mediatek,mt7629-pwm", "mediatek,mt7622-pwm": found on mt7629 SoC.
+   - "mediatek,mt7629-pwm": found on mt7629 SoC.
    - "mediatek,mt8516-pwm": found on mt8516 SoC.
  - reg: physical base address and length of the controller's registers.
- - #pwm-cells: must be 2. See pwm.txt in this directory for a description of
+ - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of
    the cell format.
  - clocks: phandle and clock specifier of the PWM reference clock.
  - clock-names: must contain the following, except for MT7628 which
index 8916323..bd02b0a 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
                          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
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
   the cells format.
 
 Optional properties:
index 6f8af2b..0521957 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
    - "mediatek,mt6595-disp-pwm": found on mt6595 SoC.
    - "mediatek,mt8173-disp-pwm": found on mt8173 SoC.
  - reg: physical base address and length of the controller's registers.
- - #pwm-cells: must be 2. See pwm.txt in this directory for a description of
+ - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of
    the cell format.
  - clocks: phandle and clock specifier of the PWM reference clock.
  - clock-names: must contain the following:
index 5ccfcc8..d722ae3 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible: Shall contain "ti,omap-dmtimer-pwm".
 - ti,timers: phandle to PWM capable OMAP timer. See timer/ti,timer.txt for info
   about these timers.
-- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
+- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
   the cells format.
 
 Optional properties:
index 2c5e52a..f70956d 100644 (file)
@@ -14,7 +14,7 @@ Required properties:
    - For newer hardware (rk3328 and future socs): specified by name
      - "pwm": This is used to derive the functional clock.
      - "pclk": This is the APB bus clock.
- - #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory
+ - #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.yaml in this directory
    for a description of the cell format.
 
 Example:
diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
deleted file mode 100644 (file)
index 5538de9..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-* Samsung PWM timers
-
-Samsung SoCs contain PWM timer blocks which can be used for system clock source
-and clock event timers, as well as to drive SoC outputs with PWM signal. Each
-PWM timer block provides 5 PWM channels (not all of them can drive physical
-outputs - see SoC and board manual).
-
-Be aware that the clocksource driver supports only uniprocessor systems.
-
-Required properties:
-- compatible : should be one of following:
-    samsung,s3c2410-pwm - for 16-bit timers present on S3C24xx SoCs
-    samsung,s3c6400-pwm - for 32-bit timers present on S3C64xx SoCs
-    samsung,s5p6440-pwm - for 32-bit timers present on S5P64x0 SoCs
-    samsung,s5pc100-pwm - for 32-bit timers present on S5PC100, S5PV210,
-                         Exynos4210 rev0 SoCs
-    samsung,exynos4210-pwm - for 32-bit timers present on Exynos4210,
-                          Exynos4x12, Exynos5250 and Exynos5420 SoCs
-- reg: base address and size of register area
-- interrupts: list of timer interrupts (one interrupt per timer, starting at
-  timer 0)
-- clock-names: should contain all following required clock names:
-    - "timers" - PWM base clock used to generate PWM signals,
-  and any subset of following optional clock names:
-    - "pwm-tclk0" - first external PWM clock source,
-    - "pwm-tclk1" - second external PWM clock source.
-  Note that not all IP variants allow using all external clock sources.
-  Refer to SoC documentation to learn which clock source configurations
-  are available.
-- clocks: should contain clock specifiers of all clocks, which input names
-  have been specified in clock-names property, in same order.
-- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
-  the cells format. The only third cell flag supported by this binding is
-  PWM_POLARITY_INVERTED.
-
-Optional properties:
-- samsung,pwm-outputs: list of PWM channels used as PWM outputs on particular
-    platform - an array of up to 5 elements being indices of PWM channels
-    (from 0 to 4), the order does not matter.
-
-Example:
-       pwm@7f006000 {
-               compatible = "samsung,s3c6400-pwm";
-               reg = <0x7f006000 0x1000>;
-               interrupt-parent = <&vic0>;
-               interrupts = <23>, <24>, <25>, <27>, <28>;
-               clocks = <&clock 67>;
-               clock-names = "timers";
-               samsung,pwm-outputs = <0>, <1>;
-               #pwm-cells = <3>;
-       }
diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml
new file mode 100644 (file)
index 0000000..ea7f329
--- /dev/null
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/pwm-samsung.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC PWM timers
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |+
+  Samsung SoCs contain PWM timer blocks which can be used for system clock source
+  and clock event timers, as well as to drive SoC outputs with PWM signal. Each
+  PWM timer block provides 5 PWM channels (not all of them can drive physical
+  outputs - see SoC and board manual).
+
+  Be aware that the clocksource driver supports only uniprocessor systems.
+
+allOf:
+  - $ref: pwm.yaml#
+
+properties:
+  compatible:
+    enum:
+      - samsung,s3c2410-pwm             # 16-bit, S3C24xx
+      - samsung,s3c6400-pwm             # 32-bit, S3C64xx
+      - samsung,s5p6440-pwm             # 32-bit, S5P64x0
+      - samsung,s5pc100-pwm             # 32-bit, S5PC100, S5PV210, Exynos4210 rev0 SoCs
+      - samsung,exynos4210-pwm          # 32-bit, Exynos
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+
+  clock-names:
+    description: |
+      Should contain all following required clock names:
+      - "timers" - PWM base clock used to generate PWM signals,
+      and any subset of following optional clock names:
+      - "pwm-tclk0" - first external PWM clock source,
+      - "pwm-tclk1" - second external PWM clock source.
+      Note that not all IP variants allow using all external clock sources.
+      Refer to SoC documentation to learn which clock source configurations
+      are available.
+    oneOf:
+      - items:
+        - const: timers
+      - items:
+        - const: timers
+        - const: pwm-tclk0
+      - items:
+        - const: timers
+        - const: pwm-tclk1
+      - items:
+        - const: timers
+        - const: pwm-tclk0
+        - const: pwm-tclk1
+
+  interrupts:
+    description:
+      One interrupt per timer, starting at timer 0.
+    minItems: 1
+    maxItems: 5
+
+  "#pwm-cells":
+    description:
+      The only third cell flag supported by this binding
+      is PWM_POLARITY_INVERTED.
+    const: 3
+
+  samsung,pwm-outputs:
+    description:
+      A list of PWM channels used as PWM outputs on particular platform.
+      It is an array of up to 5 elements being indices of PWM channels
+      (from 0 to 4), the order does not matter.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+      - uniqueItems: true
+      - items:
+          minimum: 0
+          maximum: 4
+
+required:
+  - clocks
+  - clock-names
+  - compatible
+  - interrupts
+  - "#pwm-cells"
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    pwm@7f006000 {
+        compatible = "samsung,s3c6400-pwm";
+        reg = <0x7f006000 0x1000>;
+        interrupt-parent = <&vic0>;
+        interrupts = <23>, <24>, <25>, <27>, <28>;
+        clocks = <&clock 67>;
+        clock-names = "timers";
+        samsung,pwm-outputs = <0>, <1>;
+        #pwm-cells = <3>;
+    };
index 36447e3..3d1dd7b 100644 (file)
@@ -17,7 +17,7 @@ Required properties:
   Please refer to sifive-blocks-ip-versioning.txt for details.
 - reg: physical base address and length of the controller's registers
 - clocks: Should contain a clock identifier for the PWM's parent clock.
-- #pwm-cells: Should be 3. See pwm.txt in this directory
+- #pwm-cells: Should be 3. See pwm.yaml in this directory
   for a description of the cell format.
 - interrupts: one interrupt per PWM channel
 
index 16fa5a0..87b206f 100644 (file)
@@ -9,7 +9,7 @@ Required properties:
 - clock-names: Should contain following entries:
   "pwmn": used to derive the functional clock for PWM channel n (n range: 0 ~ 3).
   "enablen": for PWM channel n enable clock (n range: 0 ~ 3).
-- #pwm-cells: Should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: Should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt
deleted file mode 100644 (file)
index 6521bc4..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-STMicroelectronics STM32 Low-Power Timer PWM
-
-STM32 Low-Power Timer provides single channel PWM.
-
-Must be a sub-node of an STM32 Low-Power Timer device tree node.
-See ../mfd/stm32-lptimer.txt for details about the parent node.
-
-Required parameters:
-- compatible:          Must be "st,stm32-pwm-lp".
-- #pwm-cells:          Should be set to 3. This PWM chip uses the default 3 cells
-                       bindings defined in pwm.txt.
-
-Optional properties:
-- pinctrl-names:       Set to "default". An additional "sleep" state can be
-                       defined to set pins in sleep state when in low power.
-- pinctrl-n:           Phandle(s) pointing to pin configuration node for PWM,
-                       respectively for "default" and "sleep" states.
-
-Example:
-       timer@40002400 {
-               compatible = "st,stm32-lptimer";
-               ...
-               pwm {
-                       compatible = "st,stm32-pwm-lp";
-                       #pwm-cells = <3>;
-                       pinctrl-names = "default", "sleep";
-                       pinctrl-0 = <&lppwm1_pins>;
-                       pinctrl-1 = <&lppwm1_sleep_pins>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
deleted file mode 100644 (file)
index a8690bf..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-STMicroelectronics STM32 Timers PWM bindings
-
-Must be a sub-node of an STM32 Timers device tree node.
-See ../mfd/stm32-timers.txt for details about the parent node.
-
-Required parameters:
-- compatible:          Must be "st,stm32-pwm".
-- pinctrl-names:       Set to "default".
-- pinctrl-0:           List of phandles pointing to pin configuration nodes for PWM module.
-                       For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt
-- #pwm-cells:          Should be set to 3. This PWM chip uses the default 3 cells
-                       bindings defined in pwm.txt.
-
-Optional parameters:
-- st,breakinput:       One or two <index level filter> to describe break input configurations.
-                       "index" indicates on which break input (0 or 1) the configuration
-                       should be applied.
-                       "level" gives the active level (0=low or 1=high) of the input signal
-                       for this configuration.
-                       "filter" gives the filtering value to be applied.
-
-Example:
-       timers@40010000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "st,stm32-timers";
-               reg = <0x40010000 0x400>;
-               clocks = <&rcc 0 160>;
-               clock-names = "int";
-
-               pwm {
-                       compatible = "st,stm32-pwm";
-                       #pwm-cells = <3>;
-                       pinctrl-0       = <&pwm1_pins>;
-                       pinctrl-names   = "default";
-                       st,breakinput = <0 1 5>;
-               };
-       };
index b9a1d74..c7c4347 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
   for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
   for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap";
   for am654  - compatible = "ti,am654-ecap", "ti,am3352-ecap";
-- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
   the cells format. The PWM channel index ranges from 0 to 4. The only third
   cell flag supported by this binding is PWM_POLARITY_INVERTED.
 - reg: physical base address and size of the registers map.
index 31c4577..c7e28f6 100644 (file)
@@ -7,7 +7,7 @@ Required properties:
   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
+- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
 - reg: physical base address and size of the registers map.
index a6bcc75..3c8fe7a 100644 (file)
@@ -7,7 +7,7 @@ Required properties:
  - clock-names: "pclk" for PCLK, "wclk" for WCLK to the PWM controller.  The
    PCLK is for register access, while WCLK is the reference clock for
    calculating period and duty cycles.
- - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
+ - #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
    the cells format.
 
 Example:
index 8556263..084886b 100644 (file)
@@ -57,13 +57,4 @@ Example with optional PWM specifier for inverse polarity
 2) PWM controller nodes
 -----------------------
 
-PWM controller nodes must specify the number of cells used for the
-specifier using the '#pwm-cells' property.
-
-An example PWM controller might look like this:
-
-       pwm: pwm@7000a000 {
-               compatible = "nvidia,tegra20-pwm";
-               reg = <0x7000a000 0x100>;
-               #pwm-cells = <2>;
-       };
+See pwm.yaml.
diff --git a/Documentation/devicetree/bindings/pwm/pwm.yaml b/Documentation/devicetree/bindings/pwm/pwm.yaml
new file mode 100644 (file)
index 0000000..fa4f9de
--- /dev/null
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PWM controllers (providers)
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+
+properties:
+  $nodename:
+    pattern: "^pwm(@.*|-[0-9a-f])*$"
+
+  "#pwm-cells":
+    description:
+      Number of cells in a PWM specifier.
+
+required:
+  - "#pwm-cells"
+
+examples:
+  - |
+    pwm: pwm@7000a000 {
+        compatible = "nvidia,tegra20-pwm";
+        reg = <0x7000a000 0x100>;
+        #pwm-cells = <2>;
+    };
diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
deleted file mode 100644 (file)
index fbd6a4f..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-* Renesas R-Car PWM Timer Controller
-
-Required Properties:
-- compatible: should be "renesas,pwm-rcar" and one of the following.
- - "renesas,pwm-r8a7743": for RZ/G1M
- - "renesas,pwm-r8a7744": for RZ/G1N
- - "renesas,pwm-r8a7745": for RZ/G1E
- - "renesas,pwm-r8a774a1": for RZ/G2M
- - "renesas,pwm-r8a774c0": for RZ/G2E
- - "renesas,pwm-r8a7778": for R-Car M1A
- - "renesas,pwm-r8a7779": for R-Car H1
- - "renesas,pwm-r8a7790": for R-Car H2
- - "renesas,pwm-r8a7791": for R-Car M2-W
- - "renesas,pwm-r8a7794": for R-Car E2
- - "renesas,pwm-r8a7795": for R-Car H3
- - "renesas,pwm-r8a7796": for R-Car M3-W
- - "renesas,pwm-r8a77965": for R-Car M3-N
- - "renesas,pwm-r8a77970": for R-Car V3M
- - "renesas,pwm-r8a77980": for R-Car V3H
- - "renesas,pwm-r8a77990": for R-Car E3
- - "renesas,pwm-r8a77995": for R-Car D3
-- reg: base address and length of the registers block for the PWM.
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
-  the cells format.
-- clocks: clock phandle and specifier pair.
-- pinctrl-0: phandle, referring to a default pin configuration node.
-- pinctrl-names: Set to "default".
-
-Example: R8A7743 (RZ/G1M) PWM Timer node
-
-       pwm0: pwm@e6e30000 {
-               compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar";
-               reg = <0 0xe6e30000 0 0x8>;
-               clocks = <&cpg CPG_MOD 523>;
-               power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-               resets = <&cpg 523>;
-               #pwm-cells = <2>;
-               pinctrl-0 = <&pwm0_pins>;
-               pinctrl-names = "default";
-       };
diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml
new file mode 100644 (file)
index 0000000..945c14e
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/renesas,pwm-rcar.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas R-Car PWM Timer Controller
+
+maintainers:
+  - Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,pwm-r8a7743   # RZ/G1M
+          - renesas,pwm-r8a7744   # RZ/G1N
+          - renesas,pwm-r8a7745   # RZ/G1E
+          - renesas,pwm-r8a77470  # RZ/G1C
+          - renesas,pwm-r8a774a1  # RZ/G2M
+          - renesas,pwm-r8a774b1  # RZ/G2N
+          - renesas,pwm-r8a774c0  # RZ/G2E
+          - renesas,pwm-r8a7778   # R-Car M1A
+          - renesas,pwm-r8a7779   # R-Car H1
+          - renesas,pwm-r8a7790   # R-Car H2
+          - renesas,pwm-r8a7791   # R-Car M2-W
+          - renesas,pwm-r8a7794   # R-Car E2
+          - renesas,pwm-r8a7795   # R-Car H3
+          - renesas,pwm-r8a7796   # R-Car M3-W
+          - renesas,pwm-r8a77965  # R-Car M3-N
+          - renesas,pwm-r8a77970  # R-Car V3M
+          - renesas,pwm-r8a77980  # R-Car V3H
+          - renesas,pwm-r8a77990  # R-Car E3
+          - renesas,pwm-r8a77995  # R-Car D3
+      - const: renesas,pwm-rcar
+
+  reg:
+    # base address and length of the registers block for the PWM.
+    maxItems: 1
+
+  '#pwm-cells':
+    # should be 2. See pwm.yaml in this directory for a description of
+    # the cells format.
+    const: 2
+
+  clocks:
+    # clock phandle and specifier pair.
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - '#pwm-cells'
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a7743-cpg-mssr.h>
+    #include <dt-bindings/power/r8a7743-sysc.h>
+
+    pwm0: pwm@e6e30000 {
+        compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar";
+        reg = <0 0xe6e30000 0 0x8>;
+        clocks = <&cpg CPG_MOD 523>;
+        power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+        resets = <&cpg 523>;
+        #pwm-cells = <2>;
+        pinctrl-0 = <&pwm0_pins>;
+        pinctrl-names = "default";
+    };
diff --git a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
deleted file mode 100644 (file)
index 848a92b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-* Renesas R-Car Timer Pulse Unit PWM Controller
-
-Required Properties:
-
-  - compatible: must contain one or more of the following:
-    - "renesas,tpu-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible PWM controller.
-    - "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) compatible PWM controller.
-    - "renesas,tpu-r8a7743": for R8A7743 (RZ/G1M) compatible PWM controller.
-    - "renesas,tpu-r8a7744": for R8A7744 (RZ/G1N) compatible PWM controller.
-    - "renesas,tpu-r8a7745": for R8A7745 (RZ/G1E) compatible PWM controller.
-    - "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) compatible PWM controller.
-    - "renesas,tpu-r8a77970": for R8A77970 (R-Car V3M) compatible PWM
-                             controller.
-    - "renesas,tpu-r8a77980": for R8A77980 (R-Car V3H) compatible PWM
-                             controller.
-    - "renesas,tpu": for the generic TPU PWM controller; this is a fallback for
-                    the entries listed above.
-
-  - reg: Base address and length of each memory resource used by the PWM
-    controller hardware module.
-
-  - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
-    the cells format. The only third cell flag supported by this binding is
-    PWM_POLARITY_INVERTED.
-
-Please refer to pwm.txt in this directory for details of the common PWM bindings
-used by client devices.
-
-Example: R8A7740 (R-Mobile A1) TPU controller node
-
-       tpu: pwm@e6600000 {
-               compatible = "renesas,tpu-r8a7740", "renesas,tpu";
-               reg = <0xe6600000 0x148>;
-               #pwm-cells = <3>;
-       };
diff --git a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml
new file mode 100644 (file)
index 0000000..4969a95
--- /dev/null
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/renesas,tpu-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas R-Car Timer Pulse Unit PWM Controller
+
+maintainers:
+  - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,tpu-r8a73a4   # R-Mobile APE6
+          - renesas,tpu-r8a7740   # R-Mobile A1
+          - renesas,tpu-r8a7743   # RZ/G1M
+          - renesas,tpu-r8a7744   # RZ/G1N
+          - renesas,tpu-r8a7745   # RZ/G1E
+          - renesas,tpu-r8a7790   # R-Car H2
+          - renesas,tpu-r8a7795   # R-Car H3
+          - renesas,tpu-r8a7796   # R-Car M3-W
+          - renesas,tpu-r8a77965  # R-Car M3-N
+          - renesas,tpu-r8a77970  # R-Car V3M
+          - renesas,tpu-r8a77980  # R-Car V3H
+      - const: renesas,tpu
+
+  reg:
+    # Base address and length of each memory resource used by the PWM
+    # controller hardware module.
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  '#pwm-cells':
+    # should be 3. See pwm.yaml in this directory for a description of
+    # the cells format. The only third cell flag supported by this binding is
+    # PWM_POLARITY_INVERTED.
+    const: 3
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - '#pwm-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a7740-clock.h>
+
+    tpu: pwm@e6600000 {
+        compatible = "renesas,tpu-r8a7740", "renesas,tpu";
+        reg = <0xe6600000 0x148>;
+        clocks = <&mstp3_clks R8A7740_CLK_TPU0>;
+        power-domains = <&pd_a3sp>;
+        #pwm-cells = <3>;
+    };
index b486de2..9589412 100644 (file)
@@ -5,7 +5,7 @@ Required properties:
   - "st,spear320-pwm"
   - "st,spear1340-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 
 Example:
index cb20964..f401316 100644 (file)
@@ -7,7 +7,7 @@ subdevices of the STMPE MFD device.
 Required properties:
 - compatible: should be:
   - "st,stmpe-pwm"
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 
 Example:
index 4e32bee..d97ca19 100644 (file)
@@ -6,7 +6,7 @@ On TWL6030 series: PWM0 and PWM1
 
 Required properties:
 - compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm"
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 
 Example:
index 9f4b460..31ca1b0 100644 (file)
@@ -6,7 +6,7 @@ On TWL6030 series: LED PWM (mainly used as charging indicator LED)
 
 Required properties:
 - compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled"
-- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
 
 Example:
index a76390e..4fba93c 100644 (file)
@@ -3,7 +3,7 @@ VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller
 Required properties:
 - compatible: should be "via,vt8500-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
+- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
 - clocks: phandle to the PWM source clock
index 59b4b73..3dbb9cf 100644 (file)
@@ -68,7 +68,6 @@ properties:
 
   vin-supply:
     description: Input supply phandle.
-    $ref: /schemas/types.yaml#/definitions/phandle
 
 required:
   - compatible
diff --git a/Documentation/devicetree/bindings/regulator/max77650-regulator.txt b/Documentation/devicetree/bindings/regulator/max77650-regulator.txt
deleted file mode 100644 (file)
index f1cbe81..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-Regulator 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 regulator controller is represented as a sub-node of the PMIC node
-on the device tree.
-
-The device has a single LDO regulator and a SIMO buck-boost regulator with
-three independent power rails.
-
-Required properties:
---------------------
-- compatible:          Must be "maxim,max77650-regulator"
-
-Each rail must be instantiated under the regulators subnode of the top PMIC
-node. Up to four regulators can be defined. For standard regulator properties
-refer to Documentation/devicetree/bindings/regulator/regulator.txt.
-
-Available regulator compatible strings are: "ldo", "sbb0", "sbb1", "sbb2".
-
-Example:
---------
-
-       regulators {
-               compatible = "maxim,max77650-regulator";
-
-               max77650_ldo: regulator@0 {
-                       regulator-compatible = "ldo";
-                       regulator-name = "max77650-ldo";
-                       regulator-min-microvolt = <1350000>;
-                       regulator-max-microvolt = <2937500>;
-               };
-
-               max77650_sbb0: regulator@1 {
-                       regulator-compatible = "sbb0";
-                       regulator-name = "max77650-sbb0";
-                       regulator-min-microvolt = <800000>;
-                       regulator-max-microvolt = <1587500>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/regulator/max77650-regulator.yaml b/Documentation/devicetree/bindings/regulator/max77650-regulator.yaml
new file mode 100644 (file)
index 0000000..7d72415
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/max77650-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Regulator driver for MAX77650 PMIC from Maxim Integrated.
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+description: |
+  This module is part of the MAX77650 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/max77650.yaml.
+
+  The regulator controller is represented as a sub-node of the PMIC node
+  on the device tree.
+
+  The device has a single LDO regulator and a SIMO buck-boost regulator with
+  three independent power rails.
+
+properties:
+  compatible:
+    const: maxim,max77650-regulator
+
+patternProperties:
+  "^regulator@[0-3]$":
+    $ref: "regulator.yaml#"
+
+required:
+  - compatible
diff --git a/Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt b/Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt
new file mode 100644 (file)
index 0000000..4bf2dbf
--- /dev/null
@@ -0,0 +1,65 @@
+NVIDIA Tegra Regulators Coupling
+================================
+
+NVIDIA Tegra SoC's have a mandatory voltage-coupling between regulators.
+Thus on Tegra20 there are 3 coupled regulators and on NVIDIA Tegra30
+there are 2.
+
+Tegra20 voltage coupling
+------------------------
+
+On Tegra20 SoC's there are 3 coupled regulators: CORE, RTC and CPU.
+The CORE and RTC voltages shall be in a range of 170mV from each other
+and they both shall be higher than the CPU voltage by at least 120mV.
+
+Tegra30 voltage coupling
+------------------------
+
+On Tegra30 SoC's there are 2 coupled regulators: CORE and CPU. The CORE
+and CPU voltages shall be in a range of 300mV from each other and CORE
+voltage shall be higher than the CPU by N mV, where N depends on the CPU
+voltage.
+
+Required properties:
+- nvidia,tegra-core-regulator: Boolean property that designates regulator
+  as the "Core domain" voltage regulator.
+- nvidia,tegra-rtc-regulator: Boolean property that designates regulator
+  as the "RTC domain" voltage regulator.
+- nvidia,tegra-cpu-regulator: Boolean property that designates regulator
+  as the "CPU domain" voltage regulator.
+
+Example:
+
+       pmic {
+               regulators {
+                       core_vdd_reg: core {
+                               regulator-name = "vdd_core";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-coupled-with = <&rtc_vdd_reg &cpu_vdd_reg>;
+                               regulator-coupled-max-spread = <170000 550000>;
+
+                               nvidia,tegra-core-regulator;
+                       };
+
+                       rtc_vdd_reg: rtc {
+                               regulator-name = "vdd_rtc";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-coupled-with = <&core_vdd_reg &cpu_vdd_reg>;
+                               regulator-coupled-max-spread = <170000 550000>;
+
+                               nvidia,tegra-rtc-regulator;
+                       };
+
+                       cpu_vdd_reg: cpu {
+                               regulator-name = "vdd_cpu";
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <1125000>;
+                               regulator-coupled-with = <&core_vdd_reg &rtc_vdd_reg>;
+                               regulator-coupled-max-spread = <550000 550000>;
+
+                               nvidia,tegra-cpu-regulator;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
new file mode 100644 (file)
index 0000000..acf18d1
--- /dev/null
@@ -0,0 +1,128 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/remoteproc/st,stm32-rproc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: STMicroelectronics STM32 remote processor controller bindings
+
+description:
+  This document defines the binding for the remoteproc component that loads and
+  boots firmwares on the ST32MP family chipset.
+
+maintainers:
+  - Fabien Dessenne <fabien.dessenne@st.com>
+  - Arnaud Pouliquen <arnaud.pouliquen@st.com>
+
+properties:
+  compatible:
+    const: st,stm32mp1-m4
+
+  reg:
+    description:
+      Address ranges of the RETRAM and MCU SRAM memories used by the remote
+      processor.
+    maxItems: 3
+
+  resets:
+     maxItems: 1
+
+  st,syscfg-holdboot:
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/phandle-array"
+    description: remote processor reset hold boot
+      - Phandle of syscon block.
+      - The offset of the hold boot setting register.
+      - The field mask of the hold boot.
+    maxItems: 1
+
+  st,syscfg-tz:
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/phandle-array"
+    description:
+      Reference to the system configuration which holds the RCC trust zone mode
+      - Phandle of syscon block.
+      - The offset of the RCC trust zone mode register.
+      - The field mask of the RCC trust zone mode.
+    maxItems: 1
+
+  interrupts:
+    description: Should contain the WWDG1 watchdog reset interrupt
+    maxItems: 1
+
+  mboxes:
+    description:
+      This property is required only if the rpmsg/virtio functionality is used.
+    items:
+      - description: |
+          A channel (a) used to communicate through virtqueues with the
+          remote proc.
+          Bi-directional channel:
+            - from local to remote = send message
+            - from remote to local = send message ack
+      - description: |
+          A channel (b) working the opposite direction of channel (a)
+      - description: |
+          A channel (c) used by the local proc to notify the remote proc that it
+          is about to be shut down.
+          Unidirectional channel:
+            - from local to remote, where ACK from the remote means that it is
+              ready for shutdown
+    minItems: 1
+    maxItems: 3
+
+  mbox-names:
+    items:
+      - const: vq0
+      - const: vq1
+      - const: shutdown
+    minItems: 1
+    maxItems: 3
+
+  memory-region:
+    description:
+      List of phandles to the reserved memory regions associated with the
+      remoteproc device. This is variable and describes the memories shared with
+      the remote processor (e.g. remoteproc firmware and carveouts, rpmsg
+      vrings, ...).
+      (see ../reserved-memory/reserved-memory.txt)
+
+  st,syscfg-pdds:
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/phandle-array"
+    description: |
+      Reference to the system configuration which holds the remote
+        1st cell: phandle to syscon block
+        2nd cell: register offset containing the deep sleep setting
+        3rd cell: register bitmask for the deep sleep bit
+    maxItems: 1
+
+  st,auto-boot:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      If defined, when remoteproc is probed, it loads the default firmware and
+      starts the remote processor.
+
+required:
+  - compatible
+  - reg
+  - resets
+  - st,syscfg-holdboot
+  - st,syscfg-tz
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    m4_rproc: m4@10000000 {
+      compatible = "st,stm32mp1-m4";
+      reg = <0x10000000 0x40000>,
+            <0x30000000 0x40000>,
+            <0x38000000 0x10000>;
+      resets = <&rcc MCU_R>;
+      st,syscfg-holdboot = <&rcc 0x10C 0x1>;
+      st,syscfg-tz = <&rcc 0x000 0x1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt
deleted file mode 100644 (file)
index 5fa915a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-STMicroelectronics STM32 Remoteproc
------------------------------------
-This document defines the binding for the remoteproc component that loads and
-boots firmwares on the ST32MP family chipset.
-
-Required properties:
-- compatible:  Must be "st,stm32mp1-m4"
-- reg:         Address ranges of the RETRAM and MCU SRAM memories used by the
-               remote processor.
-- resets:      Reference to a reset controller asserting the remote processor.
-- st,syscfg-holdboot: Reference to the system configuration which holds the
-               remote processor reset hold boot
-       1st cell: phandle of syscon block
-       2nd cell: register offset containing the hold boot setting
-       3rd cell: register bitmask for the hold boot field
-- st,syscfg-tz: Reference to the system configuration which holds the RCC trust
-               zone mode
-       1st cell: phandle to syscon block
-       2nd cell: register offset containing the RCC trust zone mode setting
-       3rd cell: register bitmask for the RCC trust zone mode bit
-
-Optional properties:
-- interrupts:  Should contain the watchdog interrupt
-- mboxes:      This property is required only if the rpmsg/virtio functionality
-               is used. List of phandle and mailbox channel specifiers:
-               - a channel (a) used to communicate through virtqueues with the
-                 remote proc.
-                 Bi-directional channel:
-                     - from local to remote = send message
-                     - from remote to local = send message ack
-               - a channel (b) working the opposite direction of channel (a)
-               - a channel (c) used by the local proc to notify the remote proc
-                 that it is about to be shut down.
-                 Unidirectional channel:
-                     - from local to remote, where ACK from the remote means
-                       that it is ready for shutdown
-- mbox-names:  This property is required if the mboxes property is used.
-               - must be "vq0" for channel (a)
-               - must be "vq1" for channel (b)
-               - must be "shutdown" for channel (c)
-- memory-region: List of phandles to the reserved memory regions associated with
-               the remoteproc device. This is variable and describes the
-               memories shared with the remote processor (eg: remoteproc
-               firmware and carveouts, rpmsg vrings, ...).
-               (see ../reserved-memory/reserved-memory.txt)
-- st,syscfg-pdds: Reference to the system configuration which holds the remote
-               processor deep sleep setting
-       1st cell: phandle to syscon block
-       2nd cell: register offset containing the deep sleep setting
-       3rd cell: register bitmask for the deep sleep bit
-- st,auto-boot:        If defined, when remoteproc is probed, it loads the default
-               firmware and starts the remote processor.
-
-Example:
-       m4_rproc: m4@10000000 {
-               compatible = "st,stm32mp1-m4";
-               reg = <0x10000000 0x40000>,
-                     <0x30000000 0x40000>,
-                     <0x38000000 0x10000>;
-               resets = <&rcc MCU_R>;
-               st,syscfg-holdboot = <&rcc 0x10C 0x1>;
-               st,syscfg-tz = <&rcc 0x000 0x1>;
-       };
index 26e542e..43e580e 100644 (file)
@@ -4,7 +4,8 @@ The Amlogic Audio ARB is a simple device which enables or
 disables the access of Audio FIFOs to DDR on AXG based SoC.
 
 Required properties:
-- compatible: 'amlogic,meson-axg-audio-arb'
+- compatible: 'amlogic,meson-axg-audio-arb' or
+             'amlogic,meson-sm1-audio-arb'
 - reg: physical base address of the controller and length of memory
        mapped region.
 - clocks: phandle to the fifo peripheral clock provided by the audio
index 00917d8..b3f57d8 100644 (file)
@@ -16,6 +16,7 @@ properties:
       - amlogic,meson8b-reset # Reset Controller on Meson8b and compatible SoCs
       - amlogic,meson-gxbb-reset # Reset Controller on GXBB and compatible SoCs
       - amlogic,meson-axg-reset # Reset Controller on AXG and compatible SoCs
+      - amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt
deleted file mode 100644 (file)
index 510c748..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-Qualcomm AOSS Reset Controller
-======================================
-
-This binding describes a reset-controller found on AOSS-CC (always on subsystem)
-for Qualcomm SDM845 SoCs.
-
-Required properties:
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be:
-                   "qcom,sdm845-aoss-cc"
-
-- reg:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: must specify the base address and size of the register
-                   space.
-
-- #reset-cells:
-       Usage: required
-       Value type: <uint>
-       Definition: must be 1; cell entry represents the reset index.
-
-Example:
-
-aoss_reset: reset-controller@c2a0000 {
-       compatible = "qcom,sdm845-aoss-cc";
-       reg = <0xc2a0000 0x31000>;
-       #reset-cells = <1>;
-};
-
-Specifying reset lines connected to IP modules
-==============================================
-
-Device nodes that need access to reset lines should
-specify them as a reset phandle in their corresponding node as
-specified in reset.txt.
-
-For list of all valid reset indicies see
-<dt-bindings/reset/qcom,sdm845-aoss.h>
-
-Example:
-
-modem-pil@4080000 {
-       ...
-
-       resets = <&aoss_reset AOSS_CC_MSS_RESTART>;
-       reset-names = "mss_restart";
-
-       ...
-};
diff --git a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml
new file mode 100644 (file)
index 0000000..e2d85a1
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/qcom,aoss-reset.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm AOSS Reset Controller
+
+maintainers:
+  - Sibi Sankar <sibis@codeaurora.org>
+
+description:
+  The bindings describe the reset-controller found on AOSS-CC (always on
+  subsystem) for Qualcomm Technologies Inc SoCs.
+
+properties:
+  compatible:
+    oneOf:
+      - description: on SC7180 SoCs the following compatibles must be specified
+        items:
+          - const: "qcom,sc7180-aoss-cc"
+          - const: "qcom,sdm845-aoss-cc"
+
+      - description: on SDM845 SoCs the following compatibles must be specified
+        items:
+          - const: "qcom,sdm845-aoss-cc"
+
+  reg:
+    maxItems: 1
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    aoss_reset: reset-controller@c2a0000 {
+      compatible = "qcom,sdm845-aoss-cc";
+      reg = <0xc2a0000 0x31000>;
+      #reset-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/reset/qcom,pdc-global.txt b/Documentation/devicetree/bindings/reset/qcom,pdc-global.txt
deleted file mode 100644 (file)
index a62a492..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-PDC Global
-======================================
-
-This binding describes a reset-controller found on PDC-Global (Power Domain
-Controller) block for Qualcomm Technologies Inc SDM845 SoCs.
-
-Required properties:
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be:
-                   "qcom,sdm845-pdc-global"
-
-- reg:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: must specify the base address and size of the register
-                   space.
-
-- #reset-cells:
-       Usage: required
-       Value type: <uint>
-       Definition: must be 1; cell entry represents the reset index.
-
-Example:
-
-pdc_reset: reset-controller@b2e0000 {
-       compatible = "qcom,sdm845-pdc-global";
-       reg = <0xb2e0000 0x20000>;
-       #reset-cells = <1>;
-};
-
-PDC reset clients
-======================================
-
-Device nodes that need access to reset lines should
-specify them as a reset phandle in their corresponding node as
-specified in reset.txt.
-
-For a list of all valid reset indices see
-<dt-bindings/reset/qcom,sdm845-pdc.h>
-
-Example:
-
-modem-pil@4080000 {
-       ...
-
-       resets = <&pdc_reset PDC_MODEM_SYNC_RESET>;
-       reset-names = "pdc_reset";
-
-       ...
-};
diff --git a/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml b/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml
new file mode 100644 (file)
index 0000000..d7d8cec
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/qcom,pdc-global.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm PDC Global
+
+maintainers:
+  - Sibi Sankar <sibis@codeaurora.org>
+
+description:
+  The bindings describes the reset-controller found on PDC-Global (Power Domain
+  Controller) block for Qualcomm Technologies Inc SoCs.
+
+properties:
+  compatible:
+    oneOf:
+      - description: on SC7180 SoCs the following compatibles must be specified
+        items:
+          - const: "qcom,sc7180-pdc-global"
+          - const: "qcom,sdm845-pdc-global"
+
+      - description: on SDM845 SoCs the following compatibles must be specified
+        items:
+          - const: "qcom,sdm845-pdc-global"
+
+  reg:
+    maxItems: 1
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    pdc_reset: reset-controller@b2e0000 {
+      compatible = "qcom,sdm845-pdc-global";
+      reg = <0xb2e0000 0x20000>;
+      #reset-cells = <1>;
+    };
index b03c48a..de7f06c 100644 (file)
@@ -20,6 +20,7 @@ Required properties:
                  - "renesas,r8a7745-rst" (RZ/G1E)
                  - "renesas,r8a77470-rst" (RZ/G1C)
                  - "renesas,r8a774a1-rst" (RZ/G2M)
+                 - "renesas,r8a774b1-rst" (RZ/G2N)
                  - "renesas,r8a774c0-rst" (RZ/G2E)
                  - "renesas,r8a7778-reset-wdt" (R-Car M1A)
                  - "renesas,r8a7779-reset-wdt" (R-Car H1)
@@ -30,6 +31,7 @@ Required properties:
                  - "renesas,r8a7794-rst" (R-Car E2)
                  - "renesas,r8a7795-rst" (R-Car H3)
                  - "renesas,r8a7796-rst" (R-Car M3-W)
+                 - "renesas,r8a77961-rst" (R-Car M3-W+)
                  - "renesas,r8a77965-rst" (R-Car M3-N)
                  - "renesas,r8a77970-rst" (R-Car V3M)
                  - "renesas,r8a77980-rst" (R-Car V3H)
index ea00517..e320a8c 100644 (file)
@@ -130,6 +130,7 @@ this layer. These clocks and resets should be described in each property.
 Required properties:
 - compatible: Should be
     "socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC USB3
+    "socionext,uniphier-pro5-usb3-reset" - for Pro5 SoC USB3
     "socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC USB3
     "socionext,uniphier-ld20-usb3-reset" - for LD20 SoC USB3
     "socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC USB3
@@ -141,12 +142,12 @@ Required properties:
 - clocks: A list of phandles to the clock gate for the glue layer.
        According to the clock-names, appropriate clocks are required.
 - clock-names: Should contain
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoCs
     "link"        - for others
 - resets: A list of phandles to the reset control for the glue layer.
        According to the reset-names, appropriate resets are required.
 - reset-names: Should contain
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoCs
     "link"        - for others
 
 Example:
diff --git a/Documentation/devicetree/bindings/rng/samsung,exynos4-rng.txt b/Documentation/devicetree/bindings/rng/samsung,exynos4-rng.txt
deleted file mode 100644 (file)
index a13fbdb..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Exynos Pseudo Random Number Generator
-
-Required properties:
-
-- compatible  : One of:
-                - "samsung,exynos4-rng" for Exynos4210 and Exynos4412
-                - "samsung,exynos5250-prng" for Exynos5250+
-- reg         : Specifies base physical address and size of the registers map.
-- clocks      : Phandle to clock-controller plus clock-specifier pair.
-- clock-names : "secss" as a clock name.
-
-Example:
-
-       rng@10830400 {
-               compatible = "samsung,exynos4-rng";
-               reg = <0x10830400 0x200>;
-               clocks = <&clock CLK_SSS>;
-               clock-names = "secss";
-       };
diff --git a/Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml b/Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml
new file mode 100644 (file)
index 0000000..3362cb1
--- /dev/null
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rng/samsung,exynos4-rng.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC Pseudo Random Number Generator
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos4-rng                   # for Exynos4210 and Exynos4412
+      - samsung,exynos5250-prng               # for Exynos5250+
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: secss
+
+required:
+  - compatible
+  - reg
+  - clock-names
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos4.h>
+
+    rng@10830400 {
+        compatible = "samsung,exynos4-rng";
+        reg = <0x10830400 0x200>;
+        clocks = <&clock CLK_SSS>;
+        clock-names = "secss";
+    };
diff --git a/Documentation/devicetree/bindings/rng/st,stm32-rng.txt b/Documentation/devicetree/bindings/rng/st,stm32-rng.txt
deleted file mode 100644 (file)
index 1dfa7d5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-STMicroelectronics STM32 HW RNG
-===============================
-
-The STM32 hardware random number generator is a simple fixed purpose IP and
-is fully separated from other crypto functions.
-
-Required properties:
-
-- compatible : Should be "st,stm32-rng"
-- reg : Should be register base and length as documented in the datasheet
-- interrupts : The designated IRQ line for the RNG
-- clocks : The clock needed to enable the RNG
-
-Optional properties:
-- resets : The reset to properly start RNG
-- clock-error-detect : Enable the clock detection management
-
-Example:
-
-       rng: rng@50060800 {
-               compatible = "st,stm32-rng";
-               reg = <0x50060800 0x400>;
-               interrupts = <80>;
-               clocks = <&rcc 0 38>;
-       };
diff --git a/Documentation/devicetree/bindings/rng/st,stm32-rng.yaml b/Documentation/devicetree/bindings/rng/st,stm32-rng.yaml
new file mode 100644 (file)
index 0000000..82bb2e9
--- /dev/null
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rng/st,stm32-rng.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 RNG bindings
+
+description: |
+  The STM32 hardware random number generator is a simple fixed purpose
+  IP and is fully separated from other crypto functions.
+
+maintainers:
+  - Lionel Debieve <lionel.debieve@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-rng
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  clock-error-detect:
+    description: If set enable the clock detection management
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    rng@54003000 {
+      compatible = "st,stm32-rng";
+      reg = <0x54003000 0x400>;
+      clocks = <&rcc RNG1_K>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/rtc/renesas,sh-rtc.yaml b/Documentation/devicetree/bindings/rtc/renesas,sh-rtc.yaml
new file mode 100644 (file)
index 0000000..dcff573
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/renesas,sh-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Real Time Clock for Renesas SH and ARM SoCs
+
+maintainers:
+  - Chris Brandt <chris.brandt@renesas.com>
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+
+properties:
+  compatible:
+    items:
+      - const: renesas,r7s72100-rtc  # RZ/A1H
+      - const: renesas,sh-rtc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 3
+
+  interrupt-names:
+    items:
+      - const: alarm
+      - const: period
+      - const: carry
+
+  clocks:
+    # The functional clock source for the RTC controller must be listed
+    # first (if it exists). Additionally, potential clock counting sources
+    # are to be listed.
+    minItems: 1
+    maxItems: 4
+
+  clock-names:
+    # The functional clock must be labeled as "fck". Other clocks
+    # may be named in accordance to the SoC hardware manuals.
+    minItems: 1
+    maxItems: 4
+    items:
+      enum: [ fck, rtc_x1, rtc_x3, extal ]
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    #include <dt-bindings/clock/r7s72100-clock.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    rtc: rtc@fcff1000 {
+        compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc";
+        reg = <0xfcff1000 0x2e>;
+        interrupts = <GIC_SPI 276 IRQ_TYPE_EDGE_RISING>,
+                     <GIC_SPI 277 IRQ_TYPE_EDGE_RISING>,
+                     <GIC_SPI 278 IRQ_TYPE_EDGE_RISING>;
+        interrupt-names = "alarm", "period", "carry";
+        clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>,
+                 <&rtc_x3_clk>, <&extal_clk>;
+        clock-names = "fck", "rtc_x1", "rtc_x3", "extal";
+    };
diff --git a/Documentation/devicetree/bindings/rtc/rtc-sh.txt b/Documentation/devicetree/bindings/rtc/rtc-sh.txt
deleted file mode 100644 (file)
index 7676c7d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-* Real Time Clock for Renesas SH and ARM SoCs
-
-Required properties:
-- compatible: Should be "renesas,r7s72100-rtc" and "renesas,sh-rtc" as a
-  fallback.
-- reg: physical base address and length of memory mapped region.
-- interrupts: 3 interrupts for alarm, period, and carry.
-- interrupt-names: The interrupts should be labeled as "alarm", "period", and
-  "carry".
-- clocks: The functional clock source for the RTC controller must be listed
-  first (if exists). Additionally, potential clock counting sources are to be
-  listed.
-- clock-names: The functional clock must be labeled as "fck". Other clocks
-  may be named in accordance to the SoC hardware manuals.
-
-
-Example:
-rtc: rtc@fcff1000 {
-       compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc";
-       reg = <0xfcff1000 0x2e>;
-       interrupts = <GIC_SPI 276 IRQ_TYPE_EDGE_RISING
-                     GIC_SPI 277 IRQ_TYPE_EDGE_RISING
-                     GIC_SPI 278 IRQ_TYPE_EDGE_RISING>;
-       interrupt-names = "alarm", "period", "carry";
-       clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>,
-                <&rtc_x3_clk>, <&extal_clk>;
-       clock-names = "fck", "rtc_x1", "rtc_x3", "extal";
-};
diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
deleted file mode 100644 (file)
index fdde63a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-* Samsung's S3C Real Time Clock controller
-
-Required properties:
-- compatible: should be one of the following.
-    * "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc.
-    * "samsung,s3c2416-rtc" - for controllers compatible with s3c2416 rtc.
-    * "samsung,s3c2443-rtc" - for controllers compatible with s3c2443 rtc.
-    * "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc.
-    * "samsung,exynos3250-rtc" - (deprecated) for controllers compatible with
-                                 exynos3250 rtc (use "samsung,s3c6410-rtc").
-- reg: physical base address of the controller and length of memory mapped
-  region.
-- interrupts: Two interrupt numbers to the cpu should be specified. First
-  interrupt number is the rtc alarm interrupt and second interrupt number
-  is the rtc tick interrupt. The number of cells representing a interrupt
-  depends on the parent interrupt controller.
-- clocks: Must contain a list of phandle and clock specifier for the rtc
-          clock and in the case of a s3c6410 compatible controller, also
-          a source clock.
-- clock-names: Must contain "rtc" and for a s3c6410 compatible controller,
-               a "rtc_src" sorted in the same order as the clocks property.
-
-Example:
-
-       rtc@10070000 {
-               compatible = "samsung,s3c6410-rtc";
-               reg = <0x10070000 0x100>;
-               interrupts = <44 0 45 0>;
-               clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>;
-               clock-names = "rtc", "rtc_src";
-       };
diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml
new file mode 100644 (file)
index 0000000..76bbf8b
--- /dev/null
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/s3c-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S3C, S5P and Exynos Real Time Clock controller
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - samsung,s3c2410-rtc
+          - samsung,s3c2416-rtc
+          - samsung,s3c2443-rtc
+          - samsung,s3c6410-rtc
+      - const: samsung,exynos3250-rtc
+        deprecated: true
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description:
+      Must contain a list of phandle and clock specifier for the rtc
+      clock and in the case of a s3c6410 compatible controller, also
+      a source clock.
+    minItems: 1
+    maxItems: 2
+
+  clock-names:
+    description:
+      Must contain "rtc" and for a s3c6410 compatible controller
+      also "rtc_src".
+    minItems: 1
+    maxItems: 2
+
+  interrupts:
+    description:
+      Two interrupt numbers to the cpu should be specified. First
+      interrupt number is the rtc alarm interrupt and second interrupt number
+      is the rtc tick interrupt. The number of cells representing a interrupt
+      depends on the parent interrupt controller.
+    minItems: 2
+    maxItems: 2
+
+allOf:
+  - $ref: rtc.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,s3c6410-rtc
+              - samsung,exynos3250-rtc
+    then:
+      properties:
+        clocks:
+          minItems: 2
+          maxItems: 2
+        clock-names:
+          items:
+            - const: rtc
+            - const: rtc_src
+    else:
+      properties:
+        clocks:
+          minItems: 1
+          maxItems: 1
+        clock-names:
+          items:
+            - const: rtc
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos5420.h>
+    #include <dt-bindings/clock/samsung,s2mps11.h>
+
+    rtc@10070000 {
+        compatible = "samsung,s3c6410-rtc";
+        reg = <0x10070000 0x100>;
+        interrupts = <0 44 4>, <0 45 4>;
+        clocks = <&clock CLK_RTC>,
+                 <&s2mps11_osc S2MPS11_CLK_AP>;
+        clock-names = "rtc", "rtc_src";
+    };
index 20d351f..55700f2 100644 (file)
@@ -56,6 +56,11 @@ Optional properties:
 - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
   line respectively. It will use specified GPIO instead of the peripheral
   function pin for the UART feature. If unsure, don't specify this property.
+- aspeed,sirq-polarity-sense: Only applicable to aspeed,ast2500-vuart.
+  phandle to aspeed,ast2500-scu compatible syscon alongside register offset
+  and bit number to identify how the SIRQ polarity should be configured.
+  One possible data source is the LPC/eSPI mode bit.
+  Example: aspeed,sirq-polarity-sense = <&syscon 0x70 25>
 
 Note:
 * fsl,ns16550:
index 3495eee..f5f5ab0 100644 (file)
@@ -21,8 +21,7 @@ Required properties:
 Optional properties:
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
-- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx,
-  linux,rs485-enabled-at-boot-time: see rs485.txt
+- rs485-rts-active-low, linux,rs485-enabled-at-boot-time: see rs485.txt
 
 Note: Optional properties for DMA support. Write them both or both not.
 
index b143d9a..a5edf4b 100644 (file)
@@ -54,8 +54,10 @@ Required properties:
     - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
     - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART.
     - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
-    - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART.
-    - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART.
+    - "renesas,scif-r8a7796" for R8A77960 (R-Car M3-W) SCIF compatible UART.
+    - "renesas,hscif-r8a7796" for R8A77960 (R-Car M3-W) HSCIF compatible UART.
+    - "renesas,scif-r8a77961" for R8A77961 (R-Car M3-W+) SCIF compatible UART.
+    - "renesas,hscif-r8a77961" for R8A77961 (R-Car M3-W+) HSCIF compatible UART.
     - "renesas,scif-r8a77965" for R8A77965 (R-Car M3-N) SCIF compatible UART.
     - "renesas,hscif-r8a77965" for R8A77965 (R-Car M3-N) HSCIF compatible UART.
     - "renesas,scif-r8a77970" for R8A77970 (R-Car V3M) SCIF compatible UART.
diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.txt b/Documentation/devicetree/bindings/serial/samsung_uart.txt
deleted file mode 100644 (file)
index e85f37e..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-* Samsung's UART Controller
-
-The Samsung's UART controller is used for interfacing SoC with serial
-communicaion devices.
-
-Required properties:
-- compatible: should be one of following:
-  - "samsung,exynos4210-uart" -  Exynos4210 SoC,
-  - "samsung,s3c2410-uart" - compatible with ports present on S3C2410 SoC,
-  - "samsung,s3c2412-uart" - compatible with ports present on S3C2412 SoC,
-  - "samsung,s3c2440-uart" - compatible with ports present on S3C2440 SoC,
-  - "samsung,s3c6400-uart" - compatible with ports present on S3C6400 SoC,
-  - "samsung,s5pv210-uart" - compatible with ports present on S5PV210 SoC.
-
-- reg: base physical address of the controller and length of memory mapped
-  region.
-
-- interrupts: a single interrupt signal to SoC interrupt controller,
-  according to interrupt bindings documentation [1].
-
-- clock-names: input names of clocks used by the controller:
-  - "uart" - controller bus clock,
-  - "clk_uart_baudN" - Nth baud base clock input (N = 0, 1, ...),
-    according to SoC User's Manual (only N = 0 is allowedfor SoCs without
-    internal baud clock mux).
-- clocks: phandles and specifiers for all clocks specified in "clock-names"
-  property, in the same order, according to clock bindings documentation [2].
-
-[1] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-[2] Documentation/devicetree/bindings/clock/clock-bindings.txt
-
-Optional properties:
-- samsung,uart-fifosize: The fifo size supported by the UART channel
-
-Note: Each Samsung UART should have an alias correctly numbered in the
-"aliases" node, according to serialN format, where N is the port number
-(non-negative decimal integer) as specified by User's Manual of respective
-SoC.
-
-Example:
-       aliases {
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-       };
-
-Example:
-       uart1: serial@7f005400 {
-               compatible = "samsung,s3c6400-uart";
-               reg = <0x7f005400 0x100>;
-               interrupt-parent = <&vic1>;
-               interrupts = <6>;
-               clock-names = "uart", "clk_uart_baud2",
-                               "clk_uart_baud3";
-               clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>,
-                               <&clocks SCLK_UART>;
-               samsung,uart-fifosize = <16>;
-       };
diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml
new file mode 100644 (file)
index 0000000..9d2ce34
--- /dev/null
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/samsung_uart.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S3C, S5P and Exynos SoC UART Controller
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+  - Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+description: |+
+  Each Samsung UART should have an alias correctly numbered in the "aliases"
+  node, according to serialN format, where N is the port number (non-negative
+  decimal integer) as specified by User's Manual of respective SoC.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - samsung,s3c2410-uart
+          - samsung,s3c2412-uart
+          - samsung,s3c2440-uart
+          - samsung,s3c6400-uart
+          - samsung,s5pv210-uart
+          - samsung,exynos4210-uart
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 2
+    maxItems: 5
+
+  clock-names:
+    description: N = 0 is allowed for SoCs without internal baud clock mux.
+    minItems: 2
+    maxItems: 5
+    items:
+      - const: uart
+      - pattern: '^clk_uart_baud[0-3]$'
+      - pattern: '^clk_uart_baud[0-3]$'
+      - pattern: '^clk_uart_baud[0-3]$'
+      - pattern: '^clk_uart_baud[0-3]$'
+
+  interrupts:
+    description: RX interrupt and optionally TX interrupt.
+    minItems: 1
+    maxItems: 2
+
+  samsung,uart-fifosize:
+    description: The fifo size supported by the UART channel.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [16, 64, 256]
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - interrupts
+  - reg
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,s3c2410-uart
+              - samsung,s5pv210-uart
+    then:
+      properties:
+        clocks:
+          minItems: 2
+          maxItems: 3
+        clock-names:
+          minItems: 2
+          maxItems: 3
+          items:
+            - const: uart
+            - pattern: '^clk_uart_baud[0-1]$'
+            - pattern: '^clk_uart_baud[0-1]$'
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos4210-uart
+    then:
+      properties:
+        clocks:
+          minItems: 2
+          maxItems: 2
+        clock-names:
+          minItems: 2
+          maxItems: 2
+          items:
+            - const: uart
+            - const: clk_uart_baud0
+
+examples:
+  - |
+    #include <dt-bindings/clock/samsung,s3c64xx-clock.h>
+
+    uart0: serial@7f005000 {
+        compatible = "samsung,s3c6400-uart";
+        reg = <0x7f005000 0x100>;
+        interrupt-parent = <&vic1>;
+        interrupts = <5>;
+        clock-names = "uart", "clk_uart_baud2",
+                      "clk_uart_baud3";
+        clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>,
+                 <&clocks SCLK_UART>;
+        samsung,uart-fifosize = <16>;
+    };
diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.txt b/Documentation/devicetree/bindings/serial/sprd-uart.txt
deleted file mode 100644 (file)
index 9607dc6..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-* Spreadtrum serial UART
-
-Required properties:
-- compatible: must be one of:
-  * "sprd,sc9836-uart"
-  * "sprd,sc9860-uart", "sprd,sc9836-uart"
-
-- reg: offset and length of the register set for the device
-- interrupts: exactly one interrupt specifier
-- clock-names: Should contain following entries:
-  "enable" for UART module enable clock,
-  "uart" for UART clock,
-  "source" for UART source (parent) clock.
-- clocks: Should contain a clock specifier for each entry in clock-names.
-  UART clock and source clock are optional properties, but enable clock
-  is required.
-
-Optional properties:
-- dma-names: Should contain "rx" for receive and "tx" for transmit channels.
-- dmas: A list of dma specifiers, one for each entry in dma-names.
-
-Example:
-       uart0: serial@0 {
-               compatible = "sprd,sc9860-uart",
-                            "sprd,sc9836-uart";
-               reg = <0x0 0x100>;
-               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-               dma-names = "rx", "tx";
-               dmas = <&ap_dma 19>, <&ap_dma 20>;
-               clock-names = "enable", "uart", "source";
-               clocks = <&clk_ap_apb_gates 9>, <&clk_uart0>, <&ext_26m>;
-       };
diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml
new file mode 100644 (file)
index 0000000..e66b2e9
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2019 Unisoc Inc.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/serial/sprd-uart.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Spreadtrum serial UART
+
+maintainers:
+  - Orson Zhai <orsonzhai@gmail.com>
+  - Baolin Wang <baolin.wang7@gmail.com>
+  - Chunyan Zhang <zhang.lyra@gmail.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - sprd,sc9860-uart
+              - sprd,sc9863a-uart
+          - const: sprd,sc9836-uart
+      - const: sprd,sc9836-uart
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+
+  clock-names:
+    description: |
+      "enable" for UART module enable clock, "uart" for UART clock, "source" 
+      for UART source (parent) clock.
+    items:
+      - const: enable
+      - const: uart
+      - const: source
+
+  dmas:
+    minItems: 1
+    maxItems: 2
+
+  dma-names:
+    minItems: 1
+    items:
+      - const: rx
+      - const: tx
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    serial@0 {
+      compatible = "sprd,sc9860-uart", "sprd,sc9836-uart";
+      reg = <0x0 0x100>;
+      interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+      dma-names = "rx", "tx";
+      dmas = <&ap_dma 19>, <&ap_dma 20>;
+      clock-names = "enable", "uart", "source";
+      clocks = <&clk_ap_apb_gates 9>, <&clk_uart0>, <&ext_26m>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml b/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml
new file mode 100644 (file)
index 0000000..ee9712f
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serio/allwinner,sun4i-a10-ps2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 PS2 Host Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+description:
+  A20 PS2 is dual role controller (PS2 host and PS2 device). These
+  bindings for PS2 A10/A20 host controller. IBM compliant IBM PS2 and
+  AT-compatible keyboard and mouse can be connected.
+
+properties:
+  compatible:
+    const: allwinner,sun4i-a10-ps2
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun7i-a20-ccu.h>
+
+    ps20: ps2@1c2a000 {
+        compatible = "allwinner,sun4i-a10-ps2";
+        reg = <0x01c2a000 0x400>;
+        interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&ccu CLK_APB1_PS20>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
deleted file mode 100644 (file)
index 75996b6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-* Device tree bindings for Allwinner A10, A20 PS2 host controller
-
-A20 PS2 is dual role controller (PS2 host and PS2 device). These bindings are
-for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard
-and mouse can be connected.
-
-Required properties:
-
- - reg             : Offset and length of the register set for the device.
- - compatible      : Should be as of the following:
-                     - "allwinner,sun4i-a10-ps2"
- - interrupts      : The interrupt line connected to the PS2.
- - clocks          : The gate clk connected to the PS2.
-
-
-Example:
-       ps20: ps2@01c2a000 {
-               compatible = "allwinner,sun4i-a10-ps2";
-               reg = <0x01c2a000 0x400>;
-               interrupts = <0 62 4>;
-               clocks = <&apb1_gates 6>;
-       };
diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt b/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt
deleted file mode 100644 (file)
index e876f3c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-Amlogic Canvas
-================================
-
-A canvas is a collection of metadata that describes a pixel buffer.
-Those metadata include: width, height, phyaddr, wrapping and block mode.
-Starting with GXBB the endianness can also be described.
-
-Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data
-rather than use the phy addresses directly. For instance, this is the case for
-the video decoders and the display.
-
-Amlogic SoCs have 256 canvas.
-
-Device Tree Bindings:
----------------------
-
-Video Lookup Table
---------------------------
-
-Required properties:
-- compatible: has to be one of:
-               - "amlogic,meson8-canvas", "amlogic,canvas" on Meson8
-               - "amlogic,meson8b-canvas", "amlogic,canvas" on Meson8b
-               - "amlogic,meson8m2-canvas", "amlogic,canvas" on Meson8m2
-               - "amlogic,canvas" on GXBB and newer
-- reg: Base physical address and size of the canvas registers.
-
-Example:
-
-canvas: video-lut@48 {
-       compatible = "amlogic,canvas";
-       reg = <0x0 0x48 0x0 0x14>;
-};
diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.yaml b/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.yaml
new file mode 100644 (file)
index 0000000..f548594
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/soc/amlogic/amlogic,canvas.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Canvas Video Lookup Table
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+  - Maxime Jourdan <mjourdan@baylibre.com>
+
+description: |
+  A canvas is a collection of metadata that describes a pixel buffer.
+  Those metadata include: width, height, phyaddr, wrapping and block mode.
+  Starting with GXBB the endianness can also be described.
+
+  Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data
+  rather than use the phy addresses directly. For instance, this is the case for
+  the video decoders and the display.
+
+  Amlogic SoCs have 256 canvas.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+        - enum:
+          - amlogic,meson8-canvas
+          - amlogic,meson8b-canvas
+          - amlogic,meson8m2-canvas
+        - const: amlogic,canvas
+      - const: amlogic,canvas # GXBB and newer SoCs
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    canvas: video-lut@48 {
+        compatible = "amlogic,canvas";
+        reg = <0x48 0x14>;
+    };
+
index 3b7d329..72ff033 100644 (file)
@@ -26,7 +26,7 @@ Optional properties:
     system power.  This node follows the power controller bindings[3].
 
 [1] Documentation/devicetree/bindings/reset/reset.txt
-[2] Documentation/devicetree/bindings/power/power_domain.txt
+[2] Documentation/devicetree/bindings/power/power-domain.yaml
 [3] Documentation/devicetree/bindings/power/power-controller.txt
 
 Example:
index e284e4e..5a33619 100644 (file)
@@ -5,7 +5,7 @@ and power management.
 
 Required properites:
   - reg : Offset and length of the register set of the RCPM block.
-  - fsl,#rcpm-wakeup-cells : The number of IPPDEXPCR register cells in the
+  - #fsl,rcpm-wakeup-cells : The number of IPPDEXPCR register cells in the
        fsl,rcpm-wakeup property.
   - compatible : Must contain a chip-specific RCPM block compatible string
        and (if applicable) may contain a chassis-version RCPM compatible
@@ -20,6 +20,7 @@ Required properites:
        * "fsl,qoriq-rcpm-1.0": for chassis 1.0 rcpm
        * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm
        * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm
+       * "fsl,qoriq-rcpm-2.1+": for chassis 2.1+ rcpm
 
 All references to "1.0" and "2.0" refer to the QorIQ chassis version to
 which the chip complies.
@@ -27,14 +28,19 @@ Chassis Version             Example Chips
 ---------------                -------------------------------
 1.0                            p4080, p5020, p5040, p2041, p3041
 2.0                            t4240, b4860, b4420
-2.1                            t1040, ls1021
+2.1                            t1040,
+2.1+                           ls1021a, ls1012a, ls1043a, ls1046a
+
+Optional properties:
+ - little-endian : RCPM register block is Little Endian. Without it RCPM
+   will be Big Endian (default case).
 
 Example:
 The RCPM node for T4240:
        rcpm: global-utilities@e2000 {
                compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0";
                reg = <0xe2000 0x1000>;
-               fsl,#rcpm-wakeup-cells = <2>;
+               #fsl,rcpm-wakeup-cells = <2>;
        };
 
 * Freescale RCPM Wakeup Source Device Tree Bindings
@@ -44,7 +50,7 @@ can be used as a wakeup source.
 
   - fsl,rcpm-wakeup: Consists of a phandle to the rcpm node and the IPPDEXPCR
        register cells. The number of IPPDEXPCR register cells is defined in
-       "fsl,#rcpm-wakeup-cells" in the rcpm node. The first register cell is
+       "#fsl,rcpm-wakeup-cells" in the rcpm node. The first register cell is
        the bit mask that should be set in IPPDEXPCR0, and the second register
        cell is for IPPDEXPCR1, and so on.
 
index 876693a..8f469d8 100644 (file)
@@ -8,7 +8,7 @@ The System Power Manager (SPM) inside the SCPSYS is for the MTCMOS power
 domain control.
 
 The driver implements the Generic PM domain bindings described in
-power/power_domain.txt. It provides the power domains defined in
+power/power-domain.yaml. It provides the power domains defined in
 - include/dt-bindings/power/mt8173-power.h
 - include/dt-bindings/power/mt6797-power.h
 - include/dt-bindings/power/mt2701-power.h
index f3fa313..616fddc 100644 (file)
@@ -22,6 +22,7 @@ resources.
                    "qcom,rpm-apq8084"
                    "qcom,rpm-msm8916"
                    "qcom,rpm-msm8974"
+                   "qcom,rpm-msm8976"
                    "qcom,rpm-msm8998"
                    "qcom,rpm-sdm660"
                    "qcom,rpm-qcs404"
index 46e27cd..f96511a 100644 (file)
@@ -10,6 +10,12 @@ From RK3368 SoCs, the GRF is divided into two sections,
 
 On RK3328 SoCs, the GRF adds a section for USB2PHYGRF,
 
+ON RK3308 SoC, the GRF is divided into four sections:
+- GRF, used for general non-secure system,
+- SGRF, used for general secure system,
+- DETECTGRF, used for audio codec system,
+- COREGRF, used for pvtm,
+
 Required Properties:
 
 - compatible: GRF should be one of the following:
@@ -19,19 +25,25 @@ Required Properties:
    - "rockchip,rk3188-grf", "syscon": for rk3188
    - "rockchip,rk3228-grf", "syscon": for rk3228
    - "rockchip,rk3288-grf", "syscon": for rk3288
+   - "rockchip,rk3308-grf", "syscon": for rk3308
    - "rockchip,rk3328-grf", "syscon": for rk3328
    - "rockchip,rk3368-grf", "syscon": for rk3368
    - "rockchip,rk3399-grf", "syscon": for rk3399
    - "rockchip,rv1108-grf", "syscon": for rv1108
+- compatible: DETECTGRF should be one of the following:
+   - "rockchip,rk3308-detect-grf", "syscon": for rk3308
+- compatilbe: COREGRF should be one of the following:
+   - "rockchip,rk3308-core-grf", "syscon": for rk3308
 - compatible: PMUGRF should be one of the following:
    - "rockchip,px30-pmugrf", "syscon": for px30
    - "rockchip,rk3368-pmugrf", "syscon": for rk3368
    - "rockchip,rk3399-pmugrf", "syscon": for rk3399
-- compatible: SGRF should be one of the following
+- compatible: SGRF should be one of the following:
    - "rockchip,rk3288-sgrf", "syscon": for rk3288
-- compatible: USB2PHYGRF should be one of the followings
+- compatible: USB2PHYGRF should be one of the following:
+   - "rockchip,px30-usb2phy-grf", "syscon": for px30
    - "rockchip,rk3328-usb2phy-grf", "syscon": for rk3328
-- compatible: USBGRF should be one of the following
+- compatible: USBGRF should be one of the following:
    - "rockchip,rv1108-usbgrf", "syscon": for rv1108
 - reg: physical base address of the controller and length of memory mapped
   region.
index f541d1f..6217e64 100644 (file)
@@ -12,7 +12,7 @@ PM Domain Node
 ==============
 The PM domain node represents the global PM domain managed by the PMMC, which
 in this case is the implementation as documented by the generic PM domain
-bindings in Documentation/devicetree/bindings/power/power_domain.txt.  Because
+bindings in Documentation/devicetree/bindings/power/power-domain.yaml.  Because
 this relies on the TI SCI protocol to communicate with the PMMC it must be a
 child of the pmmc node.
 
diff --git a/Documentation/devicetree/bindings/sram/milbeaut-smp-sram.txt b/Documentation/devicetree/bindings/sram/milbeaut-smp-sram.txt
deleted file mode 100644 (file)
index 194f6a3..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Milbeaut SRAM for smp bringup
-
-Milbeaut SoCs use a part of the sram for the bringup of the secondary cores.
-Once they get powered up in the bootloader, they stay at the specific part
-of the sram.
-Therefore the part needs to be added as the sub-node of mmio-sram.
-
-Required sub-node properties:
-- compatible : should be "socionext,milbeaut-smp-sram"
-
-Example:
-
-        sram: sram@0 {
-                compatible = "mmio-sram";
-                reg = <0x0 0x10000>;
-                #address-cells = <1>;
-                #size-cells = <1>;
-                ranges = <0 0x0 0x10000>;
-
-                smp-sram@f100 {
-                        compatible = "socionext,milbeaut-smp-sram";
-                        reg = <0xf100 0x20>;
-                };
-        };
diff --git a/Documentation/devicetree/bindings/sram/renesas,smp-sram.txt b/Documentation/devicetree/bindings/sram/renesas,smp-sram.txt
deleted file mode 100644 (file)
index 712d05e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* Renesas SMP SRAM
-
-Renesas R-Car Gen2 and RZ/G1 SoCs need a small piece of SRAM for the jump stub
-for secondary CPU bringup and CPU hotplug.
-This memory is reserved by adding a child node to a "mmio-sram" node, cfr.
-Documentation/devicetree/bindings/sram/sram.txt.
-
-Required child node properties:
-  - compatible: Must be "renesas,smp-sram",
-  - reg: Address and length of the reserved SRAM.
-    The full physical (bus) address must be aligned to a 256 KiB boundary.
-
-
-Example:
-
-       icram1: sram@e63c0000 {
-               compatible = "mmio-sram";
-               reg = <0 0xe63c0000 0 0x1000>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0 0xe63c0000 0x1000>;
-
-               smp-sram@0 {
-                       compatible = "renesas,smp-sram";
-                       reg = <0 0x10>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sram/rockchip-smp-sram.txt b/Documentation/devicetree/bindings/sram/rockchip-smp-sram.txt
deleted file mode 100644 (file)
index 800701e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Rockchip SRAM for smp bringup:
-------------------------------
-
-Rockchip's smp-capable SoCs use the first part of the sram for the bringup
-of the cores. Once the core gets powered up it executes the code that is
-residing at the very beginning of the sram.
-
-Therefore a reserved section sub-node has to be added to the mmio-sram
-declaration.
-
-Required sub-node properties:
-- compatible : should be "rockchip,rk3066-smp-sram"
-
-The rest of the properties should follow the generic mmio-sram discription
-found in Documentation/devicetree/bindings/sram/sram.txt
-
-Example:
-
-       sram: sram@10080000 {
-               compatible = "mmio-sram";
-               reg = <0x10080000 0x10000>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               smp-sram@10080000 {
-                       compatible = "rockchip,rk3066-smp-sram";
-                       reg = <0x10080000 0x50>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sram/samsung-sram.txt b/Documentation/devicetree/bindings/sram/samsung-sram.txt
deleted file mode 100644 (file)
index 61a9bbe..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Samsung Exynos SYSRAM for SMP bringup:
-------------------------------------
-
-Samsung SMP-capable Exynos SoCs use part of the SYSRAM for the bringup
-of the secondary cores. Once the core gets powered up it executes the
-code that is residing at some specific location of the SYSRAM.
-
-Therefore reserved section sub-nodes have to be added to the mmio-sram
-declaration. These nodes are of two types depending upon secure or
-non-secure execution environment.
-
-Required sub-node properties:
-- compatible : depending upon boot mode, should be
-               "samsung,exynos4210-sysram" : for Secure SYSRAM
-               "samsung,exynos4210-sysram-ns" : for Non-secure SYSRAM
-
-The rest of the properties should follow the generic mmio-sram discription
-found in Documentation/devicetree/bindings/sram/sram.txt
-
-Example:
-
-       sysram@2020000 {
-               compatible = "mmio-sram";
-               reg = <0x02020000 0x54000>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0x02020000 0x54000>;
-
-               smp-sysram@0 {
-                       compatible = "samsung,exynos4210-sysram";
-                       reg = <0x0 0x1000>;
-               };
-
-               smp-sysram@53000 {
-                       compatible = "samsung,exynos4210-sysram-ns";
-                       reg = <0x53000 0x1000>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sram/sram.txt b/Documentation/devicetree/bindings/sram/sram.txt
deleted file mode 100644 (file)
index e98908b..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-Generic on-chip SRAM
-
-Simple IO memory regions to be managed by the genalloc API.
-
-Required properties:
-
-- compatible : mmio-sram or atmel,sama5d2-securam
-
-- reg : SRAM iomem address range
-
-Reserving sram areas:
----------------------
-
-Each child of the sram node specifies a region of reserved memory. Each
-child node should use a 'reg' property to specify a specific range of
-reserved memory.
-
-Following the generic-names recommended practice, node names should
-reflect the purpose of the node. Unit address (@<address>) should be
-appended to the name.
-
-Required properties in the sram node:
-
-- #address-cells, #size-cells : should use the same values as the root node
-- ranges : standard definition, should translate from local addresses
-           within the sram to bus addresses
-
-Optional properties in the sram node:
-
-- no-memory-wc : the flag indicating, that SRAM memory region has not to
-                 be remapped as write combining. WC is used by default.
-
-Required properties in the area nodes:
-
-- reg : iomem address range, relative to the SRAM range
-
-Optional properties in the area nodes:
-
-- compatible : standard definition, should contain a vendor specific string
-               in the form <vendor>,[<device>-]<usage>
-- pool : indicates that the particular reserved SRAM area is addressable
-         and in use by another device or devices
-- export : indicates that the reserved SRAM area may be accessed outside
-           of the kernel, e.g. by bootloader or userspace
-- protect-exec : Same as 'pool' above but with the additional
-                constraint that code wil be run from the region and
-                that the memory is maintained as read-only, executable
-                during code execution. NOTE: This region must be page
-                aligned on start and end in order to properly allow
-                manipulation of the page attributes.
-- label : the name for the reserved partition, if omitted, the label
-          is taken from the node name excluding the unit address.
-- clocks : a list of phandle and clock specifier pair that controls the
-          single SRAM clock.
-
-Example:
-
-sram: sram@5c000000 {
-       compatible = "mmio-sram";
-       reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
-
-       #address-cells = <1>;
-       #size-cells = <1>;
-       ranges = <0 0x5c000000 0x40000>;
-
-       smp-sram@100 {
-               compatible = "socvendor,smp-sram";
-               reg = <0x100 0x50>;
-       };
-
-       device-sram@1000 {
-               reg = <0x1000 0x1000>;
-               pool;
-       };
-
-       exported@20000 {
-               reg = <0x20000 0x20000>;
-               export;
-       };
-};
diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml
new file mode 100644 (file)
index 0000000..ee2287a
--- /dev/null
@@ -0,0 +1,257 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sram/sram.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic on-chip SRAM
+
+maintainers:
+  - Rob Herring <robh@kernel.org>
+
+description: |+
+  Simple IO memory regions to be managed by the genalloc API.
+
+  Each child of the sram node specifies a region of reserved memory. Each
+  child node should use a 'reg' property to specify a specific range of
+  reserved memory.
+
+  Following the generic-names recommended practice, node names should
+  reflect the purpose of the node. Unit address (@<address>) should be
+  appended to the name.
+
+properties:
+  $nodename:
+    pattern: "^sram(@.*)?"
+
+  compatible:
+    contains:
+      enum:
+        - mmio-sram
+        - atmel,sama5d2-securam
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description:
+      A list of phandle and clock specifier pair that controls the single
+      SRAM clock.
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges:
+    description:
+      Should translate from local addresses within the sram to bus addresses.
+
+  no-memory-wc:
+    description:
+      The flag indicating, that SRAM memory region has not to be remapped
+      as write combining. WC is used by default.
+    type: boolean
+
+patternProperties:
+  "^([a-z]*-)?sram@[a-f0-9]+$":
+    type: object
+    description:
+      Each child of the sram node specifies a region of reserved memory.
+    properties:
+      compatible:
+        description:
+          Should contain a vendor specific string in the form
+          <vendor>,[<device>-]<usage>
+        enum:
+          - allwinner,sun9i-a80-smp-sram
+          - amlogic,meson8-smp-sram
+          - amlogic,meson8b-smp-sram
+          - renesas,smp-sram
+          - rockchip,rk3066-smp-sram
+          - samsung,exynos4210-sysram
+          - samsung,exynos4210-sysram-ns
+          - socionext,milbeaut-smp-sram
+
+      reg:
+        description:
+          IO mem address range, relative to the SRAM range.
+        maxItems: 1
+
+      pool:
+        description:
+          Indicates that the particular reserved SRAM area is addressable
+          and in use by another device or devices.
+        type: boolean
+
+      export:
+        description:
+          Indicates that the reserved SRAM area may be accessed outside
+          of the kernel, e.g. by bootloader or userspace.
+        type: boolean
+
+      protect-exec:
+        description: |
+          Same as 'pool' above but with the additional constraint that code
+          will be run from the region and that the memory is maintained as
+          read-only, executable during code execution. NOTE: This region must
+          be page aligned on start and end in order to properly allow
+          manipulation of the page attributes.
+        type: boolean
+
+      label:
+        description:
+          The name for the reserved partition, if omitted, the label is taken
+          from the node name excluding the unit address.
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    sram@5c000000 {
+        compatible = "mmio-sram";
+        reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
+
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0x5c000000 0x40000>;
+
+        smp-sram@100 {
+            reg = <0x100 0x50>;
+        };
+
+        device-sram@1000 {
+            reg = <0x1000 0x1000>;
+            pool;
+        };
+
+        exported-sram@20000 {
+            reg = <0x20000 0x20000>;
+            export;
+        };
+    };
+
+  - |
+    // Samsung SMP-capable Exynos SoCs use part of the SYSRAM for the bringup
+    // of the secondary cores. Once the core gets powered up it executes the
+    // code that is residing at some specific location of the SYSRAM.
+    //
+    // Therefore reserved section sub-nodes have to be added to the mmio-sram
+    // declaration. These nodes are of two types depending upon secure or
+    // non-secure execution environment.
+    sram@2020000 {
+        compatible = "mmio-sram";
+        reg = <0x02020000 0x54000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0x02020000 0x54000>;
+
+        smp-sram@0 {
+            compatible = "samsung,exynos4210-sysram";
+            reg = <0x0 0x1000>;
+        };
+
+        smp-sram@53000 {
+            compatible = "samsung,exynos4210-sysram-ns";
+            reg = <0x53000 0x1000>;
+        };
+    };
+
+  - |
+    // Amlogic's SMP-capable SoCs use part of the sram for the bringup of the cores.
+    // Once the core gets powered up it executes the code that is residing at a
+    // specific location.
+    //
+    // Therefore a reserved section sub-node has to be added to the mmio-sram
+    // declaration.
+    sram@d9000000 {
+        compatible = "mmio-sram";
+        reg = <0xd9000000 0x20000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0xd9000000 0x20000>;
+
+        smp-sram@1ff80 {
+            compatible = "amlogic,meson8b-smp-sram";
+            reg = <0x1ff80 0x8>;
+        };
+    };
+
+  - |
+    sram@e63c0000 {
+        compatible = "mmio-sram";
+        reg = <0xe63c0000 0x1000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0xe63c0000 0x1000>;
+
+        smp-sram@0 {
+            compatible = "renesas,smp-sram";
+            reg = <0 0x10>;
+        };
+    };
+
+  - |
+    sram@10080000 {
+        compatible = "mmio-sram";
+        reg = <0x10080000 0x10000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        smp-sram@10080000 {
+            compatible = "rockchip,rk3066-smp-sram";
+            reg = <0x10080000 0x50>;
+        };
+    };
+
+  - |
+    // Allwinner's A80 SoC uses part of the secure sram for hotplugging of the
+    // primary core (cpu0). Once the core gets powered up it checks if a magic
+    // value is set at a specific location. If it is then the BROM will jump
+    // to the software entry address, instead of executing a standard boot.
+    //
+    // Also there are no "secure-only" properties. The implementation should
+    // check if this SRAM is usable first.
+    sram@20000 {
+        // 256 KiB secure SRAM at 0x20000
+        compatible = "mmio-sram";
+        reg = <0x00020000 0x40000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0x00020000 0x40000>;
+
+        smp-sram@1000 {
+            // This is checked by BROM to determine if
+            // cpu0 should jump to SMP entry vector
+            compatible = "allwinner,sun9i-a80-smp-sram";
+            reg = <0x1000 0x8>;
+        };
+    };
+
+  - |
+    sram@0 {
+        compatible = "mmio-sram";
+        reg = <0x0 0x10000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0x0 0x10000>;
+
+        smp-sram@f100 {
+            compatible = "socionext,milbeaut-smp-sram";
+            reg = <0xf100 0x20>;
+        };
+    };
index de0d609..98bee62 100644 (file)
@@ -15,17 +15,28 @@ I. For patch submitters
      use "Documentation" or "doc" because that is implied. All bindings are
      docs. Repeating "binding" again should also be avoided.
 
-  2) Submit the entire series to the devicetree mailinglist at
+  2) DT binding files are written in DT schema format using json-schema
+     vocabulary and YAML file format. The DT binding files must pass validation
+     by running:
+
+       make dt_binding_check
+
+     See ../writing-schema.rst for more details about schema and tools setup.
+
+  3) DT binding files should be dual licensed. The preferred license tag is
+     (GPL-2.0-only OR BSD-2-Clause).
+
+  4) Submit the entire series to the devicetree mailinglist at
 
        devicetree@vger.kernel.org
 
      and Cc: the DT maintainers. Use scripts/get_maintainer.pl to identify
      all of the DT maintainers.
 
-  3) The Documentation/ portion of the patch should come in the series before
+  5) The Documentation/ portion of the patch should come in the series before
      the code implementing the binding.
 
-  4) Any compatible strings used in a chip or board DTS file must be
+  6) Any compatible strings used in a chip or board DTS file must be
      previously documented in the corresponding DT binding text file
      in Documentation/devicetree/bindings.  This rule applies even if
      the Linux device driver does not yet match on the compatible
@@ -33,7 +44,7 @@ I. For patch submitters
      followed as of commit bff5da4335256513497cc8c79f9a9d1665e09864
      ("checkpatch: add DT compatible string documentation checks"). ]
 
-  5) The wildcard "<chip>" may be used in compatible strings, as in
+  7) The wildcard "<chip>" may be used in compatible strings, as in
      the following example:
 
          - compatible: Must contain '"nvidia,<chip>-pcie",
@@ -42,7 +53,7 @@ I. For patch submitters
      As in the above example, the known values of "<chip>" should be
      documented if it is used.
 
-  6) If a documented compatible string is not yet matched by the
+  8) If a documented compatible string is not yet matched by the
      driver, the documentation should also include a compatible
      string that is matched by the driver (as in the "nvidia,tegra20-pcie"
      example above).
diff --git a/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
new file mode 100644 (file)
index 0000000..f761681
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/amlogic,thermal.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic Thermal
+
+maintainers:
+  - Guillaume La Roque <glaroque@baylibre.com>
+
+description: Binding for Amlogic Thermal
+
+properties:
+  compatible:
+      items:
+        - enum:
+            - amlogic,g12a-cpu-thermal
+            - amlogic,g12a-ddr-thermal
+        - const: amlogic,g12a-thermal
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  amlogic,ao-secure:
+    description: phandle to the ao-secure syscon
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - amlogic,ao-secure
+
+examples:
+  - |
+        cpu_temp: temperature-sensor@ff634800 {
+                compatible = "amlogic,g12a-cpu-thermal",
+                             "amlogic,g12a-thermal";
+                reg = <0xff634800 0x50>;
+                interrupts = <0x0 0x24 0x0>;
+                clocks = <&clk 164>;
+                #thermal-sensor-cells = <0>;
+                amlogic,ao-secure = <&sec_AO>;
+        };
+...
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
deleted file mode 100644 (file)
index 673cc18..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-* QCOM SoC Temperature Sensor (TSENS)
-
-Required properties:
-- compatible:
-  Must be one of the following:
-    - "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
-  register spaces separately, with order being TM before SROT.
-  See Example 2, below.
-
-- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
-- #qcom,sensors: Number of sensors in tsens block
-- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
-nvmem cells
-
-Example 1 (legacy support before a fallback tsens-v2 property was introduced):
-tsens: thermal-sensor@900000 {
-               compatible = "qcom,msm8916-tsens";
-               reg = <0x4a8000 0x2000>;
-               nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
-               nvmem-cell-names = "caldata", "calsel";
-               #thermal-sensor-cells = <1>;
-       };
-
-Example 2 (for any platform containing v2 of the TSENS IP):
-tsens0: thermal-sensor@c263000 {
-               compatible = "qcom,sdm845-tsens", "qcom,tsens-v2";
-               reg = <0xc263000 0x1ff>, /* TM */
-                       <0xc222000 0x1ff>; /* SROT */
-               #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>;
-       };
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
new file mode 100644 (file)
index 0000000..eef13b9
--- /dev/null
@@ -0,0 +1,170 @@
+# SPDX-License-Identifier: (GPL-2.0 OR MIT)
+# Copyright 2019 Linaro Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/qcom-tsens.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: QCOM SoC Temperature Sensor (TSENS)
+
+maintainers:
+  - Amit Kucheria <amit.kucheria@linaro.org>
+
+description: |
+  QCOM SoCs have TSENS IP to allow temperature measurement. There are currently
+  three distinct major versions of the IP that is supported by a single driver.
+  The IP versions are named v0.1, v1 and v2 in the driver, where v0.1 captures
+  everything before v1 when there was no versioning information.
+
+properties:
+  compatible:
+    oneOf:
+      - description: v0.1 of TSENS
+        items:
+          - enum:
+              - qcom,msm8916-tsens
+              - qcom,msm8974-tsens
+          - const: qcom,tsens-v0_1
+
+      - description: v1 of TSENS
+        items:
+          - enum:
+              - qcom,msm8976-tsens
+              - qcom,qcs404-tsens
+          - const: qcom,tsens-v1
+
+      - description: v2 of TSENS
+        items:
+          - enum:
+              - qcom,msm8996-tsens
+              - qcom,msm8998-tsens
+              - qcom,sdm845-tsens
+          - const: qcom,tsens-v2
+
+  reg:
+    maxItems: 2
+    items:
+      - description: TM registers
+      - description: SROT registers
+
+  nvmem-cells:
+    minItems: 1
+    maxItems: 2
+    description:
+      Reference to an nvmem node for the calibration data
+
+  nvmem-cells-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - enum:
+        - caldata
+        - calsel
+
+  "#qcom,sensors":
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 1
+      - maximum: 16
+    description:
+      Number of sensors enabled on this platform
+
+  "#thermal-sensor-cells":
+    const: 1
+    description:
+      Number of cells required to uniquely identify the thermal sensors. Since
+      we have multiple sensors this is set to 1
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8916-tsens
+              - qcom,msm8974-tsens
+              - qcom,msm8976-tsens
+              - qcom,qcs404-tsens
+              - qcom,tsens-v0_1
+              - qcom,tsens-v1
+    then:
+      properties:
+        interrupts:
+          items:
+            - description: Combined interrupt if upper or lower threshold crossed
+        interrupt-names:
+          items:
+            - const: uplow
+
+    else:
+      properties:
+        interrupts:
+          items:
+            - description: Combined interrupt if upper or lower threshold crossed
+            - description: Interrupt if critical threshold crossed
+        interrupt-names:
+          items:
+            - const: uplow
+            - const: critical
+
+required:
+  - compatible
+  - reg
+  - "#qcom,sensors"
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example 1 (legacy: for pre v1 IP):
+    tsens1: thermal-sensor@900000 {
+           compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1";
+           reg = <0x4a9000 0x1000>, /* TM */
+                 <0x4a8000 0x1000>; /* SROT */
+
+           nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+           nvmem-cell-names = "caldata", "calsel";
+
+           interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+           interrupt-names = "uplow";
+
+           #qcom,sensors = <5>;
+           #thermal-sensor-cells = <1>;
+    };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example 2 (for any platform containing v1 of the TSENS IP):
+    tsens2: 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";
+
+          interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>;
+          interrupt-names = "uplow";
+
+          #qcom,sensors = <10>;
+          #thermal-sensor-cells = <1>;
+    };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example 3 (for any platform containing v2 of the TSENS IP):
+    tsens3: thermal-sensor@c263000 {
+           compatible = "qcom,sdm845-tsens", "qcom,tsens-v2";
+           reg = <0xc263000 0x1ff>,
+                 <0xc222000 0x1ff>;
+
+           interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>,
+                        <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>;
+           interrupt-names = "uplow", "critical";
+
+           #qcom,sensors = <13>;
+           #thermal-sensor-cells = <1>;
+    };
+...
index b6ab60f..12c740b 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
 - compatible           : "renesas,<soctype>-thermal",
                          Examples with soctypes are:
                            - "renesas,r8a774a1-thermal" (RZ/G2M)
+                           - "renesas,r8a774b1-thermal" (RZ/G2N)
                            - "renesas,r8a7795-thermal" (R-Car H3)
                            - "renesas,r8a7796-thermal" (R-Car M3-W)
                            - "renesas,r8a77965-thermal" (R-Car M3-N)
diff --git a/Documentation/devicetree/bindings/thermal/st,stm32-thermal.yaml b/Documentation/devicetree/bindings/thermal/st,stm32-thermal.yaml
new file mode 100644 (file)
index 0000000..c0f59c5
--- /dev/null
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/st,stm32-thermal.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 digital thermal sensor (DTS) binding
+
+maintainers:
+  - David Hernandez Sanchez <david.hernandezsanchez@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-thermal
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: pclk
+
+  "#thermal-sensor-cells":
+    const: 0
+
+required:
+  - "#thermal-sensor-cells"
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    dts: thermal@50028000 {
+        compatible = "st,stm32-thermal";
+        reg = <0x50028000 0x100>;
+        clocks = <&rcc TMPSENS>;
+        clock-names = "pclk";
+        #thermal-sensor-cells = <0>;
+        interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+    thermal-zones {
+        cpu_thermal: cpu-thermal {
+            polling-delay-passive = <0>;
+            polling-delay = <0>;
+
+            thermal-sensors = <&dts>;
+            trips {
+                cpu_alert1: cpu-alert1 {
+                    temperature = <85000>;
+                    hysteresis = <0>;
+                    type = "passive";
+                };
+
+                cpu_crit: cpu-crit {
+                    temperature = <120000>;
+                    hysteresis = <0>;
+                    type = "critical";
+                };
+            };
+
+            cooling-maps {
+            };
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/thermal/stm32-thermal.txt b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt
deleted file mode 100644 (file)
index 8c0d5a4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-Binding for Thermal Sensor for STMicroelectronics STM32 series of SoCs.
-
-On STM32 SoCs, the Digital Temperature Sensor (DTS) is in charge of managing an
-analog block which delivers a frequency depending on the internal SoC's
-temperature. By using a reference frequency, DTS is able to provide a sample
-number which can be translated into a temperature by the user.
-
-DTS provides interrupt notification mechanism by threshold. This mechanism
-offers two temperature trip points: passive and critical. The first is intended
-for passive cooling notification while the second is used for over-temperature
-reset.
-
-Required parameters:
--------------------
-
-compatible:    Should be "st,stm32-thermal"
-reg:           This should be the physical base address and length of the
-               sensor's registers.
-clocks:        Phandle of the clock used by the thermal sensor.
-                 See: Documentation/devicetree/bindings/clock/clock-bindings.txt
-clock-names:   Should be "pclk" for register access clock and reference clock.
-                 See: Documentation/devicetree/bindings/resource-names.txt
-#thermal-sensor-cells: Should be 0. See ./thermal.txt for a description.
-interrupts:    Standard way to define interrupt number.
-
-Example:
-
-       thermal-zones {
-               cpu_thermal: cpu-thermal {
-                       polling-delay-passive = <0>;
-                       polling-delay = <0>;
-
-                       thermal-sensors = <&thermal>;
-
-                       trips {
-                               cpu_alert1: cpu-alert1 {
-                                       temperature = <85000>;
-                                       hysteresis = <0>;
-                                       type = "passive";
-                               };
-
-                               cpu-crit: cpu-crit {
-                                       temperature = <120000>;
-                                       hysteresis = <0>;
-                                       type = "critical";
-                               };
-                       };
-
-                       cooling-maps {
-                       };
-               };
-       };
-
-       thermal: thermal@50028000 {
-               compatible = "st,stm32-thermal";
-               reg = <0x50028000 0x100>;
-               clocks = <&rcc TMPSENS>;
-               clock-names = "pclk";
-               #thermal-sensor-cells = <0>;
-               interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
-       };
index 5a4b9dd..0b63ceb 100644 (file)
@@ -2,7 +2,7 @@ Ingenic JZ47xx SoCs Timer/Counter Unit devicetree bindings
 ==========================================================
 
 For a description of the TCU hardware and drivers, have a look at
-Documentation/mips/ingenic-tcu.txt.
+Documentation/mips/ingenic-tcu.rst.
 
 Required properties:
 
@@ -42,7 +42,7 @@ Required properties:
 - compatible: Must be one of:
   * ingenic,jz4740-pwm
   * ingenic,jz4725b-pwm
-- #pwm-cells: Should be 3. See ../pwm/pwm.txt for a description of the cell
+- #pwm-cells: Should be 3. See ../pwm/pwm.yaml for a description of the cell
   format.
 - clocks: List of phandle & clock specifiers for the TCU clocks.
 - clock-names: List of name strings for the TCU clocks.
index 74c3ead..0d25648 100644 (file)
@@ -21,6 +21,7 @@ Required properties:
        * "mediatek,mt6577-timer" for MT6577 and all above compatible timers (GPT)
 
        For those SoCs that use SYST
+       * "mediatek,mt8183-timer" for MT8183 compatible timers (SYST)
        * "mediatek,mt7629-timer" for MT7629 compatible timers (SYST)
        * "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST)
 
index 13ad074..9dff7e5 100644 (file)
@@ -10,6 +10,7 @@ Required Properties:
 
   - compatible: must contain one or more of the following:
     - "renesas,tmu-r8a7740" for the r8a7740 TMU
+    - "renesas,tmu-r8a774a1" for the r8a774A1 TMU
     - "renesas,tmu-r8a774c0" for the r8a774C0 TMU
     - "renesas,tmu-r8a7778" for the r8a7778 TMU
     - "renesas,tmu-r8a7779" for the r8a7779 TMU
diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
deleted file mode 100644 (file)
index 8f78640..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-Samsung's Multi Core Timer (MCT)
-
-The Samsung's Multi Core Timer (MCT) module includes two main blocks, the
-global timer and CPU local timers. The global timer is a 64-bit free running
-up-counter and can generate 4 interrupts when the counter reaches one of the
-four preset counter values. The CPU local timers are 32-bit free running
-down-counters and generate an interrupt when the counter expires. There is
-one CPU local timer instantiated in MCT for every CPU in the system.
-
-Required properties:
-
-- compatible: should be "samsung,exynos4210-mct".
-  (a) "samsung,exynos4210-mct", for mct compatible with Exynos4210 mct.
-  (b) "samsung,exynos4412-mct", for mct compatible with Exynos4412 mct.
-
-- reg: base address of the mct controller and length of the address space
-  it occupies.
-
-- interrupts: the list of interrupts generated by the controller. The following
-  should be the order of the interrupts specified. The local timer interrupts
-  should be specified after the four global timer interrupts have been
-  specified.
-
-       0: Global Timer Interrupt 0
-       1: Global Timer Interrupt 1
-       2: Global Timer Interrupt 2
-       3: Global Timer Interrupt 3
-       4: Local Timer Interrupt 0
-       5: Local Timer Interrupt 1
-       6: ..
-       7: ..
-       i: Local Timer Interrupt n
-
-  For MCT block that uses a per-processor interrupt for local timers, such
-  as ones compatible with "samsung,exynos4412-mct", only one local timer
-  interrupt might be specified, meaning that all local timers use the same
-  per processor interrupt.
-
-Example 1: In this example, the IP contains two local timers, using separate
-          interrupts, so two local timer interrupts have been specified,
-          in addition to four global timer interrupts.
-
-       mct@10050000 {
-               compatible = "samsung,exynos4210-mct";
-               reg = <0x10050000 0x800>;
-               interrupts = <0 57 0>, <0 69 0>, <0 70 0>, <0 71 0>,
-                            <0 42 0>, <0 48 0>;
-       };
-
-Example 2: In this example, the timer interrupts are connected to two separate
-          interrupt controllers. Hence, an interrupt-map is created to map
-          the interrupts to the respective interrupt controllers.
-
-       mct@101c0000 {
-               compatible = "samsung,exynos4210-mct";
-               reg = <0x101C0000 0x800>;
-               interrupt-parent = <&mct_map>;
-               interrupts = <0>, <1>, <2>, <3>, <4>, <5>;
-
-               mct_map: mct-map {
-                       #interrupt-cells = <1>;
-                       #address-cells = <0>;
-                       #size-cells = <0>;
-                       interrupt-map = <0 &gic 0 57 0>,
-                                       <1 &gic 0 69 0>,
-                                       <2 &combiner 12 6>,
-                                       <3 &combiner 12 7>,
-                                       <4 &gic 0 42 0>,
-                                       <5 &gic 0 48 0>;
-               };
-       };
-
-Example 3: In this example, the IP contains four local timers, but using
-          a per-processor interrupt to handle them. Either all the local
-          timer interrupts can be specified, with the same interrupt specifier
-          value or just the first one.
-
-       mct@10050000 {
-               compatible = "samsung,exynos4412-mct";
-               reg = <0x10050000 0x800>;
-
-               /* Both ways are possible in this case. Either: */
-               interrupts = <0 57 0>, <0 69 0>, <0 70 0>, <0 71 0>,
-                            <0 42 0>;
-               /* or: */
-               interrupts = <0 57 0>, <0 69 0>, <0 70 0>, <0 71 0>,
-                            <0 42 0>, <0 42 0>, <0 42 0>, <0 42 0>;
-       };
diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml
new file mode 100644 (file)
index 0000000..273e359
--- /dev/null
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/samsung,exynos4210-mct.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC Multi Core Timer (MCT)
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |+
+  The Samsung's Multi Core Timer (MCT) module includes two main blocks, the
+  global timer and CPU local timers. The global timer is a 64-bit free running
+  up-counter and can generate 4 interrupts when the counter reaches one of the
+  four preset counter values. The CPU local timers are 32-bit free running
+  down-counters and generate an interrupt when the counter expires. There is
+  one CPU local timer instantiated in MCT for every CPU in the system.
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos4210-mct
+      - samsung,exynos4412-mct
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: |
+      Interrupts should be put in specific order. This is, the local timer
+      interrupts should be specified after the four global timer interrupts
+      have been specified:
+      0: Global Timer Interrupt 0
+      1: Global Timer Interrupt 1
+      2: Global Timer Interrupt 2
+      3: Global Timer Interrupt 3
+      4: Local Timer Interrupt 0
+      5: Local Timer Interrupt 1
+      6: ..
+      7: ..
+      i: Local Timer Interrupt n
+      For MCT block that uses a per-processor interrupt for local timers, such
+      as ones compatible with "samsung,exynos4412-mct", only one local timer
+      interrupt might be specified, meaning that all local timers use the same
+      per processor interrupt.
+    minItems: 5               # 4 Global + 1 local
+    maxItems: 20              # 4 Global + 16 local
+
+required:
+  - compatible
+  - interrupts
+  - reg
+
+examples:
+  - |
+    // In this example, the IP contains two local timers, using separate
+    // interrupts, so two local timer interrupts have been specified,
+    // in addition to four global timer interrupts.
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    timer@10050000 {
+        compatible = "samsung,exynos4210-mct";
+        reg = <0x10050000 0x800>;
+        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+  - |
+    // In this example, the timer interrupts are connected to two separate
+    // interrupt controllers. Hence, an interrupts-extended is needed.
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    timer@101c0000 {
+        compatible = "samsung,exynos4210-mct";
+        reg = <0x101C0000 0x800>;
+        interrupts-extended = <&gic GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                              <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+                              <&combiner 12 6>,
+                              <&combiner 12 7>,
+                              <&gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                              <&gic GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+  - |
+    // In this example, the IP contains four local timers, but using
+    // a per-processor interrupt to handle them. Only one first local
+    // interrupt is specified.
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    timer@10050000 {
+        compatible = "samsung,exynos4412-mct";
+        reg = <0x10050000 0x800>;
+
+        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_PPI 42 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+  - |
+    // In this example, the IP contains four local timers, but using
+    // a per-processor interrupt to handle them. All the local timer
+    // interrupts are specified.
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    timer@10050000 {
+        compatible = "samsung,exynos4412-mct";
+        reg = <0x10050000 0x800>;
+
+        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_PPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_PPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_PPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_PPI 42 IRQ_TYPE_LEVEL_HIGH>;
+    };
diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
deleted file mode 100644 (file)
index 8ef28e7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-. STMicroelectronics STM32 timer
-
-The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
-
-Required properties:
-- compatible : Should be "st,stm32-timer"
-- reg : Address and length of the register set
-- clocks : Reference on the timer input clock
-- interrupts : Reference to the timer interrupt
-
-Optional properties:
-- resets: Reference to a reset controller asserting the timer
-
-Example:
-
-timer5: timer@40000c00 {
-       compatible = "st,stm32-timer";
-       reg = <0x40000c00 0x400>;
-       interrupts = <50>;
-       resets = <&rrc 259>;
-       clocks = <&clk_pmtr1>;
-};
diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.yaml b/Documentation/devicetree/bindings/timer/st,stm32-timer.yaml
new file mode 100644 (file)
index 0000000..176aa3c
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/st,stm32-timer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 general-purpose 16 and 32 bits timers bindings
+
+maintainers:
+  - Benjamin Gaignard <benjamin.gaignard@st.com>
+
+properties:
+  compatible:
+    const: st,stm32-timer
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    timer: timer@40000c00 {
+        compatible = "st,stm32-timer";
+        reg = <0x40000c00 0x400>;
+        interrupts = <50>;
+        clocks = <&clk_pmtr1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml b/Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml
new file mode 100644 (file)
index 0000000..c8a2a92
--- /dev/null
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ufs/ti,j721e-ufs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI J721e UFS Host Controller Glue Driver
+
+maintainers:
+  - Vignesh Raghavendra <vigneshr@ti.com>
+
+properties:
+  compatible:
+    items:
+      - const: ti,j721e-ufs
+
+  reg:
+    maxItems: 1
+    description: address of TI UFS glue registers
+
+  clocks:
+    maxItems: 1
+    description: phandle to the M-PHY clock
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - power-domains
+
+patternProperties:
+  "^ufs@[0-9a-f]+$":
+    type: object
+    description: |
+      Cadence UFS controller node must be the child node. Refer
+      Documentation/devicetree/bindings/ufs/cdns,ufshc.txt for binding
+      documentation of child node
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ufs_wrapper: ufs-wrapper@4e80000 {
+       compatible = "ti,j721e-ufs";
+       reg = <0x0 0x4e80000 0x0 0x100>;
+       power-domains = <&k3_pds 277>;
+       clocks = <&k3_clks 277 1>;
+       assigned-clocks = <&k3_clks 277 1>;
+       assigned-clock-parents = <&k3_clks 277 4>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       ufs@4e84000 {
+          compatible = "cdns,ufshc-m31-16nm", "jedec,ufs-2.0";
+          reg = <0x0 0x4e84000 0x0 0x10000>;
+          interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+          freq-table-hz = <19200000 19200000>;
+          power-domains = <&k3_pds 277>;
+          clocks = <&k3_clks 277 1>;
+          assigned-clocks = <&k3_clks 277 1>;
+          assigned-clock-parents = <&k3_clks 277 4>;
+          clock-names = "core_clk";
+       };
+    };
index d78ef63..415ccdd 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
                            "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"
+                           "qcom,sm8150-ufshc", "qcom,ufshc", "jedec,ufs-2.0"
 - interrupts        : <interrupt mapping for UFS host controller IRQ>
 - reg               : <registers mapping>
 
diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
deleted file mode 100644 (file)
index 50abb20..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-Allwinner sun4i A10 musb DRC/OTG controller
--------------------------------------------
-
-Required properties:
- - compatible      : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb",
-                     "allwinner,sun8i-a33-musb" or "allwinner,sun8i-h3-musb"
- - reg             : mmio address range of the musb controller
- - clocks          : clock specifier for the musb controller ahb gate clock
- - reset           : reset specifier for the ahb reset (A31 and newer only)
- - interrupts      : interrupt to which the musb controller is connected
- - interrupt-names : must be "mc"
- - phys            : phy specifier for the otg phy
- - phy-names       : must be "usb"
- - dr_mode         : Dual-Role mode must be "host" or "otg"
- - extcon          : extcon specifier for the otg phy
-
-Example:
-
-       usb_otg: usb@1c13000 {
-               compatible = "allwinner,sun4i-a10-musb";
-               reg = <0x01c13000 0x0400>;
-               clocks = <&ahb_gates 0>;
-               interrupts = <38>;
-               interrupt-names = "mc";
-               phys = <&usbphy 0>;
-               phy-names = "usb";
-               extcon = <&usbphy 0>;
-       };
diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml
new file mode 100644 (file)
index 0000000..0af70fc
--- /dev/null
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/allwinner,sun4i-a10-musb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 mUSB OTG Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: allwinner,sun4i-a10-musb
+      - const: allwinner,sun6i-a31-musb
+      - const: allwinner,sun8i-a33-musb
+      - const: allwinner,sun8i-h3-musb
+      - items:
+          - enum:
+              - allwinner,sun8i-a83t-musb
+              - allwinner,sun50i-h6-musb
+          - const: allwinner,sun8i-a33-musb
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-names:
+    const: mc
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  phys:
+    description: PHY specifier for the OTG PHY
+
+  phy-names:
+    const: usb
+
+  extcon:
+    description: Extcon specifier for the OTG PHY
+
+  dr_mode:
+    enum:
+      - host
+      - otg
+      - peripheral
+
+  allwinner,sram:
+    description: Phandle to the device SRAM
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - phys
+  - phy-names
+  - dr_mode
+  - extcon
+
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - allwinner,sun6i-a31-musb
+          - allwinner,sun8i-a33-musb
+          - allwinner,sun8i-h3-musb
+
+then:
+  required:
+    - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    usb_otg: usb@1c13000 {
+      compatible = "allwinner,sun4i-a10-musb";
+      reg = <0x01c13000 0x0400>;
+      clocks = <&ahb_gates 0>;
+      interrupts = <38>;
+      interrupt-names = "mc";
+      phys = <&usbphy 0>;
+      phy-names = "usb";
+      extcon = <&usbphy 0>;
+      dr_mode = "peripheral";
+    };
+
+...
index 6ffb09b..9a8b631 100644 (file)
@@ -40,91 +40,3 @@ Example device nodes:
                                phy-names = "usb2-phy", "usb3-phy";
                        };
                };
-
-Amlogic Meson G12A DWC3 USB SoC Controller Glue
-
-The Amlogic G12A embeds a DWC3 USB IP Core configured for USB2 and USB3
-in host-only mode, and a DWC2 IP Core configured for USB2 peripheral mode
-only.
-
-A glue connects the DWC3 core to USB2 PHYs and optionnaly to an USB3 PHY.
-
-One of the USB2 PHY can be re-routed in peripheral mode to a DWC2 USB IP.
-
-The DWC3 Glue controls the PHY routing and power, an interrupt line is
-connected to the Glue to serve as OTG ID change detection.
-
-Required properties:
-- compatible:  Should be "amlogic,meson-g12a-usb-ctrl"
-- clocks:      a handle for the "USB" clock
-- resets:      a handle for the shared "USB" reset line
-- reg:         The base address and length of the registers
-- interrupts:  the interrupt specifier for the OTG detection
-- phys:        handle to used PHYs on the system
-       - a <0> phandle can be used if a PHY is not used
-- phy-names:   names of the used PHYs on the system :
-       - "usb2-phy0" for USB2 PHY0 if USBHOST_A port is used
-       - "usb2-phy1" for USB2 PHY1 if USBOTG_B port is used
-       - "usb3-phy0" for USB3 PHY if USB3_0 is used
-- dr_mode:     should be "host", "peripheral", or "otg" depending on
-       the usage and configuration of the OTG Capable port.
-       - "host" and "peripheral" means a fixed Host or Device only connection
-       - "otg" means the port can be used as both Host or Device and
-         be switched automatically using the OTG ID pin.
-
-Optional properties:
-- vbus-supply: should be a phandle to the regulator controlling the VBUS
-               power supply when used in OTG switchable mode
-
-Required child nodes:
-
-A child node must exist to represent the core DWC3 IP block. The name of
-the node is not important. The content of the node is defined in dwc3.txt.
-
-A child node must exist to represent the core DWC2 IP block. The name of
-the node is not important. The content of the node is defined in dwc2.txt.
-
-PHY documentation is provided in the following places:
-- Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
-- Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml
-
-Example device nodes:
-       usb: usb@ffe09000 {
-                       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;
-                       };
-       };
diff --git a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml
new file mode 100644 (file)
index 0000000..4efb77b
--- /dev/null
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Meson G12A DWC3 USB SoC Controller Glue
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+
+description: |
+  The Amlogic G12A embeds a DWC3 USB IP Core configured for USB2 and USB3
+  in host-only mode, and a DWC2 IP Core configured for USB2 peripheral mode
+  only.
+
+  A glue connects the DWC3 core to USB2 PHYs and optionally to an USB3 PHY.
+
+  One of the USB2 PHYs can be re-routed in peripheral mode to a DWC2 USB IP.
+
+  The DWC3 Glue controls the PHY routing and power, an interrupt line is
+  connected to the Glue to serve as OTG ID change detection.
+
+properties:
+  compatible:
+    enum:
+      - amlogic,meson-g12a-usb-ctrl
+
+  ranges: true
+
+  "#address-cells":
+    enum: [ 1, 2 ]
+
+  "#size-cells":
+    enum: [ 1, 2 ]
+
+  clocks:
+    minItems: 1
+
+  resets:
+    minItems: 1
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  phy-names:
+    items:
+      - const: usb2-phy0 # USB2 PHY0 if USBHOST_A port is used
+      - const: usb2-phy1 # USB2 PHY1 if USBOTG_B port is used
+      - const: usb3-phy0 # USB3 PHY if USB3_0 is used
+
+  phys:
+    minItems: 1
+    maxItems: 3
+
+  dr_mode: true
+
+  power-domains:
+    maxItems: 1
+
+  vbus-supply:
+    description: VBUS power supply when used in OTG switchable mode
+
+patternProperties:
+  "^usb@[0-9a-f]+$":
+    type: object
+
+additionalProperties: false
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - clocks
+  - resets
+  - reg
+  - interrupts
+  - phy-names
+  - phys
+  - dr_mode
+
+examples:
+  - |
+    usb: usb@ffe09000 {
+          compatible = "amlogic,meson-g12a-usb-ctrl";
+          reg = <0x0 0xffe09000 0x0 0xa0>;
+          interrupts = <16>;
+          #address-cells = <1>;
+          #size-cells = <1>;
+          ranges;
+
+          clocks = <&clkc_usb>;
+          resets = <&reset_usb>;
+
+          dr_mode = "otg";
+
+          phys = <&usb2_phy0>, <&usb2_phy1>, <&usb3_phy0>;
+          phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0";
+
+          dwc2: usb@ff400000 {
+              compatible = "amlogic,meson-g12a-usb", "snps,dwc2";
+              reg = <0xff400000 0x40000>;
+              interrupts = <31>;
+              clocks = <&clkc_usb1>;
+              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 = <0xff500000 0x100000>;
+              interrupts = <30>;
+              dr_mode = "host";
+              snps,dis_u2_susphy_quirk;
+              snps,quirk-frame-length-adjustment;
+          };
+    };
+
index 1ca64c8..10edd05 100644 (file)
@@ -63,6 +63,11 @@ properties:
     description:
       Set this flag to force EHCI reset after resume.
 
+  companion:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+     Phandle of a companion.
+
   phys:
     description: PHY specifier for the USB PHY
 
index fd6fa07..6046f45 100644 (file)
@@ -707,6 +707,8 @@ patternProperties:
     description: Ortus Technology Co., Ltd.
   "^osddisplays,.*":
     description: OSD Displays
+  "^overkiz,.*":
+    description: Overkiz SAS
   "^ovti,.*":
     description: OmniVision Technologies
   "^oxsemi,.*":
@@ -990,6 +992,8 @@ patternProperties:
     description: Ubiquiti Networks
   "^udoo,.*":
     description: Udoo
+  "^ugoos,.*":
+    description: Ugoos Industrial Co., Ltd.
   "^uniwest,.*":
     description: United Western Technologies Corp (UniWest)
   "^upisemi,.*":
index d7352f7..4ddae6f 100644 (file)
@@ -10,6 +10,9 @@ title: Meson GXBB SoCs Watchdog timer
 maintainers:
   - Neil Armstrong <narmstrong@baylibre.com>
 
+allOf:
+  - $ref: watchdog.yaml#
+
 properties:
   compatible:
     enum:
index 9f365c1..a5bf04d 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
                 - "renesas,r8a7745-wdt" (RZ/G1E)
                 - "renesas,r8a77470-wdt" (RZ/G1C)
                 - "renesas,r8a774a1-wdt" (RZ/G2M)
+                - "renesas,r8a774b1-wdt" (RZ/G2N)
                 - "renesas,r8a774c0-wdt" (RZ/G2E)
                 - "renesas,r8a7790-wdt" (R-Car H2)
                 - "renesas,r8a7791-wdt" (R-Car M2-W)
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
deleted file mode 100644 (file)
index 46dcb48..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-* Samsung's Watchdog Timer Controller
-
-The Samsung's Watchdog controller is used for resuming system operation
-after a preset amount of time during which the WDT reset event has not
-occurred.
-
-Required properties:
-- compatible : should be one among the following
-       - "samsung,s3c2410-wdt" for S3C2410
-       - "samsung,s3c6410-wdt" for S3C6410, S5PV210 and Exynos4
-       - "samsung,exynos5250-wdt" for Exynos5250
-       - "samsung,exynos5420-wdt" for Exynos5420
-       - "samsung,exynos7-wdt" for Exynos7
-
-- reg : base physical address of the controller and length of memory mapped
-       region.
-- interrupts : interrupt number to the cpu.
-- samsung,syscon-phandle : reference to syscon node (This property required only
-       in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt".
-       In case of Exynos5250 and 5420 this property points to syscon node holding the PMU
-       base address)
-
-Optional properties:
-- timeout-sec : contains the watchdog timeout in seconds.
-
-Example:
-
-watchdog@101d0000 {
-       compatible = "samsung,exynos5250-wdt";
-       reg = <0x101D0000 0x100>;
-       interrupts = <0 42 0>;
-       clocks = <&clock 336>;
-       clock-names = "watchdog";
-       samsung,syscon-phandle = <&pmu_syscon>;
-};
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
new file mode 100644 (file)
index 0000000..2fa40d8
--- /dev/null
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/samsung-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC Watchdog Timer Controller
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |+
+  The Samsung's Watchdog controller is used for resuming system operation
+  after a preset amount of time during which the WDT reset event has not
+  occurred.
+
+properties:
+  compatible:
+    enum:
+      - samsung,s3c2410-wdt                   # for S3C2410
+      - samsung,s3c6410-wdt                   # for S3C6410, S5PV210 and Exynos4
+      - samsung,exynos5250-wdt                # for Exynos5250
+      - samsung,exynos5420-wdt                # for Exynos5420
+      - samsung,exynos7-wdt                   # for Exynos7
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: watchdog
+
+  interrupts:
+    maxItems: 1
+
+  samsung,syscon-phandle:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the PMU system controller node (in case of Exynos5250
+      and Exynos5420).
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - interrupts
+  - reg
+
+allOf:
+  - $ref: watchdog.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos5250-wdt
+              - samsung,exynos5420-wdt
+    then:
+      required:
+        - samsung,syscon-phandle
+
+examples:
+  - |
+    watchdog@101d0000 {
+        compatible = "samsung,exynos5250-wdt";
+        reg = <0x101D0000 0x100>;
+        interrupts = <0 42 0>;
+        clocks = <&clock 336>;
+        clock-names = "watchdog";
+        samsung,syscon-phandle = <&pmu_syscon>;
+    };
index f4a6380..efcd5d2 100644 (file)
@@ -117,6 +117,9 @@ project can be installed with pip::
 
     pip3 install git+https://github.com/devicetree-org/dt-schema.git@master
 
+Several executables (dt-doc-validate, dt-mk-schema, dt-validate) will be
+installed. Ensure they are in your PATH (~/.local/bin by default).
+
 dtc must also be built with YAML output support enabled. This requires that
 libyaml and its headers be installed on the host system.
 
@@ -130,11 +133,13 @@ binding schema. All of the DT binding documents can be validated using the
 
     make dt_binding_check
 
-In order to perform validation of DT source files, use the `dtbs_check` target::
+In order to perform validation of DT source files, use the ``dtbs_check`` target::
 
     make dtbs_check
 
-This will first run the `dt_binding_check` which generates the processed schema.
+Note that ``dtbs_check`` will skip any binding schema files with errors. It is
+necessary to use ``dt_binding_check`` to get all the validation errors in the
+binding schema files.
 
 It is also possible to run checks with a single schema file by setting the
 ``DT_SCHEMA_FILES`` variable to a specific schema file.
index 192c36a..fff6604 100644 (file)
@@ -476,6 +476,22 @@ internal: *[source-pattern ...]*
     .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
        :internal:
 
+identifiers: *[ function/type ...]*
+  Include documentation for each *function* and *type* in *source*.
+  If no *function* is specified, the documentation for all functions
+  and types in the *source* will be included.
+
+  Examples::
+
+    .. kernel-doc:: lib/bitmap.c
+       :identifiers: bitmap_parselist bitmap_parselist_user
+
+    .. kernel-doc:: lib/idr.c
+       :identifiers:
+
+functions: *[ function/type ...]*
+  This is an alias of the 'identifiers' directive and deprecated.
+
 doc: *title*
   Include documentation for the ``DOC:`` paragraph identified by *title* in
   *source*. Spaces are allowed in *title*; do not quote the *title*. The *title*
@@ -488,19 +504,6 @@ doc: *title*
     .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
        :doc: High Definition Audio over HDMI and Display Port
 
-functions: *[ function ...]*
-  Include documentation for each *function* in *source*.
-  If no *function* is specified, the documentation for all functions
-  and types in the *source* will be included.
-
-  Examples::
-
-    .. kernel-doc:: lib/bitmap.c
-       :functions: bitmap_parselist bitmap_parselist_user
-
-    .. kernel-doc:: lib/idr.c
-       :functions:
-
 Without options, the kernel-doc directive includes all documentation comments
 from the source file.
 
index 9f43928..72fc2e9 100644 (file)
@@ -179,6 +179,7 @@ mkutf8data
 modpost
 modules.builtin
 modules.builtin.modinfo
+modules.nsdeps
 modules.order
 modversions.h*
 nconf
diff --git a/Documentation/driver-api/dell_rbu.rst b/Documentation/driver-api/dell_rbu.rst
deleted file mode 100644 (file)
index 5d1ce7b..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-=============================================================
-Usage of the new open sourced rbu (Remote BIOS Update) driver
-=============================================================
-
-Purpose
-=======
-
-Document demonstrating the use of the Dell Remote BIOS Update driver.
-for updating BIOS images on Dell servers and desktops.
-
-Scope
-=====
-
-This document discusses the functionality of the rbu driver only.
-It does not cover the support needed from applications to enable the BIOS to
-update itself with the image downloaded in to the memory.
-
-Overview
-========
-
-This driver works with Dell OpenManage or Dell Update Packages for updating
-the BIOS on Dell servers (starting from servers sold since 1999), desktops
-and notebooks (starting from those sold in 2005).
-
-Please go to  http://support.dell.com register and you can find info on
-OpenManage and Dell Update packages (DUP).
-
-Libsmbios can also be used to update BIOS on Dell systems go to
-http://linux.dell.com/libsmbios/ for details.
-
-Dell_RBU driver supports BIOS update using the monolithic image and packetized
-image methods. In case of monolithic the driver allocates a contiguous chunk
-of physical pages having the BIOS image. In case of packetized the app
-using the driver breaks the image in to packets of fixed sizes and the driver
-would place each packet in contiguous physical memory. The driver also
-maintains a link list of packets for reading them back.
-
-If the dell_rbu driver is unloaded all the allocated memory is freed.
-
-The rbu driver needs to have an application (as mentioned above)which will
-inform the BIOS to enable the update in the next system reboot.
-
-The user should not unload the rbu driver after downloading the BIOS image
-or updating.
-
-The driver load creates the following directories under the /sys file system::
-
-       /sys/class/firmware/dell_rbu/loading
-       /sys/class/firmware/dell_rbu/data
-       /sys/devices/platform/dell_rbu/image_type
-       /sys/devices/platform/dell_rbu/data
-       /sys/devices/platform/dell_rbu/packet_size
-
-The driver supports two types of update mechanism; monolithic and packetized.
-These update mechanism depends upon the BIOS currently running on the system.
-Most of the Dell systems support a monolithic update where the BIOS image is
-copied to a single contiguous block of physical memory.
-
-In case of packet mechanism the single memory can be broken in smaller chunks
-of contiguous memory and the BIOS image is scattered in these packets.
-
-By default the driver uses monolithic memory for the update type. This can be
-changed to packets during the driver load time by specifying the load
-parameter image_type=packet.  This can also be changed later as below::
-
-       echo packet > /sys/devices/platform/dell_rbu/image_type
-
-In packet update mode the packet size has to be given before any packets can
-be downloaded. It is done as below::
-
-       echo XXXX > /sys/devices/platform/dell_rbu/packet_size
-
-In the packet update mechanism, the user needs to create a new file having
-packets of data arranged back to back. It can be done as follows
-The user creates packets header, gets the chunk of the BIOS image and
-places it next to the packetheader; now, the packetheader + BIOS image chunk
-added together should match the specified packet_size. This makes one
-packet, the user needs to create more such packets out of the entire BIOS
-image file and then arrange all these packets back to back in to one single
-file.
-
-This file is then copied to /sys/class/firmware/dell_rbu/data.
-Once this file gets to the driver, the driver extracts packet_size data from
-the file and spreads it across the physical memory in contiguous packet_sized
-space.
-
-This method makes sure that all the packets get to the driver in a single operation.
-
-In monolithic update the user simply get the BIOS image (.hdr file) and copies
-to the data file as is without any change to the BIOS image itself.
-
-Do the steps below to download the BIOS image.
-
-1) echo 1 > /sys/class/firmware/dell_rbu/loading
-2) cp bios_image.hdr /sys/class/firmware/dell_rbu/data
-3) echo 0 > /sys/class/firmware/dell_rbu/loading
-
-The /sys/class/firmware/dell_rbu/ entries will remain till the following is
-done.
-
-::
-
-       echo -1 > /sys/class/firmware/dell_rbu/loading
-
-Until this step is completed the driver cannot be unloaded.
-
-Also echoing either mono, packet or init in to image_type will free up the
-memory allocated by the driver.
-
-If a user by accident executes steps 1 and 3 above without executing step 2;
-it will make the /sys/class/firmware/dell_rbu/ entries disappear.
-
-The entries can be recreated by doing the following::
-
-       echo init > /sys/devices/platform/dell_rbu/image_type
-
-.. note:: echoing init in image_type does not change it original value.
-
-Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to
-read back the image downloaded.
-
-.. note::
-
-   After updating the BIOS image a user mode application needs to execute
-   code which sends the BIOS update request to the BIOS. So on the next reboot
-   the BIOS knows about the new image downloaded and it updates itself.
-   Also don't unload the rbu driver if the image has to be updated.
-
diff --git a/Documentation/driver-api/devfreq.rst b/Documentation/driver-api/devfreq.rst
new file mode 100644 (file)
index 0000000..4a0bf87
--- /dev/null
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================
+Device Frequency Scaling
+========================
+
+Introduction
+------------
+
+This framework provides a standard kernel interface for Dynamic Voltage and
+Frequency Switching on arbitrary devices.
+
+It exposes controls for adjusting frequency through sysfs files which are
+similar to the cpufreq subsystem.
+
+Devices for which current usage can be measured can have their frequency
+automatically adjusted by governors.
+
+API
+---
+
+Device drivers need to initialize a :c:type:`devfreq_profile` and call the
+:c:func:`devfreq_add_device` function to create a :c:type:`devfreq` instance.
+
+.. kernel-doc:: include/linux/devfreq.h
+.. kernel-doc:: include/linux/devfreq-event.h
+.. kernel-doc:: drivers/devfreq/devfreq.c
+        :export:
+.. kernel-doc:: drivers/devfreq/devfreq-event.c
+        :export:
index 10ef357..2ff7431 100644 (file)
@@ -500,7 +500,7 @@ available but we try to move away from this:
   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)
+  (See Documentation/driver-api/driver-model/design-patterns.rst)
 
 - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
   as discussed above regarding different types of cascaded irqchips. The
index 3bcd9a1..0ebe205 100644 (file)
@@ -40,6 +40,7 @@ available subsections can be seen below.
    ipmb
    i3c/index
    interconnect
+   devfreq
    hsi
    edac
    scsi
@@ -73,7 +74,6 @@ available subsections can be seen below.
    connector
    console
    dcdbas
-   dell_rbu
    edid
    eisa
    ipmb
@@ -93,7 +93,6 @@ available subsections can be seen below.
    pwm
    rfkill
    serial/index
-   sgi-ioc4
    sm501
    smsc_ece1099
    switchtec
index 6172f3c..06d98c4 100644 (file)
@@ -49,9 +49,6 @@ Device Drivers Base
 Device Drivers DMA Management
 -----------------------------
 
-.. kernel-doc:: kernel/dma/coherent.c
-   :export:
-
 .. kernel-doc:: kernel/dma/mapping.c
    :export:
 
index c3e0048..cdeb582 100644 (file)
@@ -1,7 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0
 
 =====================================
-GENERIC SYSTEM INTERCONNECT SUBSYSTEM
+Generic System Interconnect Subsystem
 =====================================
 
 Introduction
index 20f1cff..bacc2a4 100644 (file)
@@ -49,7 +49,9 @@ but is not just blindly executing as 'root'. Keep in mind
 the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter
 and n_tracesink line discpline drivers but is a generic
 operation for a program to use a line discpline driver
-on a tty port other than the default n_tty::
+on a tty port other than the default n_tty:
+
+.. code-block:: c
 
   /////////// To hook up n_tracerouter and n_tracesink /////////
 
index fab2c9b..b40b1f8 100644 (file)
@@ -725,24 +725,10 @@ method, the sys I/F structure will be built like this::
     |---temp1_input:           37000
     |---temp1_crit:            100000
 
-4. Event Notification
+4. Export Symbol APIs
 =====================
 
-The framework includes a simple notification mechanism, in the form of a
-netlink event. Netlink socket initialization is done during the _init_
-of the framework. Drivers which intend to use the notification mechanism
-just need to call thermal_generate_netlink_event() with two arguments viz
-(originator, event). The originator is a pointer to struct thermal_zone_device
-from where the event has been originated. An integer which represents the
-thermal zone device will be used in the message to identify the zone. The
-event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
-THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
-crosses any of the configured thresholds.
-
-5. Export Symbol APIs
-=====================
-
-5.1. get_tz_trend
+4.1. get_tz_trend
 -----------------
 
 This function returns the trend of a thermal zone, i.e the rate of change
@@ -751,14 +737,14 @@ are supposed to implement the callback. If they don't, the thermal
 framework calculated the trend by comparing the previous and the current
 temperature values.
 
-5.2. get_thermal_instance
+4.2. get_thermal_instance
 -------------------------
 
 This function returns the thermal_instance corresponding to a given
 {thermal_zone, cooling_device, trip_point} combination. Returns NULL
 if such an instance does not exist.
 
-5.3. thermal_notify_framework
+4.3. thermal_notify_framework
 -----------------------------
 
 This function handles the trip events from sensor drivers. It starts
@@ -768,14 +754,14 @@ and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
 The throttling policy is based on the configured platform data; if no
 platform data is provided, this uses the step_wise throttling policy.
 
-5.4. thermal_cdev_update
+4.4. thermal_cdev_update
 ------------------------
 
 This function serves as an arbitrator to set the state of a cooling
 device. It sets the cooling device to the deepest cooling state if
 possible.
 
-6. thermal_emergency_poweroff
+5. thermal_emergency_poweroff
 =============================
 
 On an event of critical trip temperature crossing. Thermal framework
index d344b99..9646670 100644 (file)
@@ -30,5 +30,5 @@
     |          um: | TODO |
     |   unicore32: | TODO |
     |         x86: |  ok  |
-    |      xtensa: | TODO |
+    |      xtensa: |  ok  |
     -----------------------
diff --git a/Documentation/filesystems/autofs.rst b/Documentation/filesystems/autofs.rst
new file mode 100644 (file)
index 0000000..681c6a4
--- /dev/null
@@ -0,0 +1,580 @@
+=====================
+autofs - how it works
+=====================
+
+Purpose
+=======
+
+The goal of autofs is to provide on-demand mounting and race free
+automatic unmounting of various other filesystems.  This provides two
+key advantages:
+
+1. There is no need to delay boot until all filesystems that
+   might be needed are mounted.  Processes that try to access those
+   slow filesystems might be delayed but other processes can
+   continue freely.  This is particularly important for
+   network filesystems (e.g. NFS) or filesystems stored on
+   media with a media-changing robot.
+
+2. The names and locations of filesystems can be stored in
+   a remote database and can change at any time.  The content
+   in that data base at the time of access will be used to provide
+   a target for the access.  The interpretation of names in the
+   filesystem can even be programmatic rather than database-backed,
+   allowing wildcards for example, and can vary based on the user who
+   first accessed a name.
+
+Context
+=======
+
+The "autofs" filesystem module is only one part of an autofs system.
+There also needs to be a user-space program which looks up names
+and mounts filesystems.  This will often be the "automount" program,
+though other tools including "systemd" can make use of "autofs".
+This document describes only the kernel module and the interactions
+required with any user-space program.  Subsequent text refers to this
+as the "automount daemon" or simply "the daemon".
+
+"autofs" is a Linux kernel module with provides the "autofs"
+filesystem type.  Several "autofs" filesystems can be mounted and they
+can each be managed separately, or all managed by the same daemon.
+
+Content
+=======
+
+An autofs filesystem can contain 3 sorts of objects: directories,
+symbolic links and mount traps.  Mount traps are directories with
+extra properties as described in the next section.
+
+Objects can only be created by the automount daemon: symlinks are
+created with a regular `symlink` system call, while directories and
+mount traps are created with `mkdir`.  The determination of whether a
+directory should be a mount trap is based on a master map. This master
+map is consulted by autofs to determine which directories are mount
+points. Mount points can be *direct*/*indirect*/*offset*.
+On most systems, the default master map is located at */etc/auto.master*.
+
+If neither the *direct* or *offset* mount options are given (so the
+mount is considered to be *indirect*), then the root directory is
+always a regular directory, otherwise it is a mount trap when it is
+empty and a regular directory when not empty.  Note that *direct* and
+*offset* are treated identically so a concise summary is that the root
+directory is a mount trap only if the filesystem is mounted *direct*
+and the root is empty.
+
+Directories created in the root directory are mount traps only if the
+filesystem is mounted *indirect* and they are empty.
+
+Directories further down the tree depend on the *maxproto* mount
+option and particularly whether it is less than five or not.
+When *maxproto* is five, no directories further down the
+tree are ever mount traps, they are always regular directories.  When
+the *maxproto* is four (or three), these directories are mount traps
+precisely when they are empty.
+
+So: non-empty (i.e. non-leaf) directories are never mount traps. Empty
+directories are sometimes mount traps, and sometimes not depending on
+where in the tree they are (root, top level, or lower), the *maxproto*,
+and whether the mount was *indirect* or not.
+
+Mount Traps
+===========
+
+A core element of the implementation of autofs is the Mount Traps
+which are provided by the Linux VFS.  Any directory provided by a
+filesystem can be designated as a trap.  This involves two separate
+features that work together to allow autofs to do its job.
+
+**DCACHE_NEED_AUTOMOUNT**
+
+If a dentry has the DCACHE_NEED_AUTOMOUNT flag set (which gets set if
+the inode has S_AUTOMOUNT set, or can be set directly) then it is
+(potentially) a mount trap.  Any access to this directory beyond a
+"`stat`" will (normally) cause the `d_op->d_automount()` dentry operation
+to be called. The task of this method is to find the filesystem that
+should be mounted on the directory and to return it.  The VFS is
+responsible for actually mounting the root of this filesystem on the
+directory.
+
+autofs doesn't find the filesystem itself but sends a message to the
+automount daemon asking it to find and mount the filesystem.  The
+autofs `d_automount` method then waits for the daemon to report that
+everything is ready.  It will then return "`NULL`" indicating that the
+mount has already happened.  The VFS doesn't try to mount anything but
+follows down the mount that is already there.
+
+This functionality is sufficient for some users of mount traps such
+as NFS which creates traps so that mountpoints on the server can be
+reflected on the client.  However it is not sufficient for autofs.  As
+mounting onto a directory is considered to be "beyond a `stat`", the
+automount daemon would not be able to mount a filesystem on the 'trap'
+directory without some way to avoid getting caught in the trap.  For
+that purpose there is another flag.
+
+**DCACHE_MANAGE_TRANSIT**
+
+If a dentry has DCACHE_MANAGE_TRANSIT set then two very different but
+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
+directory, d_manage() will be called with the `rcu_walk` parameter set
+to `false`.  It may return one of three things:
+
+-  A return value of zero indicates that there is nothing special
+   about this dentry and normal checks for mounts and automounts
+   should proceed.
+
+   autofs normally returns zero, but first waits for any
+   expiry (automatic unmounting of the mounted filesystem) to
+   complete.  This avoids races.
+
+-  A return value of `-EISDIR` tells the VFS to ignore any mounts
+   on the directory and to not consider calling `->d_automount()`.
+   This effectively disables the **DCACHE_NEED_AUTOMOUNT** flag
+   causing the directory not be a mount trap after all.
+
+   autofs returns this if it detects that the process performing the
+   lookup is the automount daemon and that the mount has been
+   requested but has not yet completed.  How it determines this is
+   discussed later.  This allows the automount daemon not to get
+   caught in the mount trap.
+
+   There is a subtlety here.  It is possible that a second autofs
+   filesystem can be mounted below the first and for both of them to
+   be managed by the same daemon.  For the daemon to be able to mount
+   something on the second it must be able to "walk" down past the
+   first.  This means that d_manage cannot *always* return -EISDIR for
+   the automount daemon.  It must only return it when a mount has
+   been requested, but has not yet completed.
+
+   `d_manage` also returns `-EISDIR` if the dentry shouldn't be a
+   mount trap, either because it is a symbolic link or because it is
+   not empty.
+
+-  Any other negative value is treated as an error and returned
+   to the caller.
+
+   autofs can return
+
+   - -ENOENT if the automount daemon failed to mount anything,
+   - -ENOMEM if it ran out of memory,
+   - -EINTR if a signal arrived while waiting for expiry to
+     complete
+   - or any other error sent down by the automount daemon.
+
+
+The second use case only occurs during an "RCU-walk" and so `rcu_walk`
+will be set.
+
+An RCU-walk is a fast and lightweight process for walking down a
+filename path (i.e. it is like running on tip-toes).  RCU-walk cannot
+cope with all situations so when it finds a difficulty it falls back
+to "REF-walk", which is slower but more robust.
+
+RCU-walk will never call `->d_automount`; the filesystems must already
+be mounted or RCU-walk cannot handle the path.
+To determine if a mount-trap is safe for RCU-walk mode it calls
+`->d_manage()` with `rcu_walk` set to `true`.
+
+In this case `d_manage()` must avoid blocking and should avoid taking
+spinlocks if at all possible.  Its sole purpose is to determine if it
+would be safe to follow down into any mounted directory and the only
+reason that it might not be is if an expiry of the mount is
+underway.
+
+In the `rcu_walk` case, `d_manage()` cannot return -EISDIR to tell the
+VFS that this is a directory that doesn't require d_automount.  If
+`rcu_walk` sees a dentry with DCACHE_NEED_AUTOMOUNT set but nothing
+mounted, it *will* fall back to REF-walk.  `d_manage()` cannot make the
+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 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.
+
+
+Mountpoint expiry
+=================
+
+The VFS has a mechanism for automatically expiring unused mounts,
+much as it can expire any unused dentry information from the dcache.
+This is guided by the MNT_SHRINKABLE flag.  This only applies to
+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
+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
+a previous attempt had been made, and the filesystem has been inactive
+and untouched since that previous attempt.  autofs does not depend on
+this but has its own internal tracking of whether filesystems were
+recently used.  This allows individual names in the autofs directory
+to expire separately.
+
+With version 4 of the protocol, the automount daemon can try to
+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 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.
+
+With version 5, this is not safe except for unmounting from top-level
+directories.  As lower-level directories are never mount traps, other
+processes will see an empty directory as soon as the filesystem is
+unmounted.  So it is generally safest to use the autofs expiry
+protocol described below.
+
+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 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
+considers if the entire mount-tree can be unmounted or not.  For an
+*indirect* mount, autofs considers each of the names in the top level
+directory to determine if any of those can be unmounted and cleaned
+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 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
+mounted, though this check is ignored in some cases. It also checks if
+the directory or anything below it is in use.  For symbolic links,
+only the `last_used` time is ever considered.
+
+If both appear to support expiring the directory or symlink, an action
+is taken.
+
+There are two ways to ask autofs to consider expiry.  The first is to
+use the **AUTOFS_IOC_EXPIRE** ioctl.  This only works for indirect
+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 `automount(8)`
+does not use this ioctl.
+
+The second mechanism uses either the **AUTOFS_DEV_IOCTL_EXPIRE_CMD** or
+the **AUTOFS_IOC_EXPIRE_MULTI** ioctl.  This will work for both direct and
+indirect mounts.  If it selects an object to expire, it will notify
+the daemon using the notification mechanism described below.  This
+will block until the daemon acknowledges the expiry notification.
+This implies that the "`EXPIRE`" ioctl must be sent from a different
+thread than the one which handles notification.
+
+While the ioctl is blocking, the entry is marked as "expiring" and
+`d_manage` will block until the daemon affirms that the unmount has
+completed (together with removing any directories that might have been
+necessary), or has been aborted.
+
+Communicating with autofs: detecting the daemon
+===============================================
+
+There are several forms of communication between the automount daemon
+and the filesystem.  As we have already seen, the daemon can create and
+remove directories and symlinks using normal filesystem operations.
+autofs knows whether a process requesting some operation is the daemon
+or not based on its process-group id number (see getpgid(1)).
+
+When an autofs filesystem is mounted the pgid of the mounting
+processes is recorded unless the "pgrp=" option is given, in which
+case that number is recorded instead.  Any request arriving from a
+process in that process group is considered to come from the daemon.
+If the daemon ever has to be stopped and restarted a new pgid can be
+provided through an ioctl as will be described below.
+
+Communicating with autofs: the event pipe
+=========================================
+
+When an autofs filesystem is mounted, the 'write' end of a pipe must
+be passed using the 'fd=' mount option.  autofs will write
+notification messages to this pipe for the daemon to respond to.
+For version 5, the format of the message is::
+
+       struct autofs_v5_packet {
+               struct autofs_packet_hdr hdr;
+               autofs_wqt_t wait_queue_token;
+               __u32 dev;
+               __u64 ino;
+               __u32 uid;
+               __u32 gid;
+               __u32 pid;
+               __u32 tgid;
+               __u32 len;
+               char name[NAME_MAX+1];
+        };
+
+And the format of the header is::
+
+       struct autofs_packet_hdr {
+               int proto_version;              /* Protocol version */
+               int type;                       /* Type of packet */
+       };
+
+where the type is one of ::
+
+       autofs_ptype_missing_indirect
+       autofs_ptype_expire_indirect
+       autofs_ptype_missing_direct
+       autofs_ptype_expire_direct
+
+so messages can indicate that a name is missing (something tried to
+access it but it isn't there) or that it has been selected for expiry.
+
+The pipe will be set to "packet mode" (equivalent to passing
+`O_DIRECT`) to _pipe2(2)_ so that a read from the pipe will return at
+most one packet, and any unread portion of a packet will be discarded.
+
+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 with the relevant
+`wait_queue_token`.
+
+Communicating with autofs: root directory ioctls
+================================================
+
+The root directory of an autofs filesystem will respond to a number of
+ioctls.  The process issuing the ioctl must have the CAP_SYS_ADMIN
+capability, or must be the automount daemon.
+
+The available ioctl commands are:
+
+- **AUTOFS_IOC_READY**:
+       a notification has been handled.  The argument
+       to the ioctl command is the "wait_queue_token" number
+       corresponding to the notification being acknowledged.
+- **AUTOFS_IOC_FAIL**:
+       similar to above, but indicates failure with
+       the error code `ENOENT`.
+- **AUTOFS_IOC_CATATONIC**:
+       Causes the autofs to enter "catatonic"
+       mode meaning that it stops sending notifications to the daemon.
+       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.
+- **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
+       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::
+
+               struct autofs_packet_expire_multi {
+                       struct autofs_packet_hdr hdr;
+                       autofs_wqt_t wait_queue_token;
+                       int len;
+                       char name[NAME_MAX+1];
+               };
+
+       is required.  This is filled in with the name of something
+       that can be unmounted or removed.  If nothing can be expired,
+       `errno` is set to `EAGAIN`.  Even though a `wait_queue_token`
+       is present in the structure, no "wait queue" is established
+       and no acknowledgment is needed.
+- **AUTOFS_IOC_EXPIRE_MULTI**:
+       This is similar to
+       **AUTOFS_IOC_EXPIRE** except that it causes notification to be
+       sent to the daemon, and it blocks until the daemon acknowledges.
+       The argument is an integer which can contain two different flags.
+
+       **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.
+
+Communicating with autofs: char-device ioctls
+=============================================
+
+It is not always possible to open the root of an autofs filesystem,
+particularly a *direct* mounted filesystem.  If the automount daemon
+is restarted there is no way for it to regain control of existing
+mounts using any of the above communication channels.  To address this
+need there is a "miscellaneous" character device (major 10, minor 235)
+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 summarised briefly here.
+Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure::
+
+        struct autofs_dev_ioctl {
+                __u32 ver_major;
+                __u32 ver_minor;
+                __u32 size;             /* total size of data passed in
+                                         * including this struct */
+                __s32 ioctlfd;          /* automount command fd */
+
+               /* Command parameters */
+               union {
+                       struct args_protover            protover;
+                       struct args_protosubver         protosubver;
+                       struct args_openmount           openmount;
+                       struct args_ready               ready;
+                       struct args_fail                fail;
+                       struct args_setpipefd           setpipefd;
+                       struct args_timeout             timeout;
+                       struct args_requester           requester;
+                       struct args_expire              expire;
+                       struct args_askumount           askumount;
+                       struct args_ismountpoint        ismountpoint;
+               };
+
+                char path[0];
+        };
+
+For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target
+filesystem is identified by the `path`.  All other commands identify
+the filesystem by the `ioctlfd` which is a file descriptor open on the
+root, and which can be returned by **OPEN_MOUNT**.
+
+The `ver_major` and `ver_minor` are in/out parameters which check that
+the requested version is supported, and report the maximum version
+that the kernel module can support.
+
+Commands are:
+
+- **AUTOFS_DEV_IOCTL_VERSION_CMD**:
+       does nothing, except validate and
+       set version numbers.
+- **AUTOFS_DEV_IOCTL_OPENMOUNT_CMD**:
+       return an open file descriptor
+       on the root of an autofs filesystem.  The filesystem is identified
+       by name and device number, which is stored in `openmount.devid`.
+       Device numbers for existing filesystems can be found in
+       `/proc/self/mountinfo`.
+- **AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD**:
+       same as `close(ioctlfd)`.
+- **AUTOFS_DEV_IOCTL_SETPIPEFD_CMD**:
+       if the filesystem is in
+       catatonic mode, this can provide the write end of a new pipe
+       in `setpipefd.pipefd` to re-establish communication with a daemon.
+       The process group of the calling process is used to identify the
+       daemon.
+- **AUTOFS_DEV_IOCTL_REQUESTER_CMD**:
+       `path` should be a
+       name within the filesystem that has been auto-mounted on.
+       On successful return, `requester.uid` and `requester.gid` will be
+       the UID and GID of the process which triggered that mount.
+- **AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD**:
+       Check if path is a
+       mountpoint of a particular type - see separate documentation for
+       details.
+
+- **AUTOFS_DEV_IOCTL_PROTOVER_CMD**
+- **AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD**
+- **AUTOFS_DEV_IOCTL_READY_CMD**
+- **AUTOFS_DEV_IOCTL_FAIL_CMD**
+- **AUTOFS_DEV_IOCTL_CATATONIC_CMD**
+- **AUTOFS_DEV_IOCTL_TIMEOUT_CMD**
+- **AUTOFS_DEV_IOCTL_EXPIRE_CMD**
+- **AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD**
+
+These all have the same
+function as the similarly named **AUTOFS_IOC** ioctls, except
+that **FAIL** can be given an explicit error number in `fail.status`
+instead of assuming `ENOENT`, and this **EXPIRE** command
+corresponds to **AUTOFS_IOC_EXPIRE_MULTI**.
+
+Catatonic mode
+==============
+
+As mentioned, an autofs mount can enter "catatonic" mode.  This
+happens if a write to the notification pipe fails, or if it is
+explicitly requested by an `ioctl`.
+
+When entering catatonic mode, the pipe is closed and any pending
+notifications are acknowledged with the error `ENOENT`.
+
+Once in catatonic mode attempts to access non-existing names will
+result in `ENOENT` while attempts to access existing directories will
+be treated in the same way as if they came from the daemon, so mount
+traps will not fire.
+
+When the filesystem is mounted a _uid_ and _gid_ can be given which
+set the ownership of directories and symbolic links.  When the
+filesystem is in catatonic mode, any process with a matching UID can
+create directories or symlinks in the root directory, but not in other
+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
+======================================
+
+With bind mounts and name spaces it is possible for an autofs
+filesystem to appear at multiple places in one or more filesystem
+name spaces.  For this to work sensibly, the autofs filesystem should
+always be mounted "shared". e.g. ::
+
+       mount --make-shared /autofs/mount/point
+
+The automount daemon is only able to manage a single mount location for
+an autofs filesystem and if mounts on that are not 'shared', other
+locations will not behave as expected.  In particular access to those
+other locations will likely result in the `ELOOP` error ::
+
+       Too many levels of symbolic links
diff --git a/Documentation/filesystems/autofs.txt b/Documentation/filesystems/autofs.txt
deleted file mode 100644 (file)
index 3af38c7..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-<head>
-<style> p { max-width:50em} ol, ul {max-width: 40em}</style>
-</head>
-
-autofs - how it works
-=====================
-
-Purpose
--------
-
-The goal of autofs is to provide on-demand mounting and race free
-automatic unmounting of various other filesystems.  This provides two
-key advantages:
-
-1. There is no need to delay boot until all filesystems that
-   might be needed are mounted.  Processes that try to access those
-   slow filesystems might be delayed but other processes can
-   continue freely.  This is particularly important for
-   network filesystems (e.g. NFS) or filesystems stored on
-   media with a media-changing robot.
-
-2. The names and locations of filesystems can be stored in
-   a remote database and can change at any time.  The content
-   in that data base at the time of access will be used to provide
-   a target for the access.  The interpretation of names in the
-   filesystem can even be programmatic rather than database-backed,
-   allowing wildcards for example, and can vary based on the user who
-   first accessed a name.
-
-Context
--------
-
-The "autofs" filesystem module is only one part of an autofs system.
-There also needs to be a user-space program which looks up names
-and mounts filesystems.  This will often be the "automount" program,
-though other tools including "systemd" can make use of "autofs".
-This document describes only the kernel module and the interactions
-required with any user-space program.  Subsequent text refers to this
-as the "automount daemon" or simply "the daemon".
-
-"autofs" is a Linux kernel module with provides the "autofs"
-filesystem type.  Several "autofs" filesystems can be mounted and they
-can each be managed separately, or all managed by the same daemon.
-
-Content
--------
-
-An autofs filesystem can contain 3 sorts of objects: directories,
-symbolic links and mount traps.  Mount traps are directories with
-extra properties as described in the next section.
-
-Objects can only be created by the automount daemon: symlinks are
-created with a regular `symlink` system call, while directories and
-mount traps are created with `mkdir`.  The determination of whether a
-directory should be a mount trap or not is quite _ad hoc_, largely for
-historical reasons, and is determined in part by the
-*direct*/*indirect*/*offset* mount options, and the *maxproto* mount option.
-
-If neither the *direct* or *offset* mount options are given (so the
-mount is considered to be *indirect*), then the root directory is
-always a regular directory, otherwise it is a mount trap when it is
-empty and a regular directory when not empty.  Note that *direct* and
-*offset* are treated identically so a concise summary is that the root
-directory is a mount trap only if the filesystem is mounted *direct*
-and the root is empty.
-
-Directories created in the root directory are mount traps only if the
-filesystem is mounted *indirect* and they are empty.
-
-Directories further down the tree depend on the *maxproto* mount
-option and particularly whether it is less than five or not.
-When *maxproto* is five, no directories further down the
-tree are ever mount traps, they are always regular directories.  When
-the *maxproto* is four (or three), these directories are mount traps
-precisely when they are empty.
-
-So: non-empty (i.e. non-leaf) directories are never mount traps. Empty
-directories are sometimes mount traps, and sometimes not depending on
-where in the tree they are (root, top level, or lower), the *maxproto*,
-and whether the mount was *indirect* or not.
-
-Mount Traps
----------------
-
-A core element of the implementation of autofs is the Mount Traps
-which are provided by the Linux VFS.  Any directory provided by a
-filesystem can be designated as a trap.  This involves two separate
-features that work together to allow autofs to do its job.
-
-**DCACHE_NEED_AUTOMOUNT**
-
-If a dentry has the DCACHE_NEED_AUTOMOUNT flag set (which gets set if
-the inode has S_AUTOMOUNT set, or can be set directly) then it is
-(potentially) a mount trap.  Any access to this directory beyond a
-"`stat`" will (normally) cause the `d_op->d_automount()` dentry operation
-to be called. The task of this method is to find the filesystem that
-should be mounted on the directory and to return it.  The VFS is
-responsible for actually mounting the root of this filesystem on the
-directory.
-
-autofs doesn't find the filesystem itself but sends a message to the
-automount daemon asking it to find and mount the filesystem.  The
-autofs `d_automount` method then waits for the daemon to report that
-everything is ready.  It will then return "`NULL`" indicating that the
-mount has already happened.  The VFS doesn't try to mount anything but
-follows down the mount that is already there.
-
-This functionality is sufficient for some users of mount traps such
-as NFS which creates traps so that mountpoints on the server can be
-reflected on the client.  However it is not sufficient for autofs.  As
-mounting onto a directory is considered to be "beyond a `stat`", the
-automount daemon would not be able to mount a filesystem on the 'trap'
-directory without some way to avoid getting caught in the trap.  For
-that purpose there is another flag.
-
-**DCACHE_MANAGE_TRANSIT**
-
-If a dentry has DCACHE_MANAGE_TRANSIT set then two very different but
-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
-directory, d_manage() will be called with the `rcu_walk` parameter set
-to `false`.  It may return one of three things:
-
--  A return value of zero indicates that there is nothing special
-   about this dentry and normal checks for mounts and automounts
-   should proceed.
-
-   autofs normally returns zero, but first waits for any
-   expiry (automatic unmounting of the mounted filesystem) to
-   complete.  This avoids races.
-
--  A return value of `-EISDIR` tells the VFS to ignore any mounts
-   on the directory and to not consider calling `->d_automount()`.
-   This effectively disables the **DCACHE_NEED_AUTOMOUNT** flag
-   causing the directory not be a mount trap after all.
-
-   autofs returns this if it detects that the process performing the
-   lookup is the automount daemon and that the mount has been
-   requested but has not yet completed.  How it determines this is
-   discussed later.  This allows the automount daemon not to get
-   caught in the mount trap.
-
-   There is a subtlety here.  It is possible that a second autofs
-   filesystem can be mounted below the first and for both of them to
-   be managed by the same daemon.  For the daemon to be able to mount
-   something on the second it must be able to "walk" down past the
-   first.  This means that d_manage cannot *always* return -EISDIR for
-   the automount daemon.  It must only return it when a mount has
-   been requested, but has not yet completed.
-
-   `d_manage` also returns `-EISDIR` if the dentry shouldn't be a
-   mount trap, either because it is a symbolic link or because it is
-   not empty.
-
--  Any other negative value is treated as an error and returned
-   to the caller.
-
-   autofs can return
-
-   - -ENOENT if the automount daemon failed to mount anything,
-   - -ENOMEM if it ran out of memory,
-   - -EINTR if a signal arrived while waiting for expiry to
-     complete
-   - or any other error sent down by the automount daemon.
-
-
-The second use case only occurs during an "RCU-walk" and so `rcu_walk`
-will be set.
-
-An RCU-walk is a fast and lightweight process for walking down a
-filename path (i.e. it is like running on tip-toes).  RCU-walk cannot
-cope with all situations so when it finds a difficulty it falls back
-to "REF-walk", which is slower but more robust.
-
-RCU-walk will never call `->d_automount`; the filesystems must already
-be mounted or RCU-walk cannot handle the path.
-To determine if a mount-trap is safe for RCU-walk mode it calls
-`->d_manage()` with `rcu_walk` set to `true`.
-
-In this case `d_manage()` must avoid blocking and should avoid taking
-spinlocks if at all possible.  Its sole purpose is to determine if it
-would be safe to follow down into any mounted directory and the only
-reason that it might not be is if an expiry of the mount is
-underway.
-
-In the `rcu_walk` case, `d_manage()` cannot return -EISDIR to tell the
-VFS that this is a directory that doesn't require d_automount.  If
-`rcu_walk` sees a dentry with DCACHE_NEED_AUTOMOUNT set but nothing
-mounted, it *will* fall back to REF-walk.  `d_manage()` cannot make the
-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 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.
-
-
-Mountpoint expiry
------------------
-
-The VFS has a mechanism for automatically expiring unused mounts,
-much as it can expire any unused dentry information from the dcache.
-This is guided by the MNT_SHRINKABLE flag.  This only applies to
-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
-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
-a previous attempt had been made, and the filesystem has been inactive
-and untouched since that previous attempt.  autofs does not depend on
-this but has its own internal tracking of whether filesystems were
-recently used.  This allows individual names in the autofs directory
-to expire separately.
-
-With version 4 of the protocol, the automount daemon can try to
-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 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.
-
-With version 5, this is not safe except for unmounting from top-level
-directories.  As lower-level directories are never mount traps, other
-processes will see an empty directory as soon as the filesystem is
-unmounted.  So it is generally safest to use the autofs expiry
-protocol described below.
-
-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 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
-considers if the entire mount-tree can be unmounted or not.  For an
-*indirect* mount, autofs considers each of the names in the top level
-directory to determine if any of those can be unmounted and cleaned
-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 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
-mounted, though this check is ignored in some cases. It also checks if
-the directory or anything below it is in use.  For symbolic links,
-only the `last_used` time is ever considered.
-
-If both appear to support expiring the directory or symlink, an action
-is taken.
-
-There are two ways to ask autofs to consider expiry.  The first is to
-use the **AUTOFS_IOC_EXPIRE** ioctl.  This only works for indirect
-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 `automount(8)`
-does not use this ioctl.
-
-The second mechanism uses either the **AUTOFS_DEV_IOCTL_EXPIRE_CMD** or
-the **AUTOFS_IOC_EXPIRE_MULTI** ioctl.  This will work for both direct and
-indirect mounts.  If it selects an object to expire, it will notify
-the daemon using the notification mechanism described below.  This
-will block until the daemon acknowledges the expiry notification.
-This implies that the "`EXPIRE`" ioctl must be sent from a different
-thread than the one which handles notification.
-
-While the ioctl is blocking, the entry is marked as "expiring" and
-`d_manage` will block until the daemon affirms that the unmount has
-completed (together with removing any directories that might have been
-necessary), or has been aborted.
-
-Communicating with autofs: detecting the daemon
------------------------------------------------
-
-There are several forms of communication between the automount daemon
-and the filesystem.  As we have already seen, the daemon can create and
-remove directories and symlinks using normal filesystem operations.
-autofs knows whether a process requesting some operation is the daemon
-or not based on its process-group id number (see getpgid(1)).
-
-When an autofs filesystem is mounted the pgid of the mounting
-processes is recorded unless the "pgrp=" option is given, in which
-case that number is recorded instead.  Any request arriving from a
-process in that process group is considered to come from the daemon.
-If the daemon ever has to be stopped and restarted a new pgid can be
-provided through an ioctl as will be described below.
-
-Communicating with autofs: the event pipe
------------------------------------------
-
-When an autofs filesystem is mounted, the 'write' end of a pipe must
-be passed using the 'fd=' mount option.  autofs will write
-notification messages to this pipe for the daemon to respond to.
-For version 5, the format of the message is:
-
-        struct autofs_v5_packet {
-                int proto_version;                /* Protocol version */
-                int type;                        /* Type of packet */
-                autofs_wqt_t wait_queue_token;
-                __u32 dev;
-                __u64 ino;
-                __u32 uid;
-                __u32 gid;
-                __u32 pid;
-                __u32 tgid;
-                __u32 len;
-                char name[NAME_MAX+1];
-        };
-
-where the type is one of
-
-        autofs_ptype_missing_indirect
-        autofs_ptype_expire_indirect
-        autofs_ptype_missing_direct
-        autofs_ptype_expire_direct
-
-so messages can indicate that a name is missing (something tried to
-access it but it isn't there) or that it has been selected for expiry.
-
-The pipe will be set to "packet mode" (equivalent to passing
-`O_DIRECT`) to _pipe2(2)_ so that a read from the pipe will return at
-most one packet, and any unread portion of a packet will be discarded.
-
-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 with the relevant
-`wait_queue_token`.
-
-Communicating with autofs: root directory ioctls
-------------------------------------------------
-
-The root directory of an autofs filesystem will respond to a number of
-ioctls.  The process issuing the ioctl must have the CAP_SYS_ADMIN
-capability, or must be the automount daemon.
-
-The available ioctl commands are:
-
-- **AUTOFS_IOC_READY**: a notification has been handled.  The argument
-    to the ioctl command is the "wait_queue_token" number
-    corresponding to the notification being acknowledged.
-- **AUTOFS_IOC_FAIL**: similar to above, but indicates failure with
-    the error code `ENOENT`.
-- **AUTOFS_IOC_CATATONIC**: Causes the autofs to enter "catatonic"
-    mode meaning that it stops sending notifications to the daemon.
-    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.
-- **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
-    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:
-
-        struct autofs_packet_expire_multi {
-                int proto_version;              /* Protocol version */
-                int type;                       /* Type of packet */
-                autofs_wqt_t wait_queue_token;
-                int len;
-                char name[NAME_MAX+1];
-        };
-
-     is required.  This is filled in with the name of something
-     that can be unmounted or removed.  If nothing can be expired,
-     `errno` is set to `EAGAIN`.  Even though a `wait_queue_token`
-     is present in the structure, no "wait queue" is established
-     and no acknowledgment is needed.
-- **AUTOFS_IOC_EXPIRE_MULTI**:  This is similar to
-     **AUTOFS_IOC_EXPIRE** except that it causes notification to be
-     sent to the daemon, and it blocks until the daemon acknowledges.
-     The argument is an integer which can contain two different flags.
-
-     **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.
-
-Communicating with autofs: char-device ioctls
----------------------------------------------
-
-It is not always possible to open the root of an autofs filesystem,
-particularly a *direct* mounted filesystem.  If the automount daemon
-is restarted there is no way for it to regain control of existing
-mounts using any of the above communication channels.  To address this
-need there is a "miscellaneous" character device (major 10, minor 235)
-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 summarised briefly here.
-Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:
-
-        struct autofs_dev_ioctl {
-                __u32 ver_major;
-                __u32 ver_minor;
-                __u32 size;             /* total size of data passed in
-                                         * including this struct */
-                __s32 ioctlfd;          /* automount command fd */
-
-               /* Command parameters */
-               union {
-                       struct args_protover            protover;
-                       struct args_protosubver         protosubver;
-                       struct args_openmount           openmount;
-                       struct args_ready               ready;
-                       struct args_fail                fail;
-                       struct args_setpipefd           setpipefd;
-                       struct args_timeout             timeout;
-                       struct args_requester           requester;
-                       struct args_expire              expire;
-                       struct args_askumount           askumount;
-                       struct args_ismountpoint        ismountpoint;
-               };
-
-                char path[0];
-        };
-
-For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target
-filesystem is identified by the `path`.  All other commands identify
-the filesystem by the `ioctlfd` which is a file descriptor open on the
-root, and which can be returned by **OPEN_MOUNT**.
-
-The `ver_major` and `ver_minor` are in/out parameters which check that
-the requested version is supported, and report the maximum version
-that the kernel module can support.
-
-Commands are:
-
-- **AUTOFS_DEV_IOCTL_VERSION_CMD**: does nothing, except validate and
-    set version numbers.
-- **AUTOFS_DEV_IOCTL_OPENMOUNT_CMD**: return an open file descriptor
-    on the root of an autofs filesystem.  The filesystem is identified
-    by name and device number, which is stored in `openmount.devid`.
-    Device numbers for existing filesystems can be found in
-    `/proc/self/mountinfo`.
-- **AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD**: same as `close(ioctlfd)`.
-- **AUTOFS_DEV_IOCTL_SETPIPEFD_CMD**: if the filesystem is in
-    catatonic mode, this can provide the write end of a new pipe
-    in `setpipefd.pipefd` to re-establish communication with a daemon.
-    The process group of the calling process is used to identify the
-    daemon.
-- **AUTOFS_DEV_IOCTL_REQUESTER_CMD**: `path` should be a
-    name within the filesystem that has been auto-mounted on.
-    On successful return, `requester.uid` and `requester.gid` will be
-    the UID and GID of the process which triggered that mount.
-- **AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD**: Check if path is a
-    mountpoint of a particular type - see separate documentation for
-    details.
-- **AUTOFS_DEV_IOCTL_PROTOVER_CMD**:
-- **AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD**:
-- **AUTOFS_DEV_IOCTL_READY_CMD**:
-- **AUTOFS_DEV_IOCTL_FAIL_CMD**:
-- **AUTOFS_DEV_IOCTL_CATATONIC_CMD**:
-- **AUTOFS_DEV_IOCTL_TIMEOUT_CMD**:
-- **AUTOFS_DEV_IOCTL_EXPIRE_CMD**:
-- **AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD**:  These all have the same
-    function as the similarly named **AUTOFS_IOC** ioctls, except
-    that **FAIL** can be given an explicit error number in `fail.status`
-    instead of assuming `ENOENT`, and this **EXPIRE** command
-    corresponds to **AUTOFS_IOC_EXPIRE_MULTI**.
-
-Catatonic mode
---------------
-
-As mentioned, an autofs mount can enter "catatonic" mode.  This
-happens if a write to the notification pipe fails, or if it is
-explicitly requested by an `ioctl`.
-
-When entering catatonic mode, the pipe is closed and any pending
-notifications are acknowledged with the error `ENOENT`.
-
-Once in catatonic mode attempts to access non-existing names will
-result in `ENOENT` while attempts to access existing directories will
-be treated in the same way as if they came from the daemon, so mount
-traps will not fire.
-
-When the filesystem is mounted a _uid_ and _gid_ can be given which
-set the ownership of directories and symbolic links.  When the
-filesystem is in catatonic mode, any process with a matching UID can
-create directories or symlinks in the root directory, but not in other
-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
---------------------------------------
-
-With bind mounts and name spaces it is possible for an autofs
-filesystem to appear at multiple places in one or more filesystem
-name spaces.  For this to work sensibly, the autofs filesystem should
-always be mounted "shared". e.g.
-
-> `mount --make-shared /autofs/mount/point`
-
-The automount daemon is only able to manage a single mount location for
-an autofs filesystem and if mounts on that are not 'shared', other
-locations will not behave as expected.  In particular access to those
-other locations will likely result in the `ELOOP` error
-
-> Too many levels of symbolic links
index 2c3a9f7..ad6315a 100644 (file)
@@ -46,4 +46,5 @@ Documentation for filesystem implementations.
 .. toctree::
    :maxdepth: 2
 
+   autofs
    virtiofs
index fc3a070..5057e4d 100644 (file)
@@ -105,7 +105,7 @@ getattr:    no
 listxattr:     no
 fiemap:                no
 update_time:   no
-atomic_open:   exclusive
+atomic_open:   shared (exclusive if O_CREAT is set in open flags)
 tmpfile:       no
 ============   =============================================
 
index 292c0c2..4825046 100644 (file)
@@ -17,7 +17,7 @@ Usage Notes
 -----------
 
 This driver does not auto-detect devices. You will have to instantiate the
-devices explicitly. Please see Documentation/i2c/instantiating-devices for
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
 details.
 
 Sysfs entries
index 97ca4d5..2a26e25 100644 (file)
@@ -1,4 +1,4 @@
-. SPDX-License-Identifier: GPL-2.0
+.. SPDX-License-Identifier: GPL-2.0
 
 ===============
 I2C Bus Drivers
index cd8d020..a0fbaf6 100644 (file)
@@ -1,4 +1,4 @@
-. SPDX-License-Identifier: GPL-2.0
+.. SPDX-License-Identifier: GPL-2.0
 
 ===================
 I2C/SMBus Subsystem
index 2ceab19..e99d0bd 100644 (file)
@@ -57,7 +57,6 @@ the kernel interface as seen by application developers.
    :maxdepth: 2
 
    userspace-api/index
-   ioctl/index
 
 
 Introduction to kernel development
diff --git a/Documentation/ioctl/botching-up-ioctls.rst b/Documentation/ioctl/botching-up-ioctls.rst
deleted file mode 100644 (file)
index ac697fe..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-=================================
-(How to avoid) Botching up ioctls
-=================================
-
-From: http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
-
-By: Daniel Vetter, Copyright © 2013 Intel Corporation
-
-One clear insight kernel graphics hackers gained in the past few years is that
-trying to come up with a unified interface to manage the execution units and
-memory on completely different GPUs is a futile effort. So nowadays every
-driver has its own set of ioctls to allocate memory and submit work to the GPU.
-Which is nice, since there's no more insanity in the form of fake-generic, but
-actually only used once interfaces. But the clear downside is that there's much
-more potential to screw things up.
-
-To avoid repeating all the same mistakes again I've written up some of the
-lessons learned while botching the job for the drm/i915 driver. Most of these
-only cover technicalities and not the big-picture issues like what the command
-submission ioctl exactly should look like. Learning these lessons is probably
-something every GPU driver has to do on its own.
-
-
-Prerequisites
--------------
-
-First the prerequisites. Without these you have already failed, because you
-will need to add a 32-bit compat layer:
-
- * Only use fixed sized integers. To avoid conflicts with typedefs in userspace
-   the kernel has special types like __u32, __s64. Use them.
-
- * Align everything to the natural size and use explicit padding. 32-bit
-   platforms don't necessarily align 64-bit values to 64-bit boundaries, but
-   64-bit platforms do. So we always need padding to the natural size to get
-   this right.
-
- * Pad the entire struct to a multiple of 64-bits if the structure contains
-   64-bit types - the structure size will otherwise differ on 32-bit versus
-   64-bit. Having a different structure size hurts when passing arrays of
-   structures to the kernel, or if the kernel checks the structure size, which
-   e.g. the drm core does.
-
- * Pointers are __u64, cast from/to a uintprt_t on the userspace side and
-   from/to a void __user * in the kernel. Try really hard not to delay this
-   conversion or worse, fiddle the raw __u64 through your code since that
-   diminishes the checking tools like sparse can provide. The macro
-   u64_to_user_ptr can be used in the kernel to avoid warnings about integers
-   and pointres of different sizes.
-
-
-Basics
-------
-
-With the joys of writing a compat layer avoided we can take a look at the basic
-fumbles. Neglecting these will make backward and forward compatibility a real
-pain. And since getting things wrong on the first attempt is guaranteed you
-will have a second iteration or at least an extension for any given interface.
-
- * Have a clear way for userspace to figure out whether your new ioctl or ioctl
-   extension is supported on a given kernel. If you can't rely on old kernels
-   rejecting the new flags/modes or ioctls (since doing that was botched in the
-   past) then you need a driver feature flag or revision number somewhere.
-
- * Have a plan for extending ioctls with new flags or new fields at the end of
-   the structure. The drm core checks the passed-in size for each ioctl call
-   and zero-extends any mismatches between kernel and userspace. That helps,
-   but isn't a complete solution since newer userspace on older kernels won't
-   notice that the newly added fields at the end get ignored. So this still
-   needs a new driver feature flags.
-
- * Check all unused fields and flags and all the padding for whether it's 0,
-   and reject the ioctl if that's not the case. Otherwise your nice plan for
-   future extensions is going right down the gutters since someone will submit
-   an ioctl struct with random stack garbage in the yet unused parts. Which
-   then bakes in the ABI that those fields can never be used for anything else
-   but garbage. This is also the reason why you must explicitly pad all
-   structures, even if you never use them in an array - the padding the compiler
-   might insert could contain garbage.
-
- * Have simple testcases for all of the above.
-
-
-Fun with Error Paths
---------------------
-
-Nowadays we don't have any excuse left any more for drm drivers being neat
-little root exploits. This means we both need full input validation and solid
-error handling paths - GPUs will die eventually in the oddmost corner cases
-anyway:
-
- * The ioctl must check for array overflows. Also it needs to check for
-   over/underflows and clamping issues of integer values in general. The usual
-   example is sprite positioning values fed directly into the hardware with the
-   hardware just having 12 bits or so. Works nicely until some odd display
-   server doesn't bother with clamping itself and the cursor wraps around the
-   screen.
-
- * Have simple testcases for every input validation failure case in your ioctl.
-   Check that the error code matches your expectations. And finally make sure
-   that you only test for one single error path in each subtest by submitting
-   otherwise perfectly valid data. Without this an earlier check might reject
-   the ioctl already and shadow the codepath you actually want to test, hiding
-   bugs and regressions.
-
- * Make all your ioctls restartable. First X really loves signals and second
-   this will allow you to test 90% of all error handling paths by just
-   interrupting your main test suite constantly with signals. Thanks to X's
-   love for signal you'll get an excellent base coverage of all your error
-   paths pretty much for free for graphics drivers. Also, be consistent with
-   how you handle ioctl restarting - e.g. drm has a tiny drmIoctl helper in its
-   userspace library. The i915 driver botched this with the set_tiling ioctl,
-   now we're stuck forever with some arcane semantics in both the kernel and
-   userspace.
-
- * If you can't make a given codepath restartable make a stuck task at least
-   killable. GPUs just die and your users won't like you more if you hang their
-   entire box (by means of an unkillable X process). If the state recovery is
-   still too tricky have a timeout or hangcheck safety net as a last-ditch
-   effort in case the hardware has gone bananas.
-
- * Have testcases for the really tricky corner cases in your error recovery code
-   - it's way too easy to create a deadlock between your hangcheck code and
-   waiters.
-
-
-Time, Waiting and Missing it
-----------------------------
-
-GPUs do most everything asynchronously, so we have a need to time operations and
-wait for outstanding ones. This is really tricky business; at the moment none of
-the ioctls supported by the drm/i915 get this fully right, which means there's
-still tons more lessons to learn here.
-
- * Use CLOCK_MONOTONIC as your reference time, always. It's what alsa, drm and
-   v4l use by default nowadays. But let userspace know which timestamps are
-   derived from different clock domains like your main system clock (provided
-   by the kernel) or some independent hardware counter somewhere else. Clocks
-   will mismatch if you look close enough, but if performance measuring tools
-   have this information they can at least compensate. If your userspace can
-   get at the raw values of some clocks (e.g. through in-command-stream
-   performance counter sampling instructions) consider exposing those also.
-
- * Use __s64 seconds plus __u64 nanoseconds to specify time. It's not the most
-   convenient time specification, but it's mostly the standard.
-
- * Check that input time values are normalized and reject them if not. Note
-   that the kernel native struct ktime has a signed integer for both seconds
-   and nanoseconds, so beware here.
-
- * For timeouts, use absolute times. If you're a good fellow and made your
-   ioctl restartable relative timeouts tend to be too coarse and can
-   indefinitely extend your wait time due to rounding on each restart.
-   Especially if your reference clock is something really slow like the display
-   frame counter. With a spec lawyer hat on this isn't a bug since timeouts can
-   always be extended - but users will surely hate you if their neat animations
-   starts to stutter due to this.
-
- * Consider ditching any synchronous wait ioctls with timeouts and just deliver
-   an asynchronous event on a pollable file descriptor. It fits much better
-   into event driven applications' main loop.
-
- * Have testcases for corner-cases, especially whether the return values for
-   already-completed events, successful waits and timed-out waits are all sane
-   and suiting to your needs.
-
-
-Leaking Resources, Not
-----------------------
-
-A full-blown drm driver essentially implements a little OS, but specialized to
-the given GPU platforms. This means a driver needs to expose tons of handles
-for different objects and other resources to userspace. Doing that right
-entails its own little set of pitfalls:
-
- * Always attach the lifetime of your dynamically created resources to the
-   lifetime of a file descriptor. Consider using a 1:1 mapping if your resource
-   needs to be shared across processes -  fd-passing over unix domain sockets
-   also simplifies lifetime management for userspace.
-
- * Always have O_CLOEXEC support.
-
- * Ensure that you have sufficient insulation between different clients. By
-   default pick a private per-fd namespace which forces any sharing to be done
-   explicitly. Only go with a more global per-device namespace if the objects
-   are truly device-unique. One counterexample in the drm modeset interfaces is
-   that the per-device modeset objects like connectors share a namespace with
-   framebuffer objects, which mostly are not shared at all. A separate
-   namespace, private by default, for framebuffers would have been more
-   suitable.
-
- * Think about uniqueness requirements for userspace handles. E.g. for most drm
-   drivers it's a userspace bug to submit the same object twice in the same
-   command submission ioctl. But then if objects are shareable userspace needs
-   to know whether it has seen an imported object from a different process
-   already or not. I haven't tried this myself yet due to lack of a new class
-   of objects, but consider using inode numbers on your shared file descriptors
-   as unique identifiers - it's how real files are told apart, too.
-   Unfortunately this requires a full-blown virtual filesystem in the kernel.
-
-
-Last, but not Least
--------------------
-
-Not every problem needs a new ioctl:
-
- * Think hard whether you really want a driver-private interface. Of course
-   it's much quicker to push a driver-private interface than engaging in
-   lengthy discussions for a more generic solution. And occasionally doing a
-   private interface to spearhead a new concept is what's required. But in the
-   end, once the generic interface comes around you'll end up maintainer two
-   interfaces. Indefinitely.
-
- * Consider other interfaces than ioctls. A sysfs attribute is much better for
-   per-device settings, or for child objects with fairly static lifetimes (like
-   output connectors in drm with all the detection override attributes). Or
-   maybe only your testsuite needs this interface, and then debugfs with its
-   disclaimer of not having a stable ABI would be better.
-
-Finally, the name of the game is to get it right on the first attempt, since if
-your driver proves popular and your hardware platforms long-lived then you'll
-be stuck with a given ioctl essentially forever. You can try to deprecate
-horrible ioctls on newer iterations of your hardware, but generally it takes
-years to accomplish this. And then again years until the last user able to
-complain about regressions disappears, too.
diff --git a/Documentation/ioctl/cdrom.rst b/Documentation/ioctl/cdrom.rst
deleted file mode 100644 (file)
index 3b4c050..0000000
+++ /dev/null
@@ -1,1233 +0,0 @@
-============================
-Summary of CDROM ioctl calls
-============================
-
-- Edward A. Falk <efalk@google.com>
-
-November, 2004
-
-This document attempts to describe the ioctl(2) calls supported by
-the CDROM layer.  These are by-and-large implemented (as of Linux 2.6)
-in drivers/cdrom/cdrom.c and drivers/block/scsi_ioctl.c
-
-ioctl values are listed in <linux/cdrom.h>.  As of this writing, they
-are as follows:
-
-       ======================  ===============================================
-       CDROMPAUSE              Pause Audio Operation
-       CDROMRESUME             Resume paused Audio Operation
-       CDROMPLAYMSF            Play Audio MSF (struct cdrom_msf)
-       CDROMPLAYTRKIND         Play Audio Track/index (struct cdrom_ti)
-       CDROMREADTOCHDR         Read TOC header (struct cdrom_tochdr)
-       CDROMREADTOCENTRY       Read TOC entry (struct cdrom_tocentry)
-       CDROMSTOP               Stop the cdrom drive
-       CDROMSTART              Start the cdrom drive
-       CDROMEJECT              Ejects the cdrom media
-       CDROMVOLCTRL            Control output volume (struct cdrom_volctrl)
-       CDROMSUBCHNL            Read subchannel data (struct cdrom_subchnl)
-       CDROMREADMODE2          Read CDROM mode 2 data (2336 Bytes)
-                               (struct cdrom_read)
-       CDROMREADMODE1          Read CDROM mode 1 data (2048 Bytes)
-                               (struct cdrom_read)
-       CDROMREADAUDIO          (struct cdrom_read_audio)
-       CDROMEJECT_SW           enable(1)/disable(0) auto-ejecting
-       CDROMMULTISESSION       Obtain the start-of-last-session
-                               address of multi session disks
-                               (struct cdrom_multisession)
-       CDROM_GET_MCN           Obtain the "Universal Product Code"
-                               if available (struct cdrom_mcn)
-       CDROM_GET_UPC           Deprecated, use CDROM_GET_MCN instead.
-       CDROMRESET              hard-reset the drive
-       CDROMVOLREAD            Get the drive's volume setting
-                               (struct cdrom_volctrl)
-       CDROMREADRAW            read data in raw mode (2352 Bytes)
-                               (struct cdrom_read)
-       CDROMREADCOOKED         read data in cooked mode
-       CDROMSEEK               seek msf address
-       CDROMPLAYBLK            scsi-cd only, (struct cdrom_blk)
-       CDROMREADALL            read all 2646 bytes
-       CDROMGETSPINDOWN        return 4-bit spindown value
-       CDROMSETSPINDOWN        set 4-bit spindown value
-       CDROMCLOSETRAY          pendant of CDROMEJECT
-       CDROM_SET_OPTIONS       Set behavior options
-       CDROM_CLEAR_OPTIONS     Clear behavior options
-       CDROM_SELECT_SPEED      Set the CD-ROM speed
-       CDROM_SELECT_DISC       Select disc (for juke-boxes)
-       CDROM_MEDIA_CHANGED     Check is media changed
-       CDROM_DRIVE_STATUS      Get tray position, etc.
-       CDROM_DISC_STATUS       Get disc type, etc.
-       CDROM_CHANGER_NSLOTS    Get number of slots
-       CDROM_LOCKDOOR          lock or unlock door
-       CDROM_DEBUG             Turn debug messages on/off
-       CDROM_GET_CAPABILITY    get capabilities
-       CDROMAUDIOBUFSIZ        set the audio buffer size
-       DVD_READ_STRUCT         Read structure
-       DVD_WRITE_STRUCT        Write structure
-       DVD_AUTH                Authentication
-       CDROM_SEND_PACKET       send a packet to the drive
-       CDROM_NEXT_WRITABLE     get next writable block
-       CDROM_LAST_WRITTEN      get last block written on disc
-       ======================  ===============================================
-
-
-The information that follows was determined from reading kernel source
-code.  It is likely that some corrections will be made over time.
-
-------------------------------------------------------------------------------
-
-General:
-
-       Unless otherwise specified, all ioctl calls return 0 on success
-       and -1 with errno set to an appropriate value on error.  (Some
-       ioctls return non-negative data values.)
-
-       Unless otherwise specified, all ioctl calls return -1 and set
-       errno to EFAULT on a failed attempt to copy data to or from user
-       address space.
-
-       Individual drivers may return error codes not listed here.
-
-       Unless otherwise specified, all data structures and constants
-       are defined in <linux/cdrom.h>
-
-------------------------------------------------------------------------------
-
-
-CDROMPAUSE
-       Pause Audio Operation
-
-
-       usage::
-
-         ioctl(fd, CDROMPAUSE, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-
-CDROMRESUME
-       Resume paused Audio Operation
-
-
-       usage::
-
-         ioctl(fd, CDROMRESUME, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-
-CDROMPLAYMSF
-       Play Audio MSF
-
-       (struct cdrom_msf)
-
-
-       usage::
-
-         struct cdrom_msf msf;
-
-         ioctl(fd, CDROMPLAYMSF, &msf);
-
-       inputs:
-               cdrom_msf structure, describing a segment of music to play
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-       notes:
-               - MSF stands for minutes-seconds-frames
-               - LBA stands for logical block address
-               - Segment is described as start and end times, where each time
-                 is described as minutes:seconds:frames.
-                 A frame is 1/75 of a second.
-
-
-CDROMPLAYTRKIND
-       Play Audio Track/index
-
-       (struct cdrom_ti)
-
-
-       usage::
-
-         struct cdrom_ti ti;
-
-         ioctl(fd, CDROMPLAYTRKIND, &ti);
-
-       inputs:
-               cdrom_ti structure, describing a segment of music to play
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-       notes:
-               - Segment is described as start and end times, where each time
-                 is described as a track and an index.
-
-
-
-CDROMREADTOCHDR
-       Read TOC header
-
-       (struct cdrom_tochdr)
-
-
-       usage::
-
-         cdrom_tochdr header;
-
-         ioctl(fd, CDROMREADTOCHDR, &header);
-
-       inputs:
-               cdrom_tochdr structure
-
-
-       outputs:
-               cdrom_tochdr structure
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-
-
-CDROMREADTOCENTRY
-       Read TOC entry
-
-       (struct cdrom_tocentry)
-
-
-       usage::
-
-         struct cdrom_tocentry entry;
-
-         ioctl(fd, CDROMREADTOCENTRY, &entry);
-
-       inputs:
-               cdrom_tocentry structure
-
-
-       outputs:
-               cdrom_tocentry structure
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-         - EINVAL      entry.cdte_format not CDROM_MSF or CDROM_LBA
-         - EINVAL      requested track out of bounds
-         - EIO         I/O error reading TOC
-
-       notes:
-               - TOC stands for Table Of Contents
-               - MSF stands for minutes-seconds-frames
-               - LBA stands for logical block address
-
-
-
-CDROMSTOP
-       Stop the cdrom drive
-
-
-       usage::
-
-         ioctl(fd, CDROMSTOP, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-       notes:
-         - Exact interpretation of this ioctl depends on the device,
-           but most seem to spin the drive down.
-
-
-CDROMSTART
-       Start the cdrom drive
-
-
-       usage::
-
-         ioctl(fd, CDROMSTART, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-       notes:
-         - Exact interpretation of this ioctl depends on the device,
-           but most seem to spin the drive up and/or close the tray.
-           Other devices ignore the ioctl completely.
-
-
-CDROMEJECT
-       - Ejects the cdrom media
-
-
-       usage::
-
-         ioctl(fd, CDROMEJECT, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error returns:
-         - ENOSYS      cd drive not capable of ejecting
-         - EBUSY       other processes are accessing drive, or door is locked
-
-       notes:
-               - See CDROM_LOCKDOOR, below.
-
-
-
-
-CDROMCLOSETRAY
-       pendant of CDROMEJECT
-
-
-       usage::
-
-         ioctl(fd, CDROMCLOSETRAY, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error returns:
-         - ENOSYS      cd drive not capable of closing the tray
-         - EBUSY       other processes are accessing drive, or door is locked
-
-       notes:
-               - See CDROM_LOCKDOOR, below.
-
-
-
-
-CDROMVOLCTRL
-       Control output volume (struct cdrom_volctrl)
-
-
-       usage::
-
-         struct cdrom_volctrl volume;
-
-         ioctl(fd, CDROMVOLCTRL, &volume);
-
-       inputs:
-               cdrom_volctrl structure containing volumes for up to 4
-               channels.
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-
-
-CDROMVOLREAD
-       Get the drive's volume setting
-
-       (struct cdrom_volctrl)
-
-
-       usage::
-
-         struct cdrom_volctrl volume;
-
-         ioctl(fd, CDROMVOLREAD, &volume);
-
-       inputs:
-               none
-
-
-       outputs:
-               The current volume settings.
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-
-
-
-CDROMSUBCHNL
-       Read subchannel data
-
-       (struct cdrom_subchnl)
-
-
-       usage::
-
-         struct cdrom_subchnl q;
-
-         ioctl(fd, CDROMSUBCHNL, &q);
-
-       inputs:
-               cdrom_subchnl structure
-
-
-       outputs:
-               cdrom_subchnl structure
-
-
-       error return:
-         - ENOSYS      cd drive not audio-capable.
-         - EINVAL      format not CDROM_MSF or CDROM_LBA
-
-       notes:
-               - Format is converted to CDROM_MSF or CDROM_LBA
-                 as per user request on return
-
-
-
-CDROMREADRAW
-       read data in raw mode (2352 Bytes)
-
-       (struct cdrom_read)
-
-       usage::
-
-         union {
-
-           struct cdrom_msf msf;               /* input */
-           char buffer[CD_FRAMESIZE_RAW];      /* return */
-         } arg;
-         ioctl(fd, CDROMREADRAW, &arg);
-
-       inputs:
-               cdrom_msf structure indicating an address to read.
-
-               Only the start values are significant.
-
-       outputs:
-               Data written to address provided by user.
-
-
-       error return:
-         - EINVAL      address less than 0, or msf less than 0:2:0
-         - ENOMEM      out of memory
-
-       notes:
-               - As of 2.6.8.1, comments in <linux/cdrom.h> indicate that this
-                 ioctl accepts a cdrom_read structure, but actual source code
-                 reads a cdrom_msf structure and writes a buffer of data to
-                 the same address.
-
-               - MSF values are converted to LBA values via this formula::
-
-                   lba = (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
-
-
-
-
-CDROMREADMODE1
-       Read CDROM mode 1 data (2048 Bytes)
-
-       (struct cdrom_read)
-
-       notes:
-               Identical to CDROMREADRAW except that block size is
-               CD_FRAMESIZE (2048) bytes
-
-
-
-CDROMREADMODE2
-       Read CDROM mode 2 data (2336 Bytes)
-
-       (struct cdrom_read)
-
-       notes:
-               Identical to CDROMREADRAW except that block size is
-               CD_FRAMESIZE_RAW0 (2336) bytes
-
-
-
-CDROMREADAUDIO
-       (struct cdrom_read_audio)
-
-       usage::
-
-         struct cdrom_read_audio ra;
-
-         ioctl(fd, CDROMREADAUDIO, &ra);
-
-       inputs:
-               cdrom_read_audio structure containing read start
-               point and length
-
-       outputs:
-               audio data, returned to buffer indicated by ra
-
-
-       error return:
-         - EINVAL      format not CDROM_MSF or CDROM_LBA
-         - EINVAL      nframes not in range [1 75]
-         - ENXIO       drive has no queue (probably means invalid fd)
-         - ENOMEM      out of memory
-
-
-CDROMEJECT_SW
-       enable(1)/disable(0) auto-ejecting
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, CDROMEJECT_SW, val);
-
-       inputs:
-               Flag specifying auto-eject flag.
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      Drive is not capable of ejecting.
-         - EBUSY       Door is locked
-
-
-
-
-CDROMMULTISESSION
-       Obtain the start-of-last-session address of multi session disks
-
-       (struct cdrom_multisession)
-
-       usage::
-
-         struct cdrom_multisession ms_info;
-
-         ioctl(fd, CDROMMULTISESSION, &ms_info);
-
-       inputs:
-               cdrom_multisession structure containing desired
-
-         format.
-
-       outputs:
-               cdrom_multisession structure is filled with last_session
-               information.
-
-       error return:
-         - EINVAL      format not CDROM_MSF or CDROM_LBA
-
-
-CDROM_GET_MCN
-       Obtain the "Universal Product Code"
-       if available
-
-       (struct cdrom_mcn)
-
-
-       usage::
-
-         struct cdrom_mcn mcn;
-
-         ioctl(fd, CDROM_GET_MCN, &mcn);
-
-       inputs:
-               none
-
-
-       outputs:
-               Universal Product Code
-
-
-       error return:
-         - ENOSYS      Drive is not capable of reading MCN data.
-
-       notes:
-               - Source code comments state::
-
-                   The following function is implemented, although very few
-                   audio discs give Universal Product Code information, which
-                   should just be the Medium Catalog Number on the box.  Note,
-                   that the way the code is written on the CD is /not/ uniform
-                   across all discs!
-
-
-
-
-CDROM_GET_UPC
-       CDROM_GET_MCN  (deprecated)
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-CDROMRESET
-       hard-reset the drive
-
-
-       usage::
-
-         ioctl(fd, CDROMRESET, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               none
-
-
-       error return:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - ENOSYS      Drive is not capable of resetting.
-
-
-
-
-CDROMREADCOOKED
-       read data in cooked mode
-
-
-       usage::
-
-         u8 buffer[CD_FRAMESIZE]
-
-         ioctl(fd, CDROMREADCOOKED, buffer);
-
-       inputs:
-               none
-
-
-       outputs:
-               2048 bytes of data, "cooked" mode.
-
-
-       notes:
-               Not implemented on all drives.
-
-
-
-
-
-CDROMREADALL
-       read all 2646 bytes
-
-
-       Same as CDROMREADCOOKED, but reads 2646 bytes.
-
-
-
-CDROMSEEK
-       seek msf address
-
-
-       usage::
-
-         struct cdrom_msf msf;
-
-         ioctl(fd, CDROMSEEK, &msf);
-
-       inputs:
-               MSF address to seek to.
-
-
-       outputs:
-               none
-
-
-
-
-CDROMPLAYBLK
-       scsi-cd only
-
-       (struct cdrom_blk)
-
-
-       usage::
-
-         struct cdrom_blk blk;
-
-         ioctl(fd, CDROMPLAYBLK, &blk);
-
-       inputs:
-               Region to play
-
-
-       outputs:
-               none
-
-
-
-
-CDROMGETSPINDOWN
-       usage::
-
-         char spindown;
-
-         ioctl(fd, CDROMGETSPINDOWN, &spindown);
-
-       inputs:
-               none
-
-
-       outputs:
-               The value of the current 4-bit spindown value.
-
-
-
-
-
-CDROMSETSPINDOWN
-       usage::
-
-         char spindown
-
-         ioctl(fd, CDROMSETSPINDOWN, &spindown);
-
-       inputs:
-               4-bit value used to control spindown (TODO: more detail here)
-
-
-       outputs:
-               none
-
-
-
-
-
-
-CDROM_SET_OPTIONS
-       Set behavior options
-
-
-       usage::
-
-         int options;
-
-         ioctl(fd, CDROM_SET_OPTIONS, options);
-
-       inputs:
-               New values for drive options.  The logical 'or' of:
-
-           ==============      ==================================
-           CDO_AUTO_CLOSE      close tray on first open(2)
-           CDO_AUTO_EJECT      open tray on last release
-           CDO_USE_FFLAGS      use O_NONBLOCK information on open
-           CDO_LOCK            lock tray on open files
-           CDO_CHECK_TYPE      check type on open for data
-           ==============      ==================================
-
-       outputs:
-               Returns the resulting options settings in the
-               ioctl return value.  Returns -1 on error.
-
-       error return:
-         - ENOSYS      selected option(s) not supported by drive.
-
-
-
-
-CDROM_CLEAR_OPTIONS
-       Clear behavior options
-
-
-       Same as CDROM_SET_OPTIONS, except that selected options are
-       turned off.
-
-
-
-CDROM_SELECT_SPEED
-       Set the CD-ROM speed
-
-
-       usage::
-
-         int speed;
-
-         ioctl(fd, CDROM_SELECT_SPEED, speed);
-
-       inputs:
-               New drive speed.
-
-
-       outputs:
-               none
-
-
-       error return:
-         - ENOSYS      speed selection not supported by drive.
-
-
-
-CDROM_SELECT_DISC
-       Select disc (for juke-boxes)
-
-
-       usage::
-
-         int disk;
-
-         ioctl(fd, CDROM_SELECT_DISC, disk);
-
-       inputs:
-               Disk to load into drive.
-
-
-       outputs:
-               none
-
-
-       error return:
-         - EINVAL      Disk number beyond capacity of drive
-
-
-
-CDROM_MEDIA_CHANGED
-       Check is media changed
-
-
-       usage::
-
-         int slot;
-
-         ioctl(fd, CDROM_MEDIA_CHANGED, slot);
-
-       inputs:
-               Slot number to be tested, always zero except for jukeboxes.
-
-               May also be special values CDSL_NONE or CDSL_CURRENT
-
-       outputs:
-               Ioctl return value is 0 or 1 depending on whether the media
-
-         has been changed, or -1 on error.
-
-       error returns:
-         - ENOSYS      Drive can't detect media change
-         - EINVAL      Slot number beyond capacity of drive
-         - ENOMEM      Out of memory
-
-
-
-CDROM_DRIVE_STATUS
-       Get tray position, etc.
-
-
-       usage::
-
-         int slot;
-
-         ioctl(fd, CDROM_DRIVE_STATUS, slot);
-
-       inputs:
-               Slot number to be tested, always zero except for jukeboxes.
-
-               May also be special values CDSL_NONE or CDSL_CURRENT
-
-       outputs:
-               Ioctl return value will be one of the following values
-
-         from <linux/cdrom.h>:
-
-           =================== ==========================
-           CDS_NO_INFO         Information not available.
-           CDS_NO_DISC
-           CDS_TRAY_OPEN
-           CDS_DRIVE_NOT_READY
-           CDS_DISC_OK
-           -1                  error
-           =================== ==========================
-
-       error returns:
-         - ENOSYS      Drive can't detect drive status
-         - EINVAL      Slot number beyond capacity of drive
-         - ENOMEM      Out of memory
-
-
-
-
-CDROM_DISC_STATUS
-       Get disc type, etc.
-
-
-       usage::
-
-         ioctl(fd, CDROM_DISC_STATUS, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               Ioctl return value will be one of the following values
-
-         from <linux/cdrom.h>:
-
-           - CDS_NO_INFO
-           - CDS_AUDIO
-           - CDS_MIXED
-           - CDS_XA_2_2
-           - CDS_XA_2_1
-           - CDS_DATA_1
-
-       error returns:
-               none at present
-
-       notes:
-           - Source code comments state::
-
-
-               Ok, this is where problems start.  The current interface for
-               the CDROM_DISC_STATUS ioctl is flawed.  It makes the false
-               assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.
-               Unfortunately, while this is often the case, it is also
-               very common for CDs to have some tracks with data, and some
-               tracks with audio.      Just because I feel like it, I declare
-               the following to be the best way to cope.  If the CD has
-               ANY data tracks on it, it will be returned as a data CD.
-               If it has any XA tracks, I will return it as that.      Now I
-               could simplify this interface by combining these returns with
-               the above, but this more clearly demonstrates the problem
-               with the current interface.  Too bad this wasn't designed
-               to use bitmasks...             -Erik
-
-               Well, now we have the option CDS_MIXED: a mixed-type CD.
-               User level programmers might feel the ioctl is not very
-               useful.
-                               ---david
-
-
-
-
-CDROM_CHANGER_NSLOTS
-       Get number of slots
-
-
-       usage::
-
-         ioctl(fd, CDROM_CHANGER_NSLOTS, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               The ioctl return value will be the number of slots in a
-               CD changer.  Typically 1 for non-multi-disk devices.
-
-       error returns:
-               none
-
-
-
-CDROM_LOCKDOOR
-       lock or unlock door
-
-
-       usage::
-
-         int lock;
-
-         ioctl(fd, CDROM_LOCKDOOR, lock);
-
-       inputs:
-               Door lock flag, 1=lock, 0=unlock
-
-
-       outputs:
-               none
-
-
-       error returns:
-         - EDRIVE_CANT_DO_THIS
-
-                               Door lock function not supported.
-         - EBUSY
-
-                               Attempt to unlock when multiple users
-                               have the drive open and not CAP_SYS_ADMIN
-
-       notes:
-               As of 2.6.8.1, the lock flag is a global lock, meaning that
-               all CD drives will be locked or unlocked together.  This is
-               probably a bug.
-
-               The EDRIVE_CANT_DO_THIS value is defined in <linux/cdrom.h>
-               and is currently (2.6.8.1) the same as EOPNOTSUPP
-
-
-
-CDROM_DEBUG
-       Turn debug messages on/off
-
-
-       usage::
-
-         int debug;
-
-         ioctl(fd, CDROM_DEBUG, debug);
-
-       inputs:
-               Cdrom debug flag, 0=disable, 1=enable
-
-
-       outputs:
-               The ioctl return value will be the new debug flag.
-
-
-       error return:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-
-
-
-CDROM_GET_CAPABILITY
-       get capabilities
-
-
-       usage::
-
-         ioctl(fd, CDROM_GET_CAPABILITY, 0);
-
-
-       inputs:
-               none
-
-
-       outputs:
-               The ioctl return value is the current device capability
-               flags.  See CDC_CLOSE_TRAY, CDC_OPEN_TRAY, etc.
-
-
-
-CDROMAUDIOBUFSIZ
-       set the audio buffer size
-
-
-       usage::
-
-         int arg;
-
-         ioctl(fd, CDROMAUDIOBUFSIZ, val);
-
-       inputs:
-               New audio buffer size
-
-
-       outputs:
-               The ioctl return value is the new audio buffer size, or -1
-               on error.
-
-       error return:
-         - ENOSYS      Not supported by this driver.
-
-       notes:
-               Not supported by all drivers.
-
-
-
-
-DVD_READ_STRUCT                        Read structure
-
-       usage::
-
-         dvd_struct s;
-
-         ioctl(fd, DVD_READ_STRUCT, &s);
-
-       inputs:
-               dvd_struct structure, containing:
-
-           =================== ==========================================
-           type                specifies the information desired, one of
-                               DVD_STRUCT_PHYSICAL, DVD_STRUCT_COPYRIGHT,
-                               DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA,
-                               DVD_STRUCT_MANUFACT
-           physical.layer_num  desired layer, indexed from 0
-           copyright.layer_num desired layer, indexed from 0
-           disckey.agid
-           =================== ==========================================
-
-       outputs:
-               dvd_struct structure, containing:
-
-           =================== ================================
-           physical            for type == DVD_STRUCT_PHYSICAL
-           copyright           for type == DVD_STRUCT_COPYRIGHT
-           disckey.value       for type == DVD_STRUCT_DISCKEY
-           bca.{len,value}     for type == DVD_STRUCT_BCA
-           manufact.{len,valu} for type == DVD_STRUCT_MANUFACT
-           =================== ================================
-
-       error returns:
-         - EINVAL      physical.layer_num exceeds number of layers
-         - EIO         Received invalid response from drive
-
-
-
-DVD_WRITE_STRUCT               Write structure
-
-       Not implemented, as of 2.6.8.1
-
-
-
-DVD_AUTH                       Authentication
-
-       usage::
-
-         dvd_authinfo ai;
-
-         ioctl(fd, DVD_AUTH, &ai);
-
-       inputs:
-               dvd_authinfo structure.  See <linux/cdrom.h>
-
-
-       outputs:
-               dvd_authinfo structure.
-
-
-       error return:
-         - ENOTTY      ai.type not recognized.
-
-
-
-CDROM_SEND_PACKET
-       send a packet to the drive
-
-
-       usage::
-
-         struct cdrom_generic_command cgc;
-
-         ioctl(fd, CDROM_SEND_PACKET, &cgc);
-
-       inputs:
-               cdrom_generic_command structure containing the packet to send.
-
-
-       outputs:
-               none
-
-         cdrom_generic_command structure containing results.
-
-       error return:
-         - EIO
-
-                       command failed.
-         - EPERM
-
-                       Operation not permitted, either because a
-                       write command was attempted on a drive which
-                       is opened read-only, or because the command
-                       requires CAP_SYS_RAWIO
-         - EINVAL
-
-                       cgc.data_direction not set
-
-
-
-CDROM_NEXT_WRITABLE
-       get next writable block
-
-
-       usage::
-
-         long next;
-
-         ioctl(fd, CDROM_NEXT_WRITABLE, &next);
-
-       inputs:
-               none
-
-
-       outputs:
-               The next writable block.
-
-
-       notes:
-               If the device does not support this ioctl directly, the
-
-         ioctl will return CDROM_LAST_WRITTEN + 7.
-
-
-
-CDROM_LAST_WRITTEN
-       get last block written on disc
-
-
-       usage::
-
-         long last;
-
-         ioctl(fd, CDROM_LAST_WRITTEN, &last);
-
-       inputs:
-               none
-
-
-       outputs:
-               The last block written on disc
-
-
-       notes:
-               If the device does not support this ioctl directly, the
-               result is derived from the disc's table of contents.  If the
-               table of contents can't be read, this ioctl returns an
-               error.
diff --git a/Documentation/ioctl/hdio.rst b/Documentation/ioctl/hdio.rst
deleted file mode 100644 (file)
index e822e3d..0000000
+++ /dev/null
@@ -1,1342 +0,0 @@
-==============================
-Summary of `HDIO_` ioctl calls
-==============================
-
-- Edward A. Falk <efalk@google.com>
-
-November, 2004
-
-This document attempts to describe the ioctl(2) calls supported by
-the HD/IDE layer.  These are by-and-large implemented (as of Linux 2.6)
-in drivers/ide/ide.c and drivers/block/scsi_ioctl.c
-
-ioctl values are listed in <linux/hdreg.h>.  As of this writing, they
-are as follows:
-
-    ioctls that pass argument pointers to user space:
-
-       ======================= =======================================
-       HDIO_GETGEO             get device geometry
-       HDIO_GET_UNMASKINTR     get current unmask setting
-       HDIO_GET_MULTCOUNT      get current IDE blockmode setting
-       HDIO_GET_QDMA           get use-qdma flag
-       HDIO_SET_XFER           set transfer rate via proc
-       HDIO_OBSOLETE_IDENTITY  OBSOLETE, DO NOT USE
-       HDIO_GET_KEEPSETTINGS   get keep-settings-on-reset flag
-       HDIO_GET_32BIT          get current io_32bit setting
-       HDIO_GET_NOWERR         get ignore-write-error flag
-       HDIO_GET_DMA            get use-dma flag
-       HDIO_GET_NICE           get nice flags
-       HDIO_GET_IDENTITY       get IDE identification info
-       HDIO_GET_WCACHE         get write cache mode on|off
-       HDIO_GET_ACOUSTIC       get acoustic value
-       HDIO_GET_ADDRESS        get sector addressing mode
-       HDIO_GET_BUSSTATE       get the bus state of the hwif
-       HDIO_TRISTATE_HWIF      execute a channel tristate
-       HDIO_DRIVE_RESET        execute a device reset
-       HDIO_DRIVE_TASKFILE     execute raw taskfile
-       HDIO_DRIVE_TASK         execute task and special drive command
-       HDIO_DRIVE_CMD          execute a special drive command
-       HDIO_DRIVE_CMD_AEB      HDIO_DRIVE_TASK
-       ======================= =======================================
-
-    ioctls that pass non-pointer values:
-
-       ======================= =======================================
-       HDIO_SET_MULTCOUNT      change IDE blockmode
-       HDIO_SET_UNMASKINTR     permit other irqs during I/O
-       HDIO_SET_KEEPSETTINGS   keep ioctl settings on reset
-       HDIO_SET_32BIT          change io_32bit flags
-       HDIO_SET_NOWERR         change ignore-write-error flag
-       HDIO_SET_DMA            change use-dma flag
-       HDIO_SET_PIO_MODE       reconfig interface to new speed
-       HDIO_SCAN_HWIF          register and (re)scan interface
-       HDIO_SET_NICE           set nice flags
-       HDIO_UNREGISTER_HWIF    unregister interface
-       HDIO_SET_WCACHE         change write cache enable-disable
-       HDIO_SET_ACOUSTIC       change acoustic behavior
-       HDIO_SET_BUSSTATE       set the bus state of the hwif
-       HDIO_SET_QDMA           change use-qdma flag
-       HDIO_SET_ADDRESS        change lba addressing modes
-
-       HDIO_SET_IDE_SCSI       Set scsi emulation mode on/off
-       HDIO_SET_SCSI_IDE       not implemented yet
-       ======================= =======================================
-
-
-The information that follows was determined from reading kernel source
-code.  It is likely that some corrections will be made over time.
-
-------------------------------------------------------------------------------
-
-General:
-
-       Unless otherwise specified, all ioctl calls return 0 on success
-       and -1 with errno set to an appropriate value on error.
-
-       Unless otherwise specified, all ioctl calls return -1 and set
-       errno to EFAULT on a failed attempt to copy data to or from user
-       address space.
-
-       Unless otherwise specified, all data structures and constants
-       are defined in <linux/hdreg.h>
-
-------------------------------------------------------------------------------
-
-HDIO_GETGEO
-       get device geometry
-
-
-       usage::
-
-         struct hd_geometry geom;
-
-         ioctl(fd, HDIO_GETGEO, &geom);
-
-
-       inputs:
-               none
-
-
-
-       outputs:
-               hd_geometry structure containing:
-
-
-           =========   ==================================
-           heads       number of heads
-           sectors     number of sectors/track
-           cylinders   number of cylinders, mod 65536
-           start       starting sector of this partition.
-           =========   ==================================
-
-
-       error returns:
-         - EINVAL
-
-                       if the device is not a disk drive or floppy drive,
-                       or if the user passes a null pointer
-
-
-       notes:
-               Not particularly useful with modern disk drives, whose geometry
-               is a polite fiction anyway.  Modern drives are addressed
-               purely by sector number nowadays (lba addressing), and the
-               drive geometry is an abstraction which is actually subject
-               to change.  Currently (as of Nov 2004), the geometry values
-               are the "bios" values -- presumably the values the drive had
-               when Linux first booted.
-
-               In addition, the cylinders field of the hd_geometry is an
-               unsigned short, meaning that on most architectures, this
-               ioctl will not return a meaningful value on drives with more
-               than 65535 tracks.
-
-               The start field is unsigned long, meaning that it will not
-               contain a meaningful value for disks over 219 Gb in size.
-
-
-
-
-HDIO_GET_UNMASKINTR
-       get current unmask setting
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_UNMASKINTR, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the drive's current unmask setting
-
-
-
-
-
-HDIO_SET_UNMASKINTR
-       permit other irqs during I/O
-
-
-       usage::
-
-         unsigned long val;
-
-         ioctl(fd, HDIO_SET_UNMASKINTR, val);
-
-       inputs:
-               New value for unmask flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-
-HDIO_GET_MULTCOUNT
-       get current IDE blockmode setting
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_MULTCOUNT, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current IDE block mode setting.  This
-               controls how many sectors the drive will transfer per
-               interrupt.
-
-
-
-HDIO_SET_MULTCOUNT
-       change IDE blockmode
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_MULTCOUNT, val);
-
-       inputs:
-               New value for IDE block mode setting.  This controls how many
-               sectors the drive will transfer per interrupt.
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range supported by disk.
-         - EBUSY       Controller busy or blockmode already set.
-         - EIO         Drive did not accept new block mode.
-
-       notes:
-         Source code comments read::
-
-           This is tightly woven into the driver->do_special cannot
-           touch.  DON'T do it again until a total personality rewrite
-           is committed.
-
-         If blockmode has already been set, this ioctl will fail with
-         -EBUSY
-
-
-
-HDIO_GET_QDMA
-       get use-qdma flag
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_SET_XFER
-       set transfer rate via proc
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_OBSOLETE_IDENTITY
-       OBSOLETE, DO NOT USE
-
-
-       Same as HDIO_GET_IDENTITY (see below), except that it only
-       returns the first 142 bytes of drive identity information.
-
-
-
-HDIO_GET_IDENTITY
-       get IDE identification info
-
-
-       usage::
-
-         unsigned char identity[512];
-
-         ioctl(fd, HDIO_GET_IDENTITY, identity);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               ATA drive identity information.  For full description, see
-               the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in
-               the ATA specification.
-
-       error returns:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - ENOMSG      IDENTIFY DEVICE information not available
-
-       notes:
-               Returns information that was obtained when the drive was
-               probed.  Some of this information is subject to change, and
-               this ioctl does not re-probe the drive to update the
-               information.
-
-               This information is also available from /proc/ide/hdX/identify
-
-
-
-HDIO_GET_KEEPSETTINGS
-       get keep-settings-on-reset flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_KEEPSETTINGS, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current "keep settings" flag
-
-
-
-       notes:
-               When set, indicates that kernel should restore settings
-               after a drive reset.
-
-
-
-HDIO_SET_KEEPSETTINGS
-       keep ioctl settings on reset
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_SET_KEEPSETTINGS, val);
-
-       inputs:
-               New value for keep_settings flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY               Controller busy
-
-
-
-HDIO_GET_32BIT
-       get current io_32bit setting
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_32BIT, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current io_32bit setting
-
-
-
-       notes:
-               0=16-bit, 1=32-bit, 2,3 = 32bit+sync
-
-
-
-
-
-HDIO_GET_NOWERR
-       get ignore-write-error flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_NOWERR, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current ignore-write-error flag
-
-
-
-
-
-HDIO_GET_DMA
-       get use-dma flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_DMA, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current use-dma flag
-
-
-
-
-
-HDIO_GET_NICE
-       get nice flags
-
-
-       usage::
-
-         long nice;
-
-         ioctl(fd, HDIO_GET_NICE, &nice);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The drive's "nice" values.
-
-
-
-       notes:
-               Per-drive flags which determine when the system will give more
-               bandwidth to other devices sharing the same IDE bus.
-
-               See <linux/hdreg.h>, near symbol IDE_NICE_DSC_OVERLAP.
-
-
-
-
-HDIO_SET_NICE
-       set nice flags
-
-
-       usage::
-
-         unsigned long nice;
-
-         ...
-         ioctl(fd, HDIO_SET_NICE, nice);
-
-       inputs:
-               bitmask of nice flags.
-
-
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EPERM       Flags other than DSC_OVERLAP and NICE_1 set.
-         - EPERM       DSC_OVERLAP specified but not supported by drive
-
-       notes:
-               This ioctl sets the DSC_OVERLAP and NICE_1 flags from values
-               provided by the user.
-
-               Nice flags are listed in <linux/hdreg.h>, starting with
-               IDE_NICE_DSC_OVERLAP.  These values represent shifts.
-
-
-
-
-
-HDIO_GET_WCACHE
-       get write cache mode on|off
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_WCACHE, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current write cache mode
-
-
-
-
-
-HDIO_GET_ACOUSTIC
-       get acoustic value
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_ACOUSTIC, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current acoustic settings
-
-
-
-       notes:
-               See HDIO_SET_ACOUSTIC
-
-
-
-
-
-HDIO_GET_ADDRESS
-       usage::
-
-
-         long val;
-
-         ioctl(fd, HDIO_GET_ADDRESS, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current addressing mode:
-
-           =  ===================
-           0  28-bit
-           1  48-bit
-           2  48-bit doing 28-bit
-           3  64-bit
-           =  ===================
-
-
-
-HDIO_GET_BUSSTATE
-       get the bus state of the hwif
-
-
-       usage::
-
-         long state;
-
-         ioctl(fd, HDIO_SCAN_HWIF, &state);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               Current power state of the IDE bus.  One of BUSSTATE_OFF,
-               BUSSTATE_ON, or BUSSTATE_TRISTATE
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-
-
-
-
-HDIO_SET_BUSSTATE
-       set the bus state of the hwif
-
-
-       usage::
-
-         int state;
-
-         ...
-         ioctl(fd, HDIO_SCAN_HWIF, state);
-
-       inputs:
-               Desired IDE power state.  One of BUSSTATE_OFF, BUSSTATE_ON,
-               or BUSSTATE_TRISTATE
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-         - EOPNOTSUPP  Hardware interface does not support bus power control
-
-
-
-
-HDIO_TRISTATE_HWIF
-       execute a channel tristate
-
-
-       Not implemented, as of 2.6.8.1.  See HDIO_SET_BUSSTATE
-
-
-
-HDIO_DRIVE_RESET
-       execute a device reset
-
-
-       usage::
-
-         int args[3]
-
-         ...
-         ioctl(fd, HDIO_DRIVE_RESET, args);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - ENXIO       No such device: phy dead or ctl_addr == 0
-         - EIO         I/O error:      reset timed out or hardware error
-
-       notes:
-
-         - Execute a reset on the device as soon as the current IO
-           operation has completed.
-
-         - Executes an ATAPI soft reset if applicable, otherwise
-           executes an ATA soft reset on the controller.
-
-
-
-HDIO_DRIVE_TASKFILE
-       execute raw taskfile
-
-
-       Note:
-               If you don't have a copy of the ANSI ATA specification
-               handy, you should probably ignore this ioctl.
-
-       - Execute an ATA disk command directly by writing the "taskfile"
-         registers of the drive.  Requires ADMIN and RAWIO access
-         privileges.
-
-       usage::
-
-         struct {
-
-           ide_task_request_t req_task;
-           u8 outbuf[OUTPUT_SIZE];
-           u8 inbuf[INPUT_SIZE];
-         } task;
-         memset(&task.req_task, 0, sizeof(task.req_task));
-         task.req_task.out_size = sizeof(task.outbuf);
-         task.req_task.in_size = sizeof(task.inbuf);
-         ...
-         ioctl(fd, HDIO_DRIVE_TASKFILE, &task);
-         ...
-
-       inputs:
-
-         (See below for details on memory area passed to ioctl.)
-
-         ============  ===================================================
-         io_ports[8]   values to be written to taskfile registers
-         hob_ports[8]  high-order bytes, for extended commands.
-         out_flags     flags indicating which registers are valid
-         in_flags      flags indicating which registers should be returned
-         data_phase    see below
-         req_cmd       command type to be executed
-         out_size      size of output buffer
-         outbuf        buffer of data to be transmitted to disk
-         inbuf         buffer of data to be received from disk (see [1])
-         ============  ===================================================
-
-       outputs:
-
-         ===========   ====================================================
-         io_ports[]    values returned in the taskfile registers
-         hob_ports[]   high-order bytes, for extended commands.
-         out_flags     flags indicating which registers are valid (see [2])
-         in_flags      flags indicating which registers should be returned
-         outbuf        buffer of data to be transmitted to disk (see [1])
-         inbuf         buffer of data to be received from disk
-         ===========   ====================================================
-
-       error returns:
-         - EACCES      CAP_SYS_ADMIN or CAP_SYS_RAWIO privilege not set.
-         - ENOMSG      Device is not a disk drive.
-         - ENOMEM      Unable to allocate memory for task
-         - EFAULT      req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8)
-         - EPERM
-
-                       req_cmd == TASKFILE_MULTI_OUT and drive
-                       multi-count not yet set.
-         - EIO         Drive failed the command.
-
-       notes:
-
-         [1] READ THE FOLLOWING NOTES *CAREFULLY*.  THIS IOCTL IS
-         FULL OF GOTCHAS.  Extreme caution should be used with using
-         this ioctl.  A mistake can easily corrupt data or hang the
-         system.
-
-         [2] Both the input and output buffers are copied from the
-         user and written back to the user, even when not used.
-
-         [3] If one or more bits are set in out_flags and in_flags is
-         zero, the following values are used for in_flags.all and
-         written back into in_flags on completion.
-
-          * IDE_TASKFILE_STD_IN_FLAGS | (IDE_HOB_STD_IN_FLAGS << 8)
-            if LBA48 addressing is enabled for the drive
-          * IDE_TASKFILE_STD_IN_FLAGS
-            if CHS/LBA28
-
-         The association between in_flags.all and each enable
-         bitfield flips depending on endianness; fortunately, TASKFILE
-         only uses inflags.b.data bit and ignores all other bits.
-         The end result is that, on any endian machines, it has no
-         effect other than modifying in_flags on completion.
-
-         [4] The default value of SELECT is (0xa0|DEV_bit|LBA_bit)
-         except for four drives per port chipsets.  For four drives
-         per port chipsets, it's (0xa0|DEV_bit|LBA_bit) for the first
-         pair and (0x80|DEV_bit|LBA_bit) for the second pair.
-
-         [5] The argument to the ioctl is a pointer to a region of
-         memory containing a ide_task_request_t structure, followed
-         by an optional buffer of data to be transmitted to the
-         drive, followed by an optional buffer to receive data from
-         the drive.
-
-         Command is passed to the disk drive via the ide_task_request_t
-         structure, which contains these fields:
-
-           ============        ===============================================
-           io_ports[8]         values for the taskfile registers
-           hob_ports[8]        high-order bytes, for extended commands
-           out_flags           flags indicating which entries in the
-                               io_ports[] and hob_ports[] arrays
-                               contain valid values.  Type ide_reg_valid_t.
-           in_flags            flags indicating which entries in the
-                               io_ports[] and hob_ports[] arrays
-                               are expected to contain valid values
-                               on return.
-           data_phase          See below
-           req_cmd             Command type, see below
-           out_size            output (user->drive) buffer size, bytes
-           in_size             input (drive->user) buffer size, bytes
-           ============        ===============================================
-
-         When out_flags is zero, the following registers are loaded.
-
-           ============        ===============================================
-           HOB_FEATURE         If the drive supports LBA48
-           HOB_NSECTOR         If the drive supports LBA48
-           HOB_SECTOR          If the drive supports LBA48
-           HOB_LCYL            If the drive supports LBA48
-           HOB_HCYL            If the drive supports LBA48
-           FEATURE
-           NSECTOR
-           SECTOR
-           LCYL
-           HCYL
-           SELECT              First, masked with 0xE0 if LBA48, 0xEF
-                               otherwise; then, or'ed with the default
-                               value of SELECT.
-           ============        ===============================================
-
-         If any bit in out_flags is set, the following registers are loaded.
-
-           ============        ===============================================
-           HOB_DATA            If out_flags.b.data is set.  HOB_DATA will
-                               travel on DD8-DD15 on little endian machines
-                               and on DD0-DD7 on big endian machines.
-           DATA                If out_flags.b.data is set.  DATA will
-                               travel on DD0-DD7 on little endian machines
-                               and on DD8-DD15 on big endian machines.
-           HOB_NSECTOR         If out_flags.b.nsector_hob is set
-           HOB_SECTOR          If out_flags.b.sector_hob is set
-           HOB_LCYL            If out_flags.b.lcyl_hob is set
-           HOB_HCYL            If out_flags.b.hcyl_hob is set
-           FEATURE             If out_flags.b.feature is set
-           NSECTOR             If out_flags.b.nsector is set
-           SECTOR              If out_flags.b.sector is set
-           LCYL                If out_flags.b.lcyl is set
-           HCYL                If out_flags.b.hcyl is set
-           SELECT              Or'ed with the default value of SELECT and
-                               loaded regardless of out_flags.b.select.
-           ============        ===============================================
-
-         Taskfile registers are read back from the drive into
-         {io|hob}_ports[] after the command completes iff one of the
-         following conditions is met; otherwise, the original values
-         will be written back, unchanged.
-
-           1. The drive fails the command (EIO).
-           2. One or more than one bits are set in out_flags.
-           3. The requested data_phase is TASKFILE_NO_DATA.
-
-           ============        ===============================================
-           HOB_DATA            If in_flags.b.data is set.  It will contain
-                               DD8-DD15 on little endian machines and
-                               DD0-DD7 on big endian machines.
-           DATA                If in_flags.b.data is set.  It will contain
-                               DD0-DD7 on little endian machines and
-                               DD8-DD15 on big endian machines.
-           HOB_FEATURE         If the drive supports LBA48
-           HOB_NSECTOR         If the drive supports LBA48
-           HOB_SECTOR          If the drive supports LBA48
-           HOB_LCYL            If the drive supports LBA48
-           HOB_HCYL            If the drive supports LBA48
-           NSECTOR
-           SECTOR
-           LCYL
-           HCYL
-           ============        ===============================================
-
-         The data_phase field describes the data transfer to be
-         performed.  Value is one of:
-
-           ===================        ========================================
-           TASKFILE_IN
-           TASKFILE_MULTI_IN
-           TASKFILE_OUT
-           TASKFILE_MULTI_OUT
-           TASKFILE_IN_OUT
-           TASKFILE_IN_DMA
-           TASKFILE_IN_DMAQ            == IN_DMA (queueing not supported)
-           TASKFILE_OUT_DMA
-           TASKFILE_OUT_DMAQ           == OUT_DMA (queueing not supported)
-           TASKFILE_P_IN               unimplemented
-           TASKFILE_P_IN_DMA           unimplemented
-           TASKFILE_P_IN_DMAQ          unimplemented
-           TASKFILE_P_OUT              unimplemented
-           TASKFILE_P_OUT_DMA          unimplemented
-           TASKFILE_P_OUT_DMAQ         unimplemented
-           ===================        ========================================
-
-         The req_cmd field classifies the command type.  It may be
-         one of:
-
-           ========================    =======================================
-           IDE_DRIVE_TASK_NO_DATA
-           IDE_DRIVE_TASK_SET_XFER     unimplemented
-           IDE_DRIVE_TASK_IN
-           IDE_DRIVE_TASK_OUT          unimplemented
-           IDE_DRIVE_TASK_RAW_WRITE
-           ========================    =======================================
-
-         [6] Do not access {in|out}_flags->all except for resetting
-         all the bits.  Always access individual bit fields.  ->all
-         value will flip depending on endianness.  For the same
-         reason, do not use IDE_{TASKFILE|HOB}_STD_{OUT|IN}_FLAGS
-         constants defined in hdreg.h.
-
-
-
-HDIO_DRIVE_CMD
-       execute a special drive command
-
-
-       Note:  If you don't have a copy of the ANSI ATA specification
-       handy, you should probably ignore this ioctl.
-
-       usage::
-
-         u8 args[4+XFER_SIZE];
-
-         ...
-         ioctl(fd, HDIO_DRIVE_CMD, args);
-
-       inputs:
-           Commands other than WIN_SMART:
-
-           =======     =======
-           args[0]     COMMAND
-           args[1]     NSECTOR
-           args[2]     FEATURE
-           args[3]     NSECTOR
-           =======     =======
-
-           WIN_SMART:
-
-           =======     =======
-           args[0]     COMMAND
-           args[1]     SECTOR
-           args[2]     FEATURE
-           args[3]     NSECTOR
-           =======     =======
-
-       outputs:
-               args[] buffer is filled with register values followed by any
-
-
-         data returned by the disk.
-
-           ========    ====================================================
-           args[0]     status
-           args[1]     error
-           args[2]     NSECTOR
-           args[3]     undefined
-           args[4+]    NSECTOR * 512 bytes of data returned by the command.
-           ========    ====================================================
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-         - ENOMEM      Unable to allocate memory for task
-         - EIO         Drive reports error
-
-       notes:
-
-         [1] For commands other than WIN_SMART, args[1] should equal
-         args[3].  SECTOR, LCYL and HCYL are undefined.  For
-         WIN_SMART, 0x4f and 0xc2 are loaded into LCYL and HCYL
-         respectively.  In both cases SELECT will contain the default
-         value for the drive.  Please refer to HDIO_DRIVE_TASKFILE
-         notes for the default value of SELECT.
-
-         [2] If NSECTOR value is greater than zero and the drive sets
-         DRQ when interrupting for the command, NSECTOR * 512 bytes
-         are read from the device into the area following NSECTOR.
-         In the above example, the area would be
-         args[4..4+XFER_SIZE].  16bit PIO is used regardless of
-         HDIO_SET_32BIT setting.
-
-         [3] If COMMAND == WIN_SETFEATURES && FEATURE == SETFEATURES_XFER
-         && NSECTOR >= XFER_SW_DMA_0 && the drive supports any DMA
-         mode, IDE driver will try to tune the transfer mode of the
-         drive accordingly.
-
-
-
-HDIO_DRIVE_TASK
-       execute task and special drive command
-
-
-       Note:  If you don't have a copy of the ANSI ATA specification
-       handy, you should probably ignore this ioctl.
-
-       usage::
-
-         u8 args[7];
-
-         ...
-         ioctl(fd, HDIO_DRIVE_TASK, args);
-
-       inputs:
-           Taskfile register values:
-
-           =======     =======
-           args[0]     COMMAND
-           args[1]     FEATURE
-           args[2]     NSECTOR
-           args[3]     SECTOR
-           args[4]     LCYL
-           args[5]     HCYL
-           args[6]     SELECT
-           =======     =======
-
-       outputs:
-           Taskfile register values:
-
-
-           =======     =======
-           args[0]     status
-           args[1]     error
-           args[2]     NSECTOR
-           args[3]     SECTOR
-           args[4]     LCYL
-           args[5]     HCYL
-           args[6]     SELECT
-           =======     =======
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-         - ENOMEM      Unable to allocate memory for task
-         - ENOMSG      Device is not a disk drive.
-         - EIO         Drive failed the command.
-
-       notes:
-
-         [1] DEV bit (0x10) of SELECT register is ignored and the
-         appropriate value for the drive is used.  All other bits
-         are used unaltered.
-
-
-
-HDIO_DRIVE_CMD_AEB
-       HDIO_DRIVE_TASK
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_SET_32BIT
-       change io_32bit flags
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_32BIT, val);
-
-       inputs:
-               New value for io_32bit flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 3]
-         - EBUSY       Controller busy
-
-
-
-
-HDIO_SET_NOWERR
-       change ignore-write-error flag
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_NOWERR, val);
-
-       inputs:
-               New value for ignore-write-error flag.  Used for ignoring
-
-
-         WRERR_STAT
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY               Controller busy
-
-
-
-HDIO_SET_DMA
-       change use-dma flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_SET_DMA, val);
-
-       inputs:
-               New value for use-dma flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_PIO_MODE
-       reconfig interface to new speed
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_SET_PIO_MODE, val);
-
-       inputs:
-               New interface speed.
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 255]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SCAN_HWIF
-       register and (re)scan interface
-
-
-       usage::
-
-         int args[3]
-
-         ...
-         ioctl(fd, HDIO_SCAN_HWIF, args);
-
-       inputs:
-
-         =======       =========================
-         args[0]       io address to probe
-
-
-         args[1]       control address to probe
-         args[2]       irq number
-         =======       =========================
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-         - EIO         Probe failed.
-
-       notes:
-               This ioctl initializes the addresses and irq for a disk
-               controller, probes for drives, and creates /proc/ide
-               interfaces as appropriate.
-
-
-
-HDIO_UNREGISTER_HWIF
-       unregister interface
-
-
-       usage::
-
-         int index;
-
-         ioctl(fd, HDIO_UNREGISTER_HWIF, index);
-
-       inputs:
-               index           index of hardware interface to unregister
-
-
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-
-       notes:
-               This ioctl removes a hardware interface from the kernel.
-
-               Currently (2.6.8) this ioctl silently fails if any drive on
-               the interface is busy.
-
-
-
-HDIO_SET_WCACHE
-       change write cache enable-disable
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_WCACHE, val);
-
-       inputs:
-               New value for write cache enable
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_ACOUSTIC
-       change acoustic behavior
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_ACOUSTIC, val);
-
-       inputs:
-               New value for drive acoustic settings
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 254]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_QDMA
-       change use-qdma flag
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_SET_ADDRESS
-       change lba addressing modes
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_ADDRESS, val);
-
-       inputs:
-               New value for addressing mode
-
-           =   ===================
-           0   28-bit
-           1   48-bit
-           2   48-bit doing 28-bit
-           =   ===================
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 2]
-         - EBUSY               Controller busy
-         - EIO         Drive does not support lba48 mode.
-
-
-HDIO_SET_IDE_SCSI
-       usage::
-
-
-         long val;
-
-         ioctl(fd, HDIO_SET_IDE_SCSI, val);
-
-       inputs:
-               New value for scsi emulation mode (?)
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_SCSI_IDE
-       Not implemented, as of 2.6.8.1
diff --git a/Documentation/ioctl/index.rst b/Documentation/ioctl/index.rst
deleted file mode 100644 (file)
index 0f0a857..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-======
-IOCTLs
-======
-
-.. toctree::
-   :maxdepth: 1
-
-   ioctl-number
-
-   botching-up-ioctls
-   ioctl-decoding
-
-   cdrom
-   hdio
diff --git a/Documentation/ioctl/ioctl-decoding.rst b/Documentation/ioctl/ioctl-decoding.rst
deleted file mode 100644 (file)
index 380d6bb..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-==============================
-Decoding an IOCTL Magic Number
-==============================
-
-To decode a hex IOCTL code:
-
-Most architectures use this generic format, but check
-include/ARCH/ioctl.h for specifics, e.g. powerpc
-uses 3 bits to encode read/write and 13 bits for size.
-
- ====== ==================================
- bits   meaning
- ====== ==================================
- 31-30 00 - no parameters: uses _IO macro
-       10 - read: _IOR
-       01 - write: _IOW
-       11 - read/write: _IOWR
-
- 29-16 size of arguments
-
- 15-8  ascii character supposedly
-       unique to each driver
-
- 7-0   function #
- ====== ==================================
-
-
-So for example 0x82187201 is a read with arg length of 0x218,
-character 'r' function 1. Grepping the source reveals this is::
-
-       #define VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst
deleted file mode 100644 (file)
index 4ef8643..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-=============
-Ioctl Numbers
-=============
-
-19 October 1999
-
-Michael Elizabeth Chastain
-<mec@shout.net>
-
-If you are adding new ioctl's to the kernel, you should use the _IO
-macros defined in <linux/ioctl.h>:
-
-    ====== == ============================================
-    _IO    an ioctl with no parameters
-    _IOW   an ioctl with write parameters (copy_from_user)
-    _IOR   an ioctl with read parameters  (copy_to_user)
-    _IOWR  an ioctl with both write and read parameters.
-    ====== == ============================================
-
-'Write' and 'read' are from the user's point of view, just like the
-system calls 'write' and 'read'.  For example, a SET_FOO ioctl would
-be _IOW, although the kernel would actually read data from user space;
-a GET_FOO ioctl would be _IOR, although the kernel would actually write
-data to user space.
-
-The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
-or number from the table below.  Because of the large number of drivers,
-many drivers share a partial letter with other drivers.
-
-If you are writing a driver for a new device and need a letter, pick an
-unused block with enough room for expansion: 32 to 256 ioctl commands.
-You can register the block by patching this file and submitting the
-patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and
-I'll register one for you.
-
-The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
-to distinguish ioctls from each other.  The third argument to _IOW,
-_IOR, or _IOWR is the type of the data going into the kernel or coming
-out of the kernel (e.g.  'int' or 'struct foo').  NOTE!  Do NOT use
-sizeof(arg) as the third argument as this results in your ioctl thinking
-it passes an argument of type size_t.
-
-Some devices use their major number as the identifier; this is OK, as
-long as it is unique.  Some devices are irregular and don't follow any
-convention at all.
-
-Following this convention is good because:
-
-(1) Keeping the ioctl's globally unique helps error checking:
-    if a program calls an ioctl on the wrong device, it will get an
-    error rather than some unexpected behaviour.
-
-(2) The 'strace' build procedure automatically finds ioctl numbers
-    defined with _IO, _IOW, _IOR, or _IOWR.
-
-(3) 'strace' can decode numbers back into useful names when the
-    numbers are unique.
-
-(4) People looking for ioctls can grep for them more easily when
-    this convention is used to define the ioctl numbers.
-
-(5) When following the convention, the driver code can use generic
-    code to copy the parameters between user and kernel space.
-
-This table lists ioctls visible from user land for Linux/x86.  It contains
-most drivers up to 2.6.31, but I know I am missing some.  There has been
-no attempt to list non-X86 architectures or ioctls from drivers/staging/.
-
-====  =====  ======================================================= ================================================================
-Code  Seq#    Include File                                           Comments
-      (hex)
-====  =====  ======================================================= ================================================================
-0x00  00-1F  linux/fs.h                                              conflict!
-0x00  00-1F  scsi/scsi_ioctl.h                                       conflict!
-0x00  00-1F  linux/fb.h                                              conflict!
-0x00  00-1F  linux/wavefront.h                                       conflict!
-0x02  all    linux/fd.h
-0x03  all    linux/hdreg.h
-0x04  D2-DC  linux/umsdos_fs.h                                       Dead since 2.6.11, but don't reuse these.
-0x06  all    linux/lp.h
-0x09  all    linux/raid/md_u.h
-0x10  00-0F  drivers/char/s390/vmcp.h
-0x10  10-1F  arch/s390/include/uapi/sclp_ctl.h
-0x10  20-2F  arch/s390/include/uapi/asm/hypfs.h
-0x12  all    linux/fs.h
-             linux/blkpg.h
-0x1b  all                                                            InfiniBand Subsystem
-                                                                     <http://infiniband.sourceforge.net/>
-0x20  all    drivers/cdrom/cm206.h
-0x22  all    scsi/sg.h
-'!'   00-1F  uapi/linux/seccomp.h
-'#'   00-3F                                                          IEEE 1394 Subsystem
-                                                                     Block for the entire subsystem
-'$'   00-0F  linux/perf_counter.h, linux/perf_event.h
-'%'   00-0F  include/uapi/linux/stm.h                                System Trace Module subsystem
-                                                                     <mailto:alexander.shishkin@linux.intel.com>
-'&'   00-07  drivers/firewire/nosy-user.h
-'1'   00-1F  linux/timepps.h                                         PPS kit from Ulrich Windl
-                                                                     <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
-'2'   01-04  linux/i2o.h
-'3'   00-0F  drivers/s390/char/raw3270.h                             conflict!
-'3'   00-1F  linux/suspend_ioctls.h,                                 conflict!
-             kernel/power/user.c
-'8'   all                                                            SNP8023 advanced NIC card
-                                                                     <mailto:mcr@solidum.com>
-';'   64-7F  linux/vfio.h
-'@'   00-0F  linux/radeonfb.h                                        conflict!
-'@'   00-0F  drivers/video/aty/aty128fb.c                            conflict!
-'A'   00-1F  linux/apm_bios.h                                        conflict!
-'A'   00-0F  linux/agpgart.h,                                        conflict!
-             drivers/char/agp/compat_ioctl.h
-'A'   00-7F  sound/asound.h                                          conflict!
-'B'   00-1F  linux/cciss_ioctl.h                                     conflict!
-'B'   00-0F  include/linux/pmu.h                                     conflict!
-'B'   C0-FF  advanced bbus                                           <mailto:maassen@uni-freiburg.de>
-'C'   all    linux/soundcard.h                                       conflict!
-'C'   01-2F  linux/capi.h                                            conflict!
-'C'   F0-FF  drivers/net/wan/cosa.h                                  conflict!
-'D'   all    arch/s390/include/asm/dasd.h
-'D'   40-5F  drivers/scsi/dpt/dtpi_ioctl.h
-'D'   05     drivers/scsi/pmcraid.h
-'E'   all    linux/input.h                                           conflict!
-'E'   00-0F  xen/evtchn.h                                            conflict!
-'F'   all    linux/fb.h                                              conflict!
-'F'   01-02  drivers/scsi/pmcraid.h                                  conflict!
-'F'   20     drivers/video/fsl-diu-fb.h                              conflict!
-'F'   20     drivers/video/intelfb/intelfb.h                         conflict!
-'F'   20     linux/ivtvfb.h                                          conflict!
-'F'   20     linux/matroxfb.h                                        conflict!
-'F'   20     drivers/video/aty/atyfb_base.c                          conflict!
-'F'   00-0F  video/da8xx-fb.h                                        conflict!
-'F'   80-8F  linux/arcfb.h                                           conflict!
-'F'   DD     video/sstfb.h                                           conflict!
-'G'   00-3F  drivers/misc/sgi-gru/grulib.h                           conflict!
-'G'   00-0F  linux/gigaset_dev.h                                     conflict!
-'H'   00-7F  linux/hiddev.h                                          conflict!
-'H'   00-0F  linux/hidraw.h                                          conflict!
-'H'   01     linux/mei.h                                             conflict!
-'H'   02     linux/mei.h                                             conflict!
-'H'   03     linux/mei.h                                             conflict!
-'H'   00-0F  sound/asound.h                                          conflict!
-'H'   20-40  sound/asound_fm.h                                       conflict!
-'H'   80-8F  sound/sfnt_info.h                                       conflict!
-'H'   10-8F  sound/emu10k1.h                                         conflict!
-'H'   10-1F  sound/sb16_csp.h                                        conflict!
-'H'   10-1F  sound/hda_hwdep.h                                       conflict!
-'H'   40-4F  sound/hdspm.h                                           conflict!
-'H'   40-4F  sound/hdsp.h                                            conflict!
-'H'   90     sound/usb/usx2y/usb_stream.h
-'H'   A0     uapi/linux/usb/cdc-wdm.h
-'H'   C0-F0  net/bluetooth/hci.h                                     conflict!
-'H'   C0-DF  net/bluetooth/hidp/hidp.h                               conflict!
-'H'   C0-DF  net/bluetooth/cmtp/cmtp.h                               conflict!
-'H'   C0-DF  net/bluetooth/bnep/bnep.h                               conflict!
-'H'   F1     linux/hid-roccat.h                                      <mailto:erazor_de@users.sourceforge.net>
-'H'   F8-FA  sound/firewire.h
-'I'   all    linux/isdn.h                                            conflict!
-'I'   00-0F  drivers/isdn/divert/isdn_divert.h                       conflict!
-'I'   40-4F  linux/mISDNif.h                                         conflict!
-'J'   00-1F  drivers/scsi/gdth_ioctl.h
-'K'   all    linux/kd.h
-'L'   00-1F  linux/loop.h                                            conflict!
-'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                      conflict!
-'L'   20-2F  linux/lightnvm.h
-'L'   E0-FF  linux/ppdd.h                                            encrypted disk device driver
-                                                                     <http://linux01.gwdg.de/~alatham/ppdd.html>
-'M'   all    linux/soundcard.h                                       conflict!
-'M'   01-16  mtd/mtd-abi.h                                           conflict!
-      and    drivers/mtd/mtdchar.c
-'M'   01-03  drivers/scsi/megaraid/megaraid_sas.h
-'M'   00-0F  drivers/video/fsl-diu-fb.h                              conflict!
-'N'   00-1F  drivers/usb/scanner.h
-'N'   40-7F  drivers/block/nvme.c
-'O'   00-06  mtd/ubi-user.h                                          UBI
-'P'   all    linux/soundcard.h                                       conflict!
-'P'   60-6F  sound/sscape_ioctl.h                                    conflict!
-'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
-'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
-'Q'   all    linux/soundcard.h
-'R'   00-1F  linux/random.h                                          conflict!
-'R'   01     linux/rfkill.h                                          conflict!
-'R'   C0-DF  net/bluetooth/rfcomm.h
-'S'   all    linux/cdrom.h                                           conflict!
-'S'   80-81  scsi/scsi_ioctl.h                                       conflict!
-'S'   82-FF  scsi/scsi.h                                             conflict!
-'S'   00-7F  sound/asequencer.h                                      conflict!
-'T'   all    linux/soundcard.h                                       conflict!
-'T'   00-AF  sound/asound.h                                          conflict!
-'T'   all    arch/x86/include/asm/ioctls.h                           conflict!
-'T'   C0-DF  linux/if_tun.h                                          conflict!
-'U'   all    sound/asound.h                                          conflict!
-'U'   00-CF  linux/uinput.h                                          conflict!
-'U'   00-EF  linux/usbdevice_fs.h
-'U'   C0-CF  drivers/bluetooth/hci_uart.h
-'V'   all    linux/vt.h                                              conflict!
-'V'   all    linux/videodev2.h                                       conflict!
-'V'   C0     linux/ivtvfb.h                                          conflict!
-'V'   C0     linux/ivtv.h                                            conflict!
-'V'   C0     media/davinci/vpfe_capture.h                            conflict!
-'V'   C0     media/si4713.h                                          conflict!
-'W'   00-1F  linux/watchdog.h                                        conflict!
-'W'   00-1F  linux/wanrouter.h                                       conflict! (pre 3.9)
-'W'   00-3F  sound/asound.h                                          conflict!
-'W'   40-5F  drivers/pci/switch/switchtec.c
-'X'   all    fs/xfs/xfs_fs.h,                                        conflict!
-             fs/xfs/linux-2.6/xfs_ioctl32.h,
-             include/linux/falloc.h,
-             linux/fs.h,
-'X'   all    fs/ocfs2/ocfs_fs.h                                      conflict!
-'X'   01     linux/pktcdvd.h                                         conflict!
-'Y'   all    linux/cyclades.h
-'Z'   14-15  drivers/message/fusion/mptctl.h
-'['   00-3F  linux/usb/tmc.h                                         USB Test and Measurement Devices
-                                                                     <mailto:gregkh@linuxfoundation.org>
-'a'   all    linux/atm*.h, linux/sonet.h                             ATM on linux
-                                                                     <http://lrcwww.epfl.ch/>
-'a'   00-0F  drivers/crypto/qat/qat_common/adf_cfg_common.h          conflict! qat driver
-'b'   00-FF                                                          conflict! bit3 vme host bridge
-                                                                     <mailto:natalia@nikhefk.nikhef.nl>
-'c'   all    linux/cm4000_cs.h                                       conflict!
-'c'   00-7F  linux/comstats.h                                        conflict!
-'c'   00-7F  linux/coda.h                                            conflict!
-'c'   00-1F  linux/chio.h                                            conflict!
-'c'   80-9F  arch/s390/include/asm/chsc.h                            conflict!
-'c'   A0-AF  arch/x86/include/asm/msr.h conflict!
-'d'   00-FF  linux/char/drm/drm.h                                    conflict!
-'d'   02-40  pcmcia/ds.h                                             conflict!
-'d'   F0-FF  linux/digi1.h
-'e'   all    linux/digi1.h                                           conflict!
-'f'   00-1F  linux/ext2_fs.h                                         conflict!
-'f'   00-1F  linux/ext3_fs.h                                         conflict!
-'f'   00-0F  fs/jfs/jfs_dinode.h                                     conflict!
-'f'   00-0F  fs/ext4/ext4.h                                          conflict!
-'f'   00-0F  linux/fs.h                                              conflict!
-'f'   00-0F  fs/ocfs2/ocfs2_fs.h                                     conflict!
-'f'   13-27  linux/fscrypt.h
-'f'   81-8F  linux/fsverity.h
-'g'   00-0F  linux/usb/gadgetfs.h
-'g'   20-2F  linux/usb/g_printer.h
-'h'   00-7F                                                          conflict! Charon filesystem
-                                                                     <mailto:zapman@interlan.net>
-'h'   00-1F  linux/hpet.h                                            conflict!
-'h'   80-8F  fs/hfsplus/ioctl.c
-'i'   00-3F  linux/i2o-dev.h                                         conflict!
-'i'   0B-1F  linux/ipmi.h                                            conflict!
-'i'   80-8F  linux/i8k.h
-'j'   00-3F  linux/joystick.h
-'k'   00-0F  linux/spi/spidev.h                                      conflict!
-'k'   00-05  video/kyro.h                                            conflict!
-'k'   10-17  linux/hsi/hsi_char.h                                    HSI character device
-'l'   00-3F  linux/tcfs_fs.h                                         transparent cryptographic file system
-                                                                     <http://web.archive.org/web/%2A/http://mikonos.dia.unisa.it/tcfs>
-'l'   40-7F  linux/udf_fs_i.h                                        in development:
-                                                                     <http://sourceforge.net/projects/linux-udf/>
-'m'   00-09  linux/mmtimer.h                                         conflict!
-'m'   all    linux/mtio.h                                            conflict!
-'m'   all    linux/soundcard.h                                       conflict!
-'m'   all    linux/synclink.h                                        conflict!
-'m'   00-19  drivers/message/fusion/mptctl.h                         conflict!
-'m'   00     drivers/scsi/megaraid/megaraid_ioctl.h                  conflict!
-'n'   00-7F  linux/ncp_fs.h and fs/ncpfs/ioctl.c
-'n'   80-8F  uapi/linux/nilfs2_api.h                                 NILFS2
-'n'   E0-FF  linux/matroxfb.h                                        matroxfb
-'o'   00-1F  fs/ocfs2/ocfs2_fs.h                                     OCFS2
-'o'   00-03  mtd/ubi-user.h                                          conflict! (OCFS2 and UBI overlaps)
-'o'   40-41  mtd/ubi-user.h                                          UBI
-'o'   01-A1  `linux/dvb/*.h`                                         DVB
-'p'   00-0F  linux/phantom.h                                         conflict! (OpenHaptics needs this)
-'p'   00-1F  linux/rtc.h                                             conflict!
-'p'   00-3F  linux/mc146818rtc.h                                     conflict!
-'p'   40-7F  linux/nvram.h
-'p'   80-9F  linux/ppdev.h                                           user-space parport
-                                                                     <mailto:tim@cyberelk.net>
-'p'   A1-A5  linux/pps.h                                             LinuxPPS
-                                                                     <mailto:giometti@linux.it>
-'q'   00-1F  linux/serio.h
-'q'   80-FF  linux/telephony.h                                       Internet PhoneJACK, Internet LineJACK
-             linux/ixjuser.h                                         <http://web.archive.org/web/%2A/http://www.quicknet.net>
-'r'   00-1F  linux/msdos_fs.h and fs/fat/dir.c
-'s'   all    linux/cdk.h
-'t'   00-7F  linux/ppp-ioctl.h
-'t'   80-8F  linux/isdn_ppp.h
-'t'   90-91  linux/toshiba.h                                         toshiba and toshiba_acpi SMM
-'u'   00-1F  linux/smb_fs.h                                          gone
-'u'   20-3F  linux/uvcvideo.h                                        USB video class host driver
-'u'   40-4f  linux/udmabuf.h                                         userspace dma-buf misc device
-'v'   00-1F  linux/ext2_fs.h                                         conflict!
-'v'   00-1F  linux/fs.h                                              conflict!
-'v'   00-0F  linux/sonypi.h                                          conflict!
-'v'   00-0F  media/v4l2-subdev.h                                     conflict!
-'v'   C0-FF  linux/meye.h                                            conflict!
-'w'   all                                                            CERN SCI driver
-'y'   00-1F                                                          packet based user level communications
-                                                                     <mailto:zapman@interlan.net>
-'z'   00-3F                                                          CAN bus card conflict!
-                                                                     <mailto:hdstich@connectu.ulm.circular.de>
-'z'   40-7F                                                          CAN bus card conflict!
-                                                                     <mailto:oe@port.de>
-'z'   10-4F  drivers/s390/crypto/zcrypt_api.h                        conflict!
-'|'   00-7F  linux/media.h
-0x80  00-1F  linux/fb.h
-0x89  00-06  arch/x86/include/asm/sockios.h
-0x89  0B-DF  linux/sockios.h
-0x89  E0-EF  linux/sockios.h                                         SIOCPROTOPRIVATE range
-0x89  E0-EF  linux/dn.h                                              PROTOPRIVATE range
-0x89  F0-FF  linux/sockios.h                                         SIOCDEVPRIVATE range
-0x8B  all    linux/wireless.h
-0x8C  00-3F                                                          WiNRADiO driver
-                                                                     <http://www.winradio.com.au/>
-0x90  00     drivers/cdrom/sbpcd.h
-0x92  00-0F  drivers/usb/mon/mon_bin.c
-0x93  60-7F  linux/auto_fs.h
-0x94  all    fs/btrfs/ioctl.h                                        Btrfs filesystem
-             and linux/fs.h                                          some lifted to vfs/generic
-0x97  00-7F  fs/ceph/ioctl.h                                         Ceph file system
-0x99  00-0F                                                          537-Addinboard driver
-                                                                     <mailto:buk@buks.ipn.de>
-0xA0  all    linux/sdp/sdp.h                                         Industrial Device Project
-                                                                     <mailto:kenji@bitgate.com>
-0xA1  0      linux/vtpm_proxy.h                                      TPM Emulator Proxy Driver
-0xA3  80-8F                                                          Port ACL  in development:
-                                                                     <mailto:tlewis@mindspring.com>
-0xA3  90-9F  linux/dtlk.h
-0xA4  00-1F  uapi/linux/tee.h                                        Generic TEE subsystem
-0xAA  00-3F  linux/uapi/linux/userfaultfd.h
-0xAB  00-1F  linux/nbd.h
-0xAC  00-1F  linux/raw.h
-0xAD  00                                                             Netfilter device in development:
-                                                                     <mailto:rusty@rustcorp.com.au>
-0xAE  all    linux/kvm.h                                             Kernel-based Virtual Machine
-                                                                     <mailto:kvm@vger.kernel.org>
-0xAF  00-1F  linux/fsl_hypervisor.h                                  Freescale hypervisor
-0xB0  all                                                            RATIO devices in development:
-                                                                     <mailto:vgo@ratio.de>
-0xB1  00-1F                                                          PPPoX
-                                                                     <mailto:mostrows@styx.uwaterloo.ca>
-0xB3  00     linux/mmc/ioctl.h
-0xB4  00-0F  linux/gpio.h                                            <mailto:linux-gpio@vger.kernel.org>
-0xB5  00-0F  uapi/linux/rpmsg.h                                      <mailto:linux-remoteproc@vger.kernel.org>
-0xB6  all    linux/fpga-dfl.h
-0xC0  00-0F  linux/usb/iowarrior.h
-0xCA  00-0F  uapi/misc/cxl.h
-0xCA  10-2F  uapi/misc/ocxl.h
-0xCA  80-BF  uapi/scsi/cxlflash_ioctl.h
-0xCB  00-1F                                                          CBM serial IEC bus in development:
-                                                                     <mailto:michael.klein@puffin.lb.shuttle.de>
-0xCC  00-0F  drivers/misc/ibmvmc.h                                   pseries VMC driver
-0xCD  01     linux/reiserfs_fs.h
-0xCF  02     fs/cifs/ioctl.c
-0xDB  00-0F  drivers/char/mwave/mwavepub.h
-0xDD  00-3F                                                          ZFCP device driver see drivers/s390/scsi/
-                                                                     <mailto:aherrman@de.ibm.com>
-0xE5  00-3F  linux/fuse.h
-0xEC  00-01  drivers/platform/chrome/cros_ec_dev.h                   ChromeOS EC driver
-0xF3  00-3F  drivers/usb/misc/sisusbvga/sisusb.h                     sisfb (in development)
-                                                                     <mailto:thomas@winischhofer.net>
-0xF4  00-1F  video/mbxfb.h                                           mbxfb
-                                                                     <mailto:raph@8d.com>
-0xF6  all                                                            LTTng Linux Trace Toolkit Next Generation
-                                                                     <mailto:mathieu.desnoyers@efficios.com>
-0xFD  all    linux/dm-ioctl.h
-0xFE  all    linux/isst_if.h
-====  =====  ======================================================= ================================================================
index b89c881..b9b5055 100644 (file)
@@ -1115,23 +1115,6 @@ When kbuild executes, the following steps are followed (roughly):
        In this example, extra-y is used to list object files that
        shall be built, but shall not be linked as part of built-in.a.
 
-    header-test-y
-
-       header-test-y specifies headers (`*.h`) in the current directory that
-       should be compile tested to ensure they are self-contained,
-       i.e. compilable as standalone units. If CONFIG_HEADER_TEST is enabled,
-       this builds them as part of extra-y.
-
-    header-test-pattern-y
-
-       This works as a weaker version of header-test-y, and accepts wildcard
-       patterns. The typical usage is::
-
-               header-test-pattern-y += *.h
-
-       This specifies all the files that matches to `*.h` in the current
-       directory, but the files in 'header-test-' are excluded.
-
 6.7 Commands useful for building a boot image
 ---------------------------------------------
 
index 774a998..69fa48e 100644 (file)
@@ -492,11 +492,8 @@ build.
        to the symbols from the kernel to check if all external symbols
        are defined. This is done in the MODPOST step. modpost obtains
        the symbols by reading Module.symvers from the kernel source
-       tree. If a Module.symvers file is present in the directory
-       where the external module is being built, this file will be
-       read too. During the MODPOST step, a new Module.symvers file
-       will be written containing all exported symbols that were not
-       defined in the kernel.
+       tree. During the MODPOST step, a new Module.symvers file will be
+       written containing all exported symbols from that external module.
 
 6.3 Symbols From Another External Module
 ----------------------------------------
@@ -504,7 +501,7 @@ build.
        Sometimes, an external module uses exported symbols from
        another external module. Kbuild needs to have full knowledge of
        all symbols to avoid spitting out warnings about undefined
-       symbols. Three solutions exist for this situation.
+       symbols. Two solutions exist for this situation.
 
        NOTE: The method with a top-level kbuild file is recommended
        but may be impractical in certain situations.
@@ -544,8 +541,8 @@ build.
                all symbols defined and not part of the kernel.
 
        Use "make" variable KBUILD_EXTRA_SYMBOLS
-               If it is impractical to copy Module.symvers from
-               another module, you can assign a space separated list
+               If it is impractical to add a top-level kbuild file,
+               you can assign a space separated list
                of files to KBUILD_EXTRA_SYMBOLS in your build file.
                These files will be loaded by modpost during the
                initialization of its symbol tables.
index 78bbbb0..80ae503 100644 (file)
@@ -32,3 +32,33 @@ You may also like to tell ``gpg`` which ``tty`` to use (add to your shell rc fil
 ::
 
        export GPG_TTY=$(tty)
+
+
+Creating commit links to lore.kernel.org
+----------------------------------------
+
+The web site http://lore.kernel.org is meant as a grand archive of all mail
+list traffic concerning or influencing the kernel development. Storing archives
+of patches here is a recommended practice, and when a maintainer applies a
+patch to a subsystem tree, it is a good idea to provide a Link: tag with a
+reference back to the lore archive so that people that browse the commit
+history can find related discussions and rationale behind a certain change.
+The link tag will look like this:
+
+    Link: https://lore.kernel.org/r/<message-id>
+
+This can be configured to happen automatically any time you issue ``git am``
+by adding the following hook into your git:
+
+.. code-block:: none
+
+       $ git config am.messageid true
+       $ cat >.git/hooks/applypatch-msg <<'EOF'
+       #!/bin/sh
+       . git-sh-setup
+       perl -pi -e 's|^Message-Id:\s*<?([^>]+)>?$|Link: https://lore.kernel.org/r/$1|g;' "$1"
+       test -x "$GIT_DIR/hooks/commit-msg" &&
+               exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+       :
+       EOF
+       $ chmod a+x .git/hooks/applypatch-msg
index 56e2c09..d904e74 100644 (file)
@@ -12,4 +12,5 @@ additions to this manual.
    configure-git
    rebasing-and-merging
    pull-requests
+   maintainer-entry-profile
 
diff --git a/Documentation/maintainer/maintainer-entry-profile.rst b/Documentation/maintainer/maintainer-entry-profile.rst
new file mode 100644 (file)
index 0000000..3eaddc8
--- /dev/null
@@ -0,0 +1,102 @@
+.. _maintainerentryprofile:
+
+Maintainer Entry Profile
+========================
+
+The Maintainer Entry Profile supplements the top-level process documents
+(submitting-patches, submitting drivers...) with
+subsystem/device-driver-local customs as well as details about the patch
+submission life-cycle. A contributor uses this document to level set
+their expectations and avoid common mistakes, maintainers may use these
+profiles to look across subsystems for opportunities to converge on
+common practices.
+
+
+Overview
+--------
+Provide an introduction to how the subsystem operates. While MAINTAINERS
+tells the contributor where to send patches for which files, it does not
+convey other subsystem-local infrastructure and mechanisms that aid
+development.
+
+Example questions to consider:
+
+- Are there notifications when patches are applied to the local tree, or
+  merged upstream?
+- Does the subsystem have a patchwork instance? Are patchwork state
+  changes notified?
+- Any bots or CI infrastructure that watches the list, or automated
+  testing feedback that the subsystem gates acceptance?
+- Git branches that are pulled into -next?
+- What branch should contributors submit against?
+- Links to any other Maintainer Entry Profiles? For example a
+  device-driver may point to an entry for its parent subsystem. This makes
+  the contributor aware of obligations a maintainer may have have for
+  other maintainers in the submission chain.
+
+
+Submit Checklist Addendum
+-------------------------
+List mandatory and advisory criteria, beyond the common "submit-checklist",
+for a patch to be considered healthy enough for maintainer attention.
+For example: "pass checkpatch.pl with no errors, or warning. Pass the
+unit test detailed at $URI".
+
+The Submit Checklist Addendum can also include details about the status
+of related hardware specifications. For example, does the subsystem
+require published specifications at a certain revision before patches
+will be considered.
+
+
+Key Cycle Dates
+---------------
+One of the common misunderstandings of submitters is that patches can be
+sent at any time before the merge window closes and can still be
+considered for the next -rc1. The reality is that most patches need to
+be settled in soaking in linux-next in advance of the merge window
+opening. Clarify for the submitter the key dates (in terms rc release
+week) that patches might considered for merging and when patches need to
+wait for the next -rc. At a minimum:
+
+- Last -rc for new feature submissions:
+  New feature submissions targeting the next merge window should have
+  their first posting for consideration before this point. Patches that
+  are submitted after this point should be clear that they are targeting
+  the NEXT+1 merge window, or should come with sufficient justification
+  why they should be considered on an expedited schedule. A general
+  guideline is to set expectation with contributors that new feature
+  submissions should appear before -rc5.
+
+- Last -rc to merge features: Deadline for merge decisions
+  Indicate to contributors the point at which an as yet un-applied patch
+  set will need to wait for the NEXT+1 merge window. Of course there is no
+  obligation to ever except any given patchset, but if the review has not
+  concluded by this point the expectation the contributor should wait and
+  resubmit for the following merge window.
+
+Optional:
+
+- First -rc at which the development baseline branch, listed in the
+  overview section, should be considered ready for new submissions.
+
+
+Review Cadence
+--------------
+One of the largest sources of contributor angst is how soon to ping
+after a patchset has been posted without receiving any feedback. In
+addition to specifying how long to wait before a resubmission this
+section can also indicate a preferred style of update like, resend the
+full series, or privately send a reminder email. This section might also
+list how review works for this code area and methods to get feedback
+that are not directly from the maintainer.
+
+Existing profiles
+-----------------
+
+For now, existing maintainer profiles are listed here; we will likely want
+to do something different in the near future.
+
+.. toctree::
+   :maxdepth: 1
+
+   ../nvdimm/maintainer-entry-profile
index 1adbb8a..ec3b586 100644 (file)
@@ -63,7 +63,6 @@ CONTENTS
 
      - Compiler barrier.
      - CPU memory barriers.
-     - MMIO write barrier.
 
  (*) Implicit kernel memory barriers.
 
@@ -75,7 +74,6 @@ CONTENTS
  (*) Inter-CPU acquiring barrier effects.
 
      - Acquires vs memory accesses.
-     - Acquires vs I/O accesses.
 
  (*) Where are memory barriers needed?
 
@@ -492,10 +490,9 @@ And a couple of implicit varieties:
      happen before it completes.
 
      The use of ACQUIRE and RELEASE operations generally precludes the need
-     for other sorts of memory barrier (but note the exceptions mentioned in
-     the subsection "MMIO write barrier").  In addition, a RELEASE+ACQUIRE
-     pair is -not- guaranteed to act as a full memory barrier.  However, after
-     an ACQUIRE on a given variable, all memory accesses preceding any prior
+     for other sorts of memory barrier.  In addition, a RELEASE+ACQUIRE pair is
+     -not- guaranteed to act as a full memory barrier.  However, after an
+     ACQUIRE on a given variable, all memory accesses preceding any prior
      RELEASE on that same variable are guaranteed to be visible.  In other
      words, within a given variable's critical section, all accesses of all
      previous critical sections for that variable are guaranteed to have
@@ -1512,8 +1509,6 @@ levels:
 
   (*) CPU memory barriers.
 
-  (*) MMIO write barrier.
-
 
 COMPILER BARRIER
 ----------------
index c4ef4c4..c5a646b 100644 (file)
@@ -68,4 +68,4 @@ and frameworks can be controlled from the same registers, all of these
 drivers access their registers through the same regmap.
 
 For more information regarding the devicetree bindings of the TCU drivers,
-have a look at Documentation/devicetree/bindings/mfd/ingenic,tcu.txt.
+have a look at Documentation/devicetree/bindings/timer/ingenic,tcu.txt.
diff --git a/Documentation/misc-devices/xilinx_sdfec.rst b/Documentation/misc-devices/xilinx_sdfec.rst
new file mode 100644 (file)
index 0000000..2245fcf
--- /dev/null
@@ -0,0 +1,291 @@
+.. SPDX-License-Identifier: GPL-2.0+
+====================
+Xilinx SD-FEC Driver
+====================
+
+Overview
+========
+
+This driver supports SD-FEC Integrated Block for Zynq |Ultrascale+ (TM)| RFSoCs.
+
+.. |Ultrascale+ (TM)| unicode:: Ultrascale+ U+2122
+   .. with trademark sign
+
+For a full description of SD-FEC core features, see the `SD-FEC Product Guide (PG256) <https://www.xilinx.com/cgi-bin/docs/ipdoc?c=sd_fec;v=latest;d=pg256-sdfec-integrated-block.pdf>`_
+
+This driver supports the following features:
+
+  - Retrieval of the Integrated Block configuration and status information
+  - Configuration of LDPC codes
+  - Configuration of Turbo decoding
+  - Monitoring errors
+
+Missing features, known issues, and limitations of the SD-FEC driver are as
+follows:
+
+  - Only allows a single open file handler to any instance of the driver at any time
+  - Reset of the SD-FEC Integrated Block is not controlled by this driver
+  - Does not support shared LDPC code table wraparound
+
+The device tree entry is described in:
+`linux-xlnx/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt <https://github.com/Xilinx/linux-xlnx/blob/master/Documentation/devicetree/bindings/misc/xlnx%2Csd-fec.txt>`_
+
+
+Modes of Operation
+------------------
+
+The driver works with the SD-FEC core in two modes of operation:
+
+  - Run-time configuration
+  - Programmable Logic (PL) initialization
+
+
+Run-time Configuration
+~~~~~~~~~~~~~~~~~~~~~~
+
+For Run-time configuration the role of driver is to allow the software application to do the following:
+
+       - Load the configuration parameters for either Turbo decode or LDPC encode or decode
+       - Activate the SD-FEC core
+       - Monitor the SD-FEC core for errors
+       - Retrieve the status and configuration of the SD-FEC core
+
+Programmable Logic (PL) Initialization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For PL initialization, supporting logic loads configuration parameters for either
+the Turbo decode or LDPC encode or decode.  The role of the driver is to allow
+the software application to do the following:
+
+       - Activate the SD-FEC core
+       - Monitor the SD-FEC core for errors
+       - Retrieve the status and configuration of the SD-FEC core
+
+
+Driver Structure
+================
+
+The driver provides a platform device where the ``probe`` and ``remove``
+operations are provided.
+
+  - probe: Updates configuration register with device-tree entries plus determines the current activate state of the core, for example, is the core bypassed or has the core been started.
+
+
+The driver defines the following driver file operations to provide user
+application interfaces:
+
+  - open: Implements restriction that only a single file descriptor can be open per SD-FEC instance at any time
+  - release: Allows another file descriptor to be open, that is after current file descriptor is closed
+  - poll: Provides a method to monitor for SD-FEC Error events
+  - unlocked_ioctl: Provides the the following ioctl commands that allows the application configure the SD-FEC core:
+
+               - :c:macro:`XSDFEC_START_DEV`
+               - :c:macro:`XSDFEC_STOP_DEV`
+               - :c:macro:`XSDFEC_GET_STATUS`
+               - :c:macro:`XSDFEC_SET_IRQ`
+               - :c:macro:`XSDFEC_SET_TURBO`
+               - :c:macro:`XSDFEC_ADD_LDPC_CODE_PARAMS`
+               - :c:macro:`XSDFEC_GET_CONFIG`
+               - :c:macro:`XSDFEC_SET_ORDER`
+               - :c:macro:`XSDFEC_SET_BYPASS`
+               - :c:macro:`XSDFEC_IS_ACTIVE`
+               - :c:macro:`XSDFEC_CLEAR_STATS`
+               - :c:macro:`XSDFEC_SET_DEFAULT_CONFIG`
+
+
+Driver Usage
+============
+
+
+Overview
+--------
+
+After opening the driver, the user should find out what operations need to be
+performed to configure and activate the SD-FEC core and determine the
+configuration of the driver.
+The following outlines the flow the user should perform:
+
+  - Determine Configuration
+  - Set the order, if not already configured as desired
+  - Set Turbo decode, LPDC encode or decode parameters, depending on how the
+    SD-FEC core is configured plus if the SD-FEC has not been configured for PL
+    initialization
+  - Enable interrupts, if not already enabled
+  - Bypass the SD-FEC core, if required
+  - Start the SD-FEC core if not already started
+  - Get the SD-FEC core status
+  - Monitor for interrupts
+  - Stop the SD-FEC core
+
+
+Note: When monitoring for interrupts if a critical error is detected where a reset is required, the driver will be required to load the default configuration.
+
+
+Determine Configuration
+-----------------------
+
+Determine the configuration of the SD-FEC core by using the ioctl
+:c:macro:`XSDFEC_GET_CONFIG`.
+
+Set the Order
+-------------
+
+Setting the order determines how the order of Blocks can change from input to output.
+
+Setting the order is done by using the ioctl :c:macro:`XSDFEC_SET_ORDER`
+
+Setting the order can only be done if the following restrictions are met:
+
+       - The ``state`` member of struct :c:type:`xsdfec_status <xsdfec_status>` filled by the ioctl :c:macro:`XSDFEC_GET_STATUS` indicates the SD-FEC core has not STARTED
+
+
+Add LDPC Codes
+--------------
+
+The following steps indicate how to add LDPC codes to the SD-FEC core:
+
+       - Use the auto-generated parameters to fill the :c:type:`struct xsdfec_ldpc_params <xsdfec_ldpc_params>` for the desired LDPC code.
+       - Set the SC, QA, and LA table offsets for the LPDC parameters and the parameters in the structure :c:type:`struct xsdfec_ldpc_params <xsdfec_ldpc_params>`
+       - Set the desired Code Id value in the structure :c:type:`struct xsdfec_ldpc_params <xsdfec_ldpc_params>`
+       - Add the LPDC Code Parameters using the ioctl :c:macro:`XSDFEC_ADD_LDPC_CODE_PARAMS`
+       - For the applied LPDC Code Parameter use the function :c:func:`xsdfec_calculate_shared_ldpc_table_entry_size` to calculate the size of shared LPDC code tables. This allows the user to determine the shared table usage so when selecting the table offsets for the next LDPC code parameters unused table areas can be selected.
+       - Repeat for each LDPC code parameter.
+
+Adding LDPC codes can only be done if the following restrictions are met:
+
+       - The ``code`` member of :c:type:`struct xsdfec_config <xsdfec_config>` filled by the ioctl :c:macro:`XSDFEC_GET_CONFIG` indicates the SD-FEC core is configured as LDPC
+       - The ``code_wr_protect`` of :c:type:`struct xsdfec_config <xsdfec_config>` filled by the ioctl :c:macro:`XSDFEC_GET_CONFIG` indicates that write protection is not enabled
+       - The ``state`` member of struct :c:type:`xsdfec_status <xsdfec_status>` filled by the ioctl :c:macro:`XSDFEC_GET_STATUS` indicates the SD-FEC core has not started
+
+Set Turbo Decode
+----------------
+
+Configuring the Turbo decode parameters is done by using the ioctl :c:macro:`XSDFEC_SET_TURBO` using auto-generated parameters to fill the :c:type:`struct xsdfec_turbo <xsdfec_turbo>` for the desired Turbo code.
+
+Adding Turbo decode can only be done if the following restrictions are met:
+
+       - The ``code`` member of :c:type:`struct xsdfec_config <xsdfec_config>` filled by the ioctl :c:macro:`XSDFEC_GET_CONFIG` indicates the SD-FEC core is configured as TURBO
+       - The ``state`` member of struct :c:type:`xsdfec_status <xsdfec_status>` filled by the ioctl :c:macro:`XSDFEC_GET_STATUS` indicates the SD-FEC core has not STARTED
+
+Enable Interrupts
+-----------------
+
+Enabling or disabling interrupts is done by using the ioctl :c:macro:`XSDFEC_SET_IRQ`. The members of the parameter passed, :c:type:`struct xsdfec_irq <xsdfec_irq>`, to the ioctl are used to set and clear different categories of interrupts. The category of interrupt is controlled as following:
+
+  - ``enable_isr`` controls the ``tlast`` interrupts
+  - ``enable_ecc_isr`` controls the ECC interrupts
+
+If the ``code`` member of :c:type:`struct xsdfec_config <xsdfec_config>` filled by the ioctl :c:macro:`XSDFEC_GET_CONFIG` indicates the SD-FEC core is configured as TURBO then the enabling ECC errors is not required.
+
+Bypass the SD-FEC
+-----------------
+
+Bypassing the SD-FEC is done by using the ioctl :c:macro:`XSDFEC_SET_BYPASS`
+
+Bypassing the SD-FEC can only be done if the following restrictions are met:
+
+       - The ``state`` member of :c:type:`struct xsdfec_status <xsdfec_status>` filled by the ioctl :c:macro:`XSDFEC_GET_STATUS` indicates the SD-FEC core has not STARTED
+
+Start the SD-FEC core
+---------------------
+
+Start the SD-FEC core by using the ioctl :c:macro:`XSDFEC_START_DEV`
+
+Get SD-FEC Status
+-----------------
+
+Get the SD-FEC status of the device by using the ioctl :c:macro:`XSDFEC_GET_STATUS`, which will fill the :c:type:`struct xsdfec_status <xsdfec_status>`
+
+Monitor for Interrupts
+----------------------
+
+       - Use the poll system call to monitor for an interrupt. The poll system call waits for an interrupt to wake it up or times out if no interrupt occurs.
+       - On return Poll ``revents`` will indicate whether stats and/or state have been updated
+               - ``POLLPRI`` indicates a critical error and the user should use :c:macro:`XSDFEC_GET_STATUS` and :c:macro:`XSDFEC_GET_STATS` to confirm
+               - ``POLLRDNORM`` indicates a non-critical error has occurred and the user should use  :c:macro:`XSDFEC_GET_STATS` to confirm
+       - Get stats by using the ioctl :c:macro:`XSDFEC_GET_STATS`
+               - For critical error the ``isr_err_count`` or ``uecc_count`` member  of :c:type:`struct xsdfec_stats <xsdfec_stats>` is non-zero
+               - For non-critical errors the ``cecc_count`` member of :c:type:`struct xsdfec_stats <xsdfec_stats>` is non-zero
+       - Get state by using the ioctl :c:macro:`XSDFEC_GET_STATUS`
+               - For a critical error the ``state`` of :c:type:`xsdfec_status <xsdfec_status>` will indicate a Reset Is Required
+       - Clear stats by using the ioctl :c:macro:`XSDFEC_CLEAR_STATS`
+
+If a critical error is detected where a reset is required. The application is required to call the ioctl :c:macro:`XSDFEC_SET_DEFAULT_CONFIG`, after the reset and it is not required to call the ioctl :c:macro:`XSDFEC_STOP_DEV`
+
+Note: Using poll system call prevents busy looping using :c:macro:`XSDFEC_GET_STATS` and :c:macro:`XSDFEC_GET_STATUS`
+
+Stop the SD-FEC Core
+---------------------
+
+Stop the device by using the ioctl :c:macro:`XSDFEC_STOP_DEV`
+
+Set the Default Configuration
+-----------------------------
+
+Load default configuration by using the ioctl :c:macro:`XSDFEC_SET_DEFAULT_CONFIG` to restore the driver.
+
+Limitations
+-----------
+
+Users should not duplicate SD-FEC device file handlers, for example fork() or dup() a process that has a created an SD-FEC file handler.
+
+Driver IOCTLs
+==============
+
+.. c:macro:: XSDFEC_START_DEV
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_START_DEV
+
+.. c:macro:: XSDFEC_STOP_DEV
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_STOP_DEV
+
+.. c:macro:: XSDFEC_GET_STATUS
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_GET_STATUS
+
+.. c:macro:: XSDFEC_SET_IRQ
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_SET_IRQ
+
+.. c:macro:: XSDFEC_SET_TURBO
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_SET_TURBO
+
+.. c:macro:: XSDFEC_ADD_LDPC_CODE_PARAMS
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_ADD_LDPC_CODE_PARAMS
+
+.. c:macro:: XSDFEC_GET_CONFIG
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_GET_CONFIG
+
+.. c:macro:: XSDFEC_SET_ORDER
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_SET_ORDER
+
+.. c:macro:: XSDFEC_SET_BYPASS
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_SET_BYPASS
+
+.. c:macro:: XSDFEC_IS_ACTIVE
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_IS_ACTIVE
+
+.. c:macro:: XSDFEC_CLEAR_STATS
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_CLEAR_STATS
+
+.. c:macro:: XSDFEC_GET_STATS
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_GET_STATS
+
+.. c:macro:: XSDFEC_SET_DEFAULT_CONFIG
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :doc: XSDFEC_SET_DEFAULT_CONFIG
+
+Driver Type Definitions
+=======================
+
+.. kernel-doc:: include/uapi/misc/xilinx_sdfec.h
+   :internal:
index 7599dce..f575a49 100644 (file)
@@ -279,7 +279,7 @@ mlx5 tracepoints
 ================
 
 mlx5 driver provides internal trace points for tracking and debugging using
-kernel tracepoints interfaces (refer to Documentation/trace/ftrase.rst).
+kernel tracepoints interfaces (refer to Documentation/trace/ftrace.rst).
 
 For the list of support mlx5 events check /sys/kernel/debug/tracing/events/mlx5/
 
index dc9659c..0331184 100644 (file)
@@ -233,7 +233,7 @@ help debug packet drops caused by these exceptions. The following list includes
 links to the description of driver-specific traps registered by various device
 drivers:
 
-  * :doc:`/devlink-trap-netdevsim`
+  * :doc:`devlink-trap-netdevsim`
 
 Generic Packet Trap Groups
 ==========================
index cda1c0a..e0a7c7a 100644 (file)
@@ -73,7 +73,7 @@ The Reduced Gigabit Medium Independent Interface (RGMII) is a 12-pin
 electrical signal interface using a synchronous 125Mhz clock signal and several
 data lines. Due to this design decision, a 1.5ns to 2ns delay must be added
 between the clock line (RXC or TXC) and the data lines to let the PHY (clock
-sink) have enough setup and hold times to sample the data lines correctly. The
+sink) have a large enough setup and hold time to sample the data lines correctly. The
 PHY library offers different types of PHY_INTERFACE_MODE_RGMII* values to let
 the PHY driver and optionally the MAC driver, implement the required delay. The
 values of phy_interface_t must be understood from the perspective of the PHY
diff --git a/Documentation/nvdimm/maintainer-entry-profile.rst b/Documentation/nvdimm/maintainer-entry-profile.rst
new file mode 100644 (file)
index 0000000..77081fd
--- /dev/null
@@ -0,0 +1,59 @@
+LIBNVDIMM Maintainer Entry Profile
+==================================
+
+Overview
+--------
+The libnvdimm subsystem manages persistent memory across multiple
+architectures. The mailing list, is tracked by patchwork here:
+https://patchwork.kernel.org/project/linux-nvdimm/list/
+...and that instance is configured to give feedback to submitters on
+patch acceptance and upstream merge. Patches are merged to either the
+'libnvdimm-fixes', or 'libnvdimm-for-next' branch. Those branches are
+available here:
+https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git/
+
+In general patches can be submitted against the latest -rc, however if
+the incoming code change is dependent on other pending changes then the
+patch should be based on the libnvdimm-for-next branch. However, since
+persistent memory sits at the intersection of storage and memory there
+are cases where patches are more suitable to be merged through a
+Filesystem or the Memory Management tree. When in doubt copy the nvdimm
+list and the maintainers will help route.
+
+Submissions will be exposed to the kbuild robot for compile regression
+testing. It helps to get a success notification from that infrastructure
+before submitting, but it is not required.
+
+
+Submit Checklist Addendum
+-------------------------
+There are unit tests for the subsystem via the ndctl utility:
+https://github.com/pmem/ndctl
+Those tests need to be passed before the patches go upstream, but not
+necessarily before initial posting. Contact the list if you need help
+getting the test environment set up.
+
+### ACPI Device Specific Methods (_DSM)
+Before patches enabling for a new _DSM family will be considered it must
+be assigned a format-interface-code from the NVDIMM Sub-team of the ACPI
+Specification Working Group. In general, the stance of the subsystem is
+to push back on the proliferation of NVDIMM command sets, do strongly
+consider implementing support for an existing command set. See
+drivers/acpi/nfit/nfit.h for the set of support command sets.
+
+
+Key Cycle Dates
+---------------
+New submissions can be sent at any time, but if they intend to hit the
+next merge window they should be sent before -rc4, and ideally
+stabilized in the libnvdimm-for-next branch by -rc6. Of course if a
+patch set requires more than 2 weeks of review -rc4 is already too late
+and some patches may require multiple development cycles to review.
+
+
+Review Cadence
+--------------
+In general, please wait up to one week before pinging for feedback. A
+private mail reminder is preferred. Alternatively ask for other
+developers that have Reviewed-by tags for libnvdimm changes to take a
+look and offer their opinion.
index 51e0a49..0924d29 100644 (file)
@@ -130,8 +130,8 @@ a full power-on reset sequence and the power-on defaults are restored to the
 device by hardware just as at initial power up.
 
 PCI devices supporting the PCI PM Spec can be programmed to generate PMEs
-while in a low-power state (D1-D3), but they are not required to be capable
-of generating PMEs from all supported low-power states.  In particular, the
+while in any power state (D0-D3), but they are not required to be capable
+of generating PMEs from all supported power states.  In particular, the
 capability of generating PMEs from D3cold is optional and depends on the
 presence of additional voltage (3.3Vaux) allowing the device to remain
 sufficiently active to generate a wakeup signal.
@@ -600,17 +600,17 @@ using the following PCI bus type's callbacks::
 
 respectively.
 
-The first of them, pci_pm_thaw_noirq(), is analogous to pci_pm_resume_noirq(),
-but it doesn't put the device into the full power state and doesn't attempt to
-restore its standard configuration registers.  It also executes the device
-driver's pm->thaw_noirq() callback, if defined, instead of pm->resume_noirq().
+The first of them, pci_pm_thaw_noirq(), is analogous to pci_pm_resume_noirq().
+It puts the device into the full power state and restores its standard
+configuration registers.  It also executes the device driver's pm->thaw_noirq()
+callback, if defined, instead of pm->resume_noirq().
 
 The pci_pm_thaw() routine is similar to pci_pm_resume(), but it runs the device
 driver's pm->thaw() callback instead of pm->resume().  It is executed
 asynchronously for different PCI devices that don't depend on each other in a
 known way.
 
-The complete phase it the same as for system resume.
+The complete phase is the same as for system resume.
 
 After saving the image, devices need to be powered down before the system can
 enter the target sleep state (ACPI S4 for ACPI-based systems).  This is done in
@@ -692,11 +692,11 @@ controlling the runtime power management of their devices.
 At the time of this writing there are two ways to define power management
 callbacks for a PCI device driver, the recommended one, based on using a
 dev_pm_ops structure described in Documentation/driver-api/pm/devices.rst, and
-the "legacy" one, in which the .suspend(), .suspend_late(), .resume_early(), and
-.resume() callbacks from struct pci_driver are used.  The legacy approach,
-however, doesn't allow one to define runtime power management callbacks and is
-not really suitable for any new drivers.  Therefore it is not covered by this
-document (refer to the source code to learn more about it).
+the "legacy" one, in which the .suspend() and .resume() callbacks from struct
+pci_driver are used.  The legacy approach, however, doesn't allow one to define
+runtime power management callbacks and is not really suitable for any new
+drivers.  Therefore it is not covered by this document (refer to the source code
+to learn more about it).
 
 It is recommended that all PCI device drivers define a struct dev_pm_ops object
 containing pointers to power management (PM) callbacks that will be executed by
diff --git a/Documentation/process/botching-up-ioctls.rst b/Documentation/process/botching-up-ioctls.rst
new file mode 100644 (file)
index 0000000..2d4829b
--- /dev/null
@@ -0,0 +1,225 @@
+=================================
+(How to avoid) Botching up ioctls
+=================================
+
+From: http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
+
+By: Daniel Vetter, Copyright © 2013 Intel Corporation
+
+One clear insight kernel graphics hackers gained in the past few years is that
+trying to come up with a unified interface to manage the execution units and
+memory on completely different GPUs is a futile effort. So nowadays every
+driver has its own set of ioctls to allocate memory and submit work to the GPU.
+Which is nice, since there's no more insanity in the form of fake-generic, but
+actually only used once interfaces. But the clear downside is that there's much
+more potential to screw things up.
+
+To avoid repeating all the same mistakes again I've written up some of the
+lessons learned while botching the job for the drm/i915 driver. Most of these
+only cover technicalities and not the big-picture issues like what the command
+submission ioctl exactly should look like. Learning these lessons is probably
+something every GPU driver has to do on its own.
+
+
+Prerequisites
+-------------
+
+First the prerequisites. Without these you have already failed, because you
+will need to add a 32-bit compat layer:
+
+ * Only use fixed sized integers. To avoid conflicts with typedefs in userspace
+   the kernel has special types like __u32, __s64. Use them.
+
+ * Align everything to the natural size and use explicit padding. 32-bit
+   platforms don't necessarily align 64-bit values to 64-bit boundaries, but
+   64-bit platforms do. So we always need padding to the natural size to get
+   this right.
+
+ * Pad the entire struct to a multiple of 64-bits if the structure contains
+   64-bit types - the structure size will otherwise differ on 32-bit versus
+   64-bit. Having a different structure size hurts when passing arrays of
+   structures to the kernel, or if the kernel checks the structure size, which
+   e.g. the drm core does.
+
+ * Pointers are __u64, cast from/to a uintprt_t on the userspace side and
+   from/to a void __user * in the kernel. Try really hard not to delay this
+   conversion or worse, fiddle the raw __u64 through your code since that
+   diminishes the checking tools like sparse can provide. The macro
+   u64_to_user_ptr can be used in the kernel to avoid warnings about integers
+   and pointers of different sizes.
+
+
+Basics
+------
+
+With the joys of writing a compat layer avoided we can take a look at the basic
+fumbles. Neglecting these will make backward and forward compatibility a real
+pain. And since getting things wrong on the first attempt is guaranteed you
+will have a second iteration or at least an extension for any given interface.
+
+ * Have a clear way for userspace to figure out whether your new ioctl or ioctl
+   extension is supported on a given kernel. If you can't rely on old kernels
+   rejecting the new flags/modes or ioctls (since doing that was botched in the
+   past) then you need a driver feature flag or revision number somewhere.
+
+ * Have a plan for extending ioctls with new flags or new fields at the end of
+   the structure. The drm core checks the passed-in size for each ioctl call
+   and zero-extends any mismatches between kernel and userspace. That helps,
+   but isn't a complete solution since newer userspace on older kernels won't
+   notice that the newly added fields at the end get ignored. So this still
+   needs a new driver feature flags.
+
+ * Check all unused fields and flags and all the padding for whether it's 0,
+   and reject the ioctl if that's not the case. Otherwise your nice plan for
+   future extensions is going right down the gutters since someone will submit
+   an ioctl struct with random stack garbage in the yet unused parts. Which
+   then bakes in the ABI that those fields can never be used for anything else
+   but garbage. This is also the reason why you must explicitly pad all
+   structures, even if you never use them in an array - the padding the compiler
+   might insert could contain garbage.
+
+ * Have simple testcases for all of the above.
+
+
+Fun with Error Paths
+--------------------
+
+Nowadays we don't have any excuse left any more for drm drivers being neat
+little root exploits. This means we both need full input validation and solid
+error handling paths - GPUs will die eventually in the oddmost corner cases
+anyway:
+
+ * The ioctl must check for array overflows. Also it needs to check for
+   over/underflows and clamping issues of integer values in general. The usual
+   example is sprite positioning values fed directly into the hardware with the
+   hardware just having 12 bits or so. Works nicely until some odd display
+   server doesn't bother with clamping itself and the cursor wraps around the
+   screen.
+
+ * Have simple testcases for every input validation failure case in your ioctl.
+   Check that the error code matches your expectations. And finally make sure
+   that you only test for one single error path in each subtest by submitting
+   otherwise perfectly valid data. Without this an earlier check might reject
+   the ioctl already and shadow the codepath you actually want to test, hiding
+   bugs and regressions.
+
+ * Make all your ioctls restartable. First X really loves signals and second
+   this will allow you to test 90% of all error handling paths by just
+   interrupting your main test suite constantly with signals. Thanks to X's
+   love for signal you'll get an excellent base coverage of all your error
+   paths pretty much for free for graphics drivers. Also, be consistent with
+   how you handle ioctl restarting - e.g. drm has a tiny drmIoctl helper in its
+   userspace library. The i915 driver botched this with the set_tiling ioctl,
+   now we're stuck forever with some arcane semantics in both the kernel and
+   userspace.
+
+ * If you can't make a given codepath restartable make a stuck task at least
+   killable. GPUs just die and your users won't like you more if you hang their
+   entire box (by means of an unkillable X process). If the state recovery is
+   still too tricky have a timeout or hangcheck safety net as a last-ditch
+   effort in case the hardware has gone bananas.
+
+ * Have testcases for the really tricky corner cases in your error recovery code
+   - it's way too easy to create a deadlock between your hangcheck code and
+   waiters.
+
+
+Time, Waiting and Missing it
+----------------------------
+
+GPUs do most everything asynchronously, so we have a need to time operations and
+wait for outstanding ones. This is really tricky business; at the moment none of
+the ioctls supported by the drm/i915 get this fully right, which means there's
+still tons more lessons to learn here.
+
+ * Use CLOCK_MONOTONIC as your reference time, always. It's what alsa, drm and
+   v4l use by default nowadays. But let userspace know which timestamps are
+   derived from different clock domains like your main system clock (provided
+   by the kernel) or some independent hardware counter somewhere else. Clocks
+   will mismatch if you look close enough, but if performance measuring tools
+   have this information they can at least compensate. If your userspace can
+   get at the raw values of some clocks (e.g. through in-command-stream
+   performance counter sampling instructions) consider exposing those also.
+
+ * Use __s64 seconds plus __u64 nanoseconds to specify time. It's not the most
+   convenient time specification, but it's mostly the standard.
+
+ * Check that input time values are normalized and reject them if not. Note
+   that the kernel native struct ktime has a signed integer for both seconds
+   and nanoseconds, so beware here.
+
+ * For timeouts, use absolute times. If you're a good fellow and made your
+   ioctl restartable relative timeouts tend to be too coarse and can
+   indefinitely extend your wait time due to rounding on each restart.
+   Especially if your reference clock is something really slow like the display
+   frame counter. With a spec lawyer hat on this isn't a bug since timeouts can
+   always be extended - but users will surely hate you if their neat animations
+   starts to stutter due to this.
+
+ * Consider ditching any synchronous wait ioctls with timeouts and just deliver
+   an asynchronous event on a pollable file descriptor. It fits much better
+   into event driven applications' main loop.
+
+ * Have testcases for corner-cases, especially whether the return values for
+   already-completed events, successful waits and timed-out waits are all sane
+   and suiting to your needs.
+
+
+Leaking Resources, Not
+----------------------
+
+A full-blown drm driver essentially implements a little OS, but specialized to
+the given GPU platforms. This means a driver needs to expose tons of handles
+for different objects and other resources to userspace. Doing that right
+entails its own little set of pitfalls:
+
+ * Always attach the lifetime of your dynamically created resources to the
+   lifetime of a file descriptor. Consider using a 1:1 mapping if your resource
+   needs to be shared across processes -  fd-passing over unix domain sockets
+   also simplifies lifetime management for userspace.
+
+ * Always have O_CLOEXEC support.
+
+ * Ensure that you have sufficient insulation between different clients. By
+   default pick a private per-fd namespace which forces any sharing to be done
+   explicitly. Only go with a more global per-device namespace if the objects
+   are truly device-unique. One counterexample in the drm modeset interfaces is
+   that the per-device modeset objects like connectors share a namespace with
+   framebuffer objects, which mostly are not shared at all. A separate
+   namespace, private by default, for framebuffers would have been more
+   suitable.
+
+ * Think about uniqueness requirements for userspace handles. E.g. for most drm
+   drivers it's a userspace bug to submit the same object twice in the same
+   command submission ioctl. But then if objects are shareable userspace needs
+   to know whether it has seen an imported object from a different process
+   already or not. I haven't tried this myself yet due to lack of a new class
+   of objects, but consider using inode numbers on your shared file descriptors
+   as unique identifiers - it's how real files are told apart, too.
+   Unfortunately this requires a full-blown virtual filesystem in the kernel.
+
+
+Last, but not Least
+-------------------
+
+Not every problem needs a new ioctl:
+
+ * Think hard whether you really want a driver-private interface. Of course
+   it's much quicker to push a driver-private interface than engaging in
+   lengthy discussions for a more generic solution. And occasionally doing a
+   private interface to spearhead a new concept is what's required. But in the
+   end, once the generic interface comes around you'll end up maintainer two
+   interfaces. Indefinitely.
+
+ * Consider other interfaces than ioctls. A sysfs attribute is much better for
+   per-device settings, or for child objects with fairly static lifetimes (like
+   output connectors in drm with all the detection override attributes). Or
+   maybe only your testsuite needs this interface, and then debugfs with its
+   disclaimer of not having a stable ABI would be better.
+
+Finally, the name of the game is to get it right on the first attempt, since if
+your driver proves popular and your hardware platforms long-lived then you'll
+be stuck with a given ioctl essentially forever. You can try to deprecate
+horrible ioctls on newer iterations of your hardware, but generally it takes
+years to accomplish this. And then again years until the last user able to
+complain about regressions disappears, too.
index a3c3349..799580a 100644 (file)
@@ -240,7 +240,7 @@ an involved disclosed party. The current ambassadors list:
 
   ============= ========================================================
   ARM
-  AMD
+  AMD          Tom Lendacky <tom.lendacky@amd.com>
   IBM
   Intel                Tony Luck <tony.luck@intel.com>
   Qualcomm     Trilok Soni <tsoni@codeaurora.org>
index e2c9ffc..21aa7d5 100644 (file)
@@ -46,6 +46,7 @@ Other guides to the community that are of interest to most developers are:
    kernel-docs
    deprecated
    embargoed-hardware-issues
+   maintainers
 
 These are some overall technical guides that have been put here for now for
 lack of a better place.
@@ -57,6 +58,7 @@ lack of a better place.
    adding-syscalls
    magic-number
    volatile-considered-harmful
+   botching-up-ioctls
    clang-format
 
 .. only::  subproject and html
index 547bbf2..eee9b44 100644 (file)
@@ -81,7 +81,6 @@ FF_MAGIC              0x4646           fc_info                  ``drivers/net/ip
 ISICOM_MAGIC          0x4d54           isi_port                 ``include/linux/isicom.h``
 PTY_MAGIC             0x5001                                    ``drivers/char/pty.c``
 PPP_MAGIC             0x5002           ppp                      ``include/linux/if_pppvar.h``
-SERIAL_MAGIC          0x5301           async_struct             ``include/linux/serial.h``
 SSTATE_MAGIC          0x5302           serial_state             ``include/linux/serial.h``
 SLIP_MAGIC            0x5302           slip                     ``drivers/net/slip.h``
 STRIP_MAGIC           0x5303           strip                    ``drivers/net/strip.c``
diff --git a/Documentation/process/maintainers.rst b/Documentation/process/maintainers.rst
new file mode 100644 (file)
index 0000000..6174cfb
--- /dev/null
@@ -0,0 +1 @@
+.. maintainers-include::
index fb56297..ba5e944 100644 (file)
@@ -782,7 +782,58 @@ helpful, you can use the https://lkml.kernel.org/ redirector (e.g., in
 the cover email text) to link to an earlier version of the patch series.
 
 
-16) Sending ``git pull`` requests
+16) Providing base tree information
+-----------------------------------
+
+When other developers receive your patches and start the review process,
+it is often useful for them to know where in the tree history they
+should place your work. This is particularly useful for automated CI
+processes that attempt to run a series of tests in order to establish
+the quality of your submission before the maintainer starts the review.
+
+If you are using ``git format-patch`` to generate your patches, you can
+automatically include the base tree information in your submission by
+using the ``--base`` flag. The easiest and most convenient way to use
+this option is with topical branches::
+
+    $ git checkout -t -b my-topical-branch master
+    Branch 'my-topical-branch' set up to track local branch 'master'.
+    Switched to a new branch 'my-topical-branch'
+
+    [perform your edits and commits]
+
+    $ git format-patch --base=auto --cover-letter -o outgoing/ master
+    outgoing/0000-cover-letter.patch
+    outgoing/0001-First-Commit.patch
+    outgoing/...
+
+When you open ``outgoing/0000-cover-letter.patch`` for editing, you will
+notice that it will have the ``base-commit:`` trailer at the very
+bottom, which provides the reviewer and the CI tools enough information
+to properly perform ``git am`` without worrying about conflicts::
+
+    $ git checkout -b patch-review [base-commit-id]
+    Switched to a new branch 'patch-review'
+    $ git am patches.mbox
+    Applying: First Commit
+    Applying: ...
+
+Please see ``man git-format-patch`` for more information about this
+option.
+
+.. note::
+
+    The ``--base`` feature was introduced in git version 2.9.0.
+
+If you are not using git to format your patches, you can still include
+the same ``base-commit`` trailer to indicate the commit hash of the tree
+on which your work is based. You should add it either in the cover
+letter or in the first patch of the series and it should be placed
+either below the ``---`` line or at the very bottom of all other
+content, right before your email signature.
+
+
+17) Sending ``git pull`` requests
 ---------------------------------
 
 If you have a series of patches, it may be most convenient to have the
index 7b4d1d7..518d46d 100644 (file)
@@ -21,7 +21,7 @@ The following 64-byte header is present in decompressed Linux kernel image::
        u32 res1 = 0;             /* Reserved */
        u64 res2 = 0;             /* Reserved */
        u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */
-       u32 magic2 = 0x56534905;  /* Magic number 2, little endian, "RSC\x05" */
+       u32 magic2 = 0x05435352;  /* Magic number 2, little endian, "RSC\x05" */
        u32 res4;                 /* Reserved for PE COFF offset */
 
 This header format is compliant with PE/COFF header and largely inspired from
index 0cb0aa7..dd9b99a 100644 (file)
@@ -28,7 +28,7 @@ of these will need to start with a baseline observation and then calculate
 the change in the counters at each subsequent observation.  A perl script
 which does this for many of the fields is available at
 
-    http://eaglet.rain.com/rick/linux/schedstat/
+    http://eaglet.pdxhosts.com/rick/linux/schedstat/
 
 Note that any such script will necessarily be version-specific, as the main
 reason to change versions is changes in the output format.  For those wishing
@@ -164,4 +164,4 @@ report on how well a particular process or set of processes is faring
 under the scheduler's policies.  A simple version of such a program is
 available at
 
-    http://eaglet.rain.com/rick/linux/schedstat/v12/latency.c
+    http://eaglet.pdxhosts.com/rick/linux/schedstat/v12/latency.c
index c1dd493..2a4be1c 100644 (file)
@@ -1084,7 +1084,8 @@ of interest:
                    commands to the adapter.
     this_id      - scsi id of host (scsi initiator) or -1 if not known
     sg_tablesize - maximum scatter gather elements allowed by host.
-                   0 implies scatter gather not supported by host
+                   Set this to SG_ALL or less to avoid chained SG lists.
+                   Must be at least 1.
     max_sectors  - maximum number of sectors (usually 512 bytes) allowed
                    in a single SCSI command. The default value of 0 leads
                    to a setting of SCSI_DEFAULT_MAX_SECTORS (defined in
index d6d8b0b..d9b0b85 100644 (file)
@@ -1102,7 +1102,7 @@ payload contents" for more information.
     See also Documentation/security/keys/request-key.rst.
 
 
- *  To search for a key in a specific domain, call:
+ *  To search for a key in a specific domain, call::
 
        struct key *request_key_tag(const struct key_type *type,
                                    const char *description,
index ad4dfd0..aadf47c 100644 (file)
@@ -56,7 +56,7 @@ the infrastructure to support security modules. The LSM kernel patch
 also moves most of the capabilities logic into an optional security
 module, with the system defaulting to the traditional superuser logic.
 This capabilities module is discussed further in
-`LSM Capabilities Module <#cap>`__.
+`LSM Capabilities Module`_.
 
 The LSM kernel patch adds security fields to kernel data structures and
 inserts calls to hook functions at critical points in the kernel code to
index e21e36c..459ec5b 100644 (file)
@@ -53,6 +53,16 @@ div[class^="highlight"] pre {
     line-height: normal;
 }
 
+/* Keep fields from being strangely far apart due to inheirited table CSS. */
+.rst-content table.field-list th.field-name {
+    padding-top: 1px;
+    padding-bottom: 1px;
+}
+.rst-content table.field-list td.field-body {
+    padding-top: 1px;
+    padding-bottom: 1px;
+}
+
 @media screen {
 
     /* content column
index 1159405..4bcbd6a 100644 (file)
@@ -59,9 +59,10 @@ class KernelDocDirective(Directive):
     optional_arguments = 4
     option_spec = {
         'doc': directives.unchanged_required,
-        'functions': directives.unchanged,
         'export': directives.unchanged,
         'internal': directives.unchanged,
+        'identifiers': directives.unchanged,
+        'functions': directives.unchanged,
     }
     has_content = False
 
@@ -77,6 +78,10 @@ class KernelDocDirective(Directive):
 
         tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
 
+        # 'function' is an alias of 'identifiers'
+        if 'functions' in self.options:
+            self.options['identifiers'] = self.options.get('functions')
+
         # FIXME: make this nicer and more robust against errors
         if 'export' in self.options:
             cmd += ['-export']
@@ -86,11 +91,11 @@ class KernelDocDirective(Directive):
             export_file_patterns = str(self.options.get('internal')).split()
         elif 'doc' in self.options:
             cmd += ['-function', str(self.options.get('doc'))]
-        elif 'functions' in self.options:
-            functions = self.options.get('functions').split()
-            if functions:
-                for f in functions:
-                    cmd += ['-function', f]
+        elif 'identifiers' in self.options:
+            identifiers = self.options.get('identifiers').split()
+            if identifiers:
+                for i in identifiers:
+                    cmd += ['-function', i]
             else:
                 cmd += ['-no-doc-sections']
 
diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
new file mode 100755 (executable)
index 0000000..dc8fed4
--- /dev/null
@@ -0,0 +1,197 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0
+# -*- coding: utf-8; mode: python -*-
+# pylint: disable=R0903, C0330, R0914, R0912, E0401
+
+u"""
+    maintainers-include
+    ~~~~~~~~~~~~~~~~~~~
+
+    Implementation of the ``maintainers-include`` reST-directive.
+
+    :copyright:  Copyright (C) 2019  Kees Cook <keescook@chromium.org>
+    :license:    GPL Version 2, June 1991 see linux/COPYING for details.
+
+    The ``maintainers-include`` reST-directive performs extensive parsing
+    specific to the Linux kernel's standard "MAINTAINERS" file, in an
+    effort to avoid needing to heavily mark up the original plain text.
+"""
+
+import sys
+import re
+import os.path
+
+from docutils import statemachine
+from docutils.utils.error_reporting import ErrorString
+from docutils.parsers.rst import Directive
+from docutils.parsers.rst.directives.misc import Include
+
+__version__  = '1.0'
+
+def setup(app):
+    app.add_directive("maintainers-include", MaintainersInclude)
+    return dict(
+        version = __version__,
+        parallel_read_safe = True,
+        parallel_write_safe = True
+    )
+
+class MaintainersInclude(Include):
+    u"""MaintainersInclude (``maintainers-include``) directive"""
+    required_arguments = 0
+
+    def parse_maintainers(self, path):
+        """Parse all the MAINTAINERS lines into ReST for human-readability"""
+
+        result = list()
+        result.append(".. _maintainers:")
+        result.append("")
+
+        # Poor man's state machine.
+        descriptions = False
+        maintainers = False
+        subsystems = False
+
+        # Field letter to field name mapping.
+        field_letter = None
+        fields = dict()
+
+        prev = None
+        field_prev = ""
+        field_content = ""
+
+        for line in open(path):
+            if sys.version_info.major == 2:
+                line = unicode(line, 'utf-8')
+            # Have we reached the end of the preformatted Descriptions text?
+            if descriptions and line.startswith('Maintainers'):
+                descriptions = False
+                # Ensure a blank line following the last "|"-prefixed line.
+                result.append("")
+
+            # Start subsystem processing? This is to skip processing the text
+            # between the Maintainers heading and the first subsystem name.
+            if maintainers and not subsystems:
+                if re.search('^[A-Z0-9]', line):
+                    subsystems = True
+
+            # Drop needless input whitespace.
+            line = line.rstrip()
+
+            # Linkify all non-wildcard refs to ReST files in Documentation/.
+            pat = '(Documentation/([^\s\?\*]*)\.rst)'
+            m = re.search(pat, line)
+            if m:
+                # maintainers.rst is in a subdirectory, so include "../".
+                line = re.sub(pat, ':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
+
+            # Check state machine for output rendering behavior.
+            output = None
+            if descriptions:
+                # Escape the escapes in preformatted text.
+                output = "| %s" % (line.replace("\\", "\\\\"))
+                # Look for and record field letter to field name mappings:
+                #   R: Designated *reviewer*: FullName <address@domain>
+                m = re.search("\s(\S):\s", line)
+                if m:
+                    field_letter = m.group(1)
+                if field_letter and not field_letter in fields:
+                    m = re.search("\*([^\*]+)\*", line)
+                    if m:
+                        fields[field_letter] = m.group(1)
+            elif subsystems:
+                # Skip empty lines: subsystem parser adds them as needed.
+                if len(line) == 0:
+                    continue
+                # Subsystem fields are batched into "field_content"
+                if line[1] != ':':
+                    # Render a subsystem entry as:
+                    #   SUBSYSTEM NAME
+                    #   ~~~~~~~~~~~~~~
+
+                    # Flush pending field content.
+                    output = field_content + "\n\n"
+                    field_content = ""
+
+                    # Collapse whitespace in subsystem name.
+                    heading = re.sub("\s+", " ", line)
+                    output = output + "%s\n%s" % (heading, "~" * len(heading))
+                    field_prev = ""
+                else:
+                    # Render a subsystem field as:
+                    #   :Field: entry
+                    #           entry...
+                    field, details = line.split(':', 1)
+                    details = details.strip()
+
+                    # Mark paths (and regexes) as literal text for improved
+                    # readability and to escape any escapes.
+                    if field in ['F', 'N', 'X', 'K']:
+                        # But only if not already marked :)
+                        if not ':doc:' in details:
+                            details = '``%s``' % (details)
+
+                    # Comma separate email field continuations.
+                    if field == field_prev and field_prev in ['M', 'R', 'L']:
+                        field_content = field_content + ","
+
+                    # Do not repeat field names, so that field entries
+                    # will be collapsed together.
+                    if field != field_prev:
+                        output = field_content + "\n"
+                        field_content = ":%s:" % (fields.get(field, field))
+                    field_content = field_content + "\n\t%s" % (details)
+                    field_prev = field
+            else:
+                output = line
+
+            # Re-split on any added newlines in any above parsing.
+            if output != None:
+                for separated in output.split('\n'):
+                    result.append(separated)
+
+            # Update the state machine when we find heading separators.
+            if line.startswith('----------'):
+                if prev.startswith('Descriptions'):
+                    descriptions = True
+                if prev.startswith('Maintainers'):
+                    maintainers = True
+
+            # Retain previous line for state machine transitions.
+            prev = line
+
+        # Flush pending field contents.
+        if field_content != "":
+            for separated in field_content.split('\n'):
+                result.append(separated)
+
+        output = "\n".join(result)
+        # For debugging the pre-rendered results...
+        #print(output, file=open("/tmp/MAINTAINERS.rst", "w"))
+
+        self.state_machine.insert_input(
+          statemachine.string2lines(output), path)
+
+    def run(self):
+        """Include the MAINTAINERS file as part of this reST file."""
+        if not self.state.document.settings.file_insertion_enabled:
+            raise self.warning('"%s" directive disabled.' % self.name)
+
+        # Walk up source path directories to find Documentation/../
+        path = self.state_machine.document.attributes['source']
+        path = os.path.realpath(path)
+        tail = path
+        while tail != "Documentation" and tail != "":
+            (path, tail) = os.path.split(path)
+
+        # Append "MAINTAINERS"
+        path = os.path.join(path, "MAINTAINERS")
+
+        try:
+            self.state.document.settings.record_dependencies.add(path)
+            lines = self.parse_maintainers(path)
+        except IOError as error:
+            raise self.severe('Problems with "%s" directive path:\n%s.' %
+                      (self.name, ErrorString(error)))
+
+        return []
diff --git a/Documentation/sphinx/parallel-wrapper.sh b/Documentation/sphinx/parallel-wrapper.sh
new file mode 100644 (file)
index 0000000..7daf513
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Figure out if we should follow a specific parallelism from the make
+# environment (as exported by scripts/jobserver-exec), or fall back to
+# the "auto" parallelism when "-jN" is not specified at the top-level
+# "make" invocation.
+
+sphinx="$1"
+shift || true
+
+parallel="$PARALLELISM"
+if [ -z "$parallel" ] ; then
+       # If no parallelism is specified at the top-level make, then
+       # fall back to the expected "-jauto" mode that the "htmldocs"
+       # target has had.
+       auto=$(perl -e 'open IN,"'"$sphinx"' --version 2>&1 |";
+                       while (<IN>) {
+                               if (m/([\d\.]+)/) {
+                                       print "auto" if ($1 >= "1.7")
+                               }
+                       }
+                       close IN')
+       if [ -n "$auto" ] ; then
+               parallel="$auto"
+       fi
+fi
+# Only if some parallelism has been determined do we add the -jN option.
+if [ -n "$parallel" ] ; then
+       parallel="-j$parallel"
+fi
+
+exec "$sphinx" "$parallel" "$@"
diff --git a/Documentation/trace/coresight-cpu-debug.rst b/Documentation/trace/coresight-cpu-debug.rst
deleted file mode 100644 (file)
index 993dd29..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-==========================
-Coresight CPU Debug Module
-==========================
-
-   :Author:   Leo Yan <leo.yan@linaro.org>
-   :Date:     April 5th, 2017
-
-Introduction
-------------
-
-Coresight CPU debug module is defined in ARMv8-a architecture reference manual
-(ARM DDI 0487A.k) Chapter 'Part H: External debug', the CPU can integrate
-debug module and it is mainly used for two modes: self-hosted debug and
-external debug. Usually the external debug mode is well known as the external
-debugger connects with SoC from JTAG port; on the other hand the program can
-explore debugging method which rely on self-hosted debug mode, this document
-is to focus on this part.
-
-The debug module provides sample-based profiling extension, which can be used
-to sample CPU program counter, secure state and exception level, etc; usually
-every CPU has one dedicated debug module to be connected. Based on self-hosted
-debug mechanism, Linux kernel can access these related registers from mmio
-region when the kernel panic happens. The callback notifier for kernel panic
-will dump related registers for every CPU; finally this is good for assistant
-analysis for panic.
-
-
-Implementation
---------------
-
-- During driver registration, it uses EDDEVID and EDDEVID1 - two device ID
-  registers to decide if sample-based profiling is implemented or not. On some
-  platforms this hardware feature is fully or partially implemented; and if
-  this feature is not supported then registration will fail.
-
-- At the time this documentation was written, the debug driver mainly relies on
-  information gathered by the kernel panic callback notifier from three
-  sampling registers: EDPCSR, EDVIDSR and EDCIDSR: from EDPCSR we can get
-  program counter; EDVIDSR has information for secure state, exception level,
-  bit width, etc; EDCIDSR is context ID value which contains the sampled value
-  of CONTEXTIDR_EL1.
-
-- The driver supports a CPU running in either AArch64 or AArch32 mode. The
-  registers naming convention is a bit different between them, AArch64 uses
-  'ED' for register prefix (ARM DDI 0487A.k, chapter H9.1) and AArch32 uses
-  'DBG' as prefix (ARM DDI 0487A.k, chapter G5.1). The driver is unified to
-  use AArch64 naming convention.
-
-- ARMv8-a (ARM DDI 0487A.k) and ARMv7-a (ARM DDI 0406C.b) have different
-  register bits definition. So the driver consolidates two difference:
-
-  If PCSROffset=0b0000, on ARMv8-a the feature of EDPCSR is not implemented;
-  but ARMv7-a defines "PCSR samples are offset by a value that depends on the
-  instruction set state". For ARMv7-a, the driver checks furthermore if CPU
-  runs with ARM or thumb instruction set and calibrate PCSR value, the
-  detailed description for offset is in ARMv7-a ARM (ARM DDI 0406C.b) chapter
-  C11.11.34 "DBGPCSR, Program Counter Sampling Register".
-
-  If PCSROffset=0b0010, ARMv8-a defines "EDPCSR implemented, and samples have
-  no offset applied and do not sample the instruction set state in AArch32
-  state". So on ARMv8 if EDDEVID1.PCSROffset is 0b0010 and the CPU operates
-  in AArch32 state, EDPCSR is not sampled; when the CPU operates in AArch64
-  state EDPCSR is sampled and no offset are applied.
-
-
-Clock and power domain
-----------------------
-
-Before accessing debug registers, we should ensure the clock and power domain
-have been enabled properly. In ARMv8-a ARM (ARM DDI 0487A.k) chapter 'H9.1
-Debug registers', the debug registers are spread into two domains: the debug
-domain and the CPU domain.
-::
-
-                                +---------------+
-                                |               |
-                                |               |
-                     +----------+--+            |
-        dbg_clock -->|          |**|            |<-- cpu_clock
-                     |    Debug |**|   CPU      |
- dbg_power_domain -->|          |**|            |<-- cpu_power_domain
-                     +----------+--+            |
-                                |               |
-                                |               |
-                                +---------------+
-
-For debug domain, the user uses DT binding "clocks" and "power-domains" to
-specify the corresponding clock source and power supply for the debug logic.
-The driver calls the pm_runtime_{put|get} operations as needed to handle the
-debug power domain.
-
-For CPU domain, the different SoC designs have different power management
-schemes and finally this heavily impacts external debug module. So we can
-divide into below cases:
-
-- On systems with a sane power controller which can behave correctly with
-  respect to CPU power domain, the CPU power domain can be controlled by
-  register EDPRCR in driver. The driver firstly writes bit EDPRCR.COREPURQ
-  to power up the CPU, and then writes bit EDPRCR.CORENPDRQ for emulation
-  of CPU power down. As result, this can ensure the CPU power domain is
-  powered on properly during the period when access debug related registers;
-
-- Some designs will power down an entire cluster if all CPUs on the cluster
-  are powered down - including the parts of the debug registers that should
-  remain powered in the debug power domain. The bits in EDPRCR are not
-  respected in these cases, so these designs do not support debug over
-  power down in the way that the CoreSight / Debug designers anticipated.
-  This means that even checking EDPRSR has the potential to cause a bus hang
-  if the target register is unpowered.
-
-  In this case, accessing to the debug registers while they are not powered
-  is a recipe for disaster; so we need preventing CPU low power states at boot
-  time or when user enable module at the run time. Please see chapter
-  "How to use the module" for detailed usage info for this.
-
-
-Device Tree Bindings
---------------------
-
-See Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt for details.
-
-
-How to use the module
----------------------
-
-If you want to enable debugging functionality at boot time, you can add
-"coresight_cpu_debug.enable=1" to the kernel command line parameter.
-
-The driver also can work as module, so can enable the debugging when insmod
-module::
-
-  # insmod coresight_cpu_debug.ko debug=1
-
-When boot time or insmod module you have not enabled the debugging, the driver
-uses the debugfs file system to provide a knob to dynamically enable or disable
-debugging:
-
-To enable it, write a '1' into /sys/kernel/debug/coresight_cpu_debug/enable::
-
-  # echo 1 > /sys/kernel/debug/coresight_cpu_debug/enable
-
-To disable it, write a '0' into /sys/kernel/debug/coresight_cpu_debug/enable::
-
-  # echo 0 > /sys/kernel/debug/coresight_cpu_debug/enable
-
-As explained in chapter "Clock and power domain", if you are working on one
-platform which has idle states to power off debug logic and the power
-controller cannot work well for the request from EDPRCR, then you should
-firstly constraint CPU idle states before enable CPU debugging feature; so can
-ensure the accessing to debug logic.
-
-If you want to limit idle states at boot time, you can use "nohlt" or
-"cpuidle.off=1" in the kernel command line.
-
-At the runtime you can disable idle states with below methods:
-
-It is possible to disable CPU idle states by way of the PM QoS
-subsystem, more specifically by using the "/dev/cpu_dma_latency"
-interface (see Documentation/power/pm_qos_interface.rst for more
-details).  As specified in the PM QoS documentation the requested
-parameter will stay in effect until the file descriptor is released.
-For example::
-
-  # exec 3<> /dev/cpu_dma_latency; echo 0 >&3
-  ...
-  Do some work...
-  ...
-  # exec 3<>-
-
-The same can also be done from an application program.
-
-Disable specific CPU's specific idle state from cpuidle sysfs (see
-Documentation/admin-guide/pm/cpuidle.rst)::
-
-  # echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable
-
-Output format
--------------
-
-Here is an example of the debugging output format::
-
-  ARM external debug module:
-  coresight-cpu-debug 850000.debug: CPU[0]:
-  coresight-cpu-debug 850000.debug:  EDPRSR:  00000001 (Power:On DLK:Unlock)
-  coresight-cpu-debug 850000.debug:  EDPCSR:  handle_IPI+0x174/0x1d8
-  coresight-cpu-debug 850000.debug:  EDCIDSR: 00000000
-  coresight-cpu-debug 850000.debug:  EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
-  coresight-cpu-debug 852000.debug: CPU[1]:
-  coresight-cpu-debug 852000.debug:  EDPRSR:  00000001 (Power:On DLK:Unlock)
-  coresight-cpu-debug 852000.debug:  EDPCSR:  debug_notifier_call+0x23c/0x358
-  coresight-cpu-debug 852000.debug:  EDCIDSR: 00000000
-  coresight-cpu-debug 852000.debug:  EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
diff --git a/Documentation/trace/coresight.rst b/Documentation/trace/coresight.rst
deleted file mode 100644 (file)
index 72f4b7e..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-======================================
-Coresight - HW Assisted Tracing on ARM
-======================================
-
-   :Author:   Mathieu Poirier <mathieu.poirier@linaro.org>
-   :Date:     September 11th, 2014
-
-Introduction
-------------
-
-Coresight is an umbrella of technologies allowing for the debugging of ARM
-based SoC.  It includes solutions for JTAG and HW assisted tracing.  This
-document is concerned with the latter.
-
-HW assisted tracing is becoming increasingly useful when dealing with systems
-that have many SoCs and other components like GPU and DMA engines.  ARM has
-developed a HW assisted tracing solution by means of different components, each
-being added to a design at synthesis time to cater to specific tracing needs.
-Components are generally categorised as source, link and sinks and are
-(usually) discovered using the AMBA bus.
-
-"Sources" generate a compressed stream representing the processor instruction
-path based on tracing scenarios as configured by users.  From there the stream
-flows through the coresight system (via ATB bus) using links that are connecting
-the emanating source to a sink(s).  Sinks serve as endpoints to the coresight
-implementation, either storing the compressed stream in a memory buffer or
-creating an interface to the outside world where data can be transferred to a
-host without fear of filling up the onboard coresight memory buffer.
-
-At typical coresight system would look like this::
-
-  *****************************************************************
- **************************** AMBA AXI  ****************************===||
-  *****************************************************************    ||
-        ^                    ^                            |            ||
-        |                    |                            *            **
-     0000000    :::::     0000000    :::::    :::::    @@@@@@@    ||||||||||||
-     0 CPU 0<-->: C :     0 CPU 0<-->: C :    : C :    @ STM @    || System ||
-  |->0000000    : T :  |->0000000    : T :    : T :<--->@@@@@     || Memory ||
-  |  #######<-->: I :  |  #######<-->: I :    : I :      @@@<-|   ||||||||||||
-  |  # ETM #    :::::  |  # PTM #    :::::    :::::       @   |
-  |   #####      ^ ^   |   #####      ^ !      ^ !        .   |   |||||||||
-  | |->###       | !   | |->###       | !      | !        .   |   || DAP ||
-  | |   #        | !   | |   #        | !      | !        .   |   |||||||||
-  | |   .        | !   | |   .        | !      | !        .   |      |  |
-  | |   .        | !   | |   .        | !      | !        .   |      |  *
-  | |   .        | !   | |   .        | !      | !        .   |      | SWD/
-  | |   .        | !   | |   .        | !      | !        .   |      | JTAG
-  *****************************************************************<-|
- *************************** AMBA Debug APB ************************
-  *****************************************************************
-   |    .          !         .          !        !        .    |
-   |    .          *         .          *        *        .    |
-  *****************************************************************
- ******************** Cross Trigger Matrix (CTM) *******************
-  *****************************************************************
-   |    .     ^              .                            .    |
-   |    *     !              *                            *    |
-  *****************************************************************
- ****************** AMBA Advanced Trace Bus (ATB) ******************
-  *****************************************************************
-   |          !                        ===============         |
-   |          *                         ===== F =====<---------|
-   |   :::::::::                         ==== U ====
-   |-->:: CTI ::<!!                       === N ===
-   |   :::::::::  !                        == N ==
-   |    ^         *                        == E ==
-   |    !  &&&&&&&&&       IIIIIII         == L ==
-   |------>&& ETB &&<......II     I        =======
-   |    !  &&&&&&&&&       II     I           .
-   |    !                    I     I          .
-   |    !                    I REP I<..........
-   |    !                    I     I
-   |    !!>&&&&&&&&&       II     I           *Source: ARM ltd.
-   |------>& TPIU  &<......II    I            DAP = Debug Access Port
-           &&&&&&&&&       IIIIIII            ETM = Embedded Trace Macrocell
-               ;                              PTM = Program Trace Macrocell
-               ;                              CTI = Cross Trigger Interface
-               *                              ETB = Embedded Trace Buffer
-          To trace port                       TPIU= Trace Port Interface Unit
-                                              SWD = Serial Wire Debug
-
-While on target configuration of the components is done via the APB bus,
-all trace data are carried out-of-band on the ATB bus.  The CTM provides
-a way to aggregate and distribute signals between CoreSight components.
-
-The coresight framework provides a central point to represent, configure and
-manage coresight devices on a platform.  This first implementation centers on
-the basic tracing functionality, enabling components such ETM/PTM, funnel,
-replicator, TMC, TPIU and ETB.  Future work will enable more
-intricate IP blocks such as STM and CTI.
-
-
-Acronyms and Classification
----------------------------
-
-Acronyms:
-
-PTM:
-    Program Trace Macrocell
-ETM:
-    Embedded Trace Macrocell
-STM:
-    System trace Macrocell
-ETB:
-    Embedded Trace Buffer
-ITM:
-    Instrumentation Trace Macrocell
-TPIU:
-     Trace Port Interface Unit
-TMC-ETR:
-        Trace Memory Controller, configured as Embedded Trace Router
-TMC-ETF:
-        Trace Memory Controller, configured as Embedded Trace FIFO
-CTI:
-    Cross Trigger Interface
-
-Classification:
-
-Source:
-   ETMv3.x ETMv4, PTMv1.0, PTMv1.1, STM, STM500, ITM
-Link:
-   Funnel, replicator (intelligent or not), TMC-ETR
-Sinks:
-   ETBv1.0, ETB1.1, TPIU, TMC-ETF
-Misc:
-   CTI
-
-
-Device Tree Bindings
---------------------
-
-See Documentation/devicetree/bindings/arm/coresight.txt for details.
-
-As of this writing drivers for ITM, STMs and CTIs are not provided but are
-expected to be added as the solution matures.
-
-
-Framework and implementation
-----------------------------
-
-The coresight framework provides a central point to represent, configure and
-manage coresight devices on a platform.  Any coresight compliant device can
-register with the framework for as long as they use the right APIs:
-
-.. c:function:: struct coresight_device *coresight_register(struct coresight_desc *desc);
-.. c:function:: void coresight_unregister(struct coresight_device *csdev);
-
-The registering function is taking a ``struct coresight_desc *desc`` and
-register the device with the core framework. The unregister function takes
-a reference to a ``struct coresight_device *csdev`` obtained at registration time.
-
-If everything goes well during the registration process the new devices will
-show up under /sys/bus/coresight/devices, as showns here for a TC2 platform::
-
-    root:~# ls /sys/bus/coresight/devices/
-    replicator  20030000.tpiu    2201c000.ptm  2203c000.etm  2203e000.etm
-    20010000.etb         20040000.funnel  2201d000.ptm  2203d000.etm
-    root:~#
-
-The functions take a ``struct coresight_device``, which looks like this::
-
-    struct coresight_desc {
-            enum coresight_dev_type type;
-            struct coresight_dev_subtype subtype;
-            const struct coresight_ops *ops;
-            struct coresight_platform_data *pdata;
-            struct device *dev;
-            const struct attribute_group **groups;
-    };
-
-
-The "coresight_dev_type" identifies what the device is, i.e, source link or
-sink while the "coresight_dev_subtype" will characterise that type further.
-
-The ``struct coresight_ops`` is mandatory and will tell the framework how to
-perform base operations related to the components, each component having
-a different set of requirement. For that ``struct coresight_ops_sink``,
-``struct coresight_ops_link`` and ``struct coresight_ops_source`` have been
-provided.
-
-The next field ``struct coresight_platform_data *pdata`` is acquired by calling
-``of_get_coresight_platform_data()``, as part of the driver's _probe routine and
-``struct device *dev`` gets the device reference embedded in the ``amba_device``::
-
-    static int etm_probe(struct amba_device *adev, const struct amba_id *id)
-    {
-     ...
-     ...
-     drvdata->dev = &adev->dev;
-     ...
-    }
-
-Specific class of device (source, link, or sink) have generic operations
-that can be performed on them (see ``struct coresight_ops``). The ``**groups``
-is a list of sysfs entries pertaining to operations
-specific to that component only.  "Implementation defined" customisations are
-expected to be accessed and controlled using those entries.
-
-Device Naming scheme
---------------------
-
-The devices that appear on the "coresight" bus were named the same as their
-parent devices, i.e, the real devices that appears on AMBA bus or the platform bus.
-Thus the names were based on the Linux Open Firmware layer naming convention,
-which follows the base physical address of the device followed by the device
-type. e.g::
-
-    root:~# ls /sys/bus/coresight/devices/
-     20010000.etf  20040000.funnel      20100000.stm     22040000.etm
-     22140000.etm  230c0000.funnel      23240000.etm     20030000.tpiu
-     20070000.etr  20120000.replicator  220c0000.funnel
-     23040000.etm  23140000.etm         23340000.etm
-
-However, with the introduction of ACPI support, the names of the real
-devices are a bit cryptic and non-obvious. Thus, a new naming scheme was
-introduced to use more generic names based on the type of the device. The
-following rules apply::
-
-  1) Devices that are bound to CPUs, are named based on the CPU logical
-     number.
-
-     e.g, ETM bound to CPU0 is named "etm0"
-
-  2) All other devices follow a pattern, "<device_type_prefix>N", where :
-
-       <device_type_prefix>    - A prefix specific to the type of the device
-       N                       - a sequential number assigned based on the order
-                                 of probing.
-
-       e.g, tmc_etf0, tmc_etr0, funnel0, funnel1
-
-Thus, with the new scheme the devices could appear as ::
-
-    root:~# ls /sys/bus/coresight/devices/
-     etm0     etm1     etm2         etm3  etm4      etm5      funnel0
-     funnel1  funnel2  replicator0  stm0  tmc_etf0  tmc_etr0  tpiu0
-
-Some of the examples below might refer to old naming scheme and some
-to the newer scheme, to give a confirmation that what you see on your
-system is not unexpected. One must use the "names" as they appear on
-the system under specified locations.
-
-How to use the tracer modules
------------------------------
-
-There are two ways to use the Coresight framework:
-
-1. using the perf cmd line tools.
-2. interacting directly with the Coresight devices using the sysFS interface.
-
-Preference is given to the former as using the sysFS interface
-requires a deep understanding of the Coresight HW.  The following sections
-provide details on using both methods.
-
-1) Using the sysFS interface:
-
-Before trace collection can start, a coresight sink needs to be identified.
-There is no limit on the amount of sinks (nor sources) that can be enabled at
-any given moment.  As a generic operation, all device pertaining to the sink
-class will have an "active" entry in sysfs::
-
-    root:/sys/bus/coresight/devices# ls
-    replicator  20030000.tpiu    2201c000.ptm  2203c000.etm  2203e000.etm
-    20010000.etb         20040000.funnel  2201d000.ptm  2203d000.etm
-    root:/sys/bus/coresight/devices# ls 20010000.etb
-    enable_sink  status  trigger_cntr
-    root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink
-    root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink
-    1
-    root:/sys/bus/coresight/devices#
-
-At boot time the current etm3x driver will configure the first address
-comparator with "_stext" and "_etext", essentially tracing any instruction
-that falls within that range.  As such "enabling" a source will immediately
-trigger a trace capture::
-
-    root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source
-    root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source
-    1
-    root:/sys/bus/coresight/devices# cat 20010000.etb/status
-    Depth:          0x2000
-    Status:         0x1
-    RAM read ptr:   0x0
-    RAM wrt ptr:    0x19d3   <----- The write pointer is moving
-    Trigger cnt:    0x0
-    Control:        0x1
-    Flush status:   0x0
-    Flush ctrl:     0x2001
-    root:/sys/bus/coresight/devices#
-
-Trace collection is stopped the same way::
-
-    root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source
-    root:/sys/bus/coresight/devices#
-
-The content of the ETB buffer can be harvested directly from /dev::
-
-    root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \
-    of=~/cstrace.bin
-    64+0 records in
-    64+0 records out
-    32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s
-    root:/sys/bus/coresight/devices#
-
-The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32.
-
-Following is a DS-5 output of an experimental loop that increments a variable up
-to a certain value.  The example is simple and yet provides a glimpse of the
-wealth of possibilities that coresight provides.
-::
-
-    Info                                    Tracing enabled
-    Instruction     106378866       0x8026B53C      E52DE004        false   PUSH     {lr}
-    Instruction     0       0x8026B540      E24DD00C        false   SUB      sp,sp,#0xc
-    Instruction     0       0x8026B544      E3A03000        false   MOV      r3,#0
-    Instruction     0       0x8026B548      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
-    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
-    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
-    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
-    Timestamp                                       Timestamp: 17106715833
-    Instruction     319     0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
-    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
-    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
-    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
-    Instruction     9       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
-    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
-    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
-    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
-    Instruction     7       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
-    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
-    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
-    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
-    Instruction     7       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
-    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
-    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
-    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
-    Instruction     10      0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
-    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
-    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
-    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
-    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
-    Instruction     6       0x8026B560      EE1D3F30        false   MRC      p15,#0x0,r3,c13,c0,#1
-    Instruction     0       0x8026B564      E1A0100D        false   MOV      r1,sp
-    Instruction     0       0x8026B568      E3C12D7F        false   BIC      r2,r1,#0x1fc0
-    Instruction     0       0x8026B56C      E3C2203F        false   BIC      r2,r2,#0x3f
-    Instruction     0       0x8026B570      E59D1004        false   LDR      r1,[sp,#4]
-    Instruction     0       0x8026B574      E59F0010        false   LDR      r0,[pc,#16] ; [0x8026B58C] = 0x80550368
-    Instruction     0       0x8026B578      E592200C        false   LDR      r2,[r2,#0xc]
-    Instruction     0       0x8026B57C      E59221D0        false   LDR      r2,[r2,#0x1d0]
-    Instruction     0       0x8026B580      EB07A4CF        true    BL       {pc}+0x1e9344 ; 0x804548c4
-    Info                                    Tracing enabled
-    Instruction     13570831        0x8026B584      E28DD00C        false   ADD      sp,sp,#0xc
-    Instruction     0       0x8026B588      E8BD8000        true    LDM      sp!,{pc}
-    Timestamp                                       Timestamp: 17107041535
-
-2) Using perf framework:
-
-Coresight tracers are represented using the Perf framework's Performance
-Monitoring Unit (PMU) abstraction.  As such the perf framework takes charge of
-controlling when tracing gets enabled based on when the process of interest is
-scheduled.  When configured in a system, Coresight PMUs will be listed when
-queried by the perf command line tool:
-
-       linaro@linaro-nano:~$ ./perf list pmu
-
-               List of pre-defined events (to be used in -e):
-
-               cs_etm//                                    [Kernel PMU event]
-
-       linaro@linaro-nano:~$
-
-Regardless of the number of tracers available in a system (usually equal to the
-amount of processor cores), the "cs_etm" PMU will be listed only once.
-
-A Coresight PMU works the same way as any other PMU, i.e the name of the PMU is
-listed along with configuration options within forward slashes '/'.  Since a
-Coresight system will typically have more than one sink, the name of the sink to
-work with needs to be specified as an event option.
-On newer kernels the available sinks are listed in sysFS under
-($SYSFS)/bus/event_source/devices/cs_etm/sinks/::
-
-       root@localhost:/sys/bus/event_source/devices/cs_etm/sinks# ls
-       tmc_etf0  tmc_etr0  tpiu0
-
-On older kernels, this may need to be found from the list of coresight devices,
-available under ($SYSFS)/bus/coresight/devices/::
-
-       root:~# ls /sys/bus/coresight/devices/
-        etm0     etm1     etm2         etm3  etm4      etm5      funnel0
-        funnel1  funnel2  replicator0  stm0  tmc_etf0  tmc_etr0  tpiu0
-       root@linaro-nano:~# perf record -e cs_etm/@tmc_etr0/u --per-thread program
-
-As mentioned above in section "Device Naming scheme", the names of the devices could
-look different from what is used in the example above. One must use the device names
-as it appears under the sysFS.
-
-The syntax within the forward slashes '/' is important.  The '@' character
-tells the parser that a sink is about to be specified and that this is the sink
-to use for the trace session.
-
-More information on the above and other example on how to use Coresight with
-the perf tools can be found in the "HOWTO.md" file of the openCSD gitHub
-repository [#third]_.
-
-2.1) AutoFDO analysis using the perf tools:
-
-perf can be used to record and analyze trace of programs.
-
-Execution can be recorded using 'perf record' with the cs_etm event,
-specifying the name of the sink to record to, e.g::
-
-    perf record -e cs_etm/@tmc_etr0/u --per-thread
-
-The 'perf report' and 'perf script' commands can be used to analyze execution,
-synthesizing instruction and branch events from the instruction trace.
-'perf inject' can be used to replace the trace data with the synthesized events.
-The --itrace option controls the type and frequency of synthesized events
-(see perf documentation).
-
-Note that only 64-bit programs are currently supported - further work is
-required to support instruction decode of 32-bit Arm programs.
-
-
-Generating coverage files for Feedback Directed Optimization: AutoFDO
----------------------------------------------------------------------
-
-'perf inject' accepts the --itrace option in which case tracing data is
-removed and replaced with the synthesized events. e.g.
-::
-
-       perf inject --itrace --strip -i perf.data -o perf.data.new
-
-Below is an example of using ARM ETM for autoFDO.  It requires autofdo
-(https://github.com/google/autofdo) and gcc version 5.  The bubble
-sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial).
-::
-
-       $ gcc-5 -O3 sort.c -o sort
-       $ taskset -c 2 ./sort
-       Bubble sorting array of 30000 elements
-       5910 ms
-
-       $ perf record -e cs_etm/@tmc_etr0/u --per-thread taskset -c 2 ./sort
-       Bubble sorting array of 30000 elements
-       12543 ms
-       [ perf record: Woken up 35 times to write data ]
-       [ perf record: Captured and wrote 69.640 MB perf.data ]
-
-       $ perf inject -i perf.data -o inj.data --itrace=il64 --strip
-       $ create_gcov --binary=./sort --profile=inj.data --gcov=sort.gcov -gcov_version=1
-       $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo
-       $ taskset -c 2 ./sort_autofdo
-       Bubble sorting array of 30000 elements
-       5806 ms
-
-
-How to use the STM module
--------------------------
-
-Using the System Trace Macrocell module is the same as the tracers - the only
-difference is that clients are driving the trace capture rather
-than the program flow through the code.
-
-As with any other CoreSight component, specifics about the STM tracer can be
-found in sysfs with more information on each entry being found in [#first]_::
-
-    root@genericarmv8:~# ls /sys/bus/coresight/devices/stm0
-    enable_source   hwevent_select  port_enable     subsystem       uevent
-    hwevent_enable  mgmt            port_select     traceid
-    root@genericarmv8:~#
-
-Like any other source a sink needs to be identified and the STM enabled before
-being used::
-
-    root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink
-    root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/stm0/enable_source
-
-From there user space applications can request and use channels using the devfs
-interface provided for that purpose by the generic STM API::
-
-    root@genericarmv8:~# ls -l /dev/stm0
-    crw-------    1 root     root       10,  61 Jan  3 18:11 /dev/stm0
-    root@genericarmv8:~#
-
-Details on how to use the generic STM API can be found here [#second]_.
-
-.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
-
-.. [#second] Documentation/trace/stm.rst
-
-.. [#third] https://github.com/Linaro/perf-opencsd
diff --git a/Documentation/trace/coresight/coresight-cpu-debug.rst b/Documentation/trace/coresight/coresight-cpu-debug.rst
new file mode 100644 (file)
index 0000000..993dd29
--- /dev/null
@@ -0,0 +1,192 @@
+==========================
+Coresight CPU Debug Module
+==========================
+
+   :Author:   Leo Yan <leo.yan@linaro.org>
+   :Date:     April 5th, 2017
+
+Introduction
+------------
+
+Coresight CPU debug module is defined in ARMv8-a architecture reference manual
+(ARM DDI 0487A.k) Chapter 'Part H: External debug', the CPU can integrate
+debug module and it is mainly used for two modes: self-hosted debug and
+external debug. Usually the external debug mode is well known as the external
+debugger connects with SoC from JTAG port; on the other hand the program can
+explore debugging method which rely on self-hosted debug mode, this document
+is to focus on this part.
+
+The debug module provides sample-based profiling extension, which can be used
+to sample CPU program counter, secure state and exception level, etc; usually
+every CPU has one dedicated debug module to be connected. Based on self-hosted
+debug mechanism, Linux kernel can access these related registers from mmio
+region when the kernel panic happens. The callback notifier for kernel panic
+will dump related registers for every CPU; finally this is good for assistant
+analysis for panic.
+
+
+Implementation
+--------------
+
+- During driver registration, it uses EDDEVID and EDDEVID1 - two device ID
+  registers to decide if sample-based profiling is implemented or not. On some
+  platforms this hardware feature is fully or partially implemented; and if
+  this feature is not supported then registration will fail.
+
+- At the time this documentation was written, the debug driver mainly relies on
+  information gathered by the kernel panic callback notifier from three
+  sampling registers: EDPCSR, EDVIDSR and EDCIDSR: from EDPCSR we can get
+  program counter; EDVIDSR has information for secure state, exception level,
+  bit width, etc; EDCIDSR is context ID value which contains the sampled value
+  of CONTEXTIDR_EL1.
+
+- The driver supports a CPU running in either AArch64 or AArch32 mode. The
+  registers naming convention is a bit different between them, AArch64 uses
+  'ED' for register prefix (ARM DDI 0487A.k, chapter H9.1) and AArch32 uses
+  'DBG' as prefix (ARM DDI 0487A.k, chapter G5.1). The driver is unified to
+  use AArch64 naming convention.
+
+- ARMv8-a (ARM DDI 0487A.k) and ARMv7-a (ARM DDI 0406C.b) have different
+  register bits definition. So the driver consolidates two difference:
+
+  If PCSROffset=0b0000, on ARMv8-a the feature of EDPCSR is not implemented;
+  but ARMv7-a defines "PCSR samples are offset by a value that depends on the
+  instruction set state". For ARMv7-a, the driver checks furthermore if CPU
+  runs with ARM or thumb instruction set and calibrate PCSR value, the
+  detailed description for offset is in ARMv7-a ARM (ARM DDI 0406C.b) chapter
+  C11.11.34 "DBGPCSR, Program Counter Sampling Register".
+
+  If PCSROffset=0b0010, ARMv8-a defines "EDPCSR implemented, and samples have
+  no offset applied and do not sample the instruction set state in AArch32
+  state". So on ARMv8 if EDDEVID1.PCSROffset is 0b0010 and the CPU operates
+  in AArch32 state, EDPCSR is not sampled; when the CPU operates in AArch64
+  state EDPCSR is sampled and no offset are applied.
+
+
+Clock and power domain
+----------------------
+
+Before accessing debug registers, we should ensure the clock and power domain
+have been enabled properly. In ARMv8-a ARM (ARM DDI 0487A.k) chapter 'H9.1
+Debug registers', the debug registers are spread into two domains: the debug
+domain and the CPU domain.
+::
+
+                                +---------------+
+                                |               |
+                                |               |
+                     +----------+--+            |
+        dbg_clock -->|          |**|            |<-- cpu_clock
+                     |    Debug |**|   CPU      |
+ dbg_power_domain -->|          |**|            |<-- cpu_power_domain
+                     +----------+--+            |
+                                |               |
+                                |               |
+                                +---------------+
+
+For debug domain, the user uses DT binding "clocks" and "power-domains" to
+specify the corresponding clock source and power supply for the debug logic.
+The driver calls the pm_runtime_{put|get} operations as needed to handle the
+debug power domain.
+
+For CPU domain, the different SoC designs have different power management
+schemes and finally this heavily impacts external debug module. So we can
+divide into below cases:
+
+- On systems with a sane power controller which can behave correctly with
+  respect to CPU power domain, the CPU power domain can be controlled by
+  register EDPRCR in driver. The driver firstly writes bit EDPRCR.COREPURQ
+  to power up the CPU, and then writes bit EDPRCR.CORENPDRQ for emulation
+  of CPU power down. As result, this can ensure the CPU power domain is
+  powered on properly during the period when access debug related registers;
+
+- Some designs will power down an entire cluster if all CPUs on the cluster
+  are powered down - including the parts of the debug registers that should
+  remain powered in the debug power domain. The bits in EDPRCR are not
+  respected in these cases, so these designs do not support debug over
+  power down in the way that the CoreSight / Debug designers anticipated.
+  This means that even checking EDPRSR has the potential to cause a bus hang
+  if the target register is unpowered.
+
+  In this case, accessing to the debug registers while they are not powered
+  is a recipe for disaster; so we need preventing CPU low power states at boot
+  time or when user enable module at the run time. Please see chapter
+  "How to use the module" for detailed usage info for this.
+
+
+Device Tree Bindings
+--------------------
+
+See Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt for details.
+
+
+How to use the module
+---------------------
+
+If you want to enable debugging functionality at boot time, you can add
+"coresight_cpu_debug.enable=1" to the kernel command line parameter.
+
+The driver also can work as module, so can enable the debugging when insmod
+module::
+
+  # insmod coresight_cpu_debug.ko debug=1
+
+When boot time or insmod module you have not enabled the debugging, the driver
+uses the debugfs file system to provide a knob to dynamically enable or disable
+debugging:
+
+To enable it, write a '1' into /sys/kernel/debug/coresight_cpu_debug/enable::
+
+  # echo 1 > /sys/kernel/debug/coresight_cpu_debug/enable
+
+To disable it, write a '0' into /sys/kernel/debug/coresight_cpu_debug/enable::
+
+  # echo 0 > /sys/kernel/debug/coresight_cpu_debug/enable
+
+As explained in chapter "Clock and power domain", if you are working on one
+platform which has idle states to power off debug logic and the power
+controller cannot work well for the request from EDPRCR, then you should
+firstly constraint CPU idle states before enable CPU debugging feature; so can
+ensure the accessing to debug logic.
+
+If you want to limit idle states at boot time, you can use "nohlt" or
+"cpuidle.off=1" in the kernel command line.
+
+At the runtime you can disable idle states with below methods:
+
+It is possible to disable CPU idle states by way of the PM QoS
+subsystem, more specifically by using the "/dev/cpu_dma_latency"
+interface (see Documentation/power/pm_qos_interface.rst for more
+details).  As specified in the PM QoS documentation the requested
+parameter will stay in effect until the file descriptor is released.
+For example::
+
+  # exec 3<> /dev/cpu_dma_latency; echo 0 >&3
+  ...
+  Do some work...
+  ...
+  # exec 3<>-
+
+The same can also be done from an application program.
+
+Disable specific CPU's specific idle state from cpuidle sysfs (see
+Documentation/admin-guide/pm/cpuidle.rst)::
+
+  # echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable
+
+Output format
+-------------
+
+Here is an example of the debugging output format::
+
+  ARM external debug module:
+  coresight-cpu-debug 850000.debug: CPU[0]:
+  coresight-cpu-debug 850000.debug:  EDPRSR:  00000001 (Power:On DLK:Unlock)
+  coresight-cpu-debug 850000.debug:  EDPCSR:  handle_IPI+0x174/0x1d8
+  coresight-cpu-debug 850000.debug:  EDCIDSR: 00000000
+  coresight-cpu-debug 850000.debug:  EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
+  coresight-cpu-debug 852000.debug: CPU[1]:
+  coresight-cpu-debug 852000.debug:  EDPRSR:  00000001 (Power:On DLK:Unlock)
+  coresight-cpu-debug 852000.debug:  EDPCSR:  debug_notifier_call+0x23c/0x358
+  coresight-cpu-debug 852000.debug:  EDCIDSR: 00000000
+  coresight-cpu-debug 852000.debug:  EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
diff --git a/Documentation/trace/coresight/coresight-etm4x-reference.rst b/Documentation/trace/coresight/coresight-etm4x-reference.rst
new file mode 100644 (file)
index 0000000..b64d9a9
--- /dev/null
@@ -0,0 +1,798 @@
+===============================================
+ETMv4 sysfs linux driver programming reference.
+===============================================
+
+    :Author:   Mike Leach <mike.leach@linaro.org>
+    :Date:     October 11th, 2019
+
+Supplement to existing ETMv4 driver documentation.
+
+Sysfs files and directories
+---------------------------
+
+Root: ``/sys/bus/coresight/devices/etm<N>``
+
+
+The following paragraphs explain the association between sysfs files and the
+ETMv4 registers that they effect. Note the register names are given without
+the ‘TRC’ prefix.
+
+----
+
+:File:            ``mode`` (rw)
+:Trace Registers: {CONFIGR + others}
+:Notes:
+    Bit select trace features. See ‘mode’ section below. Bits
+    in this will cause equivalent programming of trace config and
+    other registers to enable the features requested.
+
+:Syntax & eg:
+    ``echo bitfield > mode``
+
+    bitfield up to 32 bits setting trace features.
+
+:Example:
+    ``$> echo 0x012 > mode``
+
+----
+
+:File:            ``reset`` (wo)
+:Trace Registers: All
+:Notes:
+    Reset all programming to trace nothing / no logic programmed.
+
+:Syntax:
+    ``echo 1 > reset``
+
+----
+
+:File:            ``enable_source`` (wo)
+:Trace Registers: PRGCTLR, All hardware regs.
+:Notes:
+    - > 0 : Programs up the hardware with the current values held in the driver
+      and enables trace.
+
+    - = 0 : disable trace hardware.
+
+:Syntax:
+    ``echo 1 > enable_source``
+
+----
+
+:File:            ``cpu`` (ro)
+:Trace Registers: None.
+:Notes:
+    CPU ID that this ETM is attached to.
+
+:Example:
+    ``$> cat cpu``
+
+    ``$> 0``
+
+----
+
+:File:            ``addr_idx`` (rw)
+:Trace Registers: None.
+:Notes:
+    Virtual register to index address comparator and range
+    features. Set index for first of the pair in a range.
+
+:Syntax:
+    ``echo idx > addr_idx``
+
+    Where idx < nr_addr_cmp x 2
+
+----
+
+:File:            ``addr_range`` (rw)
+:Trace Registers: ACVR[idx, idx+1], VIIECTLR
+:Notes:
+    Pair of addresses for a range selected by addr_idx. Include
+    / exclude according to the optional parameter, or if omitted
+    uses the current ‘mode’ setting. Select comparator range in
+    control register. Error if index is odd value.
+
+:Depends: ``mode, addr_idx``
+:Syntax:
+   ``echo addr1 addr2 [exclude] > addr_range``
+
+   Where addr1 and addr2 define the range and addr1 < addr2.
+
+   Optional exclude value:-
+
+   - 0 for include
+   - 1 for exclude.
+:Example:
+   ``$> echo 0x0000 0x2000 0 > addr_range``
+
+----
+
+:File:            ``addr_single`` (rw)
+:Trace Registers: ACVR[idx]
+:Notes:
+    Set a single address comparator according to addr_idx. This
+    is used if the address comparator is used as part of event
+    generation logic etc.
+
+:Depends: ``addr_idx``
+:Syntax:
+   ``echo addr1 > addr_single``
+
+----
+
+:File:           ``addr_start`` (rw)
+:Trace Registers: ACVR[idx], VISSCTLR
+:Notes:
+    Set a trace start address comparator according to addr_idx.
+    Select comparator in control register.
+
+:Depends: ``addr_idx``
+:Syntax:
+    ``echo addr1 > addr_start``
+
+----
+
+:File:            ``addr_stop`` (rw)
+:Trace Registers: ACVR[idx], VISSCTLR
+:Notes:
+    Set a trace stop address comparator according to addr_idx.
+    Select comparator in control register.
+
+:Depends: ``addr_idx``
+:Syntax:
+    ``echo addr1 > addr_stop``
+
+----
+
+:File:            ``addr_context`` (rw)
+:Trace Registers: ACATR[idx,{6:4}]
+:Notes:
+    Link context ID comparator to address comparator addr_idx
+
+:Depends: ``addr_idx``
+:Syntax:
+    ``echo ctxt_idx > addr_context``
+
+    Where ctxt_idx is the index of the linked context id / vmid
+    comparator.
+
+----
+
+:File:            ``addr_ctxtype`` (rw)
+:Trace Registers: ACATR[idx,{3:2}]
+:Notes:
+    Input value string. Set type for linked context ID comparator
+
+:Depends: ``addr_idx``
+:Syntax:
+    ``echo type > addr_ctxtype``
+
+    Type one of {all, vmid, ctxid, none}
+:Example:
+    ``$> echo ctxid > addr_ctxtype``
+
+----
+
+:File:            ``addr_exlevel_s_ns`` (rw)
+:Trace Registers: ACATR[idx,{14:8}]
+:Notes:
+    Set the ELx secure and non-secure matching bits for the
+    selected address comparator
+
+:Depends: ``addr_idx``
+:Syntax:
+    ``echo val > addr_exlevel_s_ns``
+
+    val is a 7 bit value for exception levels to exclude. Input
+    value shifted to correct bits in register.
+:Example:
+    ``$> echo 0x4F > addr_exlevel_s_ns``
+
+----
+
+:File:            ``addr_instdatatype`` (rw)
+:Trace Registers: ACATR[idx,{1:0}]
+:Notes:
+    Set the comparator address type for matching. Driver only
+    supports setting instruction address type.
+
+:Depends: ``addr_idx``
+
+----
+
+:File:            ``addr_cmp_view`` (ro)
+:Trace Registers: ACVR[idx, idx+1], ACATR[idx], VIIECTLR
+:Notes:
+    Read the currently selected address comparator. If part of
+    address range then display both addresses.
+
+:Depends: ``addr_idx``
+:Syntax:
+    ``cat addr_cmp_view``
+:Example:
+    ``$> cat addr_cmp_view``
+
+   ``addr_cmp[0] range 0x0 0xffffffffffffffff include ctrl(0x4b00)``
+
+----
+
+:File:            ``nr_addr_cmp`` (ro)
+:Trace Registers: From IDR4
+:Notes:
+    Number of address comparator pairs
+
+----
+
+:File:            ``sshot_idx`` (rw)
+:Trace Registers: None
+:Notes:
+    Select single shot register set.
+
+----
+
+:File:            ``sshot_ctrl`` (rw)
+:Trace Registers: SSCCR[idx]
+:Notes:
+    Access a single shot comparator control register.
+
+:Depends: ``sshot_idx``
+:Syntax:
+    ``echo val > sshot_ctrl``
+
+    Writes val into the selected control register.
+
+----
+
+:File:            ``sshot_status`` (ro)
+:Trace Registers: SSCSR[idx]
+:Notes:
+    Read a single shot comparator status register
+
+:Depends: ``sshot_idx``
+:Syntax:
+    ``cat sshot_status``
+
+    Read status.
+:Example:
+    ``$> cat sshot_status``
+
+    ``0x1``
+
+----
+
+:File:            ``sshot_pe_ctrl`` (rw)
+:Trace Registers: SSPCICR[idx]
+:Notes:
+    Access a single shot PE comparator input control register.
+
+:Depends: ``sshot_idx``
+:Syntax:
+    ``echo val > sshot_pe_ctrl``
+
+    Writes val into the selected control register.
+
+----
+
+:File:            ``ns_exlevel_vinst`` (rw)
+:Trace Registers: VICTLR{23:20}
+:Notes:
+    Program non-secure exception level filters. Set / clear NS
+    exception filter bits. Setting ‘1’ excludes trace from the
+    exception level.
+
+:Syntax:
+    ``echo bitfield > ns_exlevel_viinst``
+
+    Where bitfield contains bits to set clear for EL0 to EL2
+:Example:
+    ``%> echo 0x4 > ns_exlevel_viinst``
+
+    Excludes EL2 NS trace.
+
+----
+
+:File:            ``vinst_pe_cmp_start_stop`` (rw)
+:Trace Registers: VIPCSSCTLR
+:Notes:
+    Access PE start stop comparator input control registers
+
+----
+
+:File:            ``bb_ctrl`` (rw)
+:Trace Registers: BBCTLR
+:Notes:
+    Define ranges that Branch Broadcast will operate in.
+    Default (0x0) is all addresses.
+
+:Depends: BB enabled.
+
+----
+
+:File:            ``cyc_threshold`` (rw)
+:Trace Registers: CCCTLR
+:Notes:
+    Set the threshold for which cycle counts will be emitted.
+    Error if attempt to set below minimum defined in IDR3, masked
+    to width of valid bits.
+
+:Depends: CC enabled.
+
+----
+
+:File:            ``syncfreq`` (rw)
+:Trace Registers: SYNCPR
+:Notes:
+    Set trace synchronisation period. Power of 2 value, 0 (off)
+    or 8-20. Driver defaults to 12 (every 4096 bytes).
+
+----
+
+:File:            ``cntr_idx`` (rw)
+:Trace Registers: none
+:Notes:
+    Select the counter to access
+
+:Syntax:
+    ``echo idx > cntr_idx``
+
+    Where idx < nr_cntr
+
+----
+
+:File:            ``cntr_ctrl`` (rw)
+:Trace Registers: CNTCTLR[idx]
+:Notes:
+    Set counter control value.
+
+:Depends: ``cntr_idx``
+:Syntax:
+    ``echo val > cntr_ctrl``
+
+    Where val is per ETMv4 spec.
+
+----
+
+:File:            ``cntrldvr`` (rw)
+:Trace Registers: CNTRLDVR[idx]
+:Notes:
+    Set counter reload value.
+
+:Depends: ``cntr_idx``
+:Syntax:
+    ``echo val > cntrldvr``
+
+    Where val is per ETMv4 spec.
+
+----
+
+:File:            ``nr_cntr`` (ro)
+:Trace Registers: From IDR5
+
+:Notes:
+    Number of counters implemented.
+
+----
+
+:File:            ``ctxid_idx`` (rw)
+:Trace Registers: None
+:Notes:
+    Select the context ID comparator to access
+
+:Syntax:
+    ``echo idx > ctxid_idx``
+
+    Where idx < numcidc
+
+----
+
+:File:            ``ctxid_pid`` (rw)
+:Trace Registers: CIDCVR[idx]
+:Notes:
+   Set the context ID comparator value
+
+:Depends: ``ctxid_idx``
+
+----
+
+:File: ``ctxid_masks`` (rw)
+:Trace Registers: CIDCCTLR0, CIDCCTLR1, CIDCVR<0-7>
+:Notes:
+    Pair of values to set the byte masks for 1-8 context ID
+    comparators. Automatically clears masked bytes to 0 in CID
+    value registers.
+
+:Syntax:
+    ``echo m3m2m1m0 [m7m6m5m4] > ctxid_masks``
+
+    32 bit values made up of mask bytes, where mN represents a
+    byte mask value for Context ID comparator N.
+
+    Second value not required on systems that have fewer than 4
+    context ID comparators
+
+----
+
+:File:            ``numcidc`` (ro)
+:Trace Registers: From IDR4
+:Notes:
+    Number of Context ID comparators
+
+----
+
+:File:            ``vmid_idx`` (rw)
+:Trace Registers: None
+:Notes:
+    Select the VM ID comparator to access.
+
+:Syntax:
+    ``echo idx > vmid_idx``
+
+    Where idx <  numvmidc
+
+----
+
+:File:            ``vmid_val`` (rw)
+:Trace Registers: VMIDCVR[idx]
+:Notes:
+    Set the VM ID comparator value
+
+:Depends: ``vmid_idx``
+
+----
+
+:File:            ``vmid_masks`` (rw)
+:Trace Registers: VMIDCCTLR0, VMIDCCTLR1, VMIDCVR<0-7>
+:Notes:
+    Pair of values to set the byte masks for 1-8 VM ID comparators.
+    Automatically clears masked bytes to 0 in VMID value registers.
+
+:Syntax:
+    ``echo m3m2m1m0 [m7m6m5m4] > vmid_masks``
+
+    Where mN represents a byte mask value for VMID comparator N.
+    Second value not required on systems that have fewer than 4
+    VMID comparators.
+
+----
+
+:File:            ``numvmidc`` (ro)
+:Trace Registers: From IDR4
+:Notes:
+    Number of VMID comparators
+
+----
+
+:File:            ``res_idx`` (rw)
+:Trace Registers: None.
+:Notes:
+    Select the resource selector control to access. Must be 2 or
+    higher as selectors 0 and 1 are hardwired.
+
+:Syntax:
+    ``echo idx > res_idx``
+
+    Where 2 <= idx < nr_resource x 2
+
+----
+
+:File:            ``res_ctrl`` (rw)
+:Trace Registers: RSCTLR[idx]
+:Notes:
+    Set resource selector control value. Value per ETMv4 spec.
+
+:Depends: ``res_idx``
+:Syntax:
+    ``echo val > res_cntr``
+
+    Where val is per ETMv4 spec.
+
+----
+
+:File:            ``nr_resource`` (ro)
+:Trace Registers: From IDR4
+:Notes:
+    Number of resource selector pairs
+
+----
+
+:File:            ``event`` (rw)
+:Trace Registers: EVENTCTRL0R
+:Notes:
+    Set up to 4 implemented event fields.
+
+:Syntax:
+    ``echo ev3ev2ev1ev0 > event``
+
+    Where evN is an 8 bit event field. Up to 4 event fields make up the
+    32-bit input value. Number of valid fields is implementation dependent,
+    defined in IDR0.
+
+----
+
+:File: ``event_instren`` (rw)
+:Trace Registers: EVENTCTRL1R
+:Notes:
+    Choose events which insert event packets into trace stream.
+
+:Depends: EVENTCTRL0R
+:Syntax:
+    ``echo bitfield > event_instren``
+
+    Where bitfield is up to 4 bits according to number of event fields.
+
+----
+
+:File:            ``event_ts`` (rw)
+:Trace Registers: TSCTLR
+:Notes:
+    Set the event that will generate timestamp requests.
+
+:Depends: ``TS activated``
+:Syntax:
+    ``echo evfield > event_ts``
+
+    Where evfield is an 8 bit event selector.
+
+----
+
+:File:            ``seq_idx`` (rw)
+:Trace Registers: None
+:Notes:
+    Sequencer event register select - 0 to 2
+
+----
+
+:File:            ``seq_state`` (rw)
+:Trace Registers: SEQSTR
+:Notes:
+    Sequencer current state - 0 to 3.
+
+----
+
+:File:            ``seq_event`` (rw)
+:Trace Registers: SEQEVR[idx]
+:Notes:
+    State transition event registers
+
+:Depends: ``seq_idx``
+:Syntax:
+    ``echo evBevF > seq_event``
+
+    Where evBevF is a 16 bit value made up of two event selectors,
+
+    - evB : back
+    - evF : forwards.
+
+----
+
+:File:            ``seq_reset_event`` (rw)
+:Trace Registers: SEQRSTEVR
+:Notes:
+    Sequencer reset event
+
+:Syntax:
+    ``echo evfield > seq_reset_event``
+
+    Where evfield is an 8 bit event selector.
+
+----
+
+:File:            ``nrseqstate`` (ro)
+:Trace Registers: From IDR5
+:Notes:
+    Number of sequencer states (0 or 4)
+
+----
+
+:File:            ``nr_pe_cmp`` (ro)
+:Trace Registers: From IDR4
+:Notes:
+    Number of PE comparator inputs
+
+----
+
+:File:            ``nr_ext_inp`` (ro)
+:Trace Registers: From IDR5
+:Notes:
+    Number of external inputs
+
+----
+
+:File:            ``nr_ss_cmp`` (ro)
+:Trace Registers: From IDR4
+:Notes:
+    Number of Single Shot control registers
+
+----
+
+*Note:* When programming any address comparator the driver will tag the
+comparator with a type used - i.e. RANGE, SINGLE, START, STOP. Once this tag
+is set, then only the values can be changed using the same sysfs file / type
+used to program it.
+
+Thus::
+
+  % echo 0 > addr_idx          ; select address comparator 0
+  % echo 0x1000 0x5000 0 > addr_range ; set address range on comparators 0, 1.
+  % echo 0x2000 > addr_start    ; error as comparator 0 is a range comparator
+  % echo 2 > addr_idx          ; select address comparator 2
+  % echo 0x2000 > addr_start   ; this is OK as comparator 2 is unused.
+  % echo 0x3000 > addr_stop    ; error as comparator 2 set as start address.
+  % echo 2 > addr_idx          ; select address comparator 3
+  % echo 0x3000 > addr_stop    ; this is OK
+
+To remove programming on all the comparators (and all the other hardware) use
+the reset parameter::
+
+  % echo 1 > reset
+
+
+
+The ‘mode’ sysfs parameter.
+---------------------------
+
+This is a bitfield selection parameter that sets the overall trace mode for the
+ETM. The table below describes the bits, using the defines from the driver
+source file, along with a description of the feature these represent. Many
+features are optional and therefore dependent on implementation in the
+hardware.
+
+Bit assignments shown below:-
+
+----
+
+**bit (0):**
+    ETM_MODE_EXCLUDE
+
+**description:**
+    This is the default value for the include / exclude function when
+    setting address ranges. Set 1 for exclude range. When the mode
+    parameter is set this value is applied to the currently indexed
+    address range.
+
+
+**bit (4):**
+    ETM_MODE_BB
+
+**description:**
+    Set to enable branch broadcast if supported in hardware [IDR0].
+
+
+**bit (5):**
+    ETMv4_MODE_CYCACC
+
+**description:**
+    Set to enable cycle accurate trace if supported [IDR0].
+
+
+**bit (6):**
+    ETMv4_MODE_CTXID
+
+**description:**
+    Set to enable context ID tracing if supported in hardware [IDR2].
+
+
+**bit (7):**
+    ETM_MODE_VMID
+
+**description:**
+    Set to enable virtual machine ID tracing if supported [IDR2].
+
+
+**bit (11):**
+    ETMv4_MODE_TIMESTAMP
+
+**description:**
+    Set to enable timestamp generation if supported [IDR0].
+
+
+**bit (12):**
+    ETM_MODE_RETURNSTACK
+**description:**
+    Set to enable trace return stack use if supported [IDR0].
+
+
+**bit (13-14):**
+    ETM_MODE_QELEM(val)
+
+**description:**
+    ‘val’ determines level of Q element support enabled if
+    implemented by the ETM [IDR0]
+
+
+**bit (19):**
+    ETM_MODE_ATB_TRIGGER
+
+**description:**
+    Set to enable the ATBTRIGGER bit in the event control register
+    [EVENTCTLR1] if supported [IDR5].
+
+
+**bit (20):**
+    ETM_MODE_LPOVERRIDE
+
+**description:**
+    Set to enable the LPOVERRIDE bit in the event control register
+    [EVENTCTLR1], if supported [IDR5].
+
+
+**bit (21):**
+    ETM_MODE_ISTALL_EN
+
+**description:**
+    Set to enable the ISTALL bit in the stall control register
+    [STALLCTLR]
+
+
+**bit (23):**
+    ETM_MODE_INSTPRIO
+
+**description:**
+             Set to enable the INSTPRIORITY bit in the stall control register
+             [STALLCTLR] , if supported [IDR0].
+
+
+**bit (24):**
+    ETM_MODE_NOOVERFLOW
+
+**description:**
+    Set to enable the NOOVERFLOW bit in the stall control register
+    [STALLCTLR], if supported [IDR3].
+
+
+**bit (25):**
+    ETM_MODE_TRACE_RESET
+
+**description:**
+    Set to enable the TRCRESET bit in the viewinst control register
+    [VICTLR] , if supported [IDR3].
+
+
+**bit (26):**
+    ETM_MODE_TRACE_ERR
+
+**description:**
+    Set to enable the TRCCTRL bit in the viewinst control register
+    [VICTLR].
+
+
+**bit (27):**
+    ETM_MODE_VIEWINST_STARTSTOP
+
+**description:**
+    Set the initial state value of the ViewInst start / stop logic
+    in the viewinst control register [VICTLR]
+
+
+**bit (30):**
+    ETM_MODE_EXCL_KERN
+
+**description:**
+    Set default trace setup to exclude kernel mode trace (see note a)
+
+
+**bit (31):**
+    ETM_MODE_EXCL_USER
+
+**description:**
+    Set default trace setup to exclude user space trace (see note a)
+
+----
+
+*Note a)* On startup the ETM is programmed to trace the complete address space
+using address range comparator 0. ‘mode’ bits 30 / 31 modify this setting to
+set EL exclude bits for NS state in either user space (EL0) or kernel space
+(EL1) in the address range comparator. (the default setting excludes all
+secure EL, and NS EL2)
+
+Once the reset parameter has been used, and/or custom programming has been
+implemented - using these bits will result in the EL bits for address
+comparator 0 being set in the same way.
+
+*Note b)* Bits 2-3, 8-10, 15-16, 18, 22, control features that only work with
+data trace. As A-profile data trace is architecturally prohibited in ETMv4,
+these have been omitted here. Possible uses could be where a kernel has
+support for control of R or M profile infrastructure as part of a heterogeneous
+system.
+
+Bits 17, 28-29 are unused.
diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst
new file mode 100644 (file)
index 0000000..a566719
--- /dev/null
@@ -0,0 +1,498 @@
+======================================
+Coresight - HW Assisted Tracing on ARM
+======================================
+
+   :Author:   Mathieu Poirier <mathieu.poirier@linaro.org>
+   :Date:     September 11th, 2014
+
+Introduction
+------------
+
+Coresight is an umbrella of technologies allowing for the debugging of ARM
+based SoC.  It includes solutions for JTAG and HW assisted tracing.  This
+document is concerned with the latter.
+
+HW assisted tracing is becoming increasingly useful when dealing with systems
+that have many SoCs and other components like GPU and DMA engines.  ARM has
+developed a HW assisted tracing solution by means of different components, each
+being added to a design at synthesis time to cater to specific tracing needs.
+Components are generally categorised as source, link and sinks and are
+(usually) discovered using the AMBA bus.
+
+"Sources" generate a compressed stream representing the processor instruction
+path based on tracing scenarios as configured by users.  From there the stream
+flows through the coresight system (via ATB bus) using links that are connecting
+the emanating source to a sink(s).  Sinks serve as endpoints to the coresight
+implementation, either storing the compressed stream in a memory buffer or
+creating an interface to the outside world where data can be transferred to a
+host without fear of filling up the onboard coresight memory buffer.
+
+At typical coresight system would look like this::
+
+  *****************************************************************
+ **************************** AMBA AXI  ****************************===||
+  *****************************************************************    ||
+        ^                    ^                            |            ||
+        |                    |                            *            **
+     0000000    :::::     0000000    :::::    :::::    @@@@@@@    ||||||||||||
+     0 CPU 0<-->: C :     0 CPU 0<-->: C :    : C :    @ STM @    || System ||
+  |->0000000    : T :  |->0000000    : T :    : T :<--->@@@@@     || Memory ||
+  |  #######<-->: I :  |  #######<-->: I :    : I :      @@@<-|   ||||||||||||
+  |  # ETM #    :::::  |  # PTM #    :::::    :::::       @   |
+  |   #####      ^ ^   |   #####      ^ !      ^ !        .   |   |||||||||
+  | |->###       | !   | |->###       | !      | !        .   |   || DAP ||
+  | |   #        | !   | |   #        | !      | !        .   |   |||||||||
+  | |   .        | !   | |   .        | !      | !        .   |      |  |
+  | |   .        | !   | |   .        | !      | !        .   |      |  *
+  | |   .        | !   | |   .        | !      | !        .   |      | SWD/
+  | |   .        | !   | |   .        | !      | !        .   |      | JTAG
+  *****************************************************************<-|
+ *************************** AMBA Debug APB ************************
+  *****************************************************************
+   |    .          !         .          !        !        .    |
+   |    .          *         .          *        *        .    |
+  *****************************************************************
+ ******************** Cross Trigger Matrix (CTM) *******************
+  *****************************************************************
+   |    .     ^              .                            .    |
+   |    *     !              *                            *    |
+  *****************************************************************
+ ****************** AMBA Advanced Trace Bus (ATB) ******************
+  *****************************************************************
+   |          !                        ===============         |
+   |          *                         ===== F =====<---------|
+   |   :::::::::                         ==== U ====
+   |-->:: CTI ::<!!                       === N ===
+   |   :::::::::  !                        == N ==
+   |    ^         *                        == E ==
+   |    !  &&&&&&&&&       IIIIIII         == L ==
+   |------>&& ETB &&<......II     I        =======
+   |    !  &&&&&&&&&       II     I           .
+   |    !                    I     I          .
+   |    !                    I REP I<..........
+   |    !                    I     I
+   |    !!>&&&&&&&&&       II     I           *Source: ARM ltd.
+   |------>& TPIU  &<......II    I            DAP = Debug Access Port
+           &&&&&&&&&       IIIIIII            ETM = Embedded Trace Macrocell
+               ;                              PTM = Program Trace Macrocell
+               ;                              CTI = Cross Trigger Interface
+               *                              ETB = Embedded Trace Buffer
+          To trace port                       TPIU= Trace Port Interface Unit
+                                              SWD = Serial Wire Debug
+
+While on target configuration of the components is done via the APB bus,
+all trace data are carried out-of-band on the ATB bus.  The CTM provides
+a way to aggregate and distribute signals between CoreSight components.
+
+The coresight framework provides a central point to represent, configure and
+manage coresight devices on a platform.  This first implementation centers on
+the basic tracing functionality, enabling components such ETM/PTM, funnel,
+replicator, TMC, TPIU and ETB.  Future work will enable more
+intricate IP blocks such as STM and CTI.
+
+
+Acronyms and Classification
+---------------------------
+
+Acronyms:
+
+PTM:
+    Program Trace Macrocell
+ETM:
+    Embedded Trace Macrocell
+STM:
+    System trace Macrocell
+ETB:
+    Embedded Trace Buffer
+ITM:
+    Instrumentation Trace Macrocell
+TPIU:
+     Trace Port Interface Unit
+TMC-ETR:
+        Trace Memory Controller, configured as Embedded Trace Router
+TMC-ETF:
+        Trace Memory Controller, configured as Embedded Trace FIFO
+CTI:
+    Cross Trigger Interface
+
+Classification:
+
+Source:
+   ETMv3.x ETMv4, PTMv1.0, PTMv1.1, STM, STM500, ITM
+Link:
+   Funnel, replicator (intelligent or not), TMC-ETR
+Sinks:
+   ETBv1.0, ETB1.1, TPIU, TMC-ETF
+Misc:
+   CTI
+
+
+Device Tree Bindings
+--------------------
+
+See Documentation/devicetree/bindings/arm/coresight.txt for details.
+
+As of this writing drivers for ITM, STMs and CTIs are not provided but are
+expected to be added as the solution matures.
+
+
+Framework and implementation
+----------------------------
+
+The coresight framework provides a central point to represent, configure and
+manage coresight devices on a platform.  Any coresight compliant device can
+register with the framework for as long as they use the right APIs:
+
+.. c:function:: struct coresight_device *coresight_register(struct coresight_desc *desc);
+.. c:function:: void coresight_unregister(struct coresight_device *csdev);
+
+The registering function is taking a ``struct coresight_desc *desc`` and
+register the device with the core framework. The unregister function takes
+a reference to a ``struct coresight_device *csdev`` obtained at registration time.
+
+If everything goes well during the registration process the new devices will
+show up under /sys/bus/coresight/devices, as showns here for a TC2 platform::
+
+    root:~# ls /sys/bus/coresight/devices/
+    replicator  20030000.tpiu    2201c000.ptm  2203c000.etm  2203e000.etm
+    20010000.etb         20040000.funnel  2201d000.ptm  2203d000.etm
+    root:~#
+
+The functions take a ``struct coresight_device``, which looks like this::
+
+    struct coresight_desc {
+            enum coresight_dev_type type;
+            struct coresight_dev_subtype subtype;
+            const struct coresight_ops *ops;
+            struct coresight_platform_data *pdata;
+            struct device *dev;
+            const struct attribute_group **groups;
+    };
+
+
+The "coresight_dev_type" identifies what the device is, i.e, source link or
+sink while the "coresight_dev_subtype" will characterise that type further.
+
+The ``struct coresight_ops`` is mandatory and will tell the framework how to
+perform base operations related to the components, each component having
+a different set of requirement. For that ``struct coresight_ops_sink``,
+``struct coresight_ops_link`` and ``struct coresight_ops_source`` have been
+provided.
+
+The next field ``struct coresight_platform_data *pdata`` is acquired by calling
+``of_get_coresight_platform_data()``, as part of the driver's _probe routine and
+``struct device *dev`` gets the device reference embedded in the ``amba_device``::
+
+    static int etm_probe(struct amba_device *adev, const struct amba_id *id)
+    {
+     ...
+     ...
+     drvdata->dev = &adev->dev;
+     ...
+    }
+
+Specific class of device (source, link, or sink) have generic operations
+that can be performed on them (see ``struct coresight_ops``). The ``**groups``
+is a list of sysfs entries pertaining to operations
+specific to that component only.  "Implementation defined" customisations are
+expected to be accessed and controlled using those entries.
+
+Device Naming scheme
+--------------------
+
+The devices that appear on the "coresight" bus were named the same as their
+parent devices, i.e, the real devices that appears on AMBA bus or the platform bus.
+Thus the names were based on the Linux Open Firmware layer naming convention,
+which follows the base physical address of the device followed by the device
+type. e.g::
+
+    root:~# ls /sys/bus/coresight/devices/
+     20010000.etf  20040000.funnel      20100000.stm     22040000.etm
+     22140000.etm  230c0000.funnel      23240000.etm     20030000.tpiu
+     20070000.etr  20120000.replicator  220c0000.funnel
+     23040000.etm  23140000.etm         23340000.etm
+
+However, with the introduction of ACPI support, the names of the real
+devices are a bit cryptic and non-obvious. Thus, a new naming scheme was
+introduced to use more generic names based on the type of the device. The
+following rules apply::
+
+  1) Devices that are bound to CPUs, are named based on the CPU logical
+     number.
+
+     e.g, ETM bound to CPU0 is named "etm0"
+
+  2) All other devices follow a pattern, "<device_type_prefix>N", where :
+
+       <device_type_prefix>    - A prefix specific to the type of the device
+       N                       - a sequential number assigned based on the order
+                                 of probing.
+
+       e.g, tmc_etf0, tmc_etr0, funnel0, funnel1
+
+Thus, with the new scheme the devices could appear as ::
+
+    root:~# ls /sys/bus/coresight/devices/
+     etm0     etm1     etm2         etm3  etm4      etm5      funnel0
+     funnel1  funnel2  replicator0  stm0  tmc_etf0  tmc_etr0  tpiu0
+
+Some of the examples below might refer to old naming scheme and some
+to the newer scheme, to give a confirmation that what you see on your
+system is not unexpected. One must use the "names" as they appear on
+the system under specified locations.
+
+How to use the tracer modules
+-----------------------------
+
+There are two ways to use the Coresight framework:
+
+1. using the perf cmd line tools.
+2. interacting directly with the Coresight devices using the sysFS interface.
+
+Preference is given to the former as using the sysFS interface
+requires a deep understanding of the Coresight HW.  The following sections
+provide details on using both methods.
+
+1) Using the sysFS interface:
+
+Before trace collection can start, a coresight sink needs to be identified.
+There is no limit on the amount of sinks (nor sources) that can be enabled at
+any given moment.  As a generic operation, all device pertaining to the sink
+class will have an "active" entry in sysfs::
+
+    root:/sys/bus/coresight/devices# ls
+    replicator  20030000.tpiu    2201c000.ptm  2203c000.etm  2203e000.etm
+    20010000.etb         20040000.funnel  2201d000.ptm  2203d000.etm
+    root:/sys/bus/coresight/devices# ls 20010000.etb
+    enable_sink  status  trigger_cntr
+    root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink
+    root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink
+    1
+    root:/sys/bus/coresight/devices#
+
+At boot time the current etm3x driver will configure the first address
+comparator with "_stext" and "_etext", essentially tracing any instruction
+that falls within that range.  As such "enabling" a source will immediately
+trigger a trace capture::
+
+    root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source
+    root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source
+    1
+    root:/sys/bus/coresight/devices# cat 20010000.etb/status
+    Depth:          0x2000
+    Status:         0x1
+    RAM read ptr:   0x0
+    RAM wrt ptr:    0x19d3   <----- The write pointer is moving
+    Trigger cnt:    0x0
+    Control:        0x1
+    Flush status:   0x0
+    Flush ctrl:     0x2001
+    root:/sys/bus/coresight/devices#
+
+Trace collection is stopped the same way::
+
+    root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source
+    root:/sys/bus/coresight/devices#
+
+The content of the ETB buffer can be harvested directly from /dev::
+
+    root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \
+    of=~/cstrace.bin
+    64+0 records in
+    64+0 records out
+    32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s
+    root:/sys/bus/coresight/devices#
+
+The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32.
+
+Following is a DS-5 output of an experimental loop that increments a variable up
+to a certain value.  The example is simple and yet provides a glimpse of the
+wealth of possibilities that coresight provides.
+::
+
+    Info                                    Tracing enabled
+    Instruction     106378866       0x8026B53C      E52DE004        false   PUSH     {lr}
+    Instruction     0       0x8026B540      E24DD00C        false   SUB      sp,sp,#0xc
+    Instruction     0       0x8026B544      E3A03000        false   MOV      r3,#0
+    Instruction     0       0x8026B548      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
+    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
+    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
+    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
+    Timestamp                                       Timestamp: 17106715833
+    Instruction     319     0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
+    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
+    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
+    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
+    Instruction     9       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
+    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
+    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
+    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
+    Instruction     7       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
+    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
+    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
+    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
+    Instruction     7       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
+    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
+    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
+    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
+    Instruction     10      0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
+    Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
+    Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
+    Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
+    Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
+    Instruction     6       0x8026B560      EE1D3F30        false   MRC      p15,#0x0,r3,c13,c0,#1
+    Instruction     0       0x8026B564      E1A0100D        false   MOV      r1,sp
+    Instruction     0       0x8026B568      E3C12D7F        false   BIC      r2,r1,#0x1fc0
+    Instruction     0       0x8026B56C      E3C2203F        false   BIC      r2,r2,#0x3f
+    Instruction     0       0x8026B570      E59D1004        false   LDR      r1,[sp,#4]
+    Instruction     0       0x8026B574      E59F0010        false   LDR      r0,[pc,#16] ; [0x8026B58C] = 0x80550368
+    Instruction     0       0x8026B578      E592200C        false   LDR      r2,[r2,#0xc]
+    Instruction     0       0x8026B57C      E59221D0        false   LDR      r2,[r2,#0x1d0]
+    Instruction     0       0x8026B580      EB07A4CF        true    BL       {pc}+0x1e9344 ; 0x804548c4
+    Info                                    Tracing enabled
+    Instruction     13570831        0x8026B584      E28DD00C        false   ADD      sp,sp,#0xc
+    Instruction     0       0x8026B588      E8BD8000        true    LDM      sp!,{pc}
+    Timestamp                                       Timestamp: 17107041535
+
+2) Using perf framework:
+
+Coresight tracers are represented using the Perf framework's Performance
+Monitoring Unit (PMU) abstraction.  As such the perf framework takes charge of
+controlling when tracing gets enabled based on when the process of interest is
+scheduled.  When configured in a system, Coresight PMUs will be listed when
+queried by the perf command line tool:
+
+       linaro@linaro-nano:~$ ./perf list pmu
+
+               List of pre-defined events (to be used in -e):
+
+               cs_etm//                                    [Kernel PMU event]
+
+       linaro@linaro-nano:~$
+
+Regardless of the number of tracers available in a system (usually equal to the
+amount of processor cores), the "cs_etm" PMU will be listed only once.
+
+A Coresight PMU works the same way as any other PMU, i.e the name of the PMU is
+listed along with configuration options within forward slashes '/'.  Since a
+Coresight system will typically have more than one sink, the name of the sink to
+work with needs to be specified as an event option.
+On newer kernels the available sinks are listed in sysFS under
+($SYSFS)/bus/event_source/devices/cs_etm/sinks/::
+
+       root@localhost:/sys/bus/event_source/devices/cs_etm/sinks# ls
+       tmc_etf0  tmc_etr0  tpiu0
+
+On older kernels, this may need to be found from the list of coresight devices,
+available under ($SYSFS)/bus/coresight/devices/::
+
+       root:~# ls /sys/bus/coresight/devices/
+        etm0     etm1     etm2         etm3  etm4      etm5      funnel0
+        funnel1  funnel2  replicator0  stm0  tmc_etf0  tmc_etr0  tpiu0
+       root@linaro-nano:~# perf record -e cs_etm/@tmc_etr0/u --per-thread program
+
+As mentioned above in section "Device Naming scheme", the names of the devices could
+look different from what is used in the example above. One must use the device names
+as it appears under the sysFS.
+
+The syntax within the forward slashes '/' is important.  The '@' character
+tells the parser that a sink is about to be specified and that this is the sink
+to use for the trace session.
+
+More information on the above and other example on how to use Coresight with
+the perf tools can be found in the "HOWTO.md" file of the openCSD gitHub
+repository [#third]_.
+
+2.1) AutoFDO analysis using the perf tools:
+
+perf can be used to record and analyze trace of programs.
+
+Execution can be recorded using 'perf record' with the cs_etm event,
+specifying the name of the sink to record to, e.g::
+
+    perf record -e cs_etm/@tmc_etr0/u --per-thread
+
+The 'perf report' and 'perf script' commands can be used to analyze execution,
+synthesizing instruction and branch events from the instruction trace.
+'perf inject' can be used to replace the trace data with the synthesized events.
+The --itrace option controls the type and frequency of synthesized events
+(see perf documentation).
+
+Note that only 64-bit programs are currently supported - further work is
+required to support instruction decode of 32-bit Arm programs.
+
+
+Generating coverage files for Feedback Directed Optimization: AutoFDO
+---------------------------------------------------------------------
+
+'perf inject' accepts the --itrace option in which case tracing data is
+removed and replaced with the synthesized events. e.g.
+::
+
+       perf inject --itrace --strip -i perf.data -o perf.data.new
+
+Below is an example of using ARM ETM for autoFDO.  It requires autofdo
+(https://github.com/google/autofdo) and gcc version 5.  The bubble
+sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial).
+::
+
+       $ gcc-5 -O3 sort.c -o sort
+       $ taskset -c 2 ./sort
+       Bubble sorting array of 30000 elements
+       5910 ms
+
+       $ perf record -e cs_etm/@tmc_etr0/u --per-thread taskset -c 2 ./sort
+       Bubble sorting array of 30000 elements
+       12543 ms
+       [ perf record: Woken up 35 times to write data ]
+       [ perf record: Captured and wrote 69.640 MB perf.data ]
+
+       $ perf inject -i perf.data -o inj.data --itrace=il64 --strip
+       $ create_gcov --binary=./sort --profile=inj.data --gcov=sort.gcov -gcov_version=1
+       $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo
+       $ taskset -c 2 ./sort_autofdo
+       Bubble sorting array of 30000 elements
+       5806 ms
+
+
+How to use the STM module
+-------------------------
+
+Using the System Trace Macrocell module is the same as the tracers - the only
+difference is that clients are driving the trace capture rather
+than the program flow through the code.
+
+As with any other CoreSight component, specifics about the STM tracer can be
+found in sysfs with more information on each entry being found in [#first]_::
+
+    root@genericarmv8:~# ls /sys/bus/coresight/devices/stm0
+    enable_source   hwevent_select  port_enable     subsystem       uevent
+    hwevent_enable  mgmt            port_select     traceid
+    root@genericarmv8:~#
+
+Like any other source a sink needs to be identified and the STM enabled before
+being used::
+
+    root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink
+    root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/stm0/enable_source
+
+From there user space applications can request and use channels using the devfs
+interface provided for that purpose by the generic STM API::
+
+    root@genericarmv8:~# ls -l /dev/stm0
+    crw-------    1 root     root       10,  61 Jan  3 18:11 /dev/stm0
+    root@genericarmv8:~#
+
+Details on how to use the generic STM API can be found here:- :doc:`../stm` [#second]_.
+
+.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
+
+.. [#second] Documentation/trace/stm.rst
+
+.. [#third] https://github.com/Linaro/perf-opencsd
diff --git a/Documentation/trace/coresight/index.rst b/Documentation/trace/coresight/index.rst
new file mode 100644 (file)
index 0000000..8d31b15
--- /dev/null
@@ -0,0 +1,9 @@
+==============================
+CoreSight - ARM Hardware Trace
+==============================
+
+.. toctree::
+   :maxdepth: 2
+   :glob:
+
+   *
index b7891cb..04acd27 100644 (file)
@@ -23,5 +23,4 @@ Linux Tracing Technologies
    intel_th
    stm
    sys-t
-   coresight
-   coresight-cpu-debug
+   coresight/index
index ed1121d..783e0de 100644 (file)
@@ -87,7 +87,6 @@ FF_MAGIC              0x4646           fc_info                  ``drivers/net/ip
 ISICOM_MAGIC          0x4d54           isi_port                 ``include/linux/isicom.h``
 PTY_MAGIC             0x5001                                    ``drivers/char/pty.c``
 PPP_MAGIC             0x5002           ppp                      ``include/linux/if_pppvar.h``
-SERIAL_MAGIC          0x5301           async_struct             ``include/linux/serial.h``
 SSTATE_MAGIC          0x5302           serial_state             ``include/linux/serial.h``
 SLIP_MAGIC            0x5302           slip                     ``drivers/net/slip.h``
 STRIP_MAGIC           0x5303           strip                    ``drivers/net/strip.c``
index 118fb41..f3c8e8d 100644 (file)
@@ -455,7 +455,7 @@ soluzioni disponibili:
   `GnuK`_ della FSIJ. Questo è uno dei pochi dispositivi a supportare le chiavi
   ECC ED25519, ma offre meno funzionalità di sicurezza (come la resistenza
   alla manomissione o alcuni attacchi ad un canale laterale).
-- `Nitrokey Pro`_: è simile alla Nitrokey Start, ma è più resistente alla
+- `Nitrokey Pro 2`_: è simile alla Nitrokey Start, ma è più resistente alla
   manomissione e offre più funzionalità di sicurezza. La Pro 2 supporta la
   crittografia ECC (NISTP).
 - `Yubikey 5`_: l'hardware e il software sono proprietari, ma è più economica
index b3f51b1..ae3ad89 100644 (file)
@@ -240,21 +240,21 @@ ReST 마크업을 사용하는 문서들은 Documentation/output 에 생성된
 서브시스템에 특화된 커널 브랜치들로 구성된다. 몇몇 다른 메인
 브랜치들은 다음과 같다.
 
-  - main 4.x 커널 트리
-  - 4.x.y - 안정된 커널 트리
-  - 서브시스템을 위한 커널 트리들과 패치들
-  - 4.x - 통합 테스트를 위한 next 커널 트리
+  - 리누스의 메인라인 트리
+  - 여러 메이저 넘버를 갖는 다양한 안정된 커널 트리들
+  - 서브시스템을 위한 커널 트리들
+  - 통합 테스트를 위한 linux-next 커널 트리
 
-4.x 커널 트리
+메인라인 트리
 ~~~~~~~~~~~~~
 
-4.x 커널들은 Linus Torvalds가 관리하며 https://kernel.org 의
-pub/linux/kernel/v4.x/ 디렉토리에서 참조될 수 있다.개발 프로세스는 다음과 같다.
+메인라인 트리는 Linus Torvalds가 관리하며 https://kernel.org  또는 소스
+저장소에서 참조될 수 있다.개발 프로세스는 다음과 같다.
 
   - 새로운 커널이 배포되자마자 2주의 시간이 주어진다. 이 기간동은
     메인테이너들은 큰 diff들을 Linus에게 제출할 수 있다. 대개 이 패치들은
-    몇 주 동안 -next 커널내에 이미 있었던 것들이다. 큰 변경들을 제출하는 데
-    선호되는 방법은  git(커널의 소스 관리 툴, 더 많은 정보들은
+    몇 주 동안 linux-next 커널내에 이미 있었던 것들이다. 큰 변경들을 제출하는
+    데 선호되는 방법은  git(커널의 소스 관리 툴, 더 많은 정보들은
     https://git-scm.com/ 에서 참조할 수 있다)를 사용하는 것이지만 순수한
     패치파일의 형식으로 보내는 것도 무관하다.
   - 2주 후에 -rc1 커널이 릴리즈되며 여기서부터의 주안점은 새로운 커널을
@@ -281,28 +281,25 @@ Andrew Morton의 글이 있다.
         버그의 상황에 따라 배포되는 것이지 미리정해 놓은 시간에 따라
         배포되는 것은 아니기 때문이다."*
 
-4.x.y - 안정 커널 트리
-~~~~~~~~~~~~~~~~~~~~~~
+여러 메이저 넘버를 갖는 다양한 안정된 커널 트리들
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-3 자리 숫자로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 4.x
-커널에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고 중요한 수정들을
-포함한다.
+3 자리 숫자로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 해당 메이저
+메인라인 릴리즈에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고 중요한
+수정들을 포함하며, 앞의 두 버전 넘버는 같은 기반 버전을 의미한다.
 
 이것은 가장 최근의 안정적인 커널을 원하는 사용자에게 추천되는 브랜치이며,
 개발/실험적 버젼을 테스트하는 것을 돕고자 하는 사용자들과는 별로 관련이 없다.
 
-어떤 4.x.y 커널도 사용할 수 없다면 그때는 가장 높은 숫자의 4.x
-커널이 현재의 안정 커널이다.
-
-4.x.y는 "stable" 팀<stable@vger.kernel.org>에 의해 관리되며 거의 매번 격주로
-배포된다.
+-stable 트리들은 "stable" 팀<stable@vger.kernel.org>에 의해 관리되며 거의 매번
+격주로 배포된다.
 
 커널 트리 문서들 내의 :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
 파일은 어떤 종류의 변경들이 -stable 트리로 들어왔는지와
 배포 프로세스가 어떻게 진행되는지를 설명한다.
 
-서브시스템 커널 트리들과 패치들
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+서브시스템 커널 트리들
+~~~~~~~~~~~~~~~~~~~~~~
 
 다양한 커널 서브시스템의 메인테이너들 --- 그리고 많은 커널 서브시스템 개발자들
 --- 은 그들의 현재 개발 상태를 소스 저장소로 노출한다. 이를 통해 다른 사람들도
@@ -324,17 +321,18 @@ Andrew Morton의 글이 있다.
 대부분의 이러한 patchwork 사이트는 https://patchwork.kernel.org/ 또는
 http://patchwork.ozlabs.org/ 에 나열되어 있다.
 
-4.x - 통합 테스트를 위한 next 커널 트리
----------------------------------------
-서브시스템 트리들의 변경사항들은 mainline 4.x 트리로 들어오기 전에 통합
-테스트를 거쳐야 한다. 이런 목적으로, 모든 서브시스템 트리의 변경사항을 거의
-매일 받아가는 특수한 테스트 저장소가 존재한다:
+통합 테스트를 위한 linux-next 커널 트리
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+서브시스템 트리들의 변경사항들은 mainline 트리로 들어오기 전에 통합 테스트를
+거쳐야 한다. 이런 목적으로, 모든 서브시스템 트리의 변경사항을 거의 매일
+받아가는 특수한 테스트 저장소가 존재한다:
 
        https://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
 
-이런 식으로, -next 커널을 통해 다음 머지 기간에 메인라인 커널에 어떤 변경이
-가해질 것인지 간략히 알 수 있다. 모험심 강한 테스터라면 -next 커널에서 테스트를
-수행하는 것도 좋을 것이다.
+이런 식으로, linux-next 커널을 통해 다음 머지 기간에 메인라인 커널에 어떤
+변경이 가해질 것인지 간략히 알 수 있다. 모험심 강한 테스터라면 linux-next
»¤ë\84\90ì\97\90ì\84\9c í\85\8cì\8a¤í\8a¸ë¥¼ ì\88\98í\96\89í\95\98ë\8a\94 ê²\83ë\8f\84 ì¢\8bì\9d\84 ê²\83ì\9d´ë\8b¤.
 
 
 버그 보고
index 0b69534..27995c4 100644 (file)
@@ -3,8 +3,8 @@
         \renewcommand\thesection*
         \renewcommand\thesubsection*
 
-Korean translations
-===================
+한국어 번역
+===========
 
 .. toctree::
    :maxdepth: 1
index 2774624..f07c40a 100644 (file)
@@ -1907,21 +1907,6 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
      위해선 Documentation/DMA-API.txt 문서를 참고하세요.
 
 
-MMIO 쓰기 배리어
-----------------
-
-리눅스 커널은 또한 memory-mapped I/O 쓰기를 위한 특별한 배리어도 가지고
-있습니다:
-
-       mmiowb();
-
-이것은 mandatory 쓰기 배리어의 변종으로, 완화된 순서 규칙의 I/O 영역에으로의
-쓰기가 부분적으로 순서를 맞추도록 해줍니다.  이 함수는 CPU->하드웨어 사이를
-넘어서 실제 하드웨어에까지 일부 수준의 영향을 끼칩니다.
-
-더 많은 정보를 위해선 "Acquire vs I/O 액세스" 서브섹션을 참고하세요.
-
-
 =========================
 암묵적 커널 메모리 배리어
 =========================
@@ -2283,73 +2268,6 @@ ACQUIRE VS 메모리 액세스
        *E, *F or *G following RELEASE Q
 
 
-
-ACQUIRE VS I/O 액세스
-----------------------
-
-특정한 (특히 NUMA 가 관련된) 환경 하에서 두개의 CPU 에서 동일한 스핀락으로
-보호되는 두개의 크리티컬 섹션 안의 I/O 액세스는 PCI 브릿지에 겹쳐진 I/O
-액세스로 보일 수 있는데, PCI 브릿지는 캐시 일관성 프로토콜과 합을 맞춰야 할
-의무가 없으므로, 필요한 읽기 메모리 배리어가 요청되지 않기 때문입니다.
-
-예를 들어서:
-
-       CPU 1                           CPU 2
-       =============================== ===============================
-       spin_lock(Q)
-       writel(0, ADDR)
-       writel(1, DATA);
-       spin_unlock(Q);
-                                       spin_lock(Q);
-                                       writel(4, ADDR);
-                                       writel(5, DATA);
-                                       spin_unlock(Q);
-
-는 PCI 브릿지에 다음과 같이 보일 수 있습니다:
-
-       STORE *ADDR = 0, STORE *ADDR = 4, STORE *DATA = 1, STORE *DATA = 5
-
-이렇게 되면 하드웨어의 오동작을 일으킬 수 있습니다.
-
-
-이런 경우엔 잡아둔 스핀락을 내려놓기 전에 mmiowb() 를 수행해야 하는데, 예를
-들면 다음과 같습니다:
-
-       CPU 1                           CPU 2
-       =============================== ===============================
-       spin_lock(Q)
-       writel(0, ADDR)
-       writel(1, DATA);
-       mmiowb();
-       spin_unlock(Q);
-                                       spin_lock(Q);
-                                       writel(4, ADDR);
-                                       writel(5, DATA);
-                                       mmiowb();
-                                       spin_unlock(Q);
-
-이 코드는 CPU 1 에서 요청된 두개의 스토어가 PCI 브릿지에 CPU 2 에서 요청된
-스토어들보다 먼저 보여짐을 보장합니다.
-
-
-또한, 같은 디바이스에서 스토어를 이어 로드가 수행되면 이 로드는 로드가 수행되기
-전에 스토어가 완료되기를 강제하므로 mmiowb() 의 필요가 없어집니다:
-
-       CPU 1                           CPU 2
-       =============================== ===============================
-       spin_lock(Q)
-       writel(0, ADDR)
-       a = readl(DATA);
-       spin_unlock(Q);
-                                       spin_lock(Q);
-                                       writel(4, ADDR);
-                                       b = readl(DATA);
-                                       spin_unlock(Q);
-
-
-더 많은 정보를 위해선 Documentation/driver-api/device-io.rst 를 참고하세요.
-
-
 =========================
 메모리 배리어가 필요한 곳
 =========================
@@ -2494,14 +2412,9 @@ _않습니다_.
 리눅스 커널 내부에서, I/O 는 어떻게 액세스들을 적절히 순차적이게 만들 수 있는지
 알고 있는, - inb() 나 writel() 과 같은 - 적절한 액세스 루틴을 통해 이루어져야만
 합니다.  이것들은 대부분의 경우에는 명시적 메모리 배리어 와 함께 사용될 필요가
-없습니다만, 다음의 두가지 상황에서는 명시적 메모리 배리어가 필요할 수 있습니다:
-
- (1) 일부 시스템에서 I/O 스토어는 모든 CPU 에 일관되게 순서 맞춰지지 않는데,
-     따라서 _모든_ 일반적인 드라이버들에 락이 사용되어야만 하고 이 크리티컬
-     섹션을 빠져나오기 전에 mmiowb() 가 꼭 호출되어야 합니다.
-
- (2) 만약 액세스 함수들이 완화된 메모리 액세스 속성을 갖는 I/O 메모리 윈도우를
-     사용한다면, 순서를 강제하기 위해선 _mandatory_ 메모리 배리어가 필요합니다.
+없습니다만, 완화된 메모리 액세스 속성으로 I/O 메모리 윈도우로의 참조를 위해
+액세스 함수가 사용된다면 순서를 강제하기 위해 _madatory_ 메모리 배리어가
+필요합니다.
 
 더 많은 정보를 위해선 Documentation/driver-api/device-io.rst 를 참고하십시오.
 
@@ -2545,10 +2458,9 @@ _않습니다_.
 인터럽트 내에서 일어난 액세스와 섞일 수 있다고 - 그리고 그 반대도 - 가정해야만
 합니다.
 
-그런 영역 안에서 일어나는 I/O 액세스들은 엄격한 순서 규칙의 I/O 레지스터에
-묵시적 I/O 배리어를 형성하는 동기적 (synchronous) 로드 오퍼레이션을 포함하기
-때문에 일반적으로는 이런게 문제가 되지 않습니다.  만약 이걸로는 충분치 않다면
-mmiowb() 가 명시적으로 사용될 필요가 있습니다.
+그런 영역 안에서 일어나는 I/O 액세스는 묵시적 I/O 배리어를 형성하는, 엄격한
+순서 규칙의 I/O 레지스터로의 로드 오퍼레이션을 포함하기 때문에 일반적으로는
+문제가 되지 않습니다.
 
 
 하나의 인터럽트 루틴과 별도의 CPU 에서 수행중이며 서로 통신을 하는 두 루틴
@@ -2560,67 +2472,102 @@ mmiowb() 가 명시적으로 사용될 필요가 있습니다.
 커널 I/O 배리어의 효과
 ======================
 
-I/O 메모리에 액세스할 때, 드라이버는 적절한 액세스 함수를 사용해야 합니다:
+I/O 액세스를 통한 주변장치와의 통신은 아키텍쳐와 기기에 매우 종속적입니다.
+따라서, 본질적으로 이식성이 없는 드라이버는 가능한 가장 적은 오버헤드로
+동기화를 하기 위해 각자의 타겟 시스템의 특정 동작에 의존할 겁니다.  다양한
+아키텍쳐와 버스 구현에 이식성을 가지려 하는 드라이버를 위해, 커널은 다양한
+정도의 순서 보장을 제공하는 일련의 액세스 함수를 제공합니다.
 
- (*) inX(), outX():
-
-     이것들은 메모리 공간보다는 I/O 공간에 이야기를 하려는 의도로
-     만들어졌습니다만, 그건 기본적으로 CPU 마다 다른 컨셉입니다.  i386 과
-     x86_64 프로세서들은 특별한 I/O 공간 액세스 사이클과 명령어를 실제로 가지고
-     있지만, 다른 많은 CPU 들에는 그런 컨셉이 존재하지 않습니다.
-
-     다른 것들 중에서도 PCI 버스가 I/O 공간 컨셉을 정의하는데, 이는 - i386 과
-     x86_64 같은 CPU 에서 - CPU 의 I/O 공간 컨셉으로 쉽게 매치됩니다.  하지만,
-     대체할 I/O 공간이 없는 CPU 에서는 CPU 의 메모리 맵의 가상 I/O 공간으로
-     매핑될 수도 있습니다.
-
-     이 공간으로의 액세스는 (i386 등에서는) 완전하게 동기화 됩니다만, 중간의
-     (PCI 호스트 브리지와 같은) 브리지들은 이를 완전히 보장하진 않을수도
-     있습니다.
+ (*) readX(), writeX():
 
-     이것들의 상호간의 순서는 완전하게 보장됩니다.
+       readX() 와 writeX() MMIO 액세스 함수는 접근되는 주변장치로의 포인터를
+       __iomem * 패러미터로 받습니다.  디폴트 I/O 기능으로 매핑되는 포인터
+       (예: ioremap() 으로 반환되는 것) 의 순서 보장은 다음과 같습니다:
+
+       1. 같은 주변장치로의 모든 readX() 와 writeX() 액세스는 각자에 대해
+          순서지어집니다.  이는 같은 CPU 쓰레드에 의한 특정 디바이스로의 MMIO
+          레지스터 액세스가 프로그램 순서대로 도착할 것을 보장합니다.
+
+       2. 한 스핀락을 잡은 CPU 쓰레드에 의한 writeX() 는 같은 스핀락을 나중에
+          잡은 다른 CPU 쓰레드에 의해 같은 주변장치를 향해 호출된 writeX()
+          앞으로 순서지어집니다.  이는 스핀락을 잡은 채 특정 디바이스를 향해
+          호출된 MMIO 레지스터 쓰기는 해당 락의 획득에 일관적인 순서로 도달할
+          것을 보장합니다.
+
+       3. 특정 주변장치를 향한 특정 CPU 쓰레드의 writeX() 는 먼저 해당
+          쓰레드로 전파되는, 또는 해당 쓰레드에 의해 요청된 모든 앞선 메모리
+          쓰기가 완료되기 전까지 먼저 기다립니다.  이는 dma_alloc_coherent()
+          를 통해 할당된 전송용 DMA 버퍼로의 해당 CPU 의 쓰기가 이 CPU 가 이
+          전송을 시작시키기 위해 MMIO 컨트롤 레지스터에 쓰기를 할 때 DMA
+          엔진에 보여질 것을 보장합니다.
+
+       4. 특정 CPU 쓰레드에 의한 주변장치로의 readX() 는 같은 쓰레드에 의한
+          모든 뒤따르는 메모리 읽기가 시작되기 전에 완료됩니다.  이는
+          dma_alloc_coherent() 를 통해 할당된 수신용 DMA 버퍼로부터의 CPU 의
+          읽기는 이 DMA 수신의 완료를 표시하는 DMA 엔진의 MMIO 상태 레지스터
+          읽기 후에는 오염된 데이터를 읽지 않을 것을 보장합니다.
+
+       5. CPU 에 의한 주변장치로의 readX() 는 모든 뒤따르는 delay() 루프가
+          수행을 시작하기 전에 완료됩니다.  이는 CPU 의 특정
+          주변장치로의 두개의 MMIO 레지스터 쓰기가 행해지는데 첫번째 쓰기가
+          readX() 를 통해 곧바로 읽어졌고 이어 두번째 writeX() 전에 udelay(1)
+          이 호출되었다면 이 두개의 쓰기는 최소 1us 의 간격을 두고 행해질 것을
+          보장합니다:
+
+               writel(42, DEVICE_REGISTER_0); // 디바이스에 도착함...
+               readl(DEVICE_REGISTER_0);
+               udelay(1);
+               writel(42, DEVICE_REGISTER_1); // ...이것보다 최소 1us 전에.
+
+       디폴트가 아닌 기능을 통해 얻어지는 __iomem 포인터 (예: ioremap_wc() 를
+       통해 리턴되는 것) 의 순서 속성은 실제 아키텍쳐에 의존적이어서 이런
+       종류의 매핑으로의 액세스는 앞서 설명된 보장사항에 의존할 수 없습니다.
 
-     다른 타입의 메모리 오퍼레이션, I/O 오퍼레이션에 대한 순서는 완전하게
-     보장되지는 않습니다.
+ (*) readX_relaxed(), writeX_relaxed()
 
- (*) readX(), writeX():
+       이것들은 readX() 와 writeX() 랑 비슷하지만, 더 완화된 메모리 순서
+       보장을 제공합니다.  구체적으로, 이것들은 일반적 메모리 액세스나 delay()
+       루프 (예:앞의 2-5 항목) 에 대해 순서를 보장하지 않습니다만 디폴트 I/O
+       기능으로 매핑된 __iomem 포인터에 대해 동작할 때, 같은 CPU 쓰레드에 의해
+       같은 주변장치로의 액세스에는 순서가 맞춰질 것이 보장됩니다.
 
-     이것들이 수행 요청되는 CPU 에서 서로에게 완전히 순서가 맞춰지고 독립적으로
-     수행되는지에 대한 보장 여부는 이들이 액세스 하는 메모리 윈도우에 정의된
-     특성에 의해 결정됩니다.  예를 들어, 최신의 i386 아키텍쳐 머신에서는 MTRR
-     레지스터로 이 특성이 조정됩니다.
+ (*) readsX(), writesX():
 
-     일반적으로는, 프리페치 (prefetch) 가능한 디바이스를 액세스 하는게
-     아니라면, 이것들은 완전히 순서가 맞춰지고 결합되지 않게 보장될 겁니다.
+       readsX() 와 writesX() MMIO 액세스 함수는 DMA 를 수행하는데 적절치 않은,
+       주변장치 내의 메모리 매핑된 레지스터 기반 FIFO 로의 액세스를 위해
+       설계되었습니다.  따라서, 이 기능들은 앞서 설명된 readX_relaxed() 와
+       writeX_relaxed() 의 순서 보장만을 제공합니다.
 
-     하지만, (PCI 브리지와 같은) 중간의 하드웨어는 자신이 원한다면 집행을
-     연기시킬 수 있습니다; 스토어 명령을 실제로 하드웨어로 내려보내기(flush)
-     위해서는 같은 위치로부터 로드를 하는 방법이 있습니다만[*], PCI 의 경우는
-     같은 디바이스나 환경 구성 영역에서의 로드만으로도 충분할 겁니다.
+ (*) inX(), outX():
 
-     [*] 주의! 쓰여진 것과 같은 위치로부터의 로드를 시도하는 것은 오동작을
-        일으킬 수도 있습니다 - 예로 16650 Rx/Tx 시리얼 레지스터를 생각해
-        보세요.
+       inX() 와 outX() 액세스 함수는 일부 아키텍쳐 (특히 x86) 에서는 특수한
+       명령어를 필요로 하며 포트에 매핑되는, 과거의 유산인 I/O 주변장치로의
+       접근을 위해 만들어졌습니다.
 
-     프리페치 가능한 I/O 메모리가 사용되면, 스토어 명령들이 순서를 지키도록
-     하기 위해 mmiowb() 배리어가 필요할 수 있습니다.
+       많은 CPU 아키텍쳐가 결국은 이런 주변장치를 내부의 가상 메모리 매핑을
+       통해 접근하기 때문에, inX() 와 outX() 가 제공하는 이식성 있는 순서
+       보장은 디폴트 I/O 기능을 통한 매핑을 접근할 때의 readX() 와 writeX() 에
+       의해 제공되는 것과 각각 동일합니다.
 
-     PCI 트랜잭션 사이의 상호작용에 대해 더 많은 정보를 위해선 PCI 명세서를
-     참고하시기 바랍니다.
+       디바이스 드라이버는 outX() 가 리턴하기 전에 해당 I/O 주변장치로부터의
+       완료 응답을 기다리는 쓰기 트랜잭션을 만들어 낸다고 기대할 수도
+       있습니다.  이는 모든 아키텍쳐에서 보장되지는 않고, 따라서 이식성 있는
+       순서 규칙의 일부분이 아닙니다.
 
- (*) readX_relaxed(), writeX_relaxed()
+ (*) insX(), outsX():
 
-     이것들은 readX() 와 writeX() 랑 비슷하지만, 더 완화된 메모리 순서 보장을
-     제공합니다.  구체적으로, 이것들은 일반적 메모리 액세스 (예: DMA 버퍼) 에도
-     LOCK 이나 UNLOCK 오퍼레이션들에도 순서를 보장하지 않습니다.  LOCK 이나
-     UNLOCK 오퍼레이션들에 맞춰지는 순서가 필요하다면, mmiowb() 배리어가 사용될
-     수 있습니다.  같은 주변 장치에의 완화된 액세스끼리는 순서가 지켜짐을 알아
-     두시기 바랍니다.
+       앞에서와 같이, insX() 와 outsX() 액세스 함수는 디폴트 I/O 기능을 통한
+       매핑을 접근할 때 각각 readX() 와 writeX() 와 같은 순서 보장을
+       제공합니다.
 
  (*) ioreadX(), iowriteX()
 
-     이것들은 inX()/outX() 나 readX()/writeX() 처럼 실제로 수행하는 액세스의
-     종류에 따라 적절하게 수행될 것입니다.
+       이것들은 inX()/outX() 나 readX()/writeX() 처럼 실제로 수행하는 액세스의
+       종류에 따라 적절하게 수행될 것입니다.
+
+String 액세스 함수 (insX(), outsX(), readsX() 그리고 writesX()) 의 예외를
+제외하고는, 앞의 모든 것이 아랫단의 주변장치가 little-endian 이라 가정하며,
+따라서 big-endian 아키텍쳐에서는 byte-swapping 오퍼레이션을 수행합니다.
 
 
 ===================================
index 15c5925..e4c2259 100644 (file)
@@ -70,7 +70,6 @@ FF_MAGIC              0x4646           fc_info                  ``drivers/net/ip
 ISICOM_MAGIC          0x4d54           isi_port                 ``include/linux/isicom.h``
 PTY_MAGIC             0x5001                                    ``drivers/char/pty.c``
 PPP_MAGIC             0x5002           ppp                      ``include/linux/if_pppvar.h``
-SERIAL_MAGIC          0x5301           async_struct             ``include/linux/serial.h``
 SSTATE_MAGIC          0x5302           serial_state             ``include/linux/serial.h``
 SLIP_MAGIC            0x5302           slip                     ``drivers/net/slip.h``
 STRIP_MAGIC           0x5303           strip                    ``drivers/net/strip.c``
index ad494da..e983488 100644 (file)
@@ -21,6 +21,7 @@ place where this information is gathered.
    unshare
    spec_ctrl
    accelerators/ocxl
+   ioctl/index
 
 .. only::  subproject and html
 
diff --git a/Documentation/userspace-api/ioctl/cdrom.rst b/Documentation/userspace-api/ioctl/cdrom.rst
new file mode 100644 (file)
index 0000000..3b4c050
--- /dev/null
@@ -0,0 +1,1233 @@
+============================
+Summary of CDROM ioctl calls
+============================
+
+- Edward A. Falk <efalk@google.com>
+
+November, 2004
+
+This document attempts to describe the ioctl(2) calls supported by
+the CDROM layer.  These are by-and-large implemented (as of Linux 2.6)
+in drivers/cdrom/cdrom.c and drivers/block/scsi_ioctl.c
+
+ioctl values are listed in <linux/cdrom.h>.  As of this writing, they
+are as follows:
+
+       ======================  ===============================================
+       CDROMPAUSE              Pause Audio Operation
+       CDROMRESUME             Resume paused Audio Operation
+       CDROMPLAYMSF            Play Audio MSF (struct cdrom_msf)
+       CDROMPLAYTRKIND         Play Audio Track/index (struct cdrom_ti)
+       CDROMREADTOCHDR         Read TOC header (struct cdrom_tochdr)
+       CDROMREADTOCENTRY       Read TOC entry (struct cdrom_tocentry)
+       CDROMSTOP               Stop the cdrom drive
+       CDROMSTART              Start the cdrom drive
+       CDROMEJECT              Ejects the cdrom media
+       CDROMVOLCTRL            Control output volume (struct cdrom_volctrl)
+       CDROMSUBCHNL            Read subchannel data (struct cdrom_subchnl)
+       CDROMREADMODE2          Read CDROM mode 2 data (2336 Bytes)
+                               (struct cdrom_read)
+       CDROMREADMODE1          Read CDROM mode 1 data (2048 Bytes)
+                               (struct cdrom_read)
+       CDROMREADAUDIO          (struct cdrom_read_audio)
+       CDROMEJECT_SW           enable(1)/disable(0) auto-ejecting
+       CDROMMULTISESSION       Obtain the start-of-last-session
+                               address of multi session disks
+                               (struct cdrom_multisession)
+       CDROM_GET_MCN           Obtain the "Universal Product Code"
+                               if available (struct cdrom_mcn)
+       CDROM_GET_UPC           Deprecated, use CDROM_GET_MCN instead.
+       CDROMRESET              hard-reset the drive
+       CDROMVOLREAD            Get the drive's volume setting
+                               (struct cdrom_volctrl)
+       CDROMREADRAW            read data in raw mode (2352 Bytes)
+                               (struct cdrom_read)
+       CDROMREADCOOKED         read data in cooked mode
+       CDROMSEEK               seek msf address
+       CDROMPLAYBLK            scsi-cd only, (struct cdrom_blk)
+       CDROMREADALL            read all 2646 bytes
+       CDROMGETSPINDOWN        return 4-bit spindown value
+       CDROMSETSPINDOWN        set 4-bit spindown value
+       CDROMCLOSETRAY          pendant of CDROMEJECT
+       CDROM_SET_OPTIONS       Set behavior options
+       CDROM_CLEAR_OPTIONS     Clear behavior options
+       CDROM_SELECT_SPEED      Set the CD-ROM speed
+       CDROM_SELECT_DISC       Select disc (for juke-boxes)
+       CDROM_MEDIA_CHANGED     Check is media changed
+       CDROM_DRIVE_STATUS      Get tray position, etc.
+       CDROM_DISC_STATUS       Get disc type, etc.
+       CDROM_CHANGER_NSLOTS    Get number of slots
+       CDROM_LOCKDOOR          lock or unlock door
+       CDROM_DEBUG             Turn debug messages on/off
+       CDROM_GET_CAPABILITY    get capabilities
+       CDROMAUDIOBUFSIZ        set the audio buffer size
+       DVD_READ_STRUCT         Read structure
+       DVD_WRITE_STRUCT        Write structure
+       DVD_AUTH                Authentication
+       CDROM_SEND_PACKET       send a packet to the drive
+       CDROM_NEXT_WRITABLE     get next writable block
+       CDROM_LAST_WRITTEN      get last block written on disc
+       ======================  ===============================================
+
+
+The information that follows was determined from reading kernel source
+code.  It is likely that some corrections will be made over time.
+
+------------------------------------------------------------------------------
+
+General:
+
+       Unless otherwise specified, all ioctl calls return 0 on success
+       and -1 with errno set to an appropriate value on error.  (Some
+       ioctls return non-negative data values.)
+
+       Unless otherwise specified, all ioctl calls return -1 and set
+       errno to EFAULT on a failed attempt to copy data to or from user
+       address space.
+
+       Individual drivers may return error codes not listed here.
+
+       Unless otherwise specified, all data structures and constants
+       are defined in <linux/cdrom.h>
+
+------------------------------------------------------------------------------
+
+
+CDROMPAUSE
+       Pause Audio Operation
+
+
+       usage::
+
+         ioctl(fd, CDROMPAUSE, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+CDROMRESUME
+       Resume paused Audio Operation
+
+
+       usage::
+
+         ioctl(fd, CDROMRESUME, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+CDROMPLAYMSF
+       Play Audio MSF
+
+       (struct cdrom_msf)
+
+
+       usage::
+
+         struct cdrom_msf msf;
+
+         ioctl(fd, CDROMPLAYMSF, &msf);
+
+       inputs:
+               cdrom_msf structure, describing a segment of music to play
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+               - MSF stands for minutes-seconds-frames
+               - LBA stands for logical block address
+               - Segment is described as start and end times, where each time
+                 is described as minutes:seconds:frames.
+                 A frame is 1/75 of a second.
+
+
+CDROMPLAYTRKIND
+       Play Audio Track/index
+
+       (struct cdrom_ti)
+
+
+       usage::
+
+         struct cdrom_ti ti;
+
+         ioctl(fd, CDROMPLAYTRKIND, &ti);
+
+       inputs:
+               cdrom_ti structure, describing a segment of music to play
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+               - Segment is described as start and end times, where each time
+                 is described as a track and an index.
+
+
+
+CDROMREADTOCHDR
+       Read TOC header
+
+       (struct cdrom_tochdr)
+
+
+       usage::
+
+         cdrom_tochdr header;
+
+         ioctl(fd, CDROMREADTOCHDR, &header);
+
+       inputs:
+               cdrom_tochdr structure
+
+
+       outputs:
+               cdrom_tochdr structure
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+
+CDROMREADTOCENTRY
+       Read TOC entry
+
+       (struct cdrom_tocentry)
+
+
+       usage::
+
+         struct cdrom_tocentry entry;
+
+         ioctl(fd, CDROMREADTOCENTRY, &entry);
+
+       inputs:
+               cdrom_tocentry structure
+
+
+       outputs:
+               cdrom_tocentry structure
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+         - EINVAL      entry.cdte_format not CDROM_MSF or CDROM_LBA
+         - EINVAL      requested track out of bounds
+         - EIO         I/O error reading TOC
+
+       notes:
+               - TOC stands for Table Of Contents
+               - MSF stands for minutes-seconds-frames
+               - LBA stands for logical block address
+
+
+
+CDROMSTOP
+       Stop the cdrom drive
+
+
+       usage::
+
+         ioctl(fd, CDROMSTOP, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+         - Exact interpretation of this ioctl depends on the device,
+           but most seem to spin the drive down.
+
+
+CDROMSTART
+       Start the cdrom drive
+
+
+       usage::
+
+         ioctl(fd, CDROMSTART, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+         - Exact interpretation of this ioctl depends on the device,
+           but most seem to spin the drive up and/or close the tray.
+           Other devices ignore the ioctl completely.
+
+
+CDROMEJECT
+       - Ejects the cdrom media
+
+
+       usage::
+
+         ioctl(fd, CDROMEJECT, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error returns:
+         - ENOSYS      cd drive not capable of ejecting
+         - EBUSY       other processes are accessing drive, or door is locked
+
+       notes:
+               - See CDROM_LOCKDOOR, below.
+
+
+
+
+CDROMCLOSETRAY
+       pendant of CDROMEJECT
+
+
+       usage::
+
+         ioctl(fd, CDROMCLOSETRAY, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error returns:
+         - ENOSYS      cd drive not capable of closing the tray
+         - EBUSY       other processes are accessing drive, or door is locked
+
+       notes:
+               - See CDROM_LOCKDOOR, below.
+
+
+
+
+CDROMVOLCTRL
+       Control output volume (struct cdrom_volctrl)
+
+
+       usage::
+
+         struct cdrom_volctrl volume;
+
+         ioctl(fd, CDROMVOLCTRL, &volume);
+
+       inputs:
+               cdrom_volctrl structure containing volumes for up to 4
+               channels.
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+
+CDROMVOLREAD
+       Get the drive's volume setting
+
+       (struct cdrom_volctrl)
+
+
+       usage::
+
+         struct cdrom_volctrl volume;
+
+         ioctl(fd, CDROMVOLREAD, &volume);
+
+       inputs:
+               none
+
+
+       outputs:
+               The current volume settings.
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+
+CDROMSUBCHNL
+       Read subchannel data
+
+       (struct cdrom_subchnl)
+
+
+       usage::
+
+         struct cdrom_subchnl q;
+
+         ioctl(fd, CDROMSUBCHNL, &q);
+
+       inputs:
+               cdrom_subchnl structure
+
+
+       outputs:
+               cdrom_subchnl structure
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+         - EINVAL      format not CDROM_MSF or CDROM_LBA
+
+       notes:
+               - Format is converted to CDROM_MSF or CDROM_LBA
+                 as per user request on return
+
+
+
+CDROMREADRAW
+       read data in raw mode (2352 Bytes)
+
+       (struct cdrom_read)
+
+       usage::
+
+         union {
+
+           struct cdrom_msf msf;               /* input */
+           char buffer[CD_FRAMESIZE_RAW];      /* return */
+         } arg;
+         ioctl(fd, CDROMREADRAW, &arg);
+
+       inputs:
+               cdrom_msf structure indicating an address to read.
+
+               Only the start values are significant.
+
+       outputs:
+               Data written to address provided by user.
+
+
+       error return:
+         - EINVAL      address less than 0, or msf less than 0:2:0
+         - ENOMEM      out of memory
+
+       notes:
+               - As of 2.6.8.1, comments in <linux/cdrom.h> indicate that this
+                 ioctl accepts a cdrom_read structure, but actual source code
+                 reads a cdrom_msf structure and writes a buffer of data to
+                 the same address.
+
+               - MSF values are converted to LBA values via this formula::
+
+                   lba = (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+
+
+
+
+CDROMREADMODE1
+       Read CDROM mode 1 data (2048 Bytes)
+
+       (struct cdrom_read)
+
+       notes:
+               Identical to CDROMREADRAW except that block size is
+               CD_FRAMESIZE (2048) bytes
+
+
+
+CDROMREADMODE2
+       Read CDROM mode 2 data (2336 Bytes)
+
+       (struct cdrom_read)
+
+       notes:
+               Identical to CDROMREADRAW except that block size is
+               CD_FRAMESIZE_RAW0 (2336) bytes
+
+
+
+CDROMREADAUDIO
+       (struct cdrom_read_audio)
+
+       usage::
+
+         struct cdrom_read_audio ra;
+
+         ioctl(fd, CDROMREADAUDIO, &ra);
+
+       inputs:
+               cdrom_read_audio structure containing read start
+               point and length
+
+       outputs:
+               audio data, returned to buffer indicated by ra
+
+
+       error return:
+         - EINVAL      format not CDROM_MSF or CDROM_LBA
+         - EINVAL      nframes not in range [1 75]
+         - ENXIO       drive has no queue (probably means invalid fd)
+         - ENOMEM      out of memory
+
+
+CDROMEJECT_SW
+       enable(1)/disable(0) auto-ejecting
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, CDROMEJECT_SW, val);
+
+       inputs:
+               Flag specifying auto-eject flag.
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      Drive is not capable of ejecting.
+         - EBUSY       Door is locked
+
+
+
+
+CDROMMULTISESSION
+       Obtain the start-of-last-session address of multi session disks
+
+       (struct cdrom_multisession)
+
+       usage::
+
+         struct cdrom_multisession ms_info;
+
+         ioctl(fd, CDROMMULTISESSION, &ms_info);
+
+       inputs:
+               cdrom_multisession structure containing desired
+
+         format.
+
+       outputs:
+               cdrom_multisession structure is filled with last_session
+               information.
+
+       error return:
+         - EINVAL      format not CDROM_MSF or CDROM_LBA
+
+
+CDROM_GET_MCN
+       Obtain the "Universal Product Code"
+       if available
+
+       (struct cdrom_mcn)
+
+
+       usage::
+
+         struct cdrom_mcn mcn;
+
+         ioctl(fd, CDROM_GET_MCN, &mcn);
+
+       inputs:
+               none
+
+
+       outputs:
+               Universal Product Code
+
+
+       error return:
+         - ENOSYS      Drive is not capable of reading MCN data.
+
+       notes:
+               - Source code comments state::
+
+                   The following function is implemented, although very few
+                   audio discs give Universal Product Code information, which
+                   should just be the Medium Catalog Number on the box.  Note,
+                   that the way the code is written on the CD is /not/ uniform
+                   across all discs!
+
+
+
+
+CDROM_GET_UPC
+       CDROM_GET_MCN  (deprecated)
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+CDROMRESET
+       hard-reset the drive
+
+
+       usage::
+
+         ioctl(fd, CDROMRESET, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - ENOSYS      Drive is not capable of resetting.
+
+
+
+
+CDROMREADCOOKED
+       read data in cooked mode
+
+
+       usage::
+
+         u8 buffer[CD_FRAMESIZE]
+
+         ioctl(fd, CDROMREADCOOKED, buffer);
+
+       inputs:
+               none
+
+
+       outputs:
+               2048 bytes of data, "cooked" mode.
+
+
+       notes:
+               Not implemented on all drives.
+
+
+
+
+
+CDROMREADALL
+       read all 2646 bytes
+
+
+       Same as CDROMREADCOOKED, but reads 2646 bytes.
+
+
+
+CDROMSEEK
+       seek msf address
+
+
+       usage::
+
+         struct cdrom_msf msf;
+
+         ioctl(fd, CDROMSEEK, &msf);
+
+       inputs:
+               MSF address to seek to.
+
+
+       outputs:
+               none
+
+
+
+
+CDROMPLAYBLK
+       scsi-cd only
+
+       (struct cdrom_blk)
+
+
+       usage::
+
+         struct cdrom_blk blk;
+
+         ioctl(fd, CDROMPLAYBLK, &blk);
+
+       inputs:
+               Region to play
+
+
+       outputs:
+               none
+
+
+
+
+CDROMGETSPINDOWN
+       usage::
+
+         char spindown;
+
+         ioctl(fd, CDROMGETSPINDOWN, &spindown);
+
+       inputs:
+               none
+
+
+       outputs:
+               The value of the current 4-bit spindown value.
+
+
+
+
+
+CDROMSETSPINDOWN
+       usage::
+
+         char spindown
+
+         ioctl(fd, CDROMSETSPINDOWN, &spindown);
+
+       inputs:
+               4-bit value used to control spindown (TODO: more detail here)
+
+
+       outputs:
+               none
+
+
+
+
+
+
+CDROM_SET_OPTIONS
+       Set behavior options
+
+
+       usage::
+
+         int options;
+
+         ioctl(fd, CDROM_SET_OPTIONS, options);
+
+       inputs:
+               New values for drive options.  The logical 'or' of:
+
+           ==============      ==================================
+           CDO_AUTO_CLOSE      close tray on first open(2)
+           CDO_AUTO_EJECT      open tray on last release
+           CDO_USE_FFLAGS      use O_NONBLOCK information on open
+           CDO_LOCK            lock tray on open files
+           CDO_CHECK_TYPE      check type on open for data
+           ==============      ==================================
+
+       outputs:
+               Returns the resulting options settings in the
+               ioctl return value.  Returns -1 on error.
+
+       error return:
+         - ENOSYS      selected option(s) not supported by drive.
+
+
+
+
+CDROM_CLEAR_OPTIONS
+       Clear behavior options
+
+
+       Same as CDROM_SET_OPTIONS, except that selected options are
+       turned off.
+
+
+
+CDROM_SELECT_SPEED
+       Set the CD-ROM speed
+
+
+       usage::
+
+         int speed;
+
+         ioctl(fd, CDROM_SELECT_SPEED, speed);
+
+       inputs:
+               New drive speed.
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      speed selection not supported by drive.
+
+
+
+CDROM_SELECT_DISC
+       Select disc (for juke-boxes)
+
+
+       usage::
+
+         int disk;
+
+         ioctl(fd, CDROM_SELECT_DISC, disk);
+
+       inputs:
+               Disk to load into drive.
+
+
+       outputs:
+               none
+
+
+       error return:
+         - EINVAL      Disk number beyond capacity of drive
+
+
+
+CDROM_MEDIA_CHANGED
+       Check is media changed
+
+
+       usage::
+
+         int slot;
+
+         ioctl(fd, CDROM_MEDIA_CHANGED, slot);
+
+       inputs:
+               Slot number to be tested, always zero except for jukeboxes.
+
+               May also be special values CDSL_NONE or CDSL_CURRENT
+
+       outputs:
+               Ioctl return value is 0 or 1 depending on whether the media
+
+         has been changed, or -1 on error.
+
+       error returns:
+         - ENOSYS      Drive can't detect media change
+         - EINVAL      Slot number beyond capacity of drive
+         - ENOMEM      Out of memory
+
+
+
+CDROM_DRIVE_STATUS
+       Get tray position, etc.
+
+
+       usage::
+
+         int slot;
+
+         ioctl(fd, CDROM_DRIVE_STATUS, slot);
+
+       inputs:
+               Slot number to be tested, always zero except for jukeboxes.
+
+               May also be special values CDSL_NONE or CDSL_CURRENT
+
+       outputs:
+               Ioctl return value will be one of the following values
+
+         from <linux/cdrom.h>:
+
+           =================== ==========================
+           CDS_NO_INFO         Information not available.
+           CDS_NO_DISC
+           CDS_TRAY_OPEN
+           CDS_DRIVE_NOT_READY
+           CDS_DISC_OK
+           -1                  error
+           =================== ==========================
+
+       error returns:
+         - ENOSYS      Drive can't detect drive status
+         - EINVAL      Slot number beyond capacity of drive
+         - ENOMEM      Out of memory
+
+
+
+
+CDROM_DISC_STATUS
+       Get disc type, etc.
+
+
+       usage::
+
+         ioctl(fd, CDROM_DISC_STATUS, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               Ioctl return value will be one of the following values
+
+         from <linux/cdrom.h>:
+
+           - CDS_NO_INFO
+           - CDS_AUDIO
+           - CDS_MIXED
+           - CDS_XA_2_2
+           - CDS_XA_2_1
+           - CDS_DATA_1
+
+       error returns:
+               none at present
+
+       notes:
+           - Source code comments state::
+
+
+               Ok, this is where problems start.  The current interface for
+               the CDROM_DISC_STATUS ioctl is flawed.  It makes the false
+               assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.
+               Unfortunately, while this is often the case, it is also
+               very common for CDs to have some tracks with data, and some
+               tracks with audio.      Just because I feel like it, I declare
+               the following to be the best way to cope.  If the CD has
+               ANY data tracks on it, it will be returned as a data CD.
+               If it has any XA tracks, I will return it as that.      Now I
+               could simplify this interface by combining these returns with
+               the above, but this more clearly demonstrates the problem
+               with the current interface.  Too bad this wasn't designed
+               to use bitmasks...             -Erik
+
+               Well, now we have the option CDS_MIXED: a mixed-type CD.
+               User level programmers might feel the ioctl is not very
+               useful.
+                               ---david
+
+
+
+
+CDROM_CHANGER_NSLOTS
+       Get number of slots
+
+
+       usage::
+
+         ioctl(fd, CDROM_CHANGER_NSLOTS, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               The ioctl return value will be the number of slots in a
+               CD changer.  Typically 1 for non-multi-disk devices.
+
+       error returns:
+               none
+
+
+
+CDROM_LOCKDOOR
+       lock or unlock door
+
+
+       usage::
+
+         int lock;
+
+         ioctl(fd, CDROM_LOCKDOOR, lock);
+
+       inputs:
+               Door lock flag, 1=lock, 0=unlock
+
+
+       outputs:
+               none
+
+
+       error returns:
+         - EDRIVE_CANT_DO_THIS
+
+                               Door lock function not supported.
+         - EBUSY
+
+                               Attempt to unlock when multiple users
+                               have the drive open and not CAP_SYS_ADMIN
+
+       notes:
+               As of 2.6.8.1, the lock flag is a global lock, meaning that
+               all CD drives will be locked or unlocked together.  This is
+               probably a bug.
+
+               The EDRIVE_CANT_DO_THIS value is defined in <linux/cdrom.h>
+               and is currently (2.6.8.1) the same as EOPNOTSUPP
+
+
+
+CDROM_DEBUG
+       Turn debug messages on/off
+
+
+       usage::
+
+         int debug;
+
+         ioctl(fd, CDROM_DEBUG, debug);
+
+       inputs:
+               Cdrom debug flag, 0=disable, 1=enable
+
+
+       outputs:
+               The ioctl return value will be the new debug flag.
+
+
+       error return:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+
+
+
+CDROM_GET_CAPABILITY
+       get capabilities
+
+
+       usage::
+
+         ioctl(fd, CDROM_GET_CAPABILITY, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               The ioctl return value is the current device capability
+               flags.  See CDC_CLOSE_TRAY, CDC_OPEN_TRAY, etc.
+
+
+
+CDROMAUDIOBUFSIZ
+       set the audio buffer size
+
+
+       usage::
+
+         int arg;
+
+         ioctl(fd, CDROMAUDIOBUFSIZ, val);
+
+       inputs:
+               New audio buffer size
+
+
+       outputs:
+               The ioctl return value is the new audio buffer size, or -1
+               on error.
+
+       error return:
+         - ENOSYS      Not supported by this driver.
+
+       notes:
+               Not supported by all drivers.
+
+
+
+
+DVD_READ_STRUCT                        Read structure
+
+       usage::
+
+         dvd_struct s;
+
+         ioctl(fd, DVD_READ_STRUCT, &s);
+
+       inputs:
+               dvd_struct structure, containing:
+
+           =================== ==========================================
+           type                specifies the information desired, one of
+                               DVD_STRUCT_PHYSICAL, DVD_STRUCT_COPYRIGHT,
+                               DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA,
+                               DVD_STRUCT_MANUFACT
+           physical.layer_num  desired layer, indexed from 0
+           copyright.layer_num desired layer, indexed from 0
+           disckey.agid
+           =================== ==========================================
+
+       outputs:
+               dvd_struct structure, containing:
+
+           =================== ================================
+           physical            for type == DVD_STRUCT_PHYSICAL
+           copyright           for type == DVD_STRUCT_COPYRIGHT
+           disckey.value       for type == DVD_STRUCT_DISCKEY
+           bca.{len,value}     for type == DVD_STRUCT_BCA
+           manufact.{len,valu} for type == DVD_STRUCT_MANUFACT
+           =================== ================================
+
+       error returns:
+         - EINVAL      physical.layer_num exceeds number of layers
+         - EIO         Received invalid response from drive
+
+
+
+DVD_WRITE_STRUCT               Write structure
+
+       Not implemented, as of 2.6.8.1
+
+
+
+DVD_AUTH                       Authentication
+
+       usage::
+
+         dvd_authinfo ai;
+
+         ioctl(fd, DVD_AUTH, &ai);
+
+       inputs:
+               dvd_authinfo structure.  See <linux/cdrom.h>
+
+
+       outputs:
+               dvd_authinfo structure.
+
+
+       error return:
+         - ENOTTY      ai.type not recognized.
+
+
+
+CDROM_SEND_PACKET
+       send a packet to the drive
+
+
+       usage::
+
+         struct cdrom_generic_command cgc;
+
+         ioctl(fd, CDROM_SEND_PACKET, &cgc);
+
+       inputs:
+               cdrom_generic_command structure containing the packet to send.
+
+
+       outputs:
+               none
+
+         cdrom_generic_command structure containing results.
+
+       error return:
+         - EIO
+
+                       command failed.
+         - EPERM
+
+                       Operation not permitted, either because a
+                       write command was attempted on a drive which
+                       is opened read-only, or because the command
+                       requires CAP_SYS_RAWIO
+         - EINVAL
+
+                       cgc.data_direction not set
+
+
+
+CDROM_NEXT_WRITABLE
+       get next writable block
+
+
+       usage::
+
+         long next;
+
+         ioctl(fd, CDROM_NEXT_WRITABLE, &next);
+
+       inputs:
+               none
+
+
+       outputs:
+               The next writable block.
+
+
+       notes:
+               If the device does not support this ioctl directly, the
+
+         ioctl will return CDROM_LAST_WRITTEN + 7.
+
+
+
+CDROM_LAST_WRITTEN
+       get last block written on disc
+
+
+       usage::
+
+         long last;
+
+         ioctl(fd, CDROM_LAST_WRITTEN, &last);
+
+       inputs:
+               none
+
+
+       outputs:
+               The last block written on disc
+
+
+       notes:
+               If the device does not support this ioctl directly, the
+               result is derived from the disc's table of contents.  If the
+               table of contents can't be read, this ioctl returns an
+               error.
diff --git a/Documentation/userspace-api/ioctl/hdio.rst b/Documentation/userspace-api/ioctl/hdio.rst
new file mode 100644 (file)
index 0000000..e822e3d
--- /dev/null
@@ -0,0 +1,1342 @@
+==============================
+Summary of `HDIO_` ioctl calls
+==============================
+
+- Edward A. Falk <efalk@google.com>
+
+November, 2004
+
+This document attempts to describe the ioctl(2) calls supported by
+the HD/IDE layer.  These are by-and-large implemented (as of Linux 2.6)
+in drivers/ide/ide.c and drivers/block/scsi_ioctl.c
+
+ioctl values are listed in <linux/hdreg.h>.  As of this writing, they
+are as follows:
+
+    ioctls that pass argument pointers to user space:
+
+       ======================= =======================================
+       HDIO_GETGEO             get device geometry
+       HDIO_GET_UNMASKINTR     get current unmask setting
+       HDIO_GET_MULTCOUNT      get current IDE blockmode setting
+       HDIO_GET_QDMA           get use-qdma flag
+       HDIO_SET_XFER           set transfer rate via proc
+       HDIO_OBSOLETE_IDENTITY  OBSOLETE, DO NOT USE
+       HDIO_GET_KEEPSETTINGS   get keep-settings-on-reset flag
+       HDIO_GET_32BIT          get current io_32bit setting
+       HDIO_GET_NOWERR         get ignore-write-error flag
+       HDIO_GET_DMA            get use-dma flag
+       HDIO_GET_NICE           get nice flags
+       HDIO_GET_IDENTITY       get IDE identification info
+       HDIO_GET_WCACHE         get write cache mode on|off
+       HDIO_GET_ACOUSTIC       get acoustic value
+       HDIO_GET_ADDRESS        get sector addressing mode
+       HDIO_GET_BUSSTATE       get the bus state of the hwif
+       HDIO_TRISTATE_HWIF      execute a channel tristate
+       HDIO_DRIVE_RESET        execute a device reset
+       HDIO_DRIVE_TASKFILE     execute raw taskfile
+       HDIO_DRIVE_TASK         execute task and special drive command
+       HDIO_DRIVE_CMD          execute a special drive command
+       HDIO_DRIVE_CMD_AEB      HDIO_DRIVE_TASK
+       ======================= =======================================
+
+    ioctls that pass non-pointer values:
+
+       ======================= =======================================
+       HDIO_SET_MULTCOUNT      change IDE blockmode
+       HDIO_SET_UNMASKINTR     permit other irqs during I/O
+       HDIO_SET_KEEPSETTINGS   keep ioctl settings on reset
+       HDIO_SET_32BIT          change io_32bit flags
+       HDIO_SET_NOWERR         change ignore-write-error flag
+       HDIO_SET_DMA            change use-dma flag
+       HDIO_SET_PIO_MODE       reconfig interface to new speed
+       HDIO_SCAN_HWIF          register and (re)scan interface
+       HDIO_SET_NICE           set nice flags
+       HDIO_UNREGISTER_HWIF    unregister interface
+       HDIO_SET_WCACHE         change write cache enable-disable
+       HDIO_SET_ACOUSTIC       change acoustic behavior
+       HDIO_SET_BUSSTATE       set the bus state of the hwif
+       HDIO_SET_QDMA           change use-qdma flag
+       HDIO_SET_ADDRESS        change lba addressing modes
+
+       HDIO_SET_IDE_SCSI       Set scsi emulation mode on/off
+       HDIO_SET_SCSI_IDE       not implemented yet
+       ======================= =======================================
+
+
+The information that follows was determined from reading kernel source
+code.  It is likely that some corrections will be made over time.
+
+------------------------------------------------------------------------------
+
+General:
+
+       Unless otherwise specified, all ioctl calls return 0 on success
+       and -1 with errno set to an appropriate value on error.
+
+       Unless otherwise specified, all ioctl calls return -1 and set
+       errno to EFAULT on a failed attempt to copy data to or from user
+       address space.
+
+       Unless otherwise specified, all data structures and constants
+       are defined in <linux/hdreg.h>
+
+------------------------------------------------------------------------------
+
+HDIO_GETGEO
+       get device geometry
+
+
+       usage::
+
+         struct hd_geometry geom;
+
+         ioctl(fd, HDIO_GETGEO, &geom);
+
+
+       inputs:
+               none
+
+
+
+       outputs:
+               hd_geometry structure containing:
+
+
+           =========   ==================================
+           heads       number of heads
+           sectors     number of sectors/track
+           cylinders   number of cylinders, mod 65536
+           start       starting sector of this partition.
+           =========   ==================================
+
+
+       error returns:
+         - EINVAL
+
+                       if the device is not a disk drive or floppy drive,
+                       or if the user passes a null pointer
+
+
+       notes:
+               Not particularly useful with modern disk drives, whose geometry
+               is a polite fiction anyway.  Modern drives are addressed
+               purely by sector number nowadays (lba addressing), and the
+               drive geometry is an abstraction which is actually subject
+               to change.  Currently (as of Nov 2004), the geometry values
+               are the "bios" values -- presumably the values the drive had
+               when Linux first booted.
+
+               In addition, the cylinders field of the hd_geometry is an
+               unsigned short, meaning that on most architectures, this
+               ioctl will not return a meaningful value on drives with more
+               than 65535 tracks.
+
+               The start field is unsigned long, meaning that it will not
+               contain a meaningful value for disks over 219 Gb in size.
+
+
+
+
+HDIO_GET_UNMASKINTR
+       get current unmask setting
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_UNMASKINTR, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the drive's current unmask setting
+
+
+
+
+
+HDIO_SET_UNMASKINTR
+       permit other irqs during I/O
+
+
+       usage::
+
+         unsigned long val;
+
+         ioctl(fd, HDIO_SET_UNMASKINTR, val);
+
+       inputs:
+               New value for unmask flag
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 1]
+         - EBUSY       Controller busy
+
+
+
+
+HDIO_GET_MULTCOUNT
+       get current IDE blockmode setting
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_MULTCOUNT, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current IDE block mode setting.  This
+               controls how many sectors the drive will transfer per
+               interrupt.
+
+
+
+HDIO_SET_MULTCOUNT
+       change IDE blockmode
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_MULTCOUNT, val);
+
+       inputs:
+               New value for IDE block mode setting.  This controls how many
+               sectors the drive will transfer per interrupt.
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range supported by disk.
+         - EBUSY       Controller busy or blockmode already set.
+         - EIO         Drive did not accept new block mode.
+
+       notes:
+         Source code comments read::
+
+           This is tightly woven into the driver->do_special cannot
+           touch.  DON'T do it again until a total personality rewrite
+           is committed.
+
+         If blockmode has already been set, this ioctl will fail with
+         -EBUSY
+
+
+
+HDIO_GET_QDMA
+       get use-qdma flag
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_XFER
+       set transfer rate via proc
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_OBSOLETE_IDENTITY
+       OBSOLETE, DO NOT USE
+
+
+       Same as HDIO_GET_IDENTITY (see below), except that it only
+       returns the first 142 bytes of drive identity information.
+
+
+
+HDIO_GET_IDENTITY
+       get IDE identification info
+
+
+       usage::
+
+         unsigned char identity[512];
+
+         ioctl(fd, HDIO_GET_IDENTITY, identity);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               ATA drive identity information.  For full description, see
+               the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in
+               the ATA specification.
+
+       error returns:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - ENOMSG      IDENTIFY DEVICE information not available
+
+       notes:
+               Returns information that was obtained when the drive was
+               probed.  Some of this information is subject to change, and
+               this ioctl does not re-probe the drive to update the
+               information.
+
+               This information is also available from /proc/ide/hdX/identify
+
+
+
+HDIO_GET_KEEPSETTINGS
+       get keep-settings-on-reset flag
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_KEEPSETTINGS, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current "keep settings" flag
+
+
+
+       notes:
+               When set, indicates that kernel should restore settings
+               after a drive reset.
+
+
+
+HDIO_SET_KEEPSETTINGS
+       keep ioctl settings on reset
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_SET_KEEPSETTINGS, val);
+
+       inputs:
+               New value for keep_settings flag
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 1]
+         - EBUSY               Controller busy
+
+
+
+HDIO_GET_32BIT
+       get current io_32bit setting
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_32BIT, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current io_32bit setting
+
+
+
+       notes:
+               0=16-bit, 1=32-bit, 2,3 = 32bit+sync
+
+
+
+
+
+HDIO_GET_NOWERR
+       get ignore-write-error flag
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_NOWERR, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current ignore-write-error flag
+
+
+
+
+
+HDIO_GET_DMA
+       get use-dma flag
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_DMA, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current use-dma flag
+
+
+
+
+
+HDIO_GET_NICE
+       get nice flags
+
+
+       usage::
+
+         long nice;
+
+         ioctl(fd, HDIO_GET_NICE, &nice);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The drive's "nice" values.
+
+
+
+       notes:
+               Per-drive flags which determine when the system will give more
+               bandwidth to other devices sharing the same IDE bus.
+
+               See <linux/hdreg.h>, near symbol IDE_NICE_DSC_OVERLAP.
+
+
+
+
+HDIO_SET_NICE
+       set nice flags
+
+
+       usage::
+
+         unsigned long nice;
+
+         ...
+         ioctl(fd, HDIO_SET_NICE, nice);
+
+       inputs:
+               bitmask of nice flags.
+
+
+
+       outputs:
+               none
+
+
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EPERM       Flags other than DSC_OVERLAP and NICE_1 set.
+         - EPERM       DSC_OVERLAP specified but not supported by drive
+
+       notes:
+               This ioctl sets the DSC_OVERLAP and NICE_1 flags from values
+               provided by the user.
+
+               Nice flags are listed in <linux/hdreg.h>, starting with
+               IDE_NICE_DSC_OVERLAP.  These values represent shifts.
+
+
+
+
+
+HDIO_GET_WCACHE
+       get write cache mode on|off
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_WCACHE, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current write cache mode
+
+
+
+
+
+HDIO_GET_ACOUSTIC
+       get acoustic value
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_GET_ACOUSTIC, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current acoustic settings
+
+
+
+       notes:
+               See HDIO_SET_ACOUSTIC
+
+
+
+
+
+HDIO_GET_ADDRESS
+       usage::
+
+
+         long val;
+
+         ioctl(fd, HDIO_GET_ADDRESS, &val);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               The value of the current addressing mode:
+
+           =  ===================
+           0  28-bit
+           1  48-bit
+           2  48-bit doing 28-bit
+           3  64-bit
+           =  ===================
+
+
+
+HDIO_GET_BUSSTATE
+       get the bus state of the hwif
+
+
+       usage::
+
+         long state;
+
+         ioctl(fd, HDIO_SCAN_HWIF, &state);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               Current power state of the IDE bus.  One of BUSSTATE_OFF,
+               BUSSTATE_ON, or BUSSTATE_TRISTATE
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+
+
+
+
+HDIO_SET_BUSSTATE
+       set the bus state of the hwif
+
+
+       usage::
+
+         int state;
+
+         ...
+         ioctl(fd, HDIO_SCAN_HWIF, state);
+
+       inputs:
+               Desired IDE power state.  One of BUSSTATE_OFF, BUSSTATE_ON,
+               or BUSSTATE_TRISTATE
+
+       outputs:
+               none
+
+
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+         - EOPNOTSUPP  Hardware interface does not support bus power control
+
+
+
+
+HDIO_TRISTATE_HWIF
+       execute a channel tristate
+
+
+       Not implemented, as of 2.6.8.1.  See HDIO_SET_BUSSTATE
+
+
+
+HDIO_DRIVE_RESET
+       execute a device reset
+
+
+       usage::
+
+         int args[3]
+
+         ...
+         ioctl(fd, HDIO_DRIVE_RESET, args);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               none
+
+
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - ENXIO       No such device: phy dead or ctl_addr == 0
+         - EIO         I/O error:      reset timed out or hardware error
+
+       notes:
+
+         - Execute a reset on the device as soon as the current IO
+           operation has completed.
+
+         - Executes an ATAPI soft reset if applicable, otherwise
+           executes an ATA soft reset on the controller.
+
+
+
+HDIO_DRIVE_TASKFILE
+       execute raw taskfile
+
+
+       Note:
+               If you don't have a copy of the ANSI ATA specification
+               handy, you should probably ignore this ioctl.
+
+       - Execute an ATA disk command directly by writing the "taskfile"
+         registers of the drive.  Requires ADMIN and RAWIO access
+         privileges.
+
+       usage::
+
+         struct {
+
+           ide_task_request_t req_task;
+           u8 outbuf[OUTPUT_SIZE];
+           u8 inbuf[INPUT_SIZE];
+         } task;
+         memset(&task.req_task, 0, sizeof(task.req_task));
+         task.req_task.out_size = sizeof(task.outbuf);
+         task.req_task.in_size = sizeof(task.inbuf);
+         ...
+         ioctl(fd, HDIO_DRIVE_TASKFILE, &task);
+         ...
+
+       inputs:
+
+         (See below for details on memory area passed to ioctl.)
+
+         ============  ===================================================
+         io_ports[8]   values to be written to taskfile registers
+         hob_ports[8]  high-order bytes, for extended commands.
+         out_flags     flags indicating which registers are valid
+         in_flags      flags indicating which registers should be returned
+         data_phase    see below
+         req_cmd       command type to be executed
+         out_size      size of output buffer
+         outbuf        buffer of data to be transmitted to disk
+         inbuf         buffer of data to be received from disk (see [1])
+         ============  ===================================================
+
+       outputs:
+
+         ===========   ====================================================
+         io_ports[]    values returned in the taskfile registers
+         hob_ports[]   high-order bytes, for extended commands.
+         out_flags     flags indicating which registers are valid (see [2])
+         in_flags      flags indicating which registers should be returned
+         outbuf        buffer of data to be transmitted to disk (see [1])
+         inbuf         buffer of data to be received from disk
+         ===========   ====================================================
+
+       error returns:
+         - EACCES      CAP_SYS_ADMIN or CAP_SYS_RAWIO privilege not set.
+         - ENOMSG      Device is not a disk drive.
+         - ENOMEM      Unable to allocate memory for task
+         - EFAULT      req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8)
+         - EPERM
+
+                       req_cmd == TASKFILE_MULTI_OUT and drive
+                       multi-count not yet set.
+         - EIO         Drive failed the command.
+
+       notes:
+
+         [1] READ THE FOLLOWING NOTES *CAREFULLY*.  THIS IOCTL IS
+         FULL OF GOTCHAS.  Extreme caution should be used with using
+         this ioctl.  A mistake can easily corrupt data or hang the
+         system.
+
+         [2] Both the input and output buffers are copied from the
+         user and written back to the user, even when not used.
+
+         [3] If one or more bits are set in out_flags and in_flags is
+         zero, the following values are used for in_flags.all and
+         written back into in_flags on completion.
+
+          * IDE_TASKFILE_STD_IN_FLAGS | (IDE_HOB_STD_IN_FLAGS << 8)
+            if LBA48 addressing is enabled for the drive
+          * IDE_TASKFILE_STD_IN_FLAGS
+            if CHS/LBA28
+
+         The association between in_flags.all and each enable
+         bitfield flips depending on endianness; fortunately, TASKFILE
+         only uses inflags.b.data bit and ignores all other bits.
+         The end result is that, on any endian machines, it has no
+         effect other than modifying in_flags on completion.
+
+         [4] The default value of SELECT is (0xa0|DEV_bit|LBA_bit)
+         except for four drives per port chipsets.  For four drives
+         per port chipsets, it's (0xa0|DEV_bit|LBA_bit) for the first
+         pair and (0x80|DEV_bit|LBA_bit) for the second pair.
+
+         [5] The argument to the ioctl is a pointer to a region of
+         memory containing a ide_task_request_t structure, followed
+         by an optional buffer of data to be transmitted to the
+         drive, followed by an optional buffer to receive data from
+         the drive.
+
+         Command is passed to the disk drive via the ide_task_request_t
+         structure, which contains these fields:
+
+           ============        ===============================================
+           io_ports[8]         values for the taskfile registers
+           hob_ports[8]        high-order bytes, for extended commands
+           out_flags           flags indicating which entries in the
+                               io_ports[] and hob_ports[] arrays
+                               contain valid values.  Type ide_reg_valid_t.
+           in_flags            flags indicating which entries in the
+                               io_ports[] and hob_ports[] arrays
+                               are expected to contain valid values
+                               on return.
+           data_phase          See below
+           req_cmd             Command type, see below
+           out_size            output (user->drive) buffer size, bytes
+           in_size             input (drive->user) buffer size, bytes
+           ============        ===============================================
+
+         When out_flags is zero, the following registers are loaded.
+
+           ============        ===============================================
+           HOB_FEATURE         If the drive supports LBA48
+           HOB_NSECTOR         If the drive supports LBA48
+           HOB_SECTOR          If the drive supports LBA48
+           HOB_LCYL            If the drive supports LBA48
+           HOB_HCYL            If the drive supports LBA48
+           FEATURE
+           NSECTOR
+           SECTOR
+           LCYL
+           HCYL
+           SELECT              First, masked with 0xE0 if LBA48, 0xEF
+                               otherwise; then, or'ed with the default
+                               value of SELECT.
+           ============        ===============================================
+
+         If any bit in out_flags is set, the following registers are loaded.
+
+           ============        ===============================================
+           HOB_DATA            If out_flags.b.data is set.  HOB_DATA will
+                               travel on DD8-DD15 on little endian machines
+                               and on DD0-DD7 on big endian machines.
+           DATA                If out_flags.b.data is set.  DATA will
+                               travel on DD0-DD7 on little endian machines
+                               and on DD8-DD15 on big endian machines.
+           HOB_NSECTOR         If out_flags.b.nsector_hob is set
+           HOB_SECTOR          If out_flags.b.sector_hob is set
+           HOB_LCYL            If out_flags.b.lcyl_hob is set
+           HOB_HCYL            If out_flags.b.hcyl_hob is set
+           FEATURE             If out_flags.b.feature is set
+           NSECTOR             If out_flags.b.nsector is set
+           SECTOR              If out_flags.b.sector is set
+           LCYL                If out_flags.b.lcyl is set
+           HCYL                If out_flags.b.hcyl is set
+           SELECT              Or'ed with the default value of SELECT and
+                               loaded regardless of out_flags.b.select.
+           ============        ===============================================
+
+         Taskfile registers are read back from the drive into
+         {io|hob}_ports[] after the command completes iff one of the
+         following conditions is met; otherwise, the original values
+         will be written back, unchanged.
+
+           1. The drive fails the command (EIO).
+           2. One or more than one bits are set in out_flags.
+           3. The requested data_phase is TASKFILE_NO_DATA.
+
+           ============        ===============================================
+           HOB_DATA            If in_flags.b.data is set.  It will contain
+                               DD8-DD15 on little endian machines and
+                               DD0-DD7 on big endian machines.
+           DATA                If in_flags.b.data is set.  It will contain
+                               DD0-DD7 on little endian machines and
+                               DD8-DD15 on big endian machines.
+           HOB_FEATURE         If the drive supports LBA48
+           HOB_NSECTOR         If the drive supports LBA48
+           HOB_SECTOR          If the drive supports LBA48
+           HOB_LCYL            If the drive supports LBA48
+           HOB_HCYL            If the drive supports LBA48
+           NSECTOR
+           SECTOR
+           LCYL
+           HCYL
+           ============        ===============================================
+
+         The data_phase field describes the data transfer to be
+         performed.  Value is one of:
+
+           ===================        ========================================
+           TASKFILE_IN
+           TASKFILE_MULTI_IN
+           TASKFILE_OUT
+           TASKFILE_MULTI_OUT
+           TASKFILE_IN_OUT
+           TASKFILE_IN_DMA
+           TASKFILE_IN_DMAQ            == IN_DMA (queueing not supported)
+           TASKFILE_OUT_DMA
+           TASKFILE_OUT_DMAQ           == OUT_DMA (queueing not supported)
+           TASKFILE_P_IN               unimplemented
+           TASKFILE_P_IN_DMA           unimplemented
+           TASKFILE_P_IN_DMAQ          unimplemented
+           TASKFILE_P_OUT              unimplemented
+           TASKFILE_P_OUT_DMA          unimplemented
+           TASKFILE_P_OUT_DMAQ         unimplemented
+           ===================        ========================================
+
+         The req_cmd field classifies the command type.  It may be
+         one of:
+
+           ========================    =======================================
+           IDE_DRIVE_TASK_NO_DATA
+           IDE_DRIVE_TASK_SET_XFER     unimplemented
+           IDE_DRIVE_TASK_IN
+           IDE_DRIVE_TASK_OUT          unimplemented
+           IDE_DRIVE_TASK_RAW_WRITE
+           ========================    =======================================
+
+         [6] Do not access {in|out}_flags->all except for resetting
+         all the bits.  Always access individual bit fields.  ->all
+         value will flip depending on endianness.  For the same
+         reason, do not use IDE_{TASKFILE|HOB}_STD_{OUT|IN}_FLAGS
+         constants defined in hdreg.h.
+
+
+
+HDIO_DRIVE_CMD
+       execute a special drive command
+
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       usage::
+
+         u8 args[4+XFER_SIZE];
+
+         ...
+         ioctl(fd, HDIO_DRIVE_CMD, args);
+
+       inputs:
+           Commands other than WIN_SMART:
+
+           =======     =======
+           args[0]     COMMAND
+           args[1]     NSECTOR
+           args[2]     FEATURE
+           args[3]     NSECTOR
+           =======     =======
+
+           WIN_SMART:
+
+           =======     =======
+           args[0]     COMMAND
+           args[1]     SECTOR
+           args[2]     FEATURE
+           args[3]     NSECTOR
+           =======     =======
+
+       outputs:
+               args[] buffer is filled with register values followed by any
+
+
+         data returned by the disk.
+
+           ========    ====================================================
+           args[0]     status
+           args[1]     error
+           args[2]     NSECTOR
+           args[3]     undefined
+           args[4+]    NSECTOR * 512 bytes of data returned by the command.
+           ========    ====================================================
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+         - ENOMEM      Unable to allocate memory for task
+         - EIO         Drive reports error
+
+       notes:
+
+         [1] For commands other than WIN_SMART, args[1] should equal
+         args[3].  SECTOR, LCYL and HCYL are undefined.  For
+         WIN_SMART, 0x4f and 0xc2 are loaded into LCYL and HCYL
+         respectively.  In both cases SELECT will contain the default
+         value for the drive.  Please refer to HDIO_DRIVE_TASKFILE
+         notes for the default value of SELECT.
+
+         [2] If NSECTOR value is greater than zero and the drive sets
+         DRQ when interrupting for the command, NSECTOR * 512 bytes
+         are read from the device into the area following NSECTOR.
+         In the above example, the area would be
+         args[4..4+XFER_SIZE].  16bit PIO is used regardless of
+         HDIO_SET_32BIT setting.
+
+         [3] If COMMAND == WIN_SETFEATURES && FEATURE == SETFEATURES_XFER
+         && NSECTOR >= XFER_SW_DMA_0 && the drive supports any DMA
+         mode, IDE driver will try to tune the transfer mode of the
+         drive accordingly.
+
+
+
+HDIO_DRIVE_TASK
+       execute task and special drive command
+
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       usage::
+
+         u8 args[7];
+
+         ...
+         ioctl(fd, HDIO_DRIVE_TASK, args);
+
+       inputs:
+           Taskfile register values:
+
+           =======     =======
+           args[0]     COMMAND
+           args[1]     FEATURE
+           args[2]     NSECTOR
+           args[3]     SECTOR
+           args[4]     LCYL
+           args[5]     HCYL
+           args[6]     SELECT
+           =======     =======
+
+       outputs:
+           Taskfile register values:
+
+
+           =======     =======
+           args[0]     status
+           args[1]     error
+           args[2]     NSECTOR
+           args[3]     SECTOR
+           args[4]     LCYL
+           args[5]     HCYL
+           args[6]     SELECT
+           =======     =======
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+         - ENOMEM      Unable to allocate memory for task
+         - ENOMSG      Device is not a disk drive.
+         - EIO         Drive failed the command.
+
+       notes:
+
+         [1] DEV bit (0x10) of SELECT register is ignored and the
+         appropriate value for the drive is used.  All other bits
+         are used unaltered.
+
+
+
+HDIO_DRIVE_CMD_AEB
+       HDIO_DRIVE_TASK
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_32BIT
+       change io_32bit flags
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_32BIT, val);
+
+       inputs:
+               New value for io_32bit flag
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 3]
+         - EBUSY       Controller busy
+
+
+
+
+HDIO_SET_NOWERR
+       change ignore-write-error flag
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_NOWERR, val);
+
+       inputs:
+               New value for ignore-write-error flag.  Used for ignoring
+
+
+         WRERR_STAT
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 1]
+         - EBUSY               Controller busy
+
+
+
+HDIO_SET_DMA
+       change use-dma flag
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_SET_DMA, val);
+
+       inputs:
+               New value for use-dma flag
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 1]
+         - EBUSY       Controller busy
+
+
+
+HDIO_SET_PIO_MODE
+       reconfig interface to new speed
+
+
+       usage::
+
+         long val;
+
+         ioctl(fd, HDIO_SET_PIO_MODE, val);
+
+       inputs:
+               New interface speed.
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 255]
+         - EBUSY       Controller busy
+
+
+
+HDIO_SCAN_HWIF
+       register and (re)scan interface
+
+
+       usage::
+
+         int args[3]
+
+         ...
+         ioctl(fd, HDIO_SCAN_HWIF, args);
+
+       inputs:
+
+         =======       =========================
+         args[0]       io address to probe
+
+
+         args[1]       control address to probe
+         args[2]       irq number
+         =======       =========================
+
+       outputs:
+               none
+
+
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+         - EIO         Probe failed.
+
+       notes:
+               This ioctl initializes the addresses and irq for a disk
+               controller, probes for drives, and creates /proc/ide
+               interfaces as appropriate.
+
+
+
+HDIO_UNREGISTER_HWIF
+       unregister interface
+
+
+       usage::
+
+         int index;
+
+         ioctl(fd, HDIO_UNREGISTER_HWIF, index);
+
+       inputs:
+               index           index of hardware interface to unregister
+
+
+
+       outputs:
+               none
+
+
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+
+       notes:
+               This ioctl removes a hardware interface from the kernel.
+
+               Currently (2.6.8) this ioctl silently fails if any drive on
+               the interface is busy.
+
+
+
+HDIO_SET_WCACHE
+       change write cache enable-disable
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_WCACHE, val);
+
+       inputs:
+               New value for write cache enable
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 1]
+         - EBUSY       Controller busy
+
+
+
+HDIO_SET_ACOUSTIC
+       change acoustic behavior
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_ACOUSTIC, val);
+
+       inputs:
+               New value for drive acoustic settings
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 254]
+         - EBUSY       Controller busy
+
+
+
+HDIO_SET_QDMA
+       change use-qdma flag
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_ADDRESS
+       change lba addressing modes
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_ADDRESS, val);
+
+       inputs:
+               New value for addressing mode
+
+           =   ===================
+           0   28-bit
+           1   48-bit
+           2   48-bit doing 28-bit
+           =   ===================
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 2]
+         - EBUSY               Controller busy
+         - EIO         Drive does not support lba48 mode.
+
+
+HDIO_SET_IDE_SCSI
+       usage::
+
+
+         long val;
+
+         ioctl(fd, HDIO_SET_IDE_SCSI, val);
+
+       inputs:
+               New value for scsi emulation mode (?)
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - EINVAL      value out of range [0 1]
+         - EBUSY       Controller busy
+
+
+
+HDIO_SET_SCSI_IDE
+       Not implemented, as of 2.6.8.1
diff --git a/Documentation/userspace-api/ioctl/index.rst b/Documentation/userspace-api/ioctl/index.rst
new file mode 100644 (file)
index 0000000..475675e
--- /dev/null
@@ -0,0 +1,15 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======
+IOCTLs
+======
+
+.. toctree::
+   :maxdepth: 1
+
+   ioctl-number
+
+   ioctl-decoding
+
+   cdrom
+   hdio
diff --git a/Documentation/userspace-api/ioctl/ioctl-decoding.rst b/Documentation/userspace-api/ioctl/ioctl-decoding.rst
new file mode 100644 (file)
index 0000000..380d6bb
--- /dev/null
@@ -0,0 +1,31 @@
+==============================
+Decoding an IOCTL Magic Number
+==============================
+
+To decode a hex IOCTL code:
+
+Most architectures use this generic format, but check
+include/ARCH/ioctl.h for specifics, e.g. powerpc
+uses 3 bits to encode read/write and 13 bits for size.
+
+ ====== ==================================
+ bits   meaning
+ ====== ==================================
+ 31-30 00 - no parameters: uses _IO macro
+       10 - read: _IOR
+       01 - write: _IOW
+       11 - read/write: _IOWR
+
+ 29-16 size of arguments
+
+ 15-8  ascii character supposedly
+       unique to each driver
+
+ 7-0   function #
+ ====== ==================================
+
+
+So for example 0x82187201 is a read with arg length of 0x218,
+character 'r' function 1. Grepping the source reveals this is::
+
+       #define VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
new file mode 100644 (file)
index 0000000..4ef8643
--- /dev/null
@@ -0,0 +1,363 @@
+=============
+Ioctl Numbers
+=============
+
+19 October 1999
+
+Michael Elizabeth Chastain
+<mec@shout.net>
+
+If you are adding new ioctl's to the kernel, you should use the _IO
+macros defined in <linux/ioctl.h>:
+
+    ====== == ============================================
+    _IO    an ioctl with no parameters
+    _IOW   an ioctl with write parameters (copy_from_user)
+    _IOR   an ioctl with read parameters  (copy_to_user)
+    _IOWR  an ioctl with both write and read parameters.
+    ====== == ============================================
+
+'Write' and 'read' are from the user's point of view, just like the
+system calls 'write' and 'read'.  For example, a SET_FOO ioctl would
+be _IOW, although the kernel would actually read data from user space;
+a GET_FOO ioctl would be _IOR, although the kernel would actually write
+data to user space.
+
+The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
+or number from the table below.  Because of the large number of drivers,
+many drivers share a partial letter with other drivers.
+
+If you are writing a driver for a new device and need a letter, pick an
+unused block with enough room for expansion: 32 to 256 ioctl commands.
+You can register the block by patching this file and submitting the
+patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and
+I'll register one for you.
+
+The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
+to distinguish ioctls from each other.  The third argument to _IOW,
+_IOR, or _IOWR is the type of the data going into the kernel or coming
+out of the kernel (e.g.  'int' or 'struct foo').  NOTE!  Do NOT use
+sizeof(arg) as the third argument as this results in your ioctl thinking
+it passes an argument of type size_t.
+
+Some devices use their major number as the identifier; this is OK, as
+long as it is unique.  Some devices are irregular and don't follow any
+convention at all.
+
+Following this convention is good because:
+
+(1) Keeping the ioctl's globally unique helps error checking:
+    if a program calls an ioctl on the wrong device, it will get an
+    error rather than some unexpected behaviour.
+
+(2) The 'strace' build procedure automatically finds ioctl numbers
+    defined with _IO, _IOW, _IOR, or _IOWR.
+
+(3) 'strace' can decode numbers back into useful names when the
+    numbers are unique.
+
+(4) People looking for ioctls can grep for them more easily when
+    this convention is used to define the ioctl numbers.
+
+(5) When following the convention, the driver code can use generic
+    code to copy the parameters between user and kernel space.
+
+This table lists ioctls visible from user land for Linux/x86.  It contains
+most drivers up to 2.6.31, but I know I am missing some.  There has been
+no attempt to list non-X86 architectures or ioctls from drivers/staging/.
+
+====  =====  ======================================================= ================================================================
+Code  Seq#    Include File                                           Comments
+      (hex)
+====  =====  ======================================================= ================================================================
+0x00  00-1F  linux/fs.h                                              conflict!
+0x00  00-1F  scsi/scsi_ioctl.h                                       conflict!
+0x00  00-1F  linux/fb.h                                              conflict!
+0x00  00-1F  linux/wavefront.h                                       conflict!
+0x02  all    linux/fd.h
+0x03  all    linux/hdreg.h
+0x04  D2-DC  linux/umsdos_fs.h                                       Dead since 2.6.11, but don't reuse these.
+0x06  all    linux/lp.h
+0x09  all    linux/raid/md_u.h
+0x10  00-0F  drivers/char/s390/vmcp.h
+0x10  10-1F  arch/s390/include/uapi/sclp_ctl.h
+0x10  20-2F  arch/s390/include/uapi/asm/hypfs.h
+0x12  all    linux/fs.h
+             linux/blkpg.h
+0x1b  all                                                            InfiniBand Subsystem
+                                                                     <http://infiniband.sourceforge.net/>
+0x20  all    drivers/cdrom/cm206.h
+0x22  all    scsi/sg.h
+'!'   00-1F  uapi/linux/seccomp.h
+'#'   00-3F                                                          IEEE 1394 Subsystem
+                                                                     Block for the entire subsystem
+'$'   00-0F  linux/perf_counter.h, linux/perf_event.h
+'%'   00-0F  include/uapi/linux/stm.h                                System Trace Module subsystem
+                                                                     <mailto:alexander.shishkin@linux.intel.com>
+'&'   00-07  drivers/firewire/nosy-user.h
+'1'   00-1F  linux/timepps.h                                         PPS kit from Ulrich Windl
+                                                                     <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
+'2'   01-04  linux/i2o.h
+'3'   00-0F  drivers/s390/char/raw3270.h                             conflict!
+'3'   00-1F  linux/suspend_ioctls.h,                                 conflict!
+             kernel/power/user.c
+'8'   all                                                            SNP8023 advanced NIC card
+                                                                     <mailto:mcr@solidum.com>
+';'   64-7F  linux/vfio.h
+'@'   00-0F  linux/radeonfb.h                                        conflict!
+'@'   00-0F  drivers/video/aty/aty128fb.c                            conflict!
+'A'   00-1F  linux/apm_bios.h                                        conflict!
+'A'   00-0F  linux/agpgart.h,                                        conflict!
+             drivers/char/agp/compat_ioctl.h
+'A'   00-7F  sound/asound.h                                          conflict!
+'B'   00-1F  linux/cciss_ioctl.h                                     conflict!
+'B'   00-0F  include/linux/pmu.h                                     conflict!
+'B'   C0-FF  advanced bbus                                           <mailto:maassen@uni-freiburg.de>
+'C'   all    linux/soundcard.h                                       conflict!
+'C'   01-2F  linux/capi.h                                            conflict!
+'C'   F0-FF  drivers/net/wan/cosa.h                                  conflict!
+'D'   all    arch/s390/include/asm/dasd.h
+'D'   40-5F  drivers/scsi/dpt/dtpi_ioctl.h
+'D'   05     drivers/scsi/pmcraid.h
+'E'   all    linux/input.h                                           conflict!
+'E'   00-0F  xen/evtchn.h                                            conflict!
+'F'   all    linux/fb.h                                              conflict!
+'F'   01-02  drivers/scsi/pmcraid.h                                  conflict!
+'F'   20     drivers/video/fsl-diu-fb.h                              conflict!
+'F'   20     drivers/video/intelfb/intelfb.h                         conflict!
+'F'   20     linux/ivtvfb.h                                          conflict!
+'F'   20     linux/matroxfb.h                                        conflict!
+'F'   20     drivers/video/aty/atyfb_base.c                          conflict!
+'F'   00-0F  video/da8xx-fb.h                                        conflict!
+'F'   80-8F  linux/arcfb.h                                           conflict!
+'F'   DD     video/sstfb.h                                           conflict!
+'G'   00-3F  drivers/misc/sgi-gru/grulib.h                           conflict!
+'G'   00-0F  linux/gigaset_dev.h                                     conflict!
+'H'   00-7F  linux/hiddev.h                                          conflict!
+'H'   00-0F  linux/hidraw.h                                          conflict!
+'H'   01     linux/mei.h                                             conflict!
+'H'   02     linux/mei.h                                             conflict!
+'H'   03     linux/mei.h                                             conflict!
+'H'   00-0F  sound/asound.h                                          conflict!
+'H'   20-40  sound/asound_fm.h                                       conflict!
+'H'   80-8F  sound/sfnt_info.h                                       conflict!
+'H'   10-8F  sound/emu10k1.h                                         conflict!
+'H'   10-1F  sound/sb16_csp.h                                        conflict!
+'H'   10-1F  sound/hda_hwdep.h                                       conflict!
+'H'   40-4F  sound/hdspm.h                                           conflict!
+'H'   40-4F  sound/hdsp.h                                            conflict!
+'H'   90     sound/usb/usx2y/usb_stream.h
+'H'   A0     uapi/linux/usb/cdc-wdm.h
+'H'   C0-F0  net/bluetooth/hci.h                                     conflict!
+'H'   C0-DF  net/bluetooth/hidp/hidp.h                               conflict!
+'H'   C0-DF  net/bluetooth/cmtp/cmtp.h                               conflict!
+'H'   C0-DF  net/bluetooth/bnep/bnep.h                               conflict!
+'H'   F1     linux/hid-roccat.h                                      <mailto:erazor_de@users.sourceforge.net>
+'H'   F8-FA  sound/firewire.h
+'I'   all    linux/isdn.h                                            conflict!
+'I'   00-0F  drivers/isdn/divert/isdn_divert.h                       conflict!
+'I'   40-4F  linux/mISDNif.h                                         conflict!
+'J'   00-1F  drivers/scsi/gdth_ioctl.h
+'K'   all    linux/kd.h
+'L'   00-1F  linux/loop.h                                            conflict!
+'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                      conflict!
+'L'   20-2F  linux/lightnvm.h
+'L'   E0-FF  linux/ppdd.h                                            encrypted disk device driver
+                                                                     <http://linux01.gwdg.de/~alatham/ppdd.html>
+'M'   all    linux/soundcard.h                                       conflict!
+'M'   01-16  mtd/mtd-abi.h                                           conflict!
+      and    drivers/mtd/mtdchar.c
+'M'   01-03  drivers/scsi/megaraid/megaraid_sas.h
+'M'   00-0F  drivers/video/fsl-diu-fb.h                              conflict!
+'N'   00-1F  drivers/usb/scanner.h
+'N'   40-7F  drivers/block/nvme.c
+'O'   00-06  mtd/ubi-user.h                                          UBI
+'P'   all    linux/soundcard.h                                       conflict!
+'P'   60-6F  sound/sscape_ioctl.h                                    conflict!
+'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
+'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
+'Q'   all    linux/soundcard.h
+'R'   00-1F  linux/random.h                                          conflict!
+'R'   01     linux/rfkill.h                                          conflict!
+'R'   C0-DF  net/bluetooth/rfcomm.h
+'S'   all    linux/cdrom.h                                           conflict!
+'S'   80-81  scsi/scsi_ioctl.h                                       conflict!
+'S'   82-FF  scsi/scsi.h                                             conflict!
+'S'   00-7F  sound/asequencer.h                                      conflict!
+'T'   all    linux/soundcard.h                                       conflict!
+'T'   00-AF  sound/asound.h                                          conflict!
+'T'   all    arch/x86/include/asm/ioctls.h                           conflict!
+'T'   C0-DF  linux/if_tun.h                                          conflict!
+'U'   all    sound/asound.h                                          conflict!
+'U'   00-CF  linux/uinput.h                                          conflict!
+'U'   00-EF  linux/usbdevice_fs.h
+'U'   C0-CF  drivers/bluetooth/hci_uart.h
+'V'   all    linux/vt.h                                              conflict!
+'V'   all    linux/videodev2.h                                       conflict!
+'V'   C0     linux/ivtvfb.h                                          conflict!
+'V'   C0     linux/ivtv.h                                            conflict!
+'V'   C0     media/davinci/vpfe_capture.h                            conflict!
+'V'   C0     media/si4713.h                                          conflict!
+'W'   00-1F  linux/watchdog.h                                        conflict!
+'W'   00-1F  linux/wanrouter.h                                       conflict! (pre 3.9)
+'W'   00-3F  sound/asound.h                                          conflict!
+'W'   40-5F  drivers/pci/switch/switchtec.c
+'X'   all    fs/xfs/xfs_fs.h,                                        conflict!
+             fs/xfs/linux-2.6/xfs_ioctl32.h,
+             include/linux/falloc.h,
+             linux/fs.h,
+'X'   all    fs/ocfs2/ocfs_fs.h                                      conflict!
+'X'   01     linux/pktcdvd.h                                         conflict!
+'Y'   all    linux/cyclades.h
+'Z'   14-15  drivers/message/fusion/mptctl.h
+'['   00-3F  linux/usb/tmc.h                                         USB Test and Measurement Devices
+                                                                     <mailto:gregkh@linuxfoundation.org>
+'a'   all    linux/atm*.h, linux/sonet.h                             ATM on linux
+                                                                     <http://lrcwww.epfl.ch/>
+'a'   00-0F  drivers/crypto/qat/qat_common/adf_cfg_common.h          conflict! qat driver
+'b'   00-FF                                                          conflict! bit3 vme host bridge
+                                                                     <mailto:natalia@nikhefk.nikhef.nl>
+'c'   all    linux/cm4000_cs.h                                       conflict!
+'c'   00-7F  linux/comstats.h                                        conflict!
+'c'   00-7F  linux/coda.h                                            conflict!
+'c'   00-1F  linux/chio.h                                            conflict!
+'c'   80-9F  arch/s390/include/asm/chsc.h                            conflict!
+'c'   A0-AF  arch/x86/include/asm/msr.h conflict!
+'d'   00-FF  linux/char/drm/drm.h                                    conflict!
+'d'   02-40  pcmcia/ds.h                                             conflict!
+'d'   F0-FF  linux/digi1.h
+'e'   all    linux/digi1.h                                           conflict!
+'f'   00-1F  linux/ext2_fs.h                                         conflict!
+'f'   00-1F  linux/ext3_fs.h                                         conflict!
+'f'   00-0F  fs/jfs/jfs_dinode.h                                     conflict!
+'f'   00-0F  fs/ext4/ext4.h                                          conflict!
+'f'   00-0F  linux/fs.h                                              conflict!
+'f'   00-0F  fs/ocfs2/ocfs2_fs.h                                     conflict!
+'f'   13-27  linux/fscrypt.h
+'f'   81-8F  linux/fsverity.h
+'g'   00-0F  linux/usb/gadgetfs.h
+'g'   20-2F  linux/usb/g_printer.h
+'h'   00-7F                                                          conflict! Charon filesystem
+                                                                     <mailto:zapman@interlan.net>
+'h'   00-1F  linux/hpet.h                                            conflict!
+'h'   80-8F  fs/hfsplus/ioctl.c
+'i'   00-3F  linux/i2o-dev.h                                         conflict!
+'i'   0B-1F  linux/ipmi.h                                            conflict!
+'i'   80-8F  linux/i8k.h
+'j'   00-3F  linux/joystick.h
+'k'   00-0F  linux/spi/spidev.h                                      conflict!
+'k'   00-05  video/kyro.h                                            conflict!
+'k'   10-17  linux/hsi/hsi_char.h                                    HSI character device
+'l'   00-3F  linux/tcfs_fs.h                                         transparent cryptographic file system
+                                                                     <http://web.archive.org/web/%2A/http://mikonos.dia.unisa.it/tcfs>
+'l'   40-7F  linux/udf_fs_i.h                                        in development:
+                                                                     <http://sourceforge.net/projects/linux-udf/>
+'m'   00-09  linux/mmtimer.h                                         conflict!
+'m'   all    linux/mtio.h                                            conflict!
+'m'   all    linux/soundcard.h                                       conflict!
+'m'   all    linux/synclink.h                                        conflict!
+'m'   00-19  drivers/message/fusion/mptctl.h                         conflict!
+'m'   00     drivers/scsi/megaraid/megaraid_ioctl.h                  conflict!
+'n'   00-7F  linux/ncp_fs.h and fs/ncpfs/ioctl.c
+'n'   80-8F  uapi/linux/nilfs2_api.h                                 NILFS2
+'n'   E0-FF  linux/matroxfb.h                                        matroxfb
+'o'   00-1F  fs/ocfs2/ocfs2_fs.h                                     OCFS2
+'o'   00-03  mtd/ubi-user.h                                          conflict! (OCFS2 and UBI overlaps)
+'o'   40-41  mtd/ubi-user.h                                          UBI
+'o'   01-A1  `linux/dvb/*.h`                                         DVB
+'p'   00-0F  linux/phantom.h                                         conflict! (OpenHaptics needs this)
+'p'   00-1F  linux/rtc.h                                             conflict!
+'p'   00-3F  linux/mc146818rtc.h                                     conflict!
+'p'   40-7F  linux/nvram.h
+'p'   80-9F  linux/ppdev.h                                           user-space parport
+                                                                     <mailto:tim@cyberelk.net>
+'p'   A1-A5  linux/pps.h                                             LinuxPPS
+                                                                     <mailto:giometti@linux.it>
+'q'   00-1F  linux/serio.h
+'q'   80-FF  linux/telephony.h                                       Internet PhoneJACK, Internet LineJACK
+             linux/ixjuser.h                                         <http://web.archive.org/web/%2A/http://www.quicknet.net>
+'r'   00-1F  linux/msdos_fs.h and fs/fat/dir.c
+'s'   all    linux/cdk.h
+'t'   00-7F  linux/ppp-ioctl.h
+'t'   80-8F  linux/isdn_ppp.h
+'t'   90-91  linux/toshiba.h                                         toshiba and toshiba_acpi SMM
+'u'   00-1F  linux/smb_fs.h                                          gone
+'u'   20-3F  linux/uvcvideo.h                                        USB video class host driver
+'u'   40-4f  linux/udmabuf.h                                         userspace dma-buf misc device
+'v'   00-1F  linux/ext2_fs.h                                         conflict!
+'v'   00-1F  linux/fs.h                                              conflict!
+'v'   00-0F  linux/sonypi.h                                          conflict!
+'v'   00-0F  media/v4l2-subdev.h                                     conflict!
+'v'   C0-FF  linux/meye.h                                            conflict!
+'w'   all                                                            CERN SCI driver
+'y'   00-1F                                                          packet based user level communications
+                                                                     <mailto:zapman@interlan.net>
+'z'   00-3F                                                          CAN bus card conflict!
+                                                                     <mailto:hdstich@connectu.ulm.circular.de>
+'z'   40-7F                                                          CAN bus card conflict!
+                                                                     <mailto:oe@port.de>
+'z'   10-4F  drivers/s390/crypto/zcrypt_api.h                        conflict!
+'|'   00-7F  linux/media.h
+0x80  00-1F  linux/fb.h
+0x89  00-06  arch/x86/include/asm/sockios.h
+0x89  0B-DF  linux/sockios.h
+0x89  E0-EF  linux/sockios.h                                         SIOCPROTOPRIVATE range
+0x89  E0-EF  linux/dn.h                                              PROTOPRIVATE range
+0x89  F0-FF  linux/sockios.h                                         SIOCDEVPRIVATE range
+0x8B  all    linux/wireless.h
+0x8C  00-3F                                                          WiNRADiO driver
+                                                                     <http://www.winradio.com.au/>
+0x90  00     drivers/cdrom/sbpcd.h
+0x92  00-0F  drivers/usb/mon/mon_bin.c
+0x93  60-7F  linux/auto_fs.h
+0x94  all    fs/btrfs/ioctl.h                                        Btrfs filesystem
+             and linux/fs.h                                          some lifted to vfs/generic
+0x97  00-7F  fs/ceph/ioctl.h                                         Ceph file system
+0x99  00-0F                                                          537-Addinboard driver
+                                                                     <mailto:buk@buks.ipn.de>
+0xA0  all    linux/sdp/sdp.h                                         Industrial Device Project
+                                                                     <mailto:kenji@bitgate.com>
+0xA1  0      linux/vtpm_proxy.h                                      TPM Emulator Proxy Driver
+0xA3  80-8F                                                          Port ACL  in development:
+                                                                     <mailto:tlewis@mindspring.com>
+0xA3  90-9F  linux/dtlk.h
+0xA4  00-1F  uapi/linux/tee.h                                        Generic TEE subsystem
+0xAA  00-3F  linux/uapi/linux/userfaultfd.h
+0xAB  00-1F  linux/nbd.h
+0xAC  00-1F  linux/raw.h
+0xAD  00                                                             Netfilter device in development:
+                                                                     <mailto:rusty@rustcorp.com.au>
+0xAE  all    linux/kvm.h                                             Kernel-based Virtual Machine
+                                                                     <mailto:kvm@vger.kernel.org>
+0xAF  00-1F  linux/fsl_hypervisor.h                                  Freescale hypervisor
+0xB0  all                                                            RATIO devices in development:
+                                                                     <mailto:vgo@ratio.de>
+0xB1  00-1F                                                          PPPoX
+                                                                     <mailto:mostrows@styx.uwaterloo.ca>
+0xB3  00     linux/mmc/ioctl.h
+0xB4  00-0F  linux/gpio.h                                            <mailto:linux-gpio@vger.kernel.org>
+0xB5  00-0F  uapi/linux/rpmsg.h                                      <mailto:linux-remoteproc@vger.kernel.org>
+0xB6  all    linux/fpga-dfl.h
+0xC0  00-0F  linux/usb/iowarrior.h
+0xCA  00-0F  uapi/misc/cxl.h
+0xCA  10-2F  uapi/misc/ocxl.h
+0xCA  80-BF  uapi/scsi/cxlflash_ioctl.h
+0xCB  00-1F                                                          CBM serial IEC bus in development:
+                                                                     <mailto:michael.klein@puffin.lb.shuttle.de>
+0xCC  00-0F  drivers/misc/ibmvmc.h                                   pseries VMC driver
+0xCD  01     linux/reiserfs_fs.h
+0xCF  02     fs/cifs/ioctl.c
+0xDB  00-0F  drivers/char/mwave/mwavepub.h
+0xDD  00-3F                                                          ZFCP device driver see drivers/s390/scsi/
+                                                                     <mailto:aherrman@de.ibm.com>
+0xE5  00-3F  linux/fuse.h
+0xEC  00-01  drivers/platform/chrome/cros_ec_dev.h                   ChromeOS EC driver
+0xF3  00-3F  drivers/usb/misc/sisusbvga/sisusb.h                     sisfb (in development)
+                                                                     <mailto:thomas@winischhofer.net>
+0xF4  00-1F  video/mbxfb.h                                           mbxfb
+                                                                     <mailto:raph@8d.com>
+0xF6  all                                                            LTTng Linux Trace Toolkit Next Generation
+                                                                     <mailto:mathieu.desnoyers@efficios.com>
+0xFD  all    linux/dm-ioctl.h
+0xFE  all    linux/isst_if.h
+====  =====  ======================================================= ================================================================
index 49183ad..ebb37b3 100644 (file)
@@ -5,7 +5,7 @@ The Definitive KVM (Kernel-based Virtual Machine) API Documentation
 ----------------------
 
 The kvm API is a set of ioctls that are issued to control various aspects
-of a virtual machine.  The ioctls belong to three classes:
+of a virtual machine.  The ioctls belong to the following classes:
 
  - System ioctls: These query and set global attributes which affect the
    whole kvm subsystem.  In addition a system ioctl is used to create
@@ -4149,6 +4149,24 @@ Valid values for 'action':
 #define KVM_PMU_EVENT_ALLOW 0
 #define KVM_PMU_EVENT_DENY 1
 
+4.121 KVM_PPC_SVM_OFF
+
+Capability: basic
+Architectures: powerpc
+Type: vm ioctl
+Parameters: none
+Returns: 0 on successful completion,
+Errors:
+  EINVAL:    if ultravisor failed to terminate the secure guest
+  ENOMEM:    if hypervisor failed to allocate new radix page tables for guest
+
+This ioctl is used to turn off the secure mode of the guest or transition
+the guest from secure mode to normal mode. This is invoked when the guest
+is reset. This has no effect if called for a normal guest.
+
+This ioctl issues an ultravisor call to terminate the secure guest,
+unpins the VPA pages and releases all the device pages that are used to
+track the secure pages by hypervisor.
 
 5. The kvm_run structure
 ------------------------
index 57cba81..156279f 100644 (file)
@@ -1,4 +1,4 @@
-. SPDX-License-Identifier: GPL-2.0
+.. SPDX-License-Identifier: GPL-2.0
 
 ================
 1-Wire Subsystem
index 8608724..067cae5 100644 (file)
@@ -1,12 +1,14 @@
-
-
-       List of maintainers and how to submit kernel changes
+List of maintainers and how to submit kernel changes
+====================================================
 
 Please try to follow the guidelines below.  This will make things
 easier on the maintainers.  Not all of these guidelines matter for every
 trivial patch so apply some common sense.
 
-1.     Always _test_ your changes, however small, on at least 4 or
+Tips for patch submitters
+-------------------------
+
+1.     Always *test* your changes, however small, on at least 4 or
        5 people, preferably many more.
 
 2.     Try to release a few ALPHA test versions to the net. Announce
@@ -25,7 +27,7 @@ trivial patch so apply some common sense.
        testing and await feedback.
 
 5.     Make a patch available to the relevant maintainer in the list. Use
-       'diff -u' to make the patch easy to merge. Be prepared to get your
+       ``diff -u`` to make the patch easy to merge. Be prepared to get your
        changes sent back with seemingly silly requests about formatting
        and variable names.  These aren't as silly as they seem. One
        job the maintainers (and especially Linus) do is to keep things
@@ -38,7 +40,7 @@ trivial patch so apply some common sense.
        See Documentation/process/coding-style.rst for guidance here.
 
        PLEASE CC: the maintainers and mailing lists that are generated
-       by scripts/get_maintainer.pl.  The results returned by the
+       by ``scripts/get_maintainer.pl.`` The results returned by the
        script will be best if you have git installed and are making
        your changes in a branch derived from Linus' latest git tree.
        See Documentation/process/submitting-patches.rst for details.
@@ -70,26 +72,27 @@ trivial patch so apply some common sense.
        not represent an immediate threat and are better handled publicly,
        and ideally, should come with a patch proposal. Please do not send
        automated reports to this list either. Such bugs will be handled
-       better and faster in the usual public places.
+       better and faster in the usual public places. See
+       Documentation/admin-guide/security-bugs.rst for details.
 
 8.     Happy hacking.
 
-Descriptions of section entries:
+Descriptions of section entries
+-------------------------------
 
-       P: Person (obsolete)
-       M: Mail patches to: FullName <address@domain>
-       R: Designated reviewer: FullName <address@domain>
+       M: *Mail* patches to: FullName <address@domain>
+       R: Designated *Reviewer*: FullName <address@domain>
           These reviewers should be CCed on patches.
-       L: Mailing list that is relevant to this area
-       W: Web-page with status/info
-       B: URI for where to file bugs. A web-page with detailed bug
+       L: *Mailing list* that is relevant to this area
+       W: *Web-page* with status/info
+       B: URI for where to file *bugs*. A web-page with detailed bug
           filing info, a direct bug tracker link, or a mailto: URI.
-       C: URI for chat protocol, server and channel where developers
+       C: URI for *chat* protocol, server and channel where developers
           usually hang out, for example irc://server/channel.
-       Q: Patchwork web based patch tracking system site
-       T: SCM tree type and location.
+       Q: *Patchwork* web based patch tracking system site
+       T: *SCM* tree type and location.
           Type is one of: git, hg, quilt, stgit, topgit
-       S: Status, one of the following:
+       S: *Status*, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
           Odd Fixes:   It has a maintainer but they don't have time to do
@@ -99,13 +102,17 @@ Descriptions of section entries:
           Obsolete:    Old code. Something tagged obsolete generally means
                        it has been replaced by a better system and you
                        should be using that.
-       F: Files and directories with wildcard patterns.
+       P: Subsystem Profile document for more details submitting
+          patches to the given subsystem. This is either an in-tree file,
+          or a URI. See Documentation/maintainer/maintainer-entry-profile.rst
+          for details.
+       F: *Files* and directories wildcard patterns.
           A trailing slash includes all files and subdirectory files.
           F:   drivers/net/    all files in and below drivers/net
           F:   drivers/net/*   all files in drivers/net, but not below
           F:   */net/*         all files in "any top level directory"/net
           One pattern per line.  Multiple F: lines acceptable.
-       N: Files and directories with regex patterns.
+       N: Files and directories *Regex* patterns.
           N:   [^a-z]tegra     all files whose path contains the word tegra
           One pattern per line.  Multiple N: lines acceptable.
           scripts/get_maintainer.pl has different behavior for files that
@@ -113,14 +120,14 @@ Descriptions of section entries:
           get_maintainer will not look at git log history when an F: pattern
           match occurs.  When an N: match occurs, git log history is used
           to also notify the people that have git commit signatures.
-       X: Files and directories that are NOT maintained, same rules as F:
-          Files exclusions are tested before file matches.
+       X: *Excluded* files and directories that are NOT maintained, same
+          rules as F:. Files exclusions are tested before file matches.
           Can be useful for excluding a specific subdirectory, for instance:
           F:   net/
           X:   net/ipv6/
           matches all files in and below net excluding net/ipv6/
-       K: Keyword perl extended regex pattern to match content in a
-          patch or file.  For instance:
+       K: *Content regex* (perl extended) pattern match in a patch or file.
+          For instance:
           K: of_get_profile
              matches patches or files that contain "of_get_profile"
           K: \b(printk|pr_(info|err))\b
@@ -128,13 +135,12 @@ Descriptions of section entries:
              printk, pr_info or pr_err
           One regex pattern per line.  Multiple K: lines acceptable.
 
-Note: For the hard of thinking, this list is meant to remain in alphabetical
-order. If you could add yourselves to it in alphabetical order that would be
-so much easier [Ed]
-
-Maintainers List (try to look for most precise areas first)
+Maintainers List
+----------------
 
-               -----------------------------------
+.. note:: When reading this list, please look for the most precise areas
+          first. When adding to this list, please keep the entries in
+          alphabetical order.
 
 3C59X NETWORK DRIVER
 M:     Steffen Klassert <klassert@kernel.org>
@@ -817,7 +823,7 @@ S:  Orphan
 F:     drivers/usb/gadget/udc/amd5536udc.*
 
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
-P:     Andres Salomon <dilinger@queued.net>
+M:     Andres Salomon <dilinger@queued.net>
 L:     linux-geode@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
 S:     Supported
@@ -1640,8 +1646,7 @@ R:        Suzuki K Poulose <suzuki.poulose@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/hwtracing/coresight/*
-F:     Documentation/trace/coresight.rst
-F:     Documentation/trace/coresight-cpu-debug.rst
+F:     Documentation/trace/coresight/*
 F:     Documentation/devicetree/bindings/arm/coresight.txt
 F:     Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
 F:     Documentation/ABI/testing/sysfs-bus-coresight-devices-*
@@ -1929,7 +1934,7 @@ F:        arch/arm/boot/dts/dove*
 F:     arch/arm/boot/dts/orion5x*
 T:     git git://git.infradead.org/linux-mvebu.git
 
-ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support
+ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Gregory Clement <gregory.clement@bootlin.com>
@@ -1941,6 +1946,7 @@ F:        arch/arm/boot/dts/kirkwood*
 F:     arch/arm/configs/mvebu_*_defconfig
 F:     arch/arm/mach-mvebu/
 F:     arch/arm64/boot/dts/marvell/armada*
+F:     arch/arm64/boot/dts/marvell/cn913*
 F:     drivers/cpufreq/armada-37xx-cpufreq.c
 F:     drivers/cpufreq/armada-8k-cpufreq.c
 F:     drivers/cpufreq/mvebu-cpufreq.c
@@ -2135,6 +2141,7 @@ S:        Maintained
 
 ARM/QUALCOMM SUPPORT
 M:     Andy Gross <agross@kernel.org>
+M:     Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/soc/qcom/
@@ -2195,6 +2202,7 @@ F:        Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
 ARM/REALTEK ARCHITECTURE
 M:     Andreas Färber <afaerber@suse.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-realtek-soc@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm64/boot/dts/realtek/
 F:     Documentation/devicetree/bindings/arm/realtek.yaml
@@ -2268,8 +2276,7 @@ F:        drivers/soc/samsung/
 F:     include/linux/soc/samsung/
 F:     Documentation/arm/samsung/
 F:     Documentation/devicetree/bindings/arm/samsung/
-F:     Documentation/devicetree/bindings/sram/samsung-sram.txt
-F:     Documentation/devicetree/bindings/power/pd-samsung.txt
+F:     Documentation/devicetree/bindings/power/pd-samsung.yaml
 N:     exynos
 
 ARM/SAMSUNG MOBILE MACHINE SUPPORT
@@ -2733,7 +2740,7 @@ M:        Bartosz Golaszewski <bgolaszewski@baylibre.com>
 L:     linux-i2c@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
 S:     Maintained
-F:     Documentation/devicetree/bindings/eeprom/at24.txt
+F:     Documentation/devicetree/bindings/eeprom/at24.yaml
 F:     drivers/misc/eeprom/at24.c
 
 ATA OVER ETHERNET (AOE) DRIVER
@@ -2894,7 +2901,6 @@ AXENTIA ARM DEVICES
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     Documentation/devicetree/bindings/arm/axentia.txt
 F:     arch/arm/boot/dts/at91-linea.dtsi
 F:     arch/arm/boot/dts/at91-natte.dtsi
 F:     arch/arm/boot/dts/at91-nattis-2-natte-2.dts
@@ -3711,7 +3717,7 @@ M:        Oleksij Rempel <o.rempel@pengutronix.de>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-can@vger.kernel.org
 S:     Maintained
-F:     Documentation/networking/j1939.txt
+F:     Documentation/networking/j1939.rst
 F:     net/can/j1939/
 F:     include/uapi/linux/can/j1939.h
 
@@ -4997,6 +5003,14 @@ F:       include/linux/dma-direct.h
 F:     include/linux/dma-mapping.h
 F:     include/linux/dma-noncoherent.h
 
+DMC FREQUENCY DRIVER FOR SAMSUNG EXYNOS5422
+M:     Lukasz Luba <l.luba@partner.samsung.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
+S:     Maintained
+F:     drivers/memory/samsung/exynos5422-dmc.c
+F:     Documentation/devicetree/bindings/memory-controllers/exynos5422-dmc.txt
+
 DME1737 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
 L:     linux-hwmon@vger.kernel.org
@@ -6932,7 +6946,7 @@ L:        linux-pm@vger.kernel.org
 S:     Supported
 F:     drivers/base/power/domain*.c
 F:     include/linux/pm_domain.h
-F:     Documentation/devicetree/bindings/power/power_domain.txt
+F:     Documentation/devicetree/bindings/power/power?domain*
 
 GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
 M:     Eugen Hristev <eugen.hristev@microchip.com>
@@ -8931,7 +8945,7 @@ F:        mm/kasan/
 F:     scripts/Makefile.kasan
 
 KCONFIG
-M:     Masahiro Yamada <yamada.masahiro@socionext.com>
+M:     Masahiro Yamada <masahiroy@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig
 L:     linux-kbuild@vger.kernel.org
 S:     Maintained
@@ -8963,7 +8977,7 @@ S:        Maintained
 F:     fs/autofs/
 
 KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
-M:     Masahiro Yamada <yamada.masahiro@socionext.com>
+M:     Masahiro Yamada <masahiroy@kernel.org>
 M:     Michal Marek <michal.lkml@markovi.net>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
 L:     linux-kbuild@vger.kernel.org
@@ -9403,6 +9417,7 @@ M:        Dan Williams <dan.j.williams@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-nvdimm@lists.01.org
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
 F:     drivers/nvdimm/blk.c
@@ -9413,6 +9428,7 @@ M:        Vishal Verma <vishal.l.verma@intel.com>
 M:     Dan Williams <dan.j.williams@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-nvdimm@lists.01.org
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
 F:     drivers/nvdimm/btt*
@@ -9422,6 +9438,7 @@ M:        Dan Williams <dan.j.williams@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-nvdimm@lists.01.org
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
 F:     drivers/nvdimm/pmem*
@@ -9440,6 +9457,7 @@ M:        Vishal Verma <vishal.l.verma@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 M:     Ira Weiny <ira.weiny@intel.com>
 L:     linux-nvdimm@lists.01.org
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
 S:     Supported
@@ -10039,8 +10057,8 @@ 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:     Documentation/devicetree/bindings/*/*max77650.yaml
+F:     Documentation/devicetree/bindings/*/max77650*.yaml
 F:     include/linux/mfd/max77650.h
 F:     drivers/mfd/max77650.c
 F:     drivers/regulator/max77650-regulator.c
@@ -10339,7 +10357,6 @@ F:      drivers/staging/media/tegra-vde/
 
 MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
-P:     LinuxTV.org Project
 L:     linux-media@vger.kernel.org
 W:     https://linuxtv.org
 Q:     http://patchwork.kernel.org/project/linux-media/list/
@@ -11053,9 +11070,18 @@ F:     drivers/media/radio/radio-miropcm20*
 MMP SUPPORT
 R:     Lubomir Rintel <lkundrak@v3.sk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp.git
 S:     Odd Fixes
 F:     arch/arm/boot/dts/mmp*
 F:     arch/arm/mach-mmp/
+F:     linux/soc/mmp/
+
+MMP USB PHY DRIVERS
+R:     Lubomir Rintel <lkundrak@v3.sk>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/phy/marvell/phy-mmp3-usb.c
+F:     drivers/phy/marvell/phy-pxa-usb.c
 
 MMU GATHER AND TLB INVALIDATION
 M:     Will Deacon <will@kernel.org>
@@ -11902,6 +11928,8 @@ F:      arch/arm/boot/dts/*am3*
 F:     arch/arm/boot/dts/*am4*
 F:     arch/arm/boot/dts/*am5*
 F:     arch/arm/boot/dts/*dra7*
+F:     arch/arm/boot/dts/logicpd-som-lv*
+F:     arch/arm/boot/dts/logicpd-torpedo*
 
 OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
 L:     linux-omap@vger.kernel.org
@@ -12594,7 +12622,6 @@ F:      Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
 F:     drivers/pci/controller/dwc/*imx6*
 
 PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
-M:     Keith Busch <keith.busch@intel.com>
 M:     Jonathan Derrick <jonathan.derrick@intel.com>
 L:     linux-pci@vger.kernel.org
 S:     Supported
@@ -12637,7 +12664,8 @@ F:      Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
 F:     drivers/pci/controller/pci-tegra.c
 
 PCI DRIVER FOR RENESAS R-CAR
-M:     Simon Horman <horms@verge.net.au>
+M:     Marek Vasut <marek.vasut+renesas@gmail.com>
+M:     Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
 S:     Maintained
@@ -13682,6 +13710,7 @@ L:      linux-pm@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
 F:     drivers/thermal/qcom/
+F:     Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
 
 QUALCOMM VENUS VIDEO ACCELERATOR DRIVER
 M:     Stanimir Varbanov <stanimir.varbanov@linaro.org>
@@ -13744,7 +13773,7 @@ F:      drivers/media/radio/radio-tea5777.c
 RADOS BLOCK DEVICE (RBD)
 M:     Ilya Dryomov <idryomov@gmail.com>
 M:     Sage Weil <sage@redhat.com>
-M:     Alex Elder <elder@kernel.org>
+R:     Dongsheng Yang <dongsheng.yang@easystack.cn>
 L:     ceph-devel@vger.kernel.org
 W:     http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
@@ -13774,7 +13803,6 @@ S:      Maintained
 F:     arch/mips/ralink
 
 RALINK RT2X00 WIRELESS LAN DRIVER
-P:     rt2x00 project
 M:     Stanislaw Gruszka <sgruszka@redhat.com>
 M:     Helmut Schaa <helmut.schaa@googlemail.com>
 L:     linux-wireless@vger.kernel.org
@@ -14022,6 +14050,7 @@ F:      include/dt-bindings/reset/
 F:     include/linux/reset.h
 F:     include/linux/reset/
 F:     include/linux/reset-controller.h
+K:      \b(?:devm_|of_)?reset_control(?:ler_[a-z]+|_[a-z_]+)?\b
 
 RESTARTABLE SEQUENCES SUPPORT
 M:     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
@@ -14110,7 +14139,6 @@ S:      Supported
 F:     drivers/net/ethernet/rocker/
 
 ROCKETPORT DRIVER
-P:     Comtrol Corp.
 W:     http://www.comtrol.com
 S:     Maintained
 F:     Documentation/driver-api/serial/rocket.rst
@@ -14389,7 +14417,7 @@ L:      linux-crypto@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
 F:     drivers/crypto/exynos-rng.c
-F:     Documentation/devicetree/bindings/rng/samsung,exynos4-rng.txt
+F:     Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml
 
 SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
 M:     Łukasz Stelmach <l.stelmach@samsung.com>
@@ -14464,8 +14492,8 @@ M:      Kamil Konieczny <k.konieczny@partner.samsung.com>
 L:     linux-crypto@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/crypto/samsung-slimsss.txt
-F:     Documentation/devicetree/bindings/crypto/samsung-sss.txt
+F:     Documentation/devicetree/bindings/crypto/samsung-slimsss.yaml
+F:     Documentation/devicetree/bindings/crypto/samsung-sss.yaml
 F:     drivers/crypto/s5p-sss.c
 
 SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
@@ -14953,6 +14981,12 @@ F:     drivers/media/usb/siano/
 F:     drivers/media/usb/siano/
 F:     drivers/media/mmc/siano/
 
+SIFIVE PDMA DRIVER
+M:     Green Wan <green.wan@sifive.com>
+S:     Maintained
+F:     drivers/dma/sf-pdma/
+F:     Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
+
 SIFIVE DRIVERS
 M:     Palmer Dabbelt <palmer@dabbelt.com>
 M:     Paul Walmsley <paul.walmsley@sifive.com>
@@ -15012,15 +15046,13 @@ F:    drivers/video/fbdev/simplefb.c
 F:     include/linux/platform_data/simplefb.h
 
 SIMTEC EB110ATX (Chalice CATS)
-P:     Ben Dooks
-P:     Vincent Sanders <vince@simtec.co.uk>
+M:     Vincent Sanders <vince@simtec.co.uk>
 M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB110ATX/
 S:     Supported
 
 SIMTEC EB2410ITX (BAST)
-P:     Ben Dooks
-P:     Vincent Sanders <vince@simtec.co.uk>
+M:     Vincent Sanders <vince@simtec.co.uk>
 M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB2410ITX/
 S:     Supported
@@ -15735,7 +15767,7 @@ SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
 L:     linux-input@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+F:     Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml
 F:     drivers/input/keyboard/sun4i-lradc-keys.c
 
 SUNDANCE NETWORK DRIVER
@@ -16302,6 +16334,15 @@ F:     Documentation/driver-api/thermal/cpu-cooling-api.rst
 F:     drivers/thermal/cpu_cooling.c
 F:     include/linux/cpu_cooling.h
 
+THERMAL DRIVER FOR AMLOGIC SOCS
+M:     Guillaume La Roque <glaroque@baylibre.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-amlogic@lists.infradead.org
+W:     http://linux-meson.com/
+S:     Supported
+F:     drivers/thermal/amlogic_thermal.c
+F:     Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
+
 THINKPAD ACPI EXTRAS DRIVER
 M:     Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
 L:     ibm-acpi-devel@lists.sourceforge.net
index d4d36c6..999a197 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -618,7 +618,6 @@ ifeq ($(KBUILD_EXTMOD),)
 init-y         := init/
 drivers-y      := drivers/ sound/
 drivers-$(CONFIG_SAMPLES) += samples/
-drivers-$(CONFIG_KERNEL_HEADER_TEST) += include/
 net-y          := net/
 libs-y         := lib/
 core-y         := usr/
@@ -1011,6 +1010,7 @@ endif
 PHONY += prepare0
 
 export MODORDER := $(extmod-prefix)modules.order
+export MODULES_NSDEPS := $(extmod-prefix)modules.nsdeps
 
 ifeq ($(KBUILD_EXTMOD),)
 core-y         += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
@@ -1196,19 +1196,15 @@ headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts
        $(Q)$(MAKE) $(hdr-inst)=include/uapi
        $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi
 
+# Deprecated. It is no-op now.
 PHONY += headers_check
-headers_check: headers
-       $(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1
-       $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi HDRCHECK=1
+headers_check:
+       @:
 
 ifdef CONFIG_HEADERS_INSTALL
 prepare: headers
 endif
 
-ifdef CONFIG_HEADERS_CHECK
-all: headers_check
-endif
-
 PHONY += scripts_unifdef
 scripts_unifdef: scripts_basic
        $(Q)$(MAKE) $(build)=scripts scripts/unifdef
@@ -1360,7 +1356,7 @@ endif # CONFIG_MODULES
 
 # Directories & files removed with 'make clean'
 CLEAN_DIRS  += include/ksym
-CLEAN_FILES += modules.builtin.modinfo
+CLEAN_FILES += modules.builtin.modinfo modules.nsdeps
 
 # Directories & files removed with 'make mrproper'
 MRPROPER_DIRS  += include/config include/generated          \
@@ -1476,7 +1472,6 @@ help:
        @echo  '  versioncheck    - Sanity check on version.h usage'
        @echo  '  includecheck    - Check for duplicate included header files'
        @echo  '  export_report   - List the usages of all exported symbols'
-       @echo  '  headers_check   - Sanity check on exported headers'
        @echo  '  headerdep       - Detect inclusion cycles in headers'
        @echo  '  coccicheck      - Check with Coccinelle'
        @echo  ''
@@ -1515,7 +1510,7 @@ help:
        @echo  ''
        @$(if $(boards), \
                $(foreach b, $(boards), \
-               printf "  %-24s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \
+               printf "  %-27s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \
                echo '')
        @$(if $(board-dirs), \
                $(foreach b, $(board-dirs), \
@@ -1526,7 +1521,8 @@ help:
        @echo  '  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
        @echo  '  make V=2   [targets] 2 => give reason for rebuild of target'
        @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
-       @echo  '  make C=1   [targets] Check re-compiled c source with $$CHECK (sparse by default)'
+       @echo  '  make C=1   [targets] Check re-compiled c source with $$CHECK'
+       @echo  '                       (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
        @echo  '  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
        @echo  '  make W=n   [targets] Enable extra build checks, n=1,2,3 where'
@@ -1622,7 +1618,7 @@ _emodinst_post: _emodinst_
        $(call cmd,depmod)
 
 clean-dirs := $(KBUILD_EXTMOD)
-clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers
+clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers $(KBUILD_EXTMOD)/modules.nsdeps
 
 PHONY += /
 /:
@@ -1641,6 +1637,50 @@ help:
 PHONY += prepare
 endif # KBUILD_EXTMOD
 
+# Single targets
+# ---------------------------------------------------------------------------
+# To build individual files in subdirectories, you can do like this:
+#
+#   make foo/bar/baz.s
+#
+# The supported suffixes for single-target are listed in 'single-targets'
+#
+# To build only under specific subdirectories, you can do like this:
+#
+#   make foo/bar/baz/
+
+ifdef single-build
+
+# .ko is special because modpost is needed
+single-ko := $(sort $(filter %.ko, $(MAKECMDGOALS)))
+single-no-ko := $(sort $(patsubst %.ko,%.mod, $(MAKECMDGOALS)))
+
+$(single-ko): single_modpost
+       @:
+$(single-no-ko): descend
+       @:
+
+ifeq ($(KBUILD_EXTMOD),)
+# For the single build of in-tree modules, use a temporary file to avoid
+# the situation of modules_install installing an invalid modules.order.
+MODORDER := .modules.tmp
+endif
+
+PHONY += single_modpost
+single_modpost: $(single-no-ko)
+       $(Q){ $(foreach m, $(single-ko), echo $(extmod-prefix)$m;) } > $(MODORDER)
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
+
+KBUILD_MODULES := 1
+
+export KBUILD_SINGLE_TARGETS := $(addprefix $(extmod-prefix), $(single-no-ko))
+
+# trim unrelated directories
+build-dirs := $(foreach d, $(build-dirs), \
+                       $(if $(filter $(d)/%, $(KBUILD_SINGLE_TARGETS)), $(d)))
+
+endif
+
 # Handle descending into subdirectories listed in $(build-dirs)
 # Preset locale variables to speed up the build process. Limit locale
 # tweaks to this spot to avoid wrong language settings when running
@@ -1649,7 +1689,9 @@ endif # KBUILD_EXTMOD
 PHONY += descend $(build-dirs)
 descend: $(build-dirs)
 $(build-dirs): prepare
-       $(Q)$(MAKE) $(build)=$@ single-build=$(single-build) need-builtin=1 need-modorder=1
+       $(Q)$(MAKE) $(build)=$@ \
+       single-build=$(if $(filter-out $@/, $(single-no-ko)),1) \
+       need-builtin=1 need-modorder=1
 
 clean-dirs := $(addprefix _clean_, $(clean-dirs))
 PHONY += $(clean-dirs) clean
@@ -1664,7 +1706,7 @@ clean: $(clean-dirs)
                -o -name '*.ko.*' \
                -o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
                -o -name '*.dwo' -o -name '*.lst' \
-               -o -name '*.su' -o -name '*.mod' -o -name '*.ns_deps' \
+               -o -name '*.su' -o -name '*.mod' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.lex.c' -o -name '*.tab.[ch]' \
                -o -name '*.asn1.[ch]' \
@@ -1686,10 +1728,9 @@ tags TAGS cscope gtags: FORCE
 # ---------------------------------------------------------------------------
 
 PHONY += nsdeps
-
+nsdeps: export KBUILD_NSDEPS=1
 nsdeps: modules
-       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost nsdeps
-       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/$@
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/nsdeps
 
 # Scripts to check various things for consistency
 # ---------------------------------------------------------------------------
@@ -1753,50 +1794,6 @@ tools/%: FORCE
        $(Q)mkdir -p $(objtree)/tools
        $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ $*
 
-# Single targets
-# ---------------------------------------------------------------------------
-# To build individual files in subdirectories, you can do like this:
-#
-#   make foo/bar/baz.s
-#
-# The supported suffixes for single-target are listed in 'single-targets'
-#
-# To build only under specific subdirectories, you can do like this:
-#
-#   make foo/bar/baz/
-
-ifdef single-build
-
-single-all := $(filter $(single-targets), $(MAKECMDGOALS))
-
-# .ko is special because modpost is needed
-single-ko := $(sort $(filter %.ko, $(single-all)))
-single-no-ko := $(sort $(patsubst %.ko,%.mod, $(single-all)))
-
-$(single-ko): single_modpost
-       @:
-$(single-no-ko): descend
-       @:
-
-ifeq ($(KBUILD_EXTMOD),)
-# For the single build of in-tree modules, use a temporary file to avoid
-# the situation of modules_install installing an invalid modules.order.
-MODORDER := .modules.tmp
-endif
-
-PHONY += single_modpost
-single_modpost: $(single-no-ko)
-       $(Q){ $(foreach m, $(single-ko), echo $(extmod-prefix)$m;) } > $(MODORDER)
-       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
-
-KBUILD_MODULES := 1
-
-export KBUILD_SINGLE_TARGETS := $(addprefix $(extmod-prefix), $(single-no-ko))
-
-single-build = $(if $(filter-out $@/, $(single-no-ko)),1)
-
-endif
-
 # FIXME Should go into a make.lib or something
 # ===========================================================================
 
index da75bab..48b5e10 100644 (file)
@@ -72,11 +72,11 @@ config KPROBES
          If in doubt, say "N".
 
 config JUMP_LABEL
-       bool "Optimize very unlikely/likely branches"
-       depends on HAVE_ARCH_JUMP_LABEL
-       depends on CC_HAS_ASM_GOTO
-       help
-         This option enables a transparent branch optimization that
+       bool "Optimize very unlikely/likely branches"
+       depends on HAVE_ARCH_JUMP_LABEL
+       depends on CC_HAS_ASM_GOTO
+       help
+        This option enables a transparent branch optimization that
         makes certain almost-always-true or almost-always-false branch
         conditions even cheaper to execute within the kernel.
 
@@ -84,7 +84,7 @@ config JUMP_LABEL
         scheduler functionality, networking code and KVM have such
         branches and include support for this optimization technique.
 
-         If it is detected that the compiler has support for "asm goto",
+        If it is detected that the compiler has support for "asm goto",
         the kernel will compile such branches with just a nop
         instruction. When the condition flag is toggled to true, the
         nop will be converted to a jump instruction to execute the
@@ -151,8 +151,8 @@ config HAVE_EFFICIENT_UNALIGNED_ACCESS
          information on the topic of unaligned memory accesses.
 
 config ARCH_USE_BUILTIN_BSWAP
-       bool
-       help
+       bool
+       help
         Modern versions of GCC (since 4.4) have builtin functions
         for handling byte-swapping. Using these, instead of the old
         inline assembler that the architecture code provides in the
@@ -221,10 +221,10 @@ config HAVE_DMA_CONTIGUOUS
        bool
 
 config GENERIC_SMP_IDLE_THREAD
-       bool
+       bool
 
 config GENERIC_IDLE_POLL_SETUP
-       bool
+       bool
 
 config ARCH_HAS_FORTIFY_SOURCE
        bool
@@ -257,7 +257,7 @@ config ARCH_HAS_UNCACHED_SEGMENT
 
 # Select if arch init_task must go in the __init_task_data section
 config ARCH_TASK_STRUCT_ON_STACK
-       bool
+       bool
 
 # Select if arch has its private alloc_task_struct() function
 config ARCH_TASK_STRUCT_ALLOCATOR
@@ -836,16 +836,17 @@ config HAVE_ARCH_VMAP_STACK
 config VMAP_STACK
        default y
        bool "Use a virtually-mapped stack"
-       depends on HAVE_ARCH_VMAP_STACK && !KASAN
+       depends on HAVE_ARCH_VMAP_STACK
+       depends on !KASAN || KASAN_VMALLOC
        ---help---
          Enable this if you want the use virtually-mapped kernel stacks
          with guard pages.  This causes kernel stack overflows to be
          caught immediately rather than causing difficult-to-diagnose
          corruption.
 
-         This is presently incompatible with KASAN because KASAN expects
-         the stack to map directly to the KASAN shadow map using a formula
-         that is incorrect if the stack is in vmalloc space.
+         To use this with KASAN, the architecture must support backing
+         virtual mappings with real shadow memory, and KASAN_VMALLOC must
+         be enabled.
 
 config ARCH_OPTIONAL_KERNEL_RWX
        def_bool n
index 889b5d3..7ee144f 100644 (file)
@@ -73,7 +73,6 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n)
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
 #define pmd_page(pmd)          (pfn_to_page(pmd_val(pmd) >> 32))
-#define pgd_page(pgd)          (pfn_to_page(pgd_val(pgd) >> 32))
 #define pte_pfn(pte)           (pte_val(pte) >> 32)
 
 #define mk_pte(page, pgprot)                                                \
index eb91f1e..a1a29f6 100644 (file)
@@ -27,9 +27,9 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 }
 
 static inline void
-pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
-       pgd_set(pgd, pmd);
+       pud_set(pud, pmd);
 }
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
index 065b57f..299791c 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _ALPHA_PGTABLE_H
 #define _ALPHA_PGTABLE_H
 
-#include <asm-generic/4level-fixup.h>
+#include <asm-generic/pgtable-nopud.h>
 
 /*
  * This file contains the functions and defines necessary to modify and use
@@ -226,8 +226,8 @@ extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 { pmd_val(*pmdp) = _PAGE_TABLE | ((((unsigned long) ptep) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
 
-extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{ pgd_val(*pgdp) = _PAGE_TABLE | ((((unsigned long) pmdp) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
+extern inline void pud_set(pud_t * pudp, pmd_t * pmdp)
+{ pud_val(*pudp) = _PAGE_TABLE | ((((unsigned long) pmdp) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
 
 
 extern inline unsigned long
@@ -238,11 +238,11 @@ pmd_page_vaddr(pmd_t pmd)
 
 #ifndef CONFIG_DISCONTIGMEM
 #define pmd_page(pmd)  (mem_map + ((pmd_val(pmd) & _PFN_MASK) >> 32))
-#define pgd_page(pgd)  (mem_map + ((pgd_val(pgd) & _PFN_MASK) >> 32))
+#define pud_page(pud)  (mem_map + ((pud_val(pud) & _PFN_MASK) >> 32))
 #endif
 
-extern inline unsigned long pgd_page_vaddr(pgd_t pgd)
-{ return PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
+extern inline unsigned long pud_page_vaddr(pud_t pgd)
+{ return PAGE_OFFSET + ((pud_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
 
 extern inline int pte_none(pte_t pte)          { return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_VALID; }
@@ -256,10 +256,10 @@ extern inline int pmd_bad(pmd_t pmd)              { return (pmd_val(pmd) & ~_PFN_MASK) != _P
 extern inline int pmd_present(pmd_t pmd)       { return pmd_val(pmd) & _PAGE_VALID; }
 extern inline void pmd_clear(pmd_t * pmdp)     { pmd_val(*pmdp) = 0; }
 
-extern inline int pgd_none(pgd_t pgd)          { return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd)           { return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE; }
-extern inline int pgd_present(pgd_t pgd)       { return pgd_val(pgd) & _PAGE_VALID; }
-extern inline void pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
+extern inline int pud_none(pud_t pud)          { return !pud_val(pud); }
+extern inline int pud_bad(pud_t pud)           { return (pud_val(pud) & ~_PFN_MASK) != _PAGE_TABLE; }
+extern inline int pud_present(pud_t pud)       { return pud_val(pud) & _PAGE_VALID; }
+extern inline void pud_clear(pud_t * pudp)     { pud_val(*pudp) = 0; }
 
 /*
  * The following only work if pte_present() is true.
@@ -301,9 +301,9 @@ extern inline pte_t pte_mkspecial(pte_t pte)        { return pte; }
  */
 
 /* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+extern inline pmd_t * pmd_offset(pud_t * dir, unsigned long address)
 {
-       pmd_t *ret = (pmd_t *) pgd_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
+       pmd_t *ret = (pmd_t *) pud_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
        smp_read_barrier_depends(); /* see above */
        return ret;
 }
index f94c732..0021580 100644 (file)
@@ -71,10 +71,10 @@ static int pci_mmap_resource(struct kobject *kobj,
        struct pci_bus_region bar;
        int i;
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+       for (i = 0; i < PCI_STD_NUM_BARS; i++)
                if (res == &pdev->resource[i])
                        break;
-       if (i >= PCI_ROM_RESOURCE)
+       if (i >= PCI_STD_NUM_BARS)
                return -ENODEV;
 
        if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
@@ -115,7 +115,7 @@ void pci_remove_resource_files(struct pci_dev *pdev)
 {
        int i;
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                struct bin_attribute *res_attr;
 
                res_attr = pdev->res_attr[i];
@@ -232,7 +232,7 @@ int pci_create_resource_files(struct pci_dev *pdev)
        int retval;
 
        /* Expose the PCI resources from this device as files */
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
 
                /* skip empty resources */
                if (!pci_resource_len(pdev, i))
index e2cbec3..12e218d 100644 (file)
@@ -146,6 +146,8 @@ callback_init(void * kernel_end)
 {
        struct crb_struct * crb;
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        void *two_pages;
 
@@ -184,8 +186,10 @@ callback_init(void * kernel_end)
        memset(two_pages, 0, 2*PAGE_SIZE);
 
        pgd = pgd_offset_k(VMALLOC_START);
-       pgd_set(pgd, (pmd_t *)two_pages);
-       pmd = pmd_offset(pgd, VMALLOC_START);
+       p4d = p4d_offset(pgd, VMALLOC_START);
+       pud = pud_offset(p4d, VMALLOC_START);
+       pud_set(pud, (pmd_t *)two_pages);
+       pmd = pmd_offset(pud, VMALLOC_START);
        pmd_set(pmd, (pte_t *)(two_pages + PAGE_SIZE));
 
        if (alpha_using_srm) {
@@ -214,9 +218,9 @@ callback_init(void * kernel_end)
                                /* Newer consoles (especially on larger
                                   systems) may require more pages of
                                   PTEs. Grab additional pages as needed. */
-                               if (pmd != pmd_offset(pgd, vaddr)) {
+                               if (pmd != pmd_offset(pud, vaddr)) {
                                        memset(kernel_end, 0, PAGE_SIZE);
-                                       pmd = pmd_offset(pgd, vaddr);
+                                       pmd = pmd_offset(pud, vaddr);
                                        pmd_set(pmd, (pte_t *)kernel_end);
                                        kernel_end += PAGE_SIZE;
                                }
index 4d7b671..26108ea 100644 (file)
@@ -29,6 +29,7 @@ config ARC
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DEBUG_STACKOVERFLOW
+       select HAVE_DEBUG_KMEMLEAK
        select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_IOREMAP_PROT
        select HAVE_KERNEL_GZIP
@@ -45,6 +46,7 @@ config ARC
        select OF_EARLY_FLATTREE
        select PCI_SYSCALL if PCI
        select PERF_USE_VMALLOC if ARC_CACHE_VIPT_ALIASING
+       select HAVE_ARCH_JUMP_LABEL if ISA_ARCV2 && !CPU_ENDIAN_BE32
 
 config ARCH_HAS_CACHE_LINE_SIZE
        def_bool y
@@ -524,6 +526,13 @@ config ARC_DW2_UNWIND
 config ARC_DBG_TLB_PARANOIA
        bool "Paranoia Checks in Low Level TLB Handlers"
 
+config ARC_DBG_JUMP_LABEL
+       bool "Paranoid checks in Static Keys (jump labels) code"
+       depends on JUMP_LABEL
+       default y if STATIC_KEYS_SELFTEST
+       help
+         Enable paranoid checks and self-test of both ARC-specific and generic
+         part of static keys (jump labels) related code.
 endif
 
 config ARC_BUILTIN_DTB_NAME
index f1c44cc..20e9ab6 100644 (file)
@@ -3,7 +3,7 @@
 # Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
 #
 
-KBUILD_DEFCONFIG := nsim_hs_defconfig
+KBUILD_DEFCONFIG := haps_hs_smp_defconfig
 
 ifeq ($(CROSS_COMPILE),)
 CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux-)
index 6ec1fcd..79ec27c 100644 (file)
                        clock-frequency = <750000000>;
                };
 
+               input_clk: input-clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <33333333>;
+               };
+
                core_intc: arc700-intc@cpu {
                        compatible = "snps,arc700-intc";
                        interrupt-controller;
index 305a7f9..c4cfc5f 100644 (file)
@@ -14,6 +14,6 @@
        compatible = "snps,axs101", "snps,arc-sdp";
 
        chosen {
-               bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60 print-fatal-signals=1";
+               bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 print-fatal-signals=1";
        };
 };
index 46c9136..a934b92 100644 (file)
@@ -17,6 +17,6 @@
        compatible = "snps,axs103", "snps,arc-sdp";
 
        chosen {
-               bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 print-fatal-signals=1 consoleblank=0 video=1280x720@60";
+               bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 print-fatal-signals=1 consoleblank=0";
        };
 };
index 08bcfed..f9a5c9d 100644 (file)
                                clock-frequency = <25000000>;
                                #clock-cells = <0>;
                        };
+               };
 
-                       pguclk: pguclk {
-                               #clock-cells = <0>;
-                               compatible = "fixed-clock";
-                               clock-frequency = <74250000>;
-                       };
+               pguclk: pguclk@10080 {
+                       compatible = "snps,axs10x-pgu-pll-clock";
+                       reg = <0x10080 0x10>, <0x110 0x10>;
+                       #clock-cells = <0>;
+                       clocks = <&input_clk>;
                };
 
                gmac: ethernet@18000 {
index 44bc522..60d578e 100644 (file)
@@ -9,13 +9,15 @@
 / {
        model = "snps,zebu_hs";
        compatible = "snps,zebu_hs";
-       #address-cells = <1>;
-       #size-cells = <1>;
+       #address-cells = <2>;
+       #size-cells = <2>;
        interrupt-parent = <&core_intc>;
 
        memory {
                device_type = "memory";
-               reg = <0x80000000 0x20000000>;  /* 512 */
+               /* CONFIG_LINUX_RAM_BASE needs to match low mem start */
+               reg = <0x0 0x80000000 0x0 0x20000000    /* 512 MB low mem */
+                      0x1 0x00000000 0x0 0x40000000>;  /* 1 GB highmem */
        };
 
        chosen {
@@ -31,8 +33,9 @@
                #address-cells = <1>;
                #size-cells = <1>;
 
-               /* child and parent address space 1:1 mapped */
-               ranges;
+               /* only perip space at end of low mem accessible
+                         bus addr,  parent bus addr, size    */
+               ranges = <0x80000000 0x0 0x80000000 0x80000000>;
 
                core_clk: core_clk {
                        #clock-cells = <0>;
@@ -47,7 +50,7 @@
                };
 
                uart0: serial@f0000000 {
-                       compatible = "ns8250";
+                       compatible = "ns16550a";
                        reg = <0xf0000000 0x2000>;
                        interrupts = <24>;
                        clock-frequency = <50000000>;
index 4d6971c..738c76c 100644 (file)
@@ -54,7 +54,6 @@
                };
 
                uart0: serial@f0000000 {
-                       /* compatible = "ns8250"; Doesn't use FIFOs */
                        compatible = "ns16550a";
                        reg = <0xf0000000 0x2000>;
                        interrupt-parent = <&idu_intc>;
index 63dbaab..f8832a1 100644 (file)
        interrupt-parent = <&core_intc>;
 
        chosen {
-               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
+               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 print-fatal-signals=1";
        };
 
        aliases {
-               serial0 = &arcuart0;
+               serial0 = &uart0;
        };
 
        fpga {
                        #interrupt-cells = <1>;
                };
 
-               arcuart0: serial@c0fc1000 {
-                       compatible = "snps,arc-uart";
-                       reg = <0xc0fc1000 0x100>;
-                       interrupts = <5>;
-                       clock-frequency = <80000000>;
-                       current-speed = <115200>;
-                       status = "okay";
-               };
-
-               ethernet@c0fc2000 {
-                       compatible = "snps,arc-emac";
-                       reg = <0xc0fc2000 0x3c>;
-                       interrupts = <6>;
-                       mac-address = [ 00 11 22 33 44 55 ];
-                       clock-frequency = <80000000>;
-                       max-speed = <100>;
-                       phy = <&phy0>;
-
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       phy0: ethernet-phy@0 {
-                               reg = <1>;
-                       };
+               uart0: serial@f0000000 {
+                       compatible = "ns16550a";
+                       reg = <0xf0000000 0x2000>;
+                       interrupts = <24>;
+                       clock-frequency = <50000000>;
+                       baud = <115200>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       no-loopback-test = <1>;
                };
 
                arcpct0: pct {
diff --git a/arch/arc/boot/dts/nsim_hs.dts b/arch/arc/boot/dts/nsim_hs.dts
deleted file mode 100644 (file)
index 851798a..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
- */
-/dts-v1/;
-
-/include/ "skeleton_hs.dtsi"
-
-/ {
-       model = "snps,nsim_hs";
-       compatible = "snps,nsim_hs";
-       #address-cells = <2>;
-       #size-cells = <2>;
-       interrupt-parent = <&core_intc>;
-
-       memory {
-               device_type = "memory";
-               /* CONFIG_LINUX_RAM_BASE needs to match low mem start */
-               reg = <0x0 0x80000000 0x0 0x20000000    /* 512 MB low mem */
-                      0x1 0x00000000 0x0 0x40000000>;  /* 1 GB highmem */
-       };
-
-       chosen {
-               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
-       };
-
-       aliases {
-               serial0 = &arcuart0;
-       };
-
-       fpga {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               /* only perip space at end of low mem accessible
-                        bus addr,   parent bus addr, size */
-               ranges = <0x80000000 0x0 0x80000000 0x80000000>;
-
-               core_clk: core_clk {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <80000000>;
-               };
-
-               core_intc: core-interrupt-controller {
-                       compatible = "snps,archs-intc";
-                       interrupt-controller;
-                       #interrupt-cells = <1>;
-               };
-
-               arcuart0: serial@c0fc1000 {
-                       compatible = "snps,arc-uart";
-                       reg = <0xc0fc1000 0x100>;
-                       interrupts = <24>;
-                       clock-frequency = <80000000>;
-                       current-speed = <115200>;
-                       status = "okay";
-               };
-
-               arcpct0: pct {
-                       compatible = "snps,archs-pct";
-                       #interrupt-cells = <1>;
-                       interrupts = <20>;
-               };
-       };
-};
diff --git a/arch/arc/boot/dts/nsim_hs_idu.dts b/arch/arc/boot/dts/nsim_hs_idu.dts
deleted file mode 100644 (file)
index 6c559a0..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
- */
-/dts-v1/;
-
-/include/ "skeleton_hs_idu.dtsi"
-
-/ {
-       model = "snps,nsim_hs-smp";
-       compatible = "snps,nsim_hs";
-       interrupt-parent = <&core_intc>;
-
-       chosen {
-               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
-       };
-
-       aliases {
-               serial0 = &arcuart0;
-       };
-
-       fpga {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               /* child and parent address space 1:1 mapped */
-               ranges;
-
-               core_clk: core_clk {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <80000000>;
-               };
-
-               core_intc: core-interrupt-controller {
-                       compatible = "snps,archs-intc";
-                       interrupt-controller;
-                       #interrupt-cells = <1>;
-               };
-
-               idu_intc: idu-interrupt-controller {
-                       compatible = "snps,archs-idu-intc";
-                       interrupt-controller;
-                       interrupt-parent = <&core_intc>;
-                       #interrupt-cells = <1>;
-               };
-
-               arcuart0: serial@c0fc1000 {
-                       compatible = "snps,arc-uart";
-                       reg = <0xc0fc1000 0x100>;
-                       interrupt-parent = <&idu_intc>;
-                       interrupts = <0>;
-                       clock-frequency = <80000000>;
-                       current-speed = <115200>;
-                       status = "okay";
-               };
-
-               arcpct0: pct {
-                       compatible = "snps,archs-pct";
-                       #interrupt-cells = <1>;
-                       interrupts = <20>;
-               };
-       };
-};
index 47ff8a9..7337cdf 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_NAMESPACES=y
@@ -15,13 +16,9 @@ CONFIG_EXPERT=y
 CONFIG_PERF_EVENTS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
+CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs"
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ISA_ARCV2=y
-CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs"
-CONFIG_PREEMPT=y
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -30,9 +27,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
@@ -42,21 +36,12 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_VIRTIO_BLK=y
 CONFIG_NETDEVICES=y
 CONFIG_VIRTIO_NET=y
-# CONFIG_NET_VENDOR_ARC is not set
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-# CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_NET_VENDOR_VIA is not set
-# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_ETHERNET is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
-CONFIG_MOUSE_PS2_TOUCHKIT=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIO_ARC_PS2=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -66,9 +51,6 @@ CONFIG_SERIAL_8250_DW=y
 CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_LOGO=y
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_VIRTIO_MMIO=y
index 9685fd5..bc92722 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_NAMESPACES=y
@@ -16,15 +17,11 @@ CONFIG_PERF_EVENTS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
+CONFIG_SMP=y
+CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs_idu"
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ISA_ARCV2=y
-CONFIG_SMP=y
-CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs_idu"
-CONFIG_PREEMPT=y
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -33,9 +30,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
@@ -43,21 +37,12 @@ CONFIG_DEVTMPFS=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_BLK_DEV is not set
 CONFIG_NETDEVICES=y
-# CONFIG_NET_VENDOR_ARC is not set
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-# CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_NET_VENDOR_VIA is not set
-# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_ETHERNET is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
-CONFIG_MOUSE_PS2_TOUCHKIT=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIO_ARC_PS2=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -67,9 +52,6 @@ CONFIG_SERIAL_8250_DW=y
 CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_LOGO=y
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_IOMMU_SUPPORT is not set
index 2b9b114..326f6cd 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_NAMESPACES=y
@@ -17,13 +18,10 @@ CONFIG_PERF_EVENTS=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_ISA_ARCOMPACT=y
+CONFIG_ARC_BUILTIN_DTB_NAME="nsim_700"
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARC_BUILTIN_DTB_NAME="nsim_700"
-CONFIG_PREEMPT=y
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -37,15 +35,18 @@ CONFIG_DEVTMPFS=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_BLK_DEV is not set
 CONFIG_NETDEVICES=y
-CONFIG_ARC_EMAC=y
-CONFIG_LXT_PHY=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_ETHERNET is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_ARC=y
-CONFIG_SERIAL_ARC_CONSOLE=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_HID is not set
diff --git a/arch/arc/configs/nsim_hs_defconfig b/arch/arc/configs/nsim_hs_defconfig
deleted file mode 100644 (file)
index bab3dd2..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_CROSS_MEMORY_ATTACH is not set
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_EMBEDDED=y
-CONFIG_PERF_EVENTS=y
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ISA_ARCV2=y
-CONFIG_ARC_BUILTIN_DTB_NAME="nsim_hs"
-CONFIG_PREEMPT=y
-# CONFIG_COMPACTION is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_UNIX_DIAG=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-# CONFIG_IPV6 is not set
-CONFIG_DEVTMPFS=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_BLK_DEV is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_ARC=y
-CONFIG_SERIAL_ARC_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_TMPFS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_NFS_FS=y
-# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_DEBUG_PREEMPT is not set
diff --git a/arch/arc/configs/nsim_hs_smp_defconfig b/arch/arc/configs/nsim_hs_smp_defconfig
deleted file mode 100644 (file)
index 90d2d50..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_EMBEDDED=y
-CONFIG_PERF_EVENTS=y
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ISA_ARCV2=y
-CONFIG_SMP=y
-CONFIG_ARC_BUILTIN_DTB_NAME="nsim_hs_idu"
-CONFIG_PREEMPT=y
-# CONFIG_COMPACTION is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_UNIX_DIAG=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-# CONFIG_IPV6 is not set
-CONFIG_DEVTMPFS=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_BLK_DEV is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_ARC=y
-CONFIG_SERIAL_ARC_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_TMPFS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_NFS_FS=y
-# CONFIG_ENABLE_MUST_CHECK is not set
index 393d4f5..1b50569 100644 (file)
@@ -17,7 +17,6 @@ generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += mmiowb.h
-generic-y += msi.h
 generic-y += parport.h
 generic-y += percpu.h
 generic-y += preempt.h
index 918804c..d8ece42 100644 (file)
@@ -25,6 +25,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/build_bug.h>
+
 /* Uncached access macros */
 #define arc_read_uncached_32(ptr)      \
 ({                                     \
index 66a2923..c3aa775 100644 (file)
  * to be saved again on kernel mode stack, as part of pt_regs.
  *-------------------------------------------------------------*/
 .macro PROLOG_FREEUP_REG       reg, mem
-#ifdef CONFIG_SMP
+#ifndef ARC_USE_SCRATCH_REG
        sr  \reg, [ARC_REG_SCRATCH_DATA0]
 #else
        st  \reg, [\mem]
 .endm
 
 .macro PROLOG_RESTORE_REG      reg, mem
-#ifdef CONFIG_SMP
+#ifndef ARC_USE_SCRATCH_REG
        lr  \reg, [ARC_REG_SCRATCH_DATA0]
 #else
        ld  \reg, [\mem]
diff --git a/arch/arc/include/asm/jump_label.h b/arch/arc/include/asm/jump_label.h
new file mode 100644 (file)
index 0000000..9d96180
--- /dev/null
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARC_JUMP_LABEL_H
+#define _ASM_ARC_JUMP_LABEL_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+/*
+ * NOTE about '.balign 4':
+ *
+ * To make atomic update of patched instruction available we need to guarantee
+ * that this instruction doesn't cross L1 cache line boundary.
+ *
+ * As of today we simply align instruction which can be patched by 4 byte using
+ * ".balign 4" directive. In that case patched instruction is aligned with one
+ * 16-bit NOP_S if this is required.
+ * However 'align by 4' directive is much stricter than it actually required.
+ * It's enough that our 32-bit instruction don't cross L1 cache line boundary /
+ * L1 I$ fetch block boundary which can be achieved by using
+ * ".bundle_align_mode" assembler directive. That will save us from adding
+ * useless NOP_S padding in most of the cases.
+ *
+ * TODO: switch to ".bundle_align_mode" directive using whin it will be
+ * supported by ARC toolchain.
+ */
+
+static __always_inline bool arch_static_branch(struct static_key *key,
+                                              bool branch)
+{
+       asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)"   \n"
+                "1:                                                    \n"
+                "nop                                                   \n"
+                ".pushsection __jump_table, \"aw\"                     \n"
+                ".word 1b, %l[l_yes], %c0                              \n"
+                ".popsection                                           \n"
+                : : "i" (&((char *)key)[branch]) : : l_yes);
+
+       return false;
+l_yes:
+       return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key *key,
+                                                   bool branch)
+{
+       asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)"   \n"
+                "1:                                                    \n"
+                "b %l[l_yes]                                           \n"
+                ".pushsection __jump_table, \"aw\"                     \n"
+                ".word 1b, %l[l_yes], %c0                              \n"
+                ".popsection                                           \n"
+                : : "i" (&((char *)key)[branch]) : : l_yes);
+
+       return false;
+l_yes:
+       return true;
+}
+
+typedef u32 jump_label_t;
+
+struct jump_entry {
+       jump_label_t code;
+       jump_label_t target;
+       jump_label_t key;
+};
+
+#endif  /* __ASSEMBLY__ */
+#endif
index 98cadf1..26b731d 100644 (file)
 #define ARC_REG_SCRATCH_DATA0  0x46c
 #endif
 
+#if defined(CONFIG_ISA_ARCV2) || !defined(CONFIG_SMP)
+#define        ARC_USE_SCRATCH_REG
+#endif
+
 /* Bits in MMU PID register */
 #define __TLB_ENABLE           (1 << 31)
 #define __PROG_ENABLE          (1 << 30)
@@ -63,6 +67,8 @@
 #if (CONFIG_ARC_MMU_VER >= 2)
 #define TLBWriteNI  0x5                /* write JTLB without inv uTLBs */
 #define TLBIVUTLB   0x6                /* explicitly inv uTLBs */
+#else
+#define TLBWriteNI  TLBWrite   /* Not present in hardware, fallback */
 #endif
 
 #if (CONFIG_ARC_MMU_VER >= 4)
index 0354708..3a5e6a5 100644 (file)
@@ -144,7 +144,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
         */
        cpumask_set_cpu(cpu, mm_cpumask(next));
 
-#ifndef CONFIG_SMP
+#ifdef ARC_USE_SCRATCH_REG
        /* PGD cached in MMU reg to avoid 3 mem lookups: task->mm->pgd */
        write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
 #endif
index 7addd03..9019ed9 100644 (file)
@@ -33,7 +33,6 @@
 #define _ASM_ARC_PGTABLE_H
 
 #include <linux/bits.h>
-#define __ARCH_USE_5LEVEL_HACK
 #include <asm-generic/pgtable-nopmd.h>
 #include <asm/page.h>
 #include <asm/mmu.h>   /* to propagate CONFIG_ARC_MMU_VER <n> */
@@ -351,7 +350,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
  * Thus use this macro only when you are certain that "current" is current
  * e.g. when dealing with signal frame setup code etc
  */
-#ifndef CONFIG_SMP
+#ifdef ARC_USE_SCRATCH_REG
 #define pgd_offset_fast(mm, addr)      \
 ({                                     \
        pgd_t *pgd_base = (pgd_t *) read_aux_reg(ARC_REG_SCRATCH_DATA0);  \
index de62511..e784f53 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_ARC_EMUL_UNALIGNED)      += unaligned.o
 obj-$(CONFIG_KGDB)                     += kgdb.o
 obj-$(CONFIG_ARC_METAWARE_HLINK)       += arc_hostlink.o
 obj-$(CONFIG_PERF_EVENTS)              += perf_event.o
+obj-$(CONFIG_JUMP_LABEL)               += jump_label.o
 
 obj-$(CONFIG_ARC_FPU_SAVE_RESTORE)     += fpu.o
 CFLAGS_fpu.o   += -mdpfp
diff --git a/arch/arc/kernel/jump_label.c b/arch/arc/kernel/jump_label.c
new file mode 100644 (file)
index 0000000..b8600dc
--- /dev/null
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+
+#include "asm/cacheflush.h"
+
+#define JUMPLABEL_ERR  "ARC: jump_label: ERROR: "
+
+/* Halt system on fatal error to make debug easier */
+#define arc_jl_fatal(format...)                                                \
+({                                                                     \
+       pr_err(JUMPLABEL_ERR format);                                   \
+       BUG();                                                          \
+})
+
+static inline u32 arc_gen_nop(void)
+{
+       /* 1x 32bit NOP in middle endian */
+       return 0x7000264a;
+}
+
+/*
+ * Atomic update of patched instruction is only available if this
+ * instruction doesn't cross L1 cache line boundary. You can read about
+ * the way we achieve this in arc/include/asm/jump_label.h
+ */
+static inline void instruction_align_assert(void *addr, int len)
+{
+       unsigned long a = (unsigned long)addr;
+
+       if ((a >> L1_CACHE_SHIFT) != ((a + len - 1) >> L1_CACHE_SHIFT))
+               arc_jl_fatal("instruction (addr %px) cross L1 cache line border",
+                            addr);
+}
+
+/*
+ * ARCv2 'Branch unconditionally' instruction:
+ * 00000ssssssssss1SSSSSSSSSSNRtttt
+ * s S[n:0] lower bits signed immediate (number is bitfield size)
+ * S S[m:n+1] upper bits signed immediate (number is bitfield size)
+ * t S[24:21] upper bits signed immediate (branch unconditionally far)
+ * N N <.d> delay slot mode
+ * R R Reserved
+ */
+static inline u32 arc_gen_branch(jump_label_t pc, jump_label_t target)
+{
+       u32 instruction_l, instruction_r;
+       u32 pcl = pc & GENMASK(31, 2);
+       u32 u_offset = target - pcl;
+       u32 s, S, t;
+
+       /*
+        * Offset in 32-bit branch instruction must to fit into s25.
+        * Something is terribly broken if we get such huge offset within one
+        * function.
+        */
+       if ((s32)u_offset < -16777216 || (s32)u_offset > 16777214)
+               arc_jl_fatal("gen branch with offset (%d) not fit in s25",
+                            (s32)u_offset);
+
+       /*
+        * All instructions are aligned by 2 bytes so we should never get offset
+        * here which is not 2 bytes aligned.
+        */
+       if (u_offset & 0x1)
+               arc_jl_fatal("gen branch with offset (%d) unaligned to 2 bytes",
+                            (s32)u_offset);
+
+       s = (u_offset >> 1)  & GENMASK(9, 0);
+       S = (u_offset >> 11) & GENMASK(9, 0);
+       t = (u_offset >> 21) & GENMASK(3, 0);
+
+       /* 00000ssssssssss1 */
+       instruction_l = (s << 1) | 0x1;
+       /* SSSSSSSSSSNRtttt */
+       instruction_r = (S << 6) | t;
+
+       return (instruction_r << 16) | (instruction_l & GENMASK(15, 0));
+}
+
+void arch_jump_label_transform(struct jump_entry *entry,
+                              enum jump_label_type type)
+{
+       jump_label_t *instr_addr = (jump_label_t *)entry->code;
+       u32 instr;
+
+       instruction_align_assert(instr_addr, JUMP_LABEL_NOP_SIZE);
+
+       if (type == JUMP_LABEL_JMP)
+               instr = arc_gen_branch(entry->code, entry->target);
+       else
+               instr = arc_gen_nop();
+
+       WRITE_ONCE(*instr_addr, instr);
+       flush_icache_range(entry->code, entry->code + JUMP_LABEL_NOP_SIZE);
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+                                     enum jump_label_type type)
+{
+       /*
+        * We use only one NOP type (1x, 4 byte) in arch_static_branch, so
+        * there's no need to patch an identical NOP over the top of it here.
+        * The generic code calls 'arch_jump_label_transform' if the NOP needs
+        * to be replaced by a branch, so 'arch_jump_label_transform_static' is
+        * never called with type other than JUMP_LABEL_NOP.
+        */
+       BUG_ON(type != JUMP_LABEL_NOP);
+}
+
+#ifdef CONFIG_ARC_DBG_JUMP_LABEL
+#define SELFTEST_MSG   "ARC: instruction generation self-test: "
+
+struct arc_gen_branch_testdata {
+       jump_label_t pc;
+       jump_label_t target_address;
+       u32 expected_instr;
+};
+
+static __init int branch_gen_test(const struct arc_gen_branch_testdata *test)
+{
+       u32 instr_got;
+
+       instr_got = arc_gen_branch(test->pc, test->target_address);
+       if (instr_got == test->expected_instr)
+               return 0;
+
+       pr_err(SELFTEST_MSG "FAIL:\n arc_gen_branch(0x%08x, 0x%08x) != 0x%08x, got 0x%08x\n",
+              test->pc, test->target_address,
+              test->expected_instr, instr_got);
+
+       return -EFAULT;
+}
+
+/*
+ * Offset field in branch instruction is not continuous. Test all
+ * available offset field and sign combinations. Test data is generated
+ * from real working code.
+ */
+static const struct arc_gen_branch_testdata arcgenbr_test_data[] __initconst = {
+       {0x90007548, 0x90007514, 0xffcf07cd}, /* tiny (-52) offs */
+       {0x9000c9c0, 0x9000c782, 0xffcf05c3}, /* tiny (-574) offs */
+       {0x9000cc1c, 0x9000c782, 0xffcf0367}, /* tiny (-1178) offs */
+       {0x9009dce0, 0x9009d106, 0xff8f0427}, /* small (-3034) offs */
+       {0x9000f5de, 0x90007d30, 0xfc0f0755}, /* big  (-30892) offs */
+       {0x900a2444, 0x90035f64, 0xc9cf0321}, /* huge (-443616) offs */
+       {0x90007514, 0x9000752c, 0x00000019}, /* tiny (+24) offs */
+       {0x9001a578, 0x9001a77a, 0x00000203}, /* tiny (+514) offs */
+       {0x90031ed8, 0x90032634, 0x0000075d}, /* tiny (+1884) offs */
+       {0x9008c7f2, 0x9008d3f0, 0x00400401}, /* small (+3072) offs */
+       {0x9000bb38, 0x9003b340, 0x17c00009}, /* big  (+194568) offs */
+       {0x90008f44, 0x90578d80, 0xb7c2063d}  /* huge (+5701180) offs */
+};
+
+static __init int instr_gen_test(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(arcgenbr_test_data); i++)
+               if (branch_gen_test(&arcgenbr_test_data[i]))
+                       return -EFAULT;
+
+       pr_info(SELFTEST_MSG "OK\n");
+
+       return 0;
+}
+early_initcall(instr_gen_test);
+
+#endif /* CONFIG_ARC_DBG_JUMP_LABEL */
index 3861543..fb86bc3 100644 (file)
@@ -30,6 +30,7 @@ noinline static int handle_kernel_vaddr_fault(unsigned long address)
         * with the 'reference' page table.
         */
        pgd_t *pgd, *pgd_k;
+       p4d_t *p4d, *p4d_k;
        pud_t *pud, *pud_k;
        pmd_t *pmd, *pmd_k;
 
@@ -39,8 +40,13 @@ noinline static int handle_kernel_vaddr_fault(unsigned long address)
        if (!pgd_present(*pgd_k))
                goto bad_area;
 
-       pud = pud_offset(pgd, address);
-       pud_k = pud_offset(pgd_k, address);
+       p4d = p4d_offset(pgd, address);
+       p4d_k = p4d_offset(pgd_k, address);
+       if (!p4d_present(*p4d_k))
+               goto bad_area;
+
+       pud = pud_offset(p4d, address);
+       pud_k = pud_offset(p4d_k, address);
        if (!pud_present(*pud_k))
                goto bad_area;
 
index a4856bf..fc8849e 100644 (file)
@@ -111,12 +111,14 @@ EXPORT_SYMBOL(__kunmap_atomic);
 static noinline pte_t * __init alloc_kmap_pgtable(unsigned long kvaddr)
 {
        pgd_t *pgd_k;
+       p4d_t *p4d_k;
        pud_t *pud_k;
        pmd_t *pmd_k;
        pte_t *pte_k;
 
        pgd_k = pgd_offset_k(kvaddr);
-       pud_k = pud_offset(pgd_k, kvaddr);
+       p4d_k = p4d_offset(pgd_k, kvaddr);
+       pud_k = pud_offset(p4d_k, kvaddr);
        pmd_k = pmd_offset(pud_k, kvaddr);
 
        pte_k = (pte_t *)memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
index 10025e1..c340acd 100644 (file)
@@ -118,6 +118,33 @@ static inline void __tlb_entry_erase(void)
        write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
 }
 
+static void utlb_invalidate(void)
+{
+#if (CONFIG_ARC_MMU_VER >= 2)
+
+#if (CONFIG_ARC_MMU_VER == 2)
+       /* MMU v2 introduced the uTLB Flush command.
+        * There was however an obscure hardware bug, where uTLB flush would
+        * fail when a prior probe for J-TLB (both totally unrelated) would
+        * return lkup err - because the entry didn't exist in MMU.
+        * The Workround was to set Index reg with some valid value, prior to
+        * flush. This was fixed in MMU v3
+        */
+       unsigned int idx;
+
+       /* make sure INDEX Reg is valid */
+       idx = read_aux_reg(ARC_REG_TLBINDEX);
+
+       /* If not write some dummy val */
+       if (unlikely(idx & TLB_LKUP_ERR))
+               write_aux_reg(ARC_REG_TLBINDEX, 0xa);
+#endif
+
+       write_aux_reg(ARC_REG_TLBCOMMAND, TLBIVUTLB);
+#endif
+
+}
+
 #if (CONFIG_ARC_MMU_VER < 4)
 
 static inline unsigned int tlb_entry_lkup(unsigned long vaddr_n_asid)
@@ -149,44 +176,6 @@ static void tlb_entry_erase(unsigned int vaddr_n_asid)
        }
 }
 
-/****************************************************************************
- * ARC700 MMU caches recently used J-TLB entries (RAM) as uTLBs (FLOPs)
- *
- * New IVUTLB cmd in MMU v2 explictly invalidates the uTLB
- *
- * utlb_invalidate ( )
- *  -For v2 MMU calls Flush uTLB Cmd
- *  -For v1 MMU does nothing (except for Metal Fix v1 MMU)
- *      This is because in v1 TLBWrite itself invalidate uTLBs
- ***************************************************************************/
-
-static void utlb_invalidate(void)
-{
-#if (CONFIG_ARC_MMU_VER >= 2)
-
-#if (CONFIG_ARC_MMU_VER == 2)
-       /* MMU v2 introduced the uTLB Flush command.
-        * There was however an obscure hardware bug, where uTLB flush would
-        * fail when a prior probe for J-TLB (both totally unrelated) would
-        * return lkup err - because the entry didn't exist in MMU.
-        * The Workround was to set Index reg with some valid value, prior to
-        * flush. This was fixed in MMU v3 hence not needed any more
-        */
-       unsigned int idx;
-
-       /* make sure INDEX Reg is valid */
-       idx = read_aux_reg(ARC_REG_TLBINDEX);
-
-       /* If not write some dummy val */
-       if (unlikely(idx & TLB_LKUP_ERR))
-               write_aux_reg(ARC_REG_TLBINDEX, 0xa);
-#endif
-
-       write_aux_reg(ARC_REG_TLBCOMMAND, TLBIVUTLB);
-#endif
-
-}
-
 static void tlb_entry_insert(unsigned int pd0, pte_t pd1)
 {
        unsigned int idx;
@@ -219,11 +208,6 @@ static void tlb_entry_insert(unsigned int pd0, pte_t pd1)
 
 #else  /* CONFIG_ARC_MMU_VER >= 4) */
 
-static void utlb_invalidate(void)
-{
-       /* No need since uTLB is always in sync with JTLB */
-}
-
 static void tlb_entry_erase(unsigned int vaddr_n_asid)
 {
        write_aux_reg(ARC_REG_TLBPD0, vaddr_n_asid | _PAGE_PRESENT);
@@ -267,7 +251,7 @@ noinline void local_flush_tlb_all(void)
        for (entry = 0; entry < num_tlb; entry++) {
                /* write this entry to the TLB */
                write_aux_reg(ARC_REG_TLBINDEX, entry);
-               write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+               write_aux_reg(ARC_REG_TLBCOMMAND, TLBWriteNI);
        }
 
        if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
@@ -278,7 +262,7 @@ noinline void local_flush_tlb_all(void)
 
                for (entry = stlb_idx; entry < stlb_idx + 16; entry++) {
                        write_aux_reg(ARC_REG_TLBINDEX, entry);
-                       write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+                       write_aux_reg(ARC_REG_TLBCOMMAND, TLBWriteNI);
                }
        }
 
@@ -355,8 +339,6 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                }
        }
 
-       utlb_invalidate();
-
        local_irq_restore(flags);
 }
 
@@ -385,8 +367,6 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
                start += PAGE_SIZE;
        }
 
-       utlb_invalidate();
-
        local_irq_restore(flags);
 }
 
@@ -407,7 +387,6 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 
        if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) {
                tlb_entry_erase((page & PAGE_MASK) | hw_pid(vma->vm_mm, cpu));
-               utlb_invalidate();
        }
 
        local_irq_restore(flags);
@@ -868,7 +847,7 @@ void arc_mmu_init(void)
        write_aux_reg(ARC_REG_PID, MMU_ENABLE);
 
        /* In smp we use this reg for interrupt 1 scratch */
-#ifndef CONFIG_SMP
+#ifdef ARC_USE_SCRATCH_REG
        /* swapper_pg_dir is the pgd for the kernel, used by vmalloc */
        write_aux_reg(ARC_REG_SCRATCH_DATA0, swapper_pg_dir);
 #endif
index c55d95d..2efaf6c 100644 (file)
@@ -122,17 +122,27 @@ ex_saved_reg1:
 #else  /* ARCv2 */
 
 .macro TLBMISS_FREEUP_REGS
+#ifdef CONFIG_ARC_HAS_LL64
+       std   r0, [sp, -16]
+       std   r2, [sp, -8]
+#else
        PUSH  r0
        PUSH  r1
        PUSH  r2
        PUSH  r3
+#endif
 .endm
 
 .macro TLBMISS_RESTORE_REGS
+#ifdef CONFIG_ARC_HAS_LL64
+       ldd   r0, [sp, -16]
+       ldd   r2, [sp, -8]
+#else
        POP   r3
        POP   r2
        POP   r1
        POP   r0
+#endif
 .endm
 
 #endif
@@ -193,7 +203,7 @@ ex_saved_reg1:
 
        lr  r2, [efa]
 
-#ifndef CONFIG_SMP
+#ifdef ARC_USE_SCRATCH_REG
        lr  r1, [ARC_REG_SCRATCH_DATA0] ; current pgd
 #else
        GET_CURR_TASK_ON_CPU  r1
@@ -282,11 +292,7 @@ ex_saved_reg1:
        sr  TLBGetIndex, [ARC_REG_TLBCOMMAND]
 
        /* Commit the Write */
-#if (CONFIG_ARC_MMU_VER >= 2)   /* introduced in v2 */
        sr TLBWriteNI, [ARC_REG_TLBCOMMAND]
-#else
-       sr TLBWrite, [ARC_REG_TLBCOMMAND]
-#endif
 
 #else
        sr TLBInsertEntry, [ARC_REG_TLBCOMMAND]
@@ -370,9 +376,7 @@ ENTRY(EV_TLBMissD)
 
        ;----------------------------------------------------------------
        ; UPDATE_PTE: Let Linux VM know that page was accessed/dirty
-       lr      r3, [ecr]
        or      r0, r0, _PAGE_ACCESSED        ; Accessed bit always
-       btst_s  r3,  ECR_C_BIT_DTLB_ST_MISS   ; See if it was a Write Access ?
        or.nz   r0, r0, _PAGE_DIRTY           ; if Write, set Dirty bit as well
        st_s    r0, [r1]                      ; Write back PTE
 
index 3765ded..2bde2a6 100644 (file)
@@ -21,7 +21,6 @@ static const char *simulation_compat[] __initconst = {
        "snps,nsim",
        "snps,nsimosci",
 #else
-       "snps,nsim_hs",
        "snps,nsimosci_hs",
        "snps,zebu_hs",
 #endif
index 5aed42e..ba75e36 100644 (file)
@@ -1357,7 +1357,7 @@ config ARCH_NR_GPIO
        int
        default 2048 if ARCH_SOCFPGA
        default 1024 if ARCH_BRCMSTB || ARCH_RENESAS || ARCH_TEGRA || \
-               ARCH_ZYNQ
+               ARCH_ZYNQ || ARCH_ASPEED
        default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \
                SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
        default 416 if ARCH_SUNXI
index b36c028..6a0f1f5 100644 (file)
@@ -2,11 +2,13 @@
 #ifndef _ARM_LIBFDT_ENV_H
 #define _ARM_LIBFDT_ENV_H
 
+#include <linux/limits.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <asm/byteorder.h>
 
-#define INT_MAX                        ((int)(~0U>>1))
+#define INT32_MAX      S32_MAX
+#define UINT32_MAX     U32_MAX
 
 typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
index b21b3a6..08011dc 100644 (file)
@@ -45,7 +45,8 @@ dtb-$(CONFIG_SOC_AT91SAM9) += \
        at91sam9x25ek.dtb \
        at91sam9x35ek.dtb
 dtb-$(CONFIG_SOC_SAM_V7) += \
-       at91-kizbox2.dtb \
+       at91-kizbox2-2.dtb \
+       at91-kizbox3-hs.dtb \
        at91-nattis-2-natte-2.dtb \
        at91-sama5d27_som1_ek.dtb \
        at91-sama5d2_ptc_ek.dtb \
@@ -83,6 +84,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
        bcm2837-rpi-3-b.dtb \
        bcm2837-rpi-3-b-plus.dtb \
        bcm2837-rpi-cm3-io3.dtb \
+       bcm2711-rpi-4-b.dtb \
        bcm2835-rpi-zero.dtb \
        bcm2835-rpi-zero-w.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += \
@@ -113,6 +115,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
        bcm47094-luxul-abr-4500.dtb \
        bcm47094-luxul-xap-1610.dtb \
        bcm47094-luxul-xbr-4500.dtb \
+       bcm47094-luxul-xwc-2000.dtb \
        bcm47094-luxul-xwr-3100.dtb \
        bcm47094-luxul-xwr-3150-v1.dtb \
        bcm47094-netgear-r8500.dtb \
@@ -337,7 +340,8 @@ dtb-$(CONFIG_ARCH_MMP) += \
        pxa168-aspenite.dtb \
        pxa910-dkb.dtb \
        mmp2-brownstone.dtb \
-       mmp2-olpc-xo-1-75.dtb
+       mmp2-olpc-xo-1-75.dtb \
+       mmp3-dell-ariel.dtb
 dtb-$(CONFIG_ARCH_MPS2) += \
        mps2-an385.dtb \
        mps2-an399.dtb
@@ -552,7 +556,8 @@ dtb-$(CONFIG_SOC_IMX6SL) += \
        imx6sl-evk.dtb \
        imx6sl-warp.dtb
 dtb-$(CONFIG_SOC_IMX6SLL) += \
-       imx6sll-evk.dtb
+       imx6sll-evk.dtb \
+       imx6sll-kobo-clarahd.dtb
 dtb-$(CONFIG_SOC_IMX6SX) += \
        imx6sx-nitrogen6sx.dtb \
        imx6sx-sabreauto.dtb \
@@ -583,6 +588,7 @@ dtb-$(CONFIG_SOC_IMX6UL) += \
        imx6ull-14x14-evk.dtb \
        imx6ull-colibri-eval-v3.dtb \
        imx6ull-colibri-wifi-eval-v3.dtb \
+       imx6ull-opos6uldev.dtb \
        imx6ull-phytec-segin-ff-rdk-nand.dtb \
        imx6ull-phytec-segin-ff-rdk-emmc.dtb \
        imx6ull-phytec-segin-lc-rdk-nand.dtb \
@@ -753,6 +759,9 @@ dtb-$(CONFIG_SOC_AM33XX) += \
        am335x-moxa-uc-2101.dtb \
        am335x-moxa-uc-8100-me-t.dtb \
        am335x-nano.dtb \
+       am335x-netcan-plus-1xx.dtb \
+       am335x-netcom-plus-2xx.dtb \
+       am335x-netcom-plus-8xx.dtb \
        am335x-pdu001.dtb \
        am335x-pepper.dtb \
        am335x-phycore-rdk.dtb \
@@ -765,6 +774,7 @@ dtb-$(CONFIG_SOC_AM33XX) += \
        am335x-wega-rdk.dtb \
        am335x-osd3358-sm-red.dtb
 dtb-$(CONFIG_ARCH_OMAP4) += \
+       omap4-droid-bionic-xt875.dtb \
        omap4-droid4-xt894.dtb \
        omap4-duovero-parlor.dtb \
        omap4-kc1.dtb \
@@ -1105,6 +1115,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
        sun8i-h3-beelink-x2.dtb \
        sun8i-h3-libretech-all-h3-cc.dtb \
        sun8i-h3-mapleboard-mp130.dtb \
+       sun8i-h3-nanopi-duo2.dtb \
        sun8i-h3-nanopi-m1.dtb  \
        sun8i-h3-nanopi-m1-plus.dtb \
        sun8i-h3-nanopi-neo.dtb \
@@ -1288,6 +1299,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
        aspeed-bmc-facebook-wedge40.dtb \
        aspeed-bmc-facebook-wedge100.dtb \
        aspeed-bmc-facebook-yamp.dtb \
+       aspeed-bmc-ibm-rainier.dtb \
        aspeed-bmc-intel-s2600wf.dtb \
        aspeed-bmc-inspur-fp5280g2.dtb \
        aspeed-bmc-lenovo-hr630.dtb \
@@ -1298,6 +1310,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
        aspeed-bmc-opp-palmetto.dtb \
        aspeed-bmc-opp-romulus.dtb \
        aspeed-bmc-opp-swift.dtb \
+       aspeed-bmc-opp-tacoma.dtb \
        aspeed-bmc-opp-vesnin.dtb \
        aspeed-bmc-opp-witherspoon.dtb \
        aspeed-bmc-opp-zaius.dtb \
index ed235f2..05e7b5d 100644 (file)
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&cppi41dma  {
-       status = "okay";
-};
-
 #include "tps65910.dtsi"
 
 &tps {
index 89b4cf2..6c9187b 100644 (file)
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "peripheral";
        interrupts-extended = <&intc 18 &tps 0>;
        interrupt-names = "mc", "vbus";
 };
 
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &i2c0 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c0_pins>;
index 2f6652e..5811fb8 100644 (file)
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "peripheral";
        interrupts-extended = <&intc 18 &tps 0>;
        interrupt-names = "mc", "vbus";
 };
 
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &i2c0 {
        baseboard_eeprom: baseboard_eeprom@50 {
                compatible = "atmel,24c256";
index 8cd81dc..b14a275 100644 (file)
 };
 
 /* USB */
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb1 {
        pinctrl-names = "default";
        pinctrl-0 = <&usb1_drvvbus>;
-
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 /* microSD */
 &mmc1 {
        pinctrl-names = "default";
index 1fe3b56..c6fe9db 100644 (file)
@@ -330,26 +330,6 @@ status = "okay";
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
-&cppi41dma  {
-       status = "okay";
-};
-
 &epwmss0 {
        status = "okay";
 
index a001457..6f0a6be 100644 (file)
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &i2c1 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c1_pins>;
index e28a5b8..a97f9df 100644 (file)
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &epwmss2 {
        status = "okay";
 
index c9611ea..81e0f63 100644 (file)
        };
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &elm {
        status = "okay";
 };
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
 &usb0 {
        dr_mode = "peripheral";
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
 };
 
 &usb1 {
        dr_mode = "host";
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
 };
 
 &am33xx_pinmux {
index eabcc8b..c9f354f 100644 (file)
        pinctrl-0 = <&uart0_pins>;
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 #include "tps65910.dtsi"
 
 &tps {
index a8005e9..fef5828 100644 (file)
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "host";
 };
 
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &cpsw_emac0 {
        phy-handle = <&ethphy0>;
        phy-mode = "rmii";
index 671d4a5..6495a12 100644 (file)
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 /* Power */
 &vbat {
        regulator-name = "vbat";
index 783d411..244df9c 100644 (file)
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "host";
 };
 
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 #include "tps65910.dtsi"
 
 &tps {
diff --git a/arch/arm/boot/dts/am335x-netcan-plus-1xx.dts b/arch/arm/boot/dts/am335x-netcan-plus-1xx.dts
new file mode 100644 (file)
index 0000000..1e4dbc8
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/*
+ * VScom OnRISC
+ * http://www.vscom.de
+ */
+
+/dts-v1/;
+
+#include "am335x-baltos.dtsi"
+#include "am335x-baltos-leds.dtsi"
+
+/ {
+       model = "NetCAN";
+
+       leds {
+               pinctrl-names = "default";
+               pinctrl-0 = <&user_leds_s0>;
+
+               compatible = "gpio-leds";
+
+               led@1 {
+                       label = "can_data";
+                       linux,default-trigger = "netdev";
+                       gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+               led@2 {
+                       label = "can_error";
+                       gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+       };
+};
+
+&am33xx_pinmux {
+       user_leds_s0: user_leds_s0 {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* CAN Data LED */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* CAN Error LED */
+               >;
+       };
+
+       dcan1_pins: pinmux_dcan1_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT, MUX_MODE2)    /* CAN TX */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT, MUX_MODE2)     /* CAN RX */
+               >;
+       };
+};
+
+&usb0_phy {
+       status = "okay";
+};
+
+&usb0 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&davinci_mdio {
+       phy0: ethernet-phy@0 {
+               reg = <1>;
+       };
+};
+
+&cpsw_emac0 {
+       phy-mode = "rmii";
+       dual_emac_res_vlan = <1>;
+       phy-handle = <&phy0>;
+};
+
+&cpsw_emac1 {
+       phy-mode = "rgmii-id";
+       dual_emac_res_vlan = <2>;
+       phy-handle = <&phy1>;
+};
+
+&dcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&dcan1_pins>;
+
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/am335x-netcom-plus-2xx.dts b/arch/arm/boot/dts/am335x-netcom-plus-2xx.dts
new file mode 100644 (file)
index 0000000..9a6cd8e
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/*
+ * VScom OnRISC
+ * http://www.vscom.de
+ */
+
+/dts-v1/;
+
+#include "am335x-baltos.dtsi"
+#include "am335x-baltos-leds.dtsi"
+
+/ {
+       model = "NetCom Plus";
+};
+
+&am33xx_pinmux {
+       uart1_pins: pinmux_uart1_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE0)                      /* RX */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT, MUX_MODE0)                      /* TX */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE0)            /* CTS */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)           /* RTS */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE7)            /* DTR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)             /* DSR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)              /* DCD */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)        /* RI */
+               >;
+       };
+
+       uart2_pins: pinmux_uart2_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1)              /* RX */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1)               /* TX */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* CTS */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_OUTPUT_PULLDOWN, MUX_MODE2)     /* RTS */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* DTR */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* DSR */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* DCD */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* RI */
+               >;
+       };
+};
+
+&usb0_phy {
+       status = "okay";
+};
+
+&usb0 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_pins>;
+       dtr-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>;
+       dsr-gpios = <&gpio2 23 GPIO_ACTIVE_LOW>;
+       dcd-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
+       rng-gpios = <&gpio2 25 GPIO_ACTIVE_LOW>;
+
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pins>;
+       dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+       dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+       dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+       rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+
+       status = "okay";
+};
+
+&davinci_mdio {
+       phy0: ethernet-phy@0 {
+               reg = <1>;
+       };
+};
+
+&cpsw_emac0 {
+       phy-mode = "rmii";
+       dual_emac_res_vlan = <1>;
+       phy-handle = <&phy0>;
+};
+
+&cpsw_emac1 {
+       phy-mode = "rgmii-id";
+       dual_emac_res_vlan = <2>;
+       phy-handle = <&phy1>;
+};
diff --git a/arch/arm/boot/dts/am335x-netcom-plus-8xx.dts b/arch/arm/boot/dts/am335x-netcom-plus-8xx.dts
new file mode 100644 (file)
index 0000000..2298563
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/*
+ * VScom OnRISC
+ * http://www.vscom.de
+ */
+
+/dts-v1/;
+
+#include "am335x-baltos.dtsi"
+
+/ {
+       model = "NetCom Plus";
+};
+
+&am33xx_pinmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&dip_switches>;
+
+       dip_switches: pinmux_dip_switches {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLDOWN, MUX_MODE7)
+               >;
+       };
+
+       tca6416_pins: pinmux_tca6416_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_INPUT_PULLUP, MUX_MODE7)
+               >;
+       };
+
+       i2c2_pins: pinmux_i2c2_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLDOWN, MUX_MODE3)
+               >;
+       };
+};
+
+&usb0_phy {
+       status = "okay";
+};
+
+&usb1_phy {
+       status = "okay";
+};
+
+&usb0 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&usb1 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&i2c1 {
+       tca6416a: gpio@20 {
+               compatible = "ti,tca6416";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <20 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&tca6416_pins>;
+       };
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c2_pins>;
+
+       status = "okay";
+       clock-frequency = <400000>;
+
+       tca6416b: gpio@20 {
+               compatible = "ti,tca6416";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       tca6416c: gpio@21 {
+               compatible = "ti,tca6416";
+               reg = <0x21>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+};
+
+&davinci_mdio {
+       phy0: ethernet-phy@0 {
+               reg = <1>;
+       };
+};
+
+&cpsw_emac0 {
+       phy-mode = "rmii";
+       dual_emac_res_vlan = <1>;
+       phy-handle = <&phy0>;
+};
+
+&cpsw_emac1 {
+       phy-mode = "rgmii-id";
+       dual_emac_res_vlan = <2>;
+       phy-handle = <&phy1>;
+};
index f47cc9f..1d29020 100644 (file)
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "peripheral";
        interrupts-extended = <&intc 18 &tps 0>;
        interrupt-names = "mc", "vbus";
 };
 
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &i2c2 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c2_pins>;
index 9bfa032..6c547c8 100644 (file)
 };
 
 /* USB */
-&cppi41dma {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
-
-&usb1_phy {
-       status = "okay";
-};
index 3141255..e4dcfa0 100644 (file)
        };
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
-&usb1 {
-       status = "okay";
-};
-
-&cppi41dma  {
-       status = "okay";
-};
-
 /*
  * Disable soc's rtc as we have no VBAT for it. This makes the board
  * rtc (Microchip MCP79400) the default rtc device 'rtc0'.
index e7764ec..6d7608d 100644 (file)
 
 /* USB */
 &usb {
-       status = "okay";
-
        pinctrl-names = "default";
        pinctrl-0 = <&usb_pins>;
 };
 
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
         dr_mode = "host";
 };
 
 &usb1 {
-       status = "okay";
         dr_mode = "host";
 };
 
-&cppi41dma {
-       status = "okay";
-};
-
 &am33xx_pinmux {
        usb_pins: pinmux_usb {
                pinctrl-single,pins = <
index ff4f919..4da7190 100644 (file)
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "otg";
 };
 
-&usb1_phy {
-       status = "okay";
-};
-
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
-
-&cppi41dma  {
-       status = "okay";
-};
index 5aff02a..6fbf4ac 100644 (file)
        status = "okay";
        linux,rs485-enabled-at-boot-time;
 };
-
-/* USB */
-&cppi41dma {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
index 5b03685..1eaa265 100644 (file)
        status = "okay";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &davinci_mdio {
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&davinci_mdio_default>;
        status = "okay";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
index 2f82095..f4684c8 100644 (file)
        status = "disabled";
 };
 
-&usb {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
-};
-
 &usb0 {
-       status = "okay";
        dr_mode = "otg";
 };
 
 &usb1 {
-       status = "okay";
        dr_mode = "host";
 };
 
-&cppi41dma  {
-       status = "okay";
-};
-
 &mmc1 {
        status = "okay";
        pinctrl-names = "default";
index 61fc4cd..1359bf8 100644 (file)
        status = "okay";
 };
 
-/* USB */
-&cppi41dma {
-       status = "okay";
-};
-
-&usb_ctrl_mod {
-       status = "okay";
-};
-
-&usb {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-};
-
-&usb0_phy {
-       status = "okay";
-};
-
 &usb1 {
        dr_mode = "host";
-       status = "okay";
-};
-
-&usb1_phy {
-       status = "okay";
 };
index 7a9eb2b..3a8a205 100644 (file)
 
                gpio0_target: target-module@7000 {      /* 0x44e07000, ap 14 20.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio1";
                        reg = <0x7000 0x4>,
                              <0x7010 0x4>,
                              <0x7114 0x4>;
 
                target-module@9000 {                    /* 0x44e09000, ap 16 04.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart1";
                        reg = <0x9050 0x4>,
                              <0x9054 0x4>,
                              <0x9058 0x4>;
 
                target-module@b000 {                    /* 0x44e0b000, ap 18 48.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c1";
                        reg = <0xb000 0x8>,
                              <0xb010 0x8>,
                              <0xb090 0x8>;
                                        };
                                };
 
+                               usb_ctrl_mod: control@620 {
+                                       compatible = "ti,am335x-usb-ctrl-module";
+                                       reg = <0x620 0x10>,
+                                             <0x648 0x4>;
+                                       reg-names = "phy_ctrl", "wakeup";
+                               };
+
                                wkup_m3_ipc: wkup_m3_ipc@1324 {
                                        compatible = "ti,am3352-wkup-m3-ipc";
                                        reg = <0x1324 0x24>;
 
                target-module@35000 {                   /* 0x44e35000, ap 29 50.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "wd_timer2";
                        reg = <0x35000 0x4>,
                              <0x35010 0x4>,
                              <0x35014 0x4>;
 
                target-module@22000 {                   /* 0x48022000, ap 10 12.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart2";
                        reg = <0x22050 0x4>,
                              <0x22054 0x4>,
                              <0x22058 0x4>;
 
                target-module@24000 {                   /* 0x48024000, ap 12 14.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart3";
                        reg = <0x24050 0x4>,
                              <0x24054 0x4>,
                              <0x24058 0x4>;
 
                target-module@2a000 {                   /* 0x4802a000, ap 14 2a.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c2";
                        reg = <0x2a000 0x8>,
                              <0x2a010 0x8>,
                              <0x2a090 0x8>;
 
                target-module@38000 {                   /* 0x48038000, ap 16 02.0 */
                        compatible = "ti,sysc-omap4-simple", "ti,sysc";
-                       ti,hwmods = "mcasp0";
                        reg = <0x38000 0x4>,
                              <0x38004 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@3c000 {                   /* 0x4803c000, ap 20 32.0 */
                        compatible = "ti,sysc-omap4-simple", "ti,sysc";
-                       ti,hwmods = "mcasp1";
                        reg = <0x3c000 0x4>,
                              <0x3c004 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@4c000 {                   /* 0x4804c000, ap 32 36.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio2";
                        reg = <0x4c000 0x4>,
                              <0x4c010 0x4>,
                              <0x4c114 0x4>;
 
                target-module@60000 {                   /* 0x48060000, ap 36 0c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mmc1";
                        reg = <0x602fc 0x4>,
                              <0x60110 0x4>,
                              <0x60114 0x4>;
 
                target-module@c8000 {                   /* 0x480c8000, ap 87 06.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox";
                        reg = <0xc8000 0x4>,
                              <0xc8010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@9c000 {                   /* 0x4819c000, ap 46 5a.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c3";
                        reg = <0x9c000 0x8>,
                              <0x9c010 0x8>,
                              <0x9c090 0x8>;
 
                target-module@a6000 {                   /* 0x481a6000, ap 48 16.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart4";
                        reg = <0xa6050 0x4>,
                              <0xa6054 0x4>,
                              <0xa6058 0x4>;
 
                target-module@a8000 {                   /* 0x481a8000, ap 50 20.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart5";
                        reg = <0xa8050 0x4>,
                              <0xa8054 0x4>,
                              <0xa8058 0x4>;
 
                target-module@aa000 {                   /* 0x481aa000, ap 52 1a.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart6";
                        reg = <0xaa050 0x4>,
                              <0xaa054 0x4>,
                              <0xaa058 0x4>;
 
                target-module@ac000 {                   /* 0x481ac000, ap 54 38.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio3";
                        reg = <0xac000 0x4>,
                              <0xac010 0x4>,
                              <0xac114 0x4>;
 
                target-module@ae000 {                   /* 0x481ae000, ap 56 3a.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio4";
                        reg = <0xae000 0x4>,
                              <0xae010 0x4>,
                              <0xae114 0x4>;
 
                target-module@d8000 {                   /* 0x481d8000, ap 64 66.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mmc2";
                        reg = <0xd82fc 0x4>,
                              <0xd8110 0x4>,
                              <0xd8114 0x4>;
 
                target-module@10000 {                   /* 0x48310000, ap 76 4e.1 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "rng";
                        reg = <0x11fe0 0x4>,
                              <0x11fe4 0x4>;
                        reg-names = "rev", "sysc";
index fb6b8aa..646f114 100644 (file)
 
                target-module@47810000 {
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mmc3";
                        reg = <0x478102fc 0x4>,
                              <0x47810110 0x4>,
                              <0x47810114 0x4>;
                        };
                };
 
-               usb: usb@47400000 {
-                       compatible = "ti,am33xx-usb";
-                       reg = <0x47400000 0x1000>;
-                       ranges;
+               usb: target-module@47400000 {
+                       compatible = "ti,sysc-omap4", "ti,sysc";
+                       reg = <0x47400000 0x4>,
+                             <0x47400010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-midle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       clocks = <&l3s_clkctrl AM3_L3S_USB_OTG_HS_CLKCTRL 0>;
+                       clock-names = "fck";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ti,hwmods = "usb_otg_hs";
-                       status = "disabled";
-
-                       usb_ctrl_mod: control@44e10620 {
-                               compatible = "ti,am335x-usb-ctrl-module";
-                               reg = <0x44e10620 0x10
-                                       0x44e10648 0x4>;
-                               reg-names = "phy_ctrl", "wakeup";
-                               status = "disabled";
-                       };
+                       ranges = <0x0 0x47400000 0x5000>;
 
-                       usb0_phy: usb-phy@47401300 {
+                       usb0_phy: usb-phy@1300 {
                                compatible = "ti,am335x-usb-phy";
-                               reg = <0x47401300 0x100>;
+                               reg = <0x1300 0x100>;
                                reg-names = "phy";
-                               status = "disabled";
                                ti,ctrl_mod = <&usb_ctrl_mod>;
                                #phy-cells = <0>;
                        };
 
-                       usb0: usb@47401000 {
+                       usb0: usb@1400 {
                                compatible = "ti,musb-am33xx";
-                               status = "disabled";
-                               reg = <0x47401400 0x400
-                                       0x47401000 0x200>;
+                               reg = <0x1400 0x400>,
+                                     <0x1000 0x200>;
                                reg-names = "mc", "control";
 
                                interrupts = <18>;
                                        "tx14", "tx15";
                        };
 
-                       usb1_phy: usb-phy@47401b00 {
+                       usb1_phy: usb-phy@1b00 {
                                compatible = "ti,am335x-usb-phy";
-                               reg = <0x47401b00 0x100>;
+                               reg = <0x1b00 0x100>;
                                reg-names = "phy";
-                               status = "disabled";
                                ti,ctrl_mod = <&usb_ctrl_mod>;
                                #phy-cells = <0>;
                        };
 
-                       usb1: usb@47401800 {
+                       usb1: usb@1800 {
                                compatible = "ti,musb-am33xx";
-                               status = "disabled";
-                               reg = <0x47401c00 0x400
-                                       0x47401800 0x200>;
+                               reg = <0x1c00 0x400>,
+                                     <0x1800 0x200>;
                                reg-names = "mc", "control";
                                interrupts = <19>;
                                interrupt-names = "mc";
                                        "tx14", "tx15";
                        };
 
-                       cppi41dma: dma-controller@47402000 {
+                       cppi41dma: dma-controller@2000 {
                                compatible = "ti,am3359-cppi41";
-                               reg =  <0x47400000 0x1000
-                                       0x47402000 0x1000
-                                       0x47403000 0x1000
-                                       0x47404000 0x4000>;
+                               reg =  <0x0000 0x1000>,
+                                      <0x2000 0x1000>,
+                                      <0x3000 0x1000>,
+                                      <0x4000 0x4000>;
                                reg-names = "glue", "controller", "scheduler", "queuemgr";
                                interrupts = <17>;
                                interrupt-names = "glue";
                                #dma-cells = <2>;
                                #dma-channels = <30>;
                                #dma-requests = <256>;
-                               status = "disabled";
                        };
                };
 
-               ocmcram: ocmcram@40300000 {
+               ocmcram: sram@40300000 {
                        compatible = "mmio-sram";
                        reg = <0x40300000 0x10000>; /* 64k */
                        ranges = <0x0 0x40300000 0x10000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
 
-                       pm_sram_code: pm-sram-code@0 {
+                       pm_sram_code: pm-code-sram@0 {
                                compatible = "ti,sram";
                                reg = <0x0 0x1000>;
                                protect-exec;
                        };
 
-                       pm_sram_data: pm-sram-data@1000 {
+                       pm_sram_data: pm-data-sram@1000 {
                                compatible = "ti,sram";
                                reg = <0x1000 0x1000>;
                                pool;
 
 #include "am33xx-l4.dtsi"
 #include "am33xx-clocks.dtsi"
+
+&prcm {
+       prm_per: prm@c00 {
+               compatible = "ti,am3-prm-inst", "ti,omap-prm-inst";
+               reg = <0xc00 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_wkup: prm@d00 {
+               compatible = "ti,am3-prm-inst", "ti,omap-prm-inst";
+               reg = <0xd00 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_device: prm@f00 {
+               compatible = "ti,am3-prm-inst", "ti,omap-prm-inst";
+               reg = <0xf00 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_gfx: prm@1100 {
+               compatible = "ti,am3-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1100 0x100>;
+               #reset-cells = <1>;
+       };
+};
index 76f819f..125379e 100644 (file)
        };
 };
 
+/* Not currently working, probably needs at least different clocks */
+&rng_target {
+       status = "disabled";
+       /delete-property/ clocks;
+};
+
 /* Table Table 5-79 of the TRM shows 480ab000 is reserved */
 &usb_otg_hs {
        status = "disabled";
index 14bbc43..ca0aa3f 100644 (file)
 
                target-module@47810000 {
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mmc3";
                        reg = <0x478102fc 0x4>,
                              <0x47810110 0x4>,
                              <0x47810114 0x4>;
                        };
                };
 
-               ocmcram: ocmcram@40300000 {
+               ocmcram: sram@40300000 {
                        compatible = "mmio-sram";
                        reg = <0x40300000 0x40000>; /* 256k */
                        ranges = <0x0 0x40300000 0x40000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
 
-                       pm_sram_code: pm-sram-code@0 {
+                       pm_sram_code: pm-code-sram@0 {
                                compatible = "ti,sram";
                                reg = <0x0 0x1000>;
                                protect-exec;
                        };
 
-                       pm_sram_data: pm-sram-data@1000 {
+                       pm_sram_data: pm-data-sram@1000 {
                                compatible = "ti,sram";
                                reg = <0x1000 0x1000>;
                                pool;
 
 #include "am437x-l4.dtsi"
 #include "am43xx-clocks.dtsi"
+
+&prcm {
+       prm_gfx: prm@400 {
+               compatible = "ti,am4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x400 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_per: prm@800 {
+               compatible = "ti,am4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x800 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_wkup: prm@2000 {
+               compatible = "ti,am4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x2000 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_device: prm@4000 {
+               compatible = "ti,am4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x4000 0x100>;
+               #reset-cells = <1>;
+       };
+};
index 59770dd..0dd59ee 100644 (file)
 
                target-module@7000 {                    /* 0x44e07000, ap 14 20.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio1";
                        reg = <0x7000 0x4>,
                              <0x7010 0x4>,
                              <0x7114 0x4>;
 
                target-module@9000 {                    /* 0x44e09000, ap 16 04.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart1";
                        reg = <0x9050 0x4>,
                              <0x9054 0x4>,
                              <0x9058 0x4>;
 
                target-module@b000 {                    /* 0x44e0b000, ap 18 48.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c1";
                        reg = <0xb000 0x8>,
                              <0xb010 0x8>,
                              <0xb090 0x8>;
 
                target-module@35000 {                   /* 0x44e35000, ap 28 50.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "wd_timer2";
                        reg = <0x35000 0x4>,
                              <0x35010 0x4>,
                              <0x35014 0x4>;
 
                target-module@22000 {                   /* 0x48022000, ap 8 0a.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart2";
                        reg = <0x22050 0x4>,
                              <0x22054 0x4>,
                              <0x22058 0x4>;
 
                target-module@24000 {                   /* 0x48024000, ap 10 1c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart3";
                        reg = <0x24050 0x4>,
                              <0x24054 0x4>,
                              <0x24058 0x4>;
 
                target-module@2a000 {                   /* 0x4802a000, ap 12 22.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c2";
                        reg = <0x2a000 0x8>,
                              <0x2a010 0x8>,
                              <0x2a090 0x8>;
 
                target-module@38000 {                   /* 0x48038000, ap 14 04.0 */
                        compatible = "ti,sysc-omap4-simple", "ti,sysc";
-                       ti,hwmods = "mcasp0";
                        reg = <0x38000 0x4>,
                              <0x38004 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@3c000 {                   /* 0x4803c000, ap 16 2a.0 */
                        compatible = "ti,sysc-omap4-simple", "ti,sysc";
-                       ti,hwmods = "mcasp1";
                        reg = <0x3c000 0x4>,
                              <0x3c004 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@4c000 {                   /* 0x4804c000, ap 28 36.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio2";
                        reg = <0x4c000 0x4>,
                              <0x4c010 0x4>,
                              <0x4c114 0x4>;
 
                target-module@60000 {                   /* 0x48060000, ap 30 14.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mmc1";
                        reg = <0x602fc 0x4>,
                              <0x60110 0x4>,
                              <0x60114 0x4>;
 
                target-module@c8000 {                   /* 0x480c8000, ap 73 06.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox";
                        reg = <0xc8000 0x4>,
                              <0xc8010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@9c000 {                   /* 0x4819c000, ap 38 52.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c3";
                        reg = <0x9c000 0x8>,
                              <0x9c010 0x8>,
                              <0x9c090 0x8>;
 
                target-module@a6000 {                   /* 0x481a6000, ap 40 16.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart4";
                        reg = <0xa6050 0x4>,
                              <0xa6054 0x4>,
                              <0xa6058 0x4>;
 
                target-module@a8000 {                   /* 0x481a8000, ap 42 20.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart5";
                        reg = <0xa8050 0x4>,
                              <0xa8054 0x4>,
                              <0xa8058 0x4>;
 
                target-module@aa000 {                   /* 0x481aa000, ap 44 12.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart6";
                        reg = <0xaa050 0x4>,
                              <0xaa054 0x4>,
                              <0xaa058 0x4>;
 
                target-module@ac000 {                   /* 0x481ac000, ap 46 30.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio3";
                        reg = <0xac000 0x4>,
                              <0xac010 0x4>,
                              <0xac114 0x4>;
 
                target-module@ae000 {                   /* 0x481ae000, ap 48 32.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio4";
                        reg = <0xae000 0x4>,
                              <0xae010 0x4>,
                              <0xae114 0x4>;
 
                target-module@d8000 {                   /* 0x481d8000, ap 54 5e.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mmc2";
                        reg = <0xd82fc 0x4>,
                              <0xd8110 0x4>,
                              <0xd8114 0x4>;
 
                target-module@10000 {                   /* 0x48310000, ap 64 4e.1 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "rng";
                        reg = <0x11fe0 0x4>,
                              <0x11fe4 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@20000 {                   /* 0x48320000, ap 82 34.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio5";
                        reg = <0x20000 0x4>,
                              <0x20010 0x4>,
                              <0x20114 0x4>;
 
                target-module@22000 {                   /* 0x48322000, ap 116 64.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio6";
                        reg = <0x22000 0x4>,
                              <0x22010 0x4>,
                              <0x22114 0x4>;
 
                target-module@47000 {                   /* 0x48347000, ap 110 70.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "hdq1w";
                        reg = <0x47000 0x4>,
                              <0x47014 0x4>,
                              <0x47018 0x4>;
index 3f4bb44..e038abc 100644 (file)
                        #size-cells = <1>;
                        ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
 
+                       sdramc: sdramc@1400 {
+                               compatible = "marvell,armada-xp-sdram-controller";
+                               reg = <0x1400 0x500>;
+                       };
+
                        L2: cache-controller@8000 {
                                compatible = "arm,pl310-cache";
                                reg = <0x8000 0x1000>;
index 267d0c1..654648b 100644 (file)
@@ -90,7 +90,7 @@
                };
 
                internal-regs {
-                       sdramc@1400 {
+                       sdramc: sdramc@1400 {
                                compatible = "marvell,armada-xp-sdram-controller";
                                reg = <0x1400 0x500>;
                        };
index df04805..4ec0ae0 100644 (file)
        };
 };
 
+&L2 {
+       arm,parity-enable;
+       marvell,ecc-enable;
+};
+
 &devbus_bootcs {
        status = "okay";
 
index ee15c77..6c19984 100644 (file)
@@ -36,7 +36,7 @@
                };
 
                internal-regs {
-                       sdramc@1400 {
+                       sdramc: sdramc@1400 {
                                compatible = "marvell,armada-xp-sdram-controller";
                                reg = <0x1400 0x500>;
                        };
index c9d88c9..8bec21e 100644 (file)
@@ -40,6 +40,7 @@
                status = "okay";
                m25p,fast-read;
                label = "bmc";
+               spi-max-frequency = <50000000>;
 #include "openbmc-flash-layout.dtsi"
        };
 };
@@ -50,6 +51,7 @@
                status = "okay";
                m25p,fast-read;
                label = "pnor";
+               spi-max-frequency = <100000000>;
        };
 };
 
index 9870553..4afa866 100644 (file)
@@ -55,6 +55,9 @@
 
        phy-mode = "rgmii";
        phy-handle = <&ethphy1>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii2_default>;
 };
 
 &mac2 {
@@ -62,6 +65,9 @@
 
        phy-mode = "rgmii";
        phy-handle = <&ethphy2>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii3_default>;
 };
 
 &mac3 {
 
        phy-mode = "rgmii";
        phy-handle = <&ethphy3>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii4_default>;
 };
 
-&emmc {
+&emmc_controller {
        status = "okay";
 };
 
+&emmc {
+       non-removable;
+       bus-width = <4>;
+       max-frequency = <52000000>;
+};
+
 &rtc {
        status = "okay";
 };
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+               spi-max-frequency = <50000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       u-boot@0 {
+                               reg = <0x0 0xe0000>; // 896KB
+                               label = "u-boot";
+                       };
+
+                       u-boot-env@e0000 {
+                               reg = <0xe0000 0x20000>; // 128KB
+                               label = "u-boot-env";
+                       };
+
+                       kernel@100000 {
+                               reg = <0x100000 0x900000>; // 9MB
+                               label = "kernel";
+                       };
+
+                       rofs@a00000 {
+                               reg = <0xa00000 0x2000000>; // 32MB
+                               label = "rofs";
+                       };
+
+                       rwfs@6000000 {
+                               reg = <0x2a00000 0x1600000>; // 22MB
+                               label = "rwfs";
+                       };
+               };
+       };
+};
+
+&spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "pnor";
+               spi-max-frequency = <100000000>;
+       };
+};
+
+&uart5 {
+       // Workaround for A0
+       compatible = "snps,dw-apb-uart";
+};
+
+&i2c0 {
+       status = "okay";
+
+       temp@2e {
+               compatible = "adi,adt7490";
+               reg = <0x2e>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+};
+
+&i2c5 {
+       status = "okay";
+};
+
+&i2c6 {
+       status = "okay";
+};
+
+&i2c7 {
+       status = "okay";
+};
+
+&i2c8 {
+       status = "okay";
+};
+
+&i2c9 {
+       status = "okay";
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&i2c14 {
+       status = "okay";
+};
+
+&i2c15 {
+       status = "okay";
+};
index 521afbe..2c29ac0 100644 (file)
@@ -92,6 +92,9 @@
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii2_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>,
+                <&syscon ASPEED_CLK_MAC2RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index d519d30..016bbcb 100644 (file)
@@ -2,7 +2,7 @@
 // Copyright (c) 2018 Facebook Inc.
 /dts-v1/;
 
-#include "aspeed-g5.dtsi"
+#include "ast2500-facebook-netbmc-common.dtsi"
 
 / {
        model = "Facebook Backpack CMM BMC";
                bootargs = "console=ttyS1,9600n8 root=/dev/ram rw earlyprintk";
        };
 
-       memory@80000000 {
-               reg = <0x80000000 0x20000000>;
-       };
-
        ast-adc-hwmon {
                compatible = "iio-hwmon";
                io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
        };
 };
 
-&pinctrl {
-       aspeed,external-nodes = <&gfx &lhc>;
-};
-
-/*
- * Update reset type to "system" (full chip) to fix warm reboot hang issue
- * when reset type is set to default ("soc", gated by reset mask registers).
- */
-&wdt1 {
-       status = "okay";
-       aspeed,reset-type = "system";
-};
-
-/*
- * wdt2 is not used by Backpack CMM.
- */
-&wdt2 {
-       status = "disabled";
-};
-
-&fmc {
-       status = "okay";
-       flash@0 {
-               status = "okay";
-               m25p,fast-read;
-               label = "bmc";
-#include "facebook-bmc-flash-layout.dtsi"
-       };
-};
-
 &uart1 {
-       status = "okay";
-       pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_txd1_default
                     &pinctrl_rxd1_default
                     &pinctrl_ncts1_default
 };
 
 &uart3 {
-       status = "okay";
-       pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_txd3_default
                     &pinctrl_rxd3_default
                     &pinctrl_ncts3_default
                     &pinctrl_rxd4_default>;
 };
 
-&uart5 {
-       status = "okay";
-};
-
-&mac1 {
-       status = "okay";
-       no-hw-checksum;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
-};
-
 /*
  * I2C bus reserved for communication with COM-E.
  */
 &ehci1 {
        status = "okay";
 };
+
+&vhub {
+       status = "disabled";
+};
+
+&sdhci0 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sd1_default>;
+};
+
+&sdhci1 {
+       status = "disabled";
+};
index c054782..88ce4ff 100644 (file)
@@ -2,7 +2,7 @@
 // Copyright (c) 2018 Facebook Inc.
 /dts-v1/;
 
-#include "aspeed-g5.dtsi"
+#include "ast2500-facebook-netbmc-common.dtsi"
 
 / {
        model = "Facebook Minipack 100 BMC";
                stdout-path = &uart1;
                bootargs = "debug console=ttyS1,9600n8 root=/dev/ram rw";
        };
-
-       memory@80000000 {
-               reg = <0x80000000 0x20000000>;
-       };
 };
 
-&wdt1 {
+&wdt2 {
        status = "okay";
        aspeed,reset-type = "system";
 };
 
-&wdt2 {
-       status = "okay";
-       aspeed,reset-type = "system";
+/*
+ * Both firmware flashes are 64MB on Minipack BMC.
+ */
+&fmc_flash0 {
+       partitions {
+               data0@1c00000 {
+                       reg = <0x1c00000 0x2400000>;
+               };
+               flash0@0 {
+                       reg = <0x0 0x4000000>;
+               };
+       };
 };
 
-&fmc {
-       status = "okay";
-       flash@0 {
-               status = "okay";
-               m25p,fast-read;
-               label = "bmc";
-#include "facebook-bmc-flash-layout.dtsi"
+&fmc_flash1 {
+       partitions {
+               flash1@0 {
+                       reg = <0x0 0x4000000>;
+               };
        };
 };
 
 &uart1 {
-       status = "okay";
-       pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_txd1_default
                     &pinctrl_rxd1_default
                     &pinctrl_ncts1_default
                     &pinctrl_rxd2_default>;
 };
 
-&uart3 {
-       status = "okay";
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_txd3_default
-                    &pinctrl_rxd3_default>;
-};
-
 &uart4 {
        status = "okay";
        pinctrl-names = "default";
                     &pinctrl_rxd4_default>;
 };
 
-&uart5 {
-       status = "okay";
-};
-
-&mac1 {
-       status = "okay";
-       no-hw-checksum;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
-};
-
 &i2c0 {
        status = "okay";
        bus-frequency = <400000>;
 &i2c13 {
        status = "okay";
 };
-
-&vhub {
-       status = "okay";
-};
index 682f729..5d7cbd9 100644 (file)
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index 4e09a9c..5293359 100644 (file)
@@ -2,7 +2,7 @@
 // Copyright (c) 2018 Facebook Inc.
 /dts-v1/;
 
-#include "aspeed-g5.dtsi"
+#include "ast2500-facebook-netbmc-common.dtsi"
 
 / {
        model = "Facebook YAMP 100 BMC";
                stdout-path = &uart5;
                bootargs = "console=ttyS0,9600n8 root=/dev/ram rw";
        };
-
-       memory@80000000 {
-               reg = <0x80000000 0x20000000>;
-       };
-};
-
-&pinctrl {
-       aspeed,external-nodes = <&gfx &lhc>;
-};
-
-/*
- * Update reset type to "system" (full chip) to fix warm reboot hang issue
- * when reset type is set to default ("soc", gated by reset mask registers).
- */
-&wdt1 {
-       status = "okay";
-       aspeed,reset-type = "system";
-};
-
-/*
- * wdt2 is not used by Yamp.
- */
-&wdt2 {
-       status = "disabled";
-};
-
-&fmc {
-       status = "okay";
-       flash@0 {
-               status = "okay";
-               m25p,fast-read;
-               label = "bmc";
-#include "facebook-bmc-flash-layout.dtsi"
-       };
-};
-
-&uart1 {
-       status = "okay";
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_txd1_default
-                    &pinctrl_rxd1_default>;
 };
 
 &uart2 {
                     &pinctrl_rxd2_default>;
 };
 
-&uart3 {
-       status = "okay";
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_txd3_default
-                    &pinctrl_rxd3_default>;
-};
-
-&uart5 {
-       status = "okay";
-};
-
 &mac0 {
        status = "okay";
        use-ncsi;
        no-hw-checksum;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
+};
+
+&mac1 {
+       status = "disabled";
 };
 
 &i2c0 {
 &i2c13 {
        status = "okay";
 };
-
-&vhub {
-       status = "okay";
-};
diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
new file mode 100644 (file)
index 0000000..c1c9cd3
--- /dev/null
@@ -0,0 +1,972 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2019 IBM Corp.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+       model = "Rainier";
+       compatible = "ibm,rainier-bmc", "aspeed,ast2600";
+
+       aliases {
+               serial4 = &uart5;
+       };
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS4,115200n8";
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x40000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               flash_memory: region@B8000000 {
+                       no-map;
+                       reg = <0xB8000000 0x04000000>; /* 64M */
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               ps0-presence {
+                       label = "ps0-presence";
+                       gpios = <&gpio0 ASPEED_GPIO(S, 0) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(S, 0)>;
+               };
+
+               ps1-presence {
+                       label = "ps1-presence";
+                       gpios = <&gpio0 ASPEED_GPIO(S, 1) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(S, 1)>;
+               };
+
+               ps2-presence {
+                       label = "ps2-presence";
+                       gpios = <&gpio0 ASPEED_GPIO(S, 2) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(S, 2)>;
+               };
+
+               ps3-presence {
+                       label = "ps3-presence";
+                       gpios = <&gpio0 ASPEED_GPIO(S, 3) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(S, 3)>;
+               };
+       };
+
+};
+
+&emmc_controller {
+       status = "okay";
+};
+
+&emmc {
+       status = "okay";
+};
+
+&ibt {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+
+       power-supply@68 {
+               compatible = "ibm,cffps2";
+               reg = <0x68>;
+       };
+
+       power-supply@69 {
+               compatible = "ibm,cffps2";
+               reg = <0x69>;
+       };
+
+       power-supply@6a {
+               compatible = "ibm,cffps2";
+               reg = <0x6a>;
+       };
+
+       power-supply@6b {
+               compatible = "ibm,cffps2";
+               reg = <0x6b>;
+       };
+};
+
+&i2c4 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@49 {
+               compatible = "ti,tmp275";
+               reg = <0x49>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+
+       eeprom@52 {
+               compatible = "atmel,24c64";
+               reg = <0x52>;
+       };
+};
+
+&i2c5 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@49 {
+               compatible = "ti,tmp275";
+               reg = <0x49>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+};
+
+&i2c6 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+
+       tmp275@4b {
+               compatible = "ti,tmp275";
+               reg = <0x4b>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+
+       eeprom@52 {
+               compatible = "atmel,24c64";
+               reg = <0x52>;
+       };
+
+       eeprom@53 {
+               compatible = "atmel,24c64";
+               reg = <0x53>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+
+       si7021-a20@20 {
+               compatible = "silabs,si7020";
+               reg = <0x20>;
+       };
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       max31785@52 {
+               compatible = "maxim,max31785a";
+               reg = <0x52>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               fan@0 {
+                       compatible = "pmbus-fan";
+                       reg = <0>;
+                       tach-pulses = <2>;
+               };
+
+               fan@1 {
+                       compatible = "pmbus-fan";
+                       reg = <1>;
+                       tach-pulses = <2>;
+               };
+
+               fan@2 {
+                       compatible = "pmbus-fan";
+                       reg = <2>;
+                       tach-pulses = <2>;
+               };
+
+               fan@3 {
+                       compatible = "pmbus-fan";
+                       reg = <3>;
+                       tach-pulses = <2>;
+               };
+       };
+
+       pca0: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+               };
+       };
+
+       dps: dps310@76 {
+               compatible = "infineon,dps310";
+               reg = <0x76>;
+               #io-channel-cells = <0>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+};
+
+&i2c8 {
+       status = "okay";
+
+       ucd90320@b {
+               compatible = "ti,ucd90160";
+               reg = <0x0b>;
+       };
+
+       ucd90320@c {
+               compatible = "ti,ucd90160";
+               reg = <0x0c>;
+       };
+
+       ucd90320@11 {
+               compatible = "ti,ucd90160";
+               reg = <0x11>;
+       };
+
+       rtc@32 {
+               compatible = "epson,rx8900";
+               reg = <0x32>;
+       };
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+};
+
+&i2c9 {
+       status = "okay";
+
+       ir35221@42 {
+               compatible = "infineon,ir35221";
+               reg = <0x42>;
+       };
+
+       ir35221@43 {
+               compatible = "infineon,ir35221";
+               reg = <0x43>;
+       };
+
+       ir35221@44 {
+               compatible = "infineon,ir35221";
+               reg = <0x44>;
+       };
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       tmp423b@4d {
+               compatible = "ti,tmp423";
+               reg = <0x4d>;
+       };
+
+       ir35221@72 {
+               compatible = "infineon,ir35221";
+               reg = <0x72>;
+       };
+
+       ir35221@73 {
+               compatible = "infineon,ir35221";
+               reg = <0x73>;
+       };
+
+       ir35221@74 {
+               compatible = "infineon,ir35221";
+               reg = <0x74>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c128";
+               reg = <0x50>;
+       };
+};
+
+&i2c10 {
+       status = "okay";
+
+       ir35221@42 {
+               compatible = "infineon,ir35221";
+               reg = <0x42>;
+       };
+
+       ir35221@43 {
+               compatible = "infineon,ir35221";
+               reg = <0x43>;
+       };
+
+       ir35221@44 {
+               compatible = "infineon,ir35221";
+               reg = <0x44>;
+       };
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       tmp423b@4d {
+               compatible = "ti,tmp423";
+               reg = <0x4d>;
+       };
+
+       ir35221@72 {
+               compatible = "infineon,ir35221";
+               reg = <0x72>;
+       };
+
+       ir35221@73 {
+               compatible = "infineon,ir35221";
+               reg = <0x73>;
+       };
+
+       ir35221@74 {
+               compatible = "infineon,ir35221";
+               reg = <0x74>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c128";
+               reg = <0x50>;
+       };
+};
+
+&i2c11 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@49 {
+               compatible = "ti,tmp275";
+               reg = <0x49>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&i2c14 {
+       status = "okay";
+};
+
+&i2c15 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+
+       power-supply@68 {
+               compatible = "ibm,cffps2";
+               reg = <0x68>;
+       };
+
+       power-supply@69 {
+               compatible = "ibm,cffps2";
+               reg = <0x69>;
+       };
+
+       power-supply@6a {
+               compatible = "ibm,cffps2";
+               reg = <0x6a>;
+       };
+
+       power-supply@6b {
+               compatible = "ibm,cffps2";
+               reg = <0x6b>;
+       };
+};
+
+&i2c4 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@49 {
+               compatible = "ti,tmp275";
+               reg = <0x49>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+};
+
+&i2c5 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@49 {
+               compatible = "ti,tmp275";
+               reg = <0x49>;
+       };
+};
+
+&i2c6 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+
+       tmp275@4b {
+               compatible = "ti,tmp275";
+               reg = <0x4b>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+
+       si7021-a20@20 {
+               compatible = "silabs,si7020";
+               reg = <0x20>;
+       };
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       max31785@52 {
+               compatible = "maxim,max31785a";
+               reg = <0x52>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               fan@0 {
+                       compatible = "pmbus-fan";
+                       reg = <0>;
+                       tach-pulses = <2>;
+               };
+
+               fan@1 {
+                       compatible = "pmbus-fan";
+                       reg = <1>;
+                       tach-pulses = <2>;
+               };
+
+               fan@2 {
+                       compatible = "pmbus-fan";
+                       reg = <2>;
+                       tach-pulses = <2>;
+               };
+
+               fan@3 {
+                       compatible = "pmbus-fan";
+                       reg = <3>;
+                       tach-pulses = <2>;
+               };
+       };
+
+       pca0: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+               };
+       };
+
+       dps: dps310@76 {
+               compatible = "infineon,dps310";
+               reg = <0x76>;
+               #io-channel-cells = <0>;
+       };
+};
+
+&i2c8 {
+       status = "okay";
+
+       ucd90320@b {
+               compatible = "ti,ucd90160";
+               reg = <0x0b>;
+       };
+
+       ucd90320@c {
+               compatible = "ti,ucd90160";
+               reg = <0x0c>;
+       };
+
+       ucd90320@11 {
+               compatible = "ti,ucd90160";
+               reg = <0x11>;
+       };
+
+       rtc@32 {
+               compatible = "epson,rx8900";
+               reg = <0x32>;
+       };
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+};
+
+&i2c9 {
+       status = "okay";
+
+       ir35221@42 {
+               compatible = "infineon,ir35221";
+               reg = <0x42>;
+       };
+
+       ir35221@43 {
+               compatible = "infineon,ir35221";
+               reg = <0x43>;
+       };
+
+       ir35221@44 {
+               compatible = "infineon,ir35221";
+               reg = <0x44>;
+       };
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       tmp423b@4d {
+               compatible = "ti,tmp423";
+               reg = <0x4d>;
+       };
+
+       ir35221@72 {
+               compatible = "infineon,ir35221";
+               reg = <0x72>;
+       };
+
+       ir35221@73 {
+               compatible = "infineon,ir35221";
+               reg = <0x73>;
+       };
+
+       ir35221@74 {
+               compatible = "infineon,ir35221";
+               reg = <0x74>;
+       };
+};
+
+&i2c10 {
+       status = "okay";
+
+       ir35221@42 {
+               compatible = "infineon,ir35221";
+               reg = <0x42>;
+       };
+
+       ir35221@43 {
+               compatible = "infineon,ir35221";
+               reg = <0x43>;
+       };
+
+       ir35221@44 {
+               compatible = "infineon,ir35221";
+               reg = <0x44>;
+       };
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       tmp423b@4d {
+               compatible = "ti,tmp423";
+               reg = <0x4d>;
+       };
+
+       ir35221@72 {
+               compatible = "infineon,ir35221";
+               reg = <0x72>;
+       };
+
+       ir35221@73 {
+               compatible = "infineon,ir35221";
+               reg = <0x73>;
+       };
+
+       ir35221@74 {
+               compatible = "infineon,ir35221";
+               reg = <0x74>;
+       };
+};
+
+&i2c11 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@49 {
+               compatible = "ti,tmp275";
+               reg = <0x49>;
+       };
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&i2c13 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+};
+
+&i2c14 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+};
+
+&i2c15 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+};
+
+&vuart1 {
+       status = "okay";
+};
+
+&lpc_ctrl {
+       status = "okay";
+       memory-region = <&flash_memory>;
+};
+
+&mac2 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii3_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>,
+                <&syscon ASPEED_CLK_MAC3RCLK>;
+       clock-names = "MACCLK", "RCLK";
+       use-ncsi;
+};
+
+&mac3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii4_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC4CLK>,
+                <&syscon ASPEED_CLK_MAC4RCLK>;
+       clock-names = "MACCLK", "RCLK";
+       use-ncsi;
+};
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+               spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout-128.dtsi"
+       };
+
+       flash@1 {
+               status = "okay";
+               m25p,fast-read;
+               label = "alt-bmc";
+               spi-max-frequency = <50000000>;
+       };
+};
+
+&spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "pnor";
+               spi-max-frequency = <100000000>;
+       };
+};
index e9d714a..c17bb7f 100644 (file)
        };
 
        leds {
-           compatible = "gpio-leds";
+               compatible = "gpio-leds";
 
-           power {
-                   label = "power";
-                   /* TODO: dummy gpio */
-                   gpios = <&gpio ASPEED_GPIO(R, 1) GPIO_ACTIVE_LOW>;
-           };
+               power {
+                       label = "power";
+                       /* TODO: dummy gpio */
+                       gpios = <&gpio ASPEED_GPIO(R, 1) GPIO_ACTIVE_LOW>;
+               };
+
+               init-ok {
+                       label = "init-ok";
+                       gpios = <&gpio ASPEED_GPIO(B, 7) GPIO_ACTIVE_LOW>;
+               };
+
+               front-memory {
+                       label = "front-memory";
+                       gpios = <&gpio ASPEED_GPIO(F, 4) GPIO_ACTIVE_LOW>;
+               };
+
+               front-syshot {
+                       label = "front-syshot";
+                       gpios = <&gpio ASPEED_GPIO(I, 1) GPIO_ACTIVE_LOW>;
+               };
+
+               front-syshealth {
+                       label = "front-syshealth";
+                       gpios = <&gpio ASPEED_GPIO(I, 0) GPIO_ACTIVE_LOW>;
+               };
 
+               front-fan {
+                       label = "front-fan";
+                       gpios = <&gpio ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>;
+               };
+
+               front-psu {
+                       label = "front-psu";
+                       gpios = <&gpio ASPEED_GPIO(B, 2) GPIO_ACTIVE_LOW>;
+               };
+
+               identify {
+                       label = "identify";
+                       gpios = <&gpio ASPEED_GPIO(Z, 7) GPIO_ACTIVE_LOW>;
+               };
        };
 
        iio-hwmon-battery {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
        aspeed,external-nodes = <&gfx &lhc>;
 };
 
-&gpio {
-       pin_gpio_b7 {
-               gpio-hog;
-               gpios = <ASPEED_GPIO(B,7) GPIO_ACTIVE_LOW>;
-               output-high;
-               line-name = "BMC_INIT_OK";
-       };
-};
-
 &wdt1 {
        aspeed,reset-type = "none";
        aspeed,external-signal;
index 2337ee2..80c92e0 100644 (file)
@@ -77,6 +77,9 @@
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index 22dade6..1deb30e 100644 (file)
@@ -69,6 +69,9 @@
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index d3695a3..c29e5f4 100644 (file)
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index 118eb8b..084c455 100644 (file)
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index de95112..42b37a2 100644 (file)
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index e55cc45..f7e935e 100644 (file)
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index b0cb34c..eb4e93a 100644 (file)
@@ -87,6 +87,7 @@
                status = "okay";
                m25p,fast-read;
                label = "bmc";
+               spi-max-frequency = <50000000>;
 #include "openbmc-flash-layout.dtsi"
        };
 };
        flash@0 {
                status = "okay";
                m25p,fast-read;
+               spi-max-frequency = <50000000>;
                label = "pnor";
        };
 };
index 9628ecb..edfa44f 100644 (file)
                status = "okay";
                m25p,fast-read;
                label = "bmc";
+               spi-max-frequency = <50000000>;
 #include "openbmc-flash-layout.dtsi"
        };
 };
                status = "okay";
                m25p,fast-read;
                label = "pnor";
+               spi-max-frequency = <100000000>;
        };
 };
 
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
 };
 
 &i2c1 {
index f67fef1..b8fdd2a 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
        use-ncsi;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
 };
 
 &i2c2 {
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts
new file mode 100644 (file)
index 0000000..f02de4a
--- /dev/null
@@ -0,0 +1,1195 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2019 IBM Corp.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+       model = "Tacoma";
+       compatible = "ibm,tacoma-bmc", "aspeed,ast2600";
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS4,115200n8";
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x40000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               flash_memory: region@ba000000 {
+                       no-map;
+                       reg = <0xb8000000 0x4000000>; /* 64M */
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               air-water {
+                       label = "air-water";
+                       gpios = <&gpio0 ASPEED_GPIO(Q, 7) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(Q, 7)>;
+               };
+
+               checkstop {
+                       label = "checkstop";
+                       gpios = <&gpio0 ASPEED_GPIO(E, 3) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(E, 3)>;
+               };
+
+               ps0-presence {
+                       label = "ps0-presence";
+                       gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(H, 3)>;
+               };
+
+               ps1-presence {
+                       label = "ps1-presence";
+                       gpios = <&gpio0 ASPEED_GPIO(E, 5) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(E, 5)>;
+               };
+       };
+
+       gpio-keys-polled {
+               compatible = "gpio-keys-polled";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               poll-interval = <1000>;
+
+               fan0-presence {
+                       label = "fan0-presence";
+                       gpios = <&pca0 4 GPIO_ACTIVE_LOW>;
+                       linux,code = <4>;
+               };
+
+               fan1-presence {
+                       label = "fan1-presence";
+                       gpios = <&pca0 5 GPIO_ACTIVE_LOW>;
+                       linux,code = <5>;
+               };
+
+               fan2-presence {
+                       label = "fan2-presence";
+                       gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
+                       linux,code = <6>;
+               };
+
+               fan3-presence {
+                       label = "fan3-presence";
+                       gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <7>;
+               };
+       };
+};
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+               spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout-128.dtsi"
+       };
+
+       flash@1 {
+               status = "okay";
+               m25p,fast-read;
+               label = "alt-bmc";
+               spi-max-frequency = <50000000>;
+       };
+};
+
+&spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "pnor";
+               spi-max-frequency = <100000000>;
+       };
+};
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+               spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout-128.dtsi"
+       };
+
+       flash@1 {
+               status = "okay";
+               m25p,fast-read;
+               label = "alt-bmc";
+               spi-max-frequency = <50000000>;
+       };
+};
+
+&spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "pnor";
+               spi-max-frequency = <100000000>;
+       };
+};
+
+&mac2 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii3_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>,
+                <&syscon ASPEED_CLK_MAC3RCLK>;
+       clock-names = "MACCLK", "RCLK";
+       use-ncsi;
+};
+
+&emmc {
+       status = "okay";
+       #address-cells = <2>;
+       #size-cells = <0>;
+
+       cfam@0,0 {
+               reg = <0 0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               chip-id = <0>;
+
+               scom@1000 {
+                       compatible = "ibm,fsi2pib";
+                       reg = <0x1000 0x400>;
+               };
+
+               i2c@1800 {
+                       compatible = "ibm,fsi-i2c-master";
+                       reg = <0x1800 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       cfam0_i2c0: i2c-bus@0 {
+                               reg = <0>;
+                       };
+
+                       cfam0_i2c1: i2c-bus@1 {
+                               reg = <1>;
+                       };
+
+                       cfam0_i2c2: i2c-bus@2 {
+                               reg = <2>;
+                       };
+
+                       cfam0_i2c3: i2c-bus@3 {
+                               reg = <3>;
+                       };
+
+                       cfam0_i2c4: i2c-bus@4 {
+                               reg = <4>;
+                       };
+
+                       cfam0_i2c5: i2c-bus@5 {
+                               reg = <5>;
+                       };
+
+                       cfam0_i2c6: i2c-bus@6 {
+                               reg = <6>;
+                       };
+
+                       cfam0_i2c7: i2c-bus@7 {
+                               reg = <7>;
+                       };
+
+                       cfam0_i2c8: i2c-bus@8 {
+                               reg = <8>;
+                       };
+
+                       cfam0_i2c9: i2c-bus@9 {
+                               reg = <9>;
+                       };
+
+                       cfam0_i2c10: i2c-bus@a {
+                               reg = <10>;
+                       };
+
+                       cfam0_i2c11: i2c-bus@b {
+                               reg = <11>;
+                       };
+
+                       cfam0_i2c12: i2c-bus@c {
+                               reg = <12>;
+                       };
+
+                       cfam0_i2c13: i2c-bus@d {
+                               reg = <13>;
+                       };
+
+                       cfam0_i2c14: i2c-bus@e {
+                               reg = <14>;
+                       };
+               };
+
+               sbefifo@2400 {
+                       compatible = "ibm,p9-sbefifo";
+                       reg = <0x2400 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       fsi_occ0: occ {
+                               compatible = "ibm,p9-occ";
+                       };
+               };
+
+               fsi_hub0: hub@3400 {
+                       compatible = "fsi-master-hub";
+                       reg = <0x3400 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+
+                       no-scan-on-init;
+               };
+       };
+};
+
+&fsi_hub0 {
+       cfam@1,0 {
+               reg = <1 0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               chip-id = <1>;
+
+               scom@1000 {
+                       compatible = "ibm,fsi2pib";
+                       reg = <0x1000 0x400>;
+               };
+
+               i2c@1800 {
+                       compatible = "ibm,fsi-i2c-master";
+                       reg = <0x1800 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       cfam1_i2c0: i2c-bus@0 {
+                               reg = <0>;
+                       };
+
+                       cfam1_i2c1: i2c-bus@1 {
+                               reg = <1>;
+                       };
+
+                       cfam1_i2c2: i2c-bus@2 {
+                               reg = <2>;
+                       };
+
+                       cfam1_i2c3: i2c-bus@3 {
+                               reg = <3>;
+                       };
+
+                       cfam1_i2c4: i2c-bus@4 {
+                               reg = <4>;
+                       };
+
+                       cfam1_i2c5: i2c-bus@5 {
+                               reg = <5>;
+                       };
+
+                       cfam1_i2c6: i2c-bus@6 {
+                               reg = <6>;
+                       };
+
+                       cfam1_i2c7: i2c-bus@7 {
+                               reg = <7>;
+                       };
+
+                       cfam1_i2c8: i2c-bus@8 {
+                               reg = <8>;
+                       };
+
+                       cfam1_i2c9: i2c-bus@9 {
+                               reg = <9>;
+                       };
+
+                       cfam1_i2c10: i2c-bus@a {
+                               reg = <10>;
+                       };
+
+                       cfam1_i2c11: i2c-bus@b {
+                               reg = <11>;
+                       };
+
+                       cfam1_i2c12: i2c-bus@c {
+                               reg = <12>;
+                       };
+
+                       cfam1_i2c13: i2c-bus@d {
+                               reg = <13>;
+                       };
+
+                       cfam1_i2c14: i2c-bus@e {
+                               reg = <14>;
+                       };
+               };
+
+               sbefifo@2400 {
+                       compatible = "ibm,p9-sbefifo";
+                       reg = <0x2400 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       fsi_occ1: occ {
+                               compatible = "ibm,p9-occ";
+                       };
+               };
+
+               fsi_hub1: hub@3400 {
+                       compatible = "fsi-master-hub";
+                       reg = <0x3400 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+
+                       no-scan-on-init;
+               };
+       };
+};
+
+/* Legacy OCC numbering (to get rid of when userspace is fixed) */
+&fsi_occ0 {
+       reg = <1>;
+};
+
+&fsi_occ1 {
+       reg = <2>;
+};
+
+/ {
+       aliases {
+               i2c100 = &cfam0_i2c0;
+               i2c101 = &cfam0_i2c1;
+               i2c102 = &cfam0_i2c2;
+               i2c103 = &cfam0_i2c3;
+               i2c104 = &cfam0_i2c4;
+               i2c105 = &cfam0_i2c5;
+               i2c106 = &cfam0_i2c6;
+               i2c107 = &cfam0_i2c7;
+               i2c108 = &cfam0_i2c8;
+               i2c109 = &cfam0_i2c9;
+               i2c110 = &cfam0_i2c10;
+               i2c111 = &cfam0_i2c11;
+               i2c112 = &cfam0_i2c12;
+               i2c113 = &cfam0_i2c13;
+               i2c114 = &cfam0_i2c14;
+               i2c200 = &cfam1_i2c0;
+               i2c201 = &cfam1_i2c1;
+               i2c202 = &cfam1_i2c2;
+               i2c203 = &cfam1_i2c3;
+               i2c204 = &cfam1_i2c4;
+               i2c205 = &cfam1_i2c5;
+               i2c206 = &cfam1_i2c6;
+               i2c207 = &cfam1_i2c7;
+               i2c208 = &cfam1_i2c8;
+               i2c209 = &cfam1_i2c9;
+               i2c210 = &cfam1_i2c10;
+               i2c211 = &cfam1_i2c11;
+               i2c212 = &cfam1_i2c12;
+               i2c213 = &cfam1_i2c13;
+               i2c214 = &cfam1_i2c14;
+       };
+
+};
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+
+       bmp: bmp280@77 {
+               compatible = "bosch,bmp280";
+               reg = <0x77>;
+               #io-channel-cells = <1>;
+       };
+
+       max31785@52 {
+               compatible = "maxim,max31785a";
+               reg = <0x52>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               fan@0 {
+                       compatible = "pmbus-fan";
+                       reg = <0>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@1 {
+                       compatible = "pmbus-fan";
+                       reg = <1>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@2 {
+                       compatible = "pmbus-fan";
+                       reg = <2>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@3 {
+                       compatible = "pmbus-fan";
+                       reg = <3>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+       };
+
+       dps: dps310@76 {
+               compatible = "infineon,dps310";
+               reg = <0x76>;
+               #io-channel-cells = <0>;
+       };
+
+       pca0: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       power-supply@68 {
+               compatible = "ibm,cffps1";
+               reg = <0x68>;
+       };
+
+       power-supply@69 {
+               compatible = "ibm,cffps1";
+               reg = <0x69>;
+       };
+};
+
+&i2c4 {
+       status = "okay";
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       ir35221@70 {
+               compatible = "infineon,ir35221";
+               reg = <0x70>;
+       };
+
+       ir35221@71 {
+               compatible = "infineon,ir35221";
+               reg = <0x71>;
+       };
+};
+
+&i2c5 {
+       status = "okay";
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       ir35221@70 {
+               compatible = "infineon,ir35221";
+               reg = <0x70>;
+       };
+
+       ir35221@71 {
+               compatible = "infineon,ir35221";
+               reg = <0x71>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+};
+
+&i2c9 {
+       status = "okay";
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+};
+
+&i2c10 {
+       status = "okay";
+};
+
+&i2c11 {
+       status = "okay";
+
+       pca9552: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio-line-names = "PS_SMBUS_RESET_N", "APSS_RESET_N",
+                       "GPU0_TH_OVERT_N_BUFF", "GPU1_TH_OVERT_N_BUFF",
+                       "GPU2_TH_OVERT_N_BUFF", "GPU3_TH_OVERT_N_BUFF",
+                       "GPU4_TH_OVERT_N_BUFF", "GPU5_TH_OVERT_N_BUFF",
+                       "GPU0_PWR_GOOD_BUFF", "GPU1_PWR_GOOD_BUFF",
+                       "GPU2_PWR_GOOD_BUFF", "GPU3_PWR_GOOD_BUFF",
+                       "GPU4_PWR_GOOD_BUFF", "GPU5_PWR_GOOD_BUFF",
+                       "12V_BREAKER_FLT_N", "THROTTLE_UNLATCHED_N";
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       rtc@32 {
+               compatible = "epson,rx8900";
+               reg = <0x32>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+
+       ucd90160@64 {
+               compatible = "ti,ucd90160";
+               reg = <0x64>;
+       };
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&ibt {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+       // Workaround for A0
+       compatible = "snps,dw-apb-uart";
+};
+
+&uart5 {
+       // Workaround for A0
+       compatible = "snps,dw-apb-uart";
+};
+
+&vuart1 {
+       status = "okay";
+};
+
+&lpc_ctrl {
+       status = "okay";
+       memory-region = <&flash_memory>;
+       flash = <&spi1>;
+};
+
+&wdt1 {
+       aspeed,reset-type = "none";
+       aspeed,external-signal;
+       aspeed,ext-push-pull;
+       aspeed,ext-active-high;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdtrst1_default>;
+};
+
+&wdt2 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+
+       bmp: bmp280@77 {
+               compatible = "bosch,bmp280";
+               reg = <0x77>;
+               #io-channel-cells = <1>;
+       };
+
+       max31785@52 {
+               compatible = "maxim,max31785a";
+               reg = <0x52>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               fan@0 {
+                       compatible = "pmbus-fan";
+                       reg = <0>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@1 {
+                       compatible = "pmbus-fan";
+                       reg = <1>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@2 {
+                       compatible = "pmbus-fan";
+                       reg = <2>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@3 {
+                       compatible = "pmbus-fan";
+                       reg = <3>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-dual-tach;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+       };
+
+       dps: dps310@76 {
+               compatible = "infineon,dps310";
+               reg = <0x76>;
+               #io-channel-cells = <0>;
+       };
+
+       pca0: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       power-supply@68 {
+               compatible = "ibm,cffps1";
+               reg = <0x68>;
+       };
+
+       power-supply@69 {
+               compatible = "ibm,cffps1";
+               reg = <0x69>;
+       };
+};
+
+&i2c4 {
+       status = "okay";
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       ir35221@70 {
+               compatible = "infineon,ir35221";
+               reg = <0x70>;
+       };
+
+       ir35221@71 {
+               compatible = "infineon,ir35221";
+               reg = <0x71>;
+       };
+};
+
+&i2c5 {
+       status = "okay";
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       ir35221@70 {
+               compatible = "infineon,ir35221";
+               reg = <0x70>;
+       };
+
+       ir35221@71 {
+               compatible = "infineon,ir35221";
+               reg = <0x71>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+};
+
+&i2c9 {
+       status = "okay";
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+};
+
+&i2c10 {
+       status = "okay";
+};
+
+&i2c11 {
+       status = "okay";
+
+       pca9552: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio-line-names = "PS_SMBUS_RESET_N", "APSS_RESET_N",
+                       "GPU0_TH_OVERT_N_BUFF", "GPU1_TH_OVERT_N_BUFF",
+                       "GPU2_TH_OVERT_N_BUFF", "GPU3_TH_OVERT_N_BUFF",
+                       "GPU4_TH_OVERT_N_BUFF", "GPU5_TH_OVERT_N_BUFF",
+                       "GPU0_PWR_GOOD_BUFF", "GPU1_PWR_GOOD_BUFF",
+                       "GPU2_PWR_GOOD_BUFF", "GPU3_PWR_GOOD_BUFF",
+                       "GPU4_PWR_GOOD_BUFF", "GPU5_PWR_GOOD_BUFF",
+                       "12V_BREAKER_FLT_N", "THROTTLE_UNLATCHED_N";
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       rtc@32 {
+               compatible = "epson,rx8900";
+               reg = <0x32>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+
+       ucd90160@64 {
+               compatible = "ti,ucd90160";
+               reg = <0x64>;
+       };
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&pinctrl {
+       /* Hog these as no driver is probed for the entire LPC block */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpc_default>,
+                   <&pinctrl_lsirq_default>;
+};
index a27c88d..affd2c8 100644 (file)
                        gpios = <&gpio ASPEED_GPIO(N, 1) GPIO_ACTIVE_LOW>;
                };
 
+               power_green {
+                       gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
+               };
+
                id_blue {
                        gpios = <&gpio ASPEED_GPIO(O, 0) GPIO_ACTIVE_LOW>;
                };
index 31ea34e..569dad9 100644 (file)
                status = "okay";
                label = "bmc";
                m25p,fast-read;
+               spi-max-frequency = <50000000>;
 
                partitions {
                        #address-cells = < 1 >;
                status = "okay";
                label = "alt-bmc";
                m25p,fast-read;
+               spi-max-frequency = <50000000>;
 
                partitions {
                        #address-cells = < 1 >;
                                label = "alt-obmc-ubi";
                        };
                };
-
        };
 };
 
                status = "okay";
                label = "pnor";
                m25p,fast-read;
+               spi-max-frequency = <100000000>;
        };
 };
 
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index 3062437..bc60ec2 100644 (file)
                status = "okay";
                label = "bmc";
                m25p,fast-read;
+               spi-max-frequency = <50000000>;
 #include "openbmc-flash-layout.dtsi"
        };
 };
                status = "okay";
                label = "pnor";
                m25p,fast-read;
+               spi-max-frequency = <100000000>;
        };
 };
 
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index 33d7045..4a1ca8f 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii1_default
                     &pinctrl_mdio1_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+                <&syscon ASPEED_CLK_MAC1RCLK>;
+       clock-names = "MACCLK", "RCLK";
 };
 
 &mac1 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_rmii2_default>;
+       clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>,
+                <&syscon ASPEED_CLK_MAC2RCLK>;
+       clock-names = "MACCLK", "RCLK";
        use-ncsi;
 };
 
index dffb595..46c0891 100644 (file)
@@ -65,6 +65,7 @@
                        flash@0 {
                                reg = < 0 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                        flash@1 {
                        flash@0 {
                                reg = < 0 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                };
                                #reset-cells = <1>;
 
                                pinctrl: pinctrl {
-                                       compatible = "aspeed,g4-pinctrl";
+                                       compatible = "aspeed,ast2400-pinctrl";
                                };
 
                                p2a: p2a-control {
index e8feb8b..a259c63 100644 (file)
                        flash@0 {
                                reg = < 0 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                        flash@1 {
                                reg = < 1 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                        flash@2 {
                                reg = < 2 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                };
                        flash@0 {
                                reg = < 0 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                        flash@1 {
                                reg = < 1 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                };
                        flash@0 {
                                reg = < 0 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                        flash@1 {
                                reg = < 1 >;
                                compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
                                status = "disabled";
                        };
                };
                                #reset-cells = <1>;
 
                                pinctrl: pinctrl {
-                                       compatible = "aspeed,g5-pinctrl";
+                                       compatible = "aspeed,ast2500-pinctrl";
                                        aspeed,external-nodes = <&gfx &lhc>;
 
                                };
                                #gpio-cells = <2>;
                                gpio-controller;
                                compatible = "aspeed,ast2500-gpio";
-                               reg = <0x1e780000 0x1000>;
+                               reg = <0x1e780000 0x200>;
                                interrupts = <20>;
                                gpio-ranges = <&pinctrl 0 0 232>;
                                clocks = <&syscon ASPEED_CLK_APB>;
                                #interrupt-cells = <2>;
                        };
 
+                       sgpio: sgpio@1e780200 {
+                               #gpio-cells = <2>;
+                               compatible = "aspeed,ast2500-sgpio";
+                               gpio-controller;
+                               interrupts = <40>;
+                               reg = <0x1e780200 0x0100>;
+                               clocks = <&syscon ASPEED_CLK_APB>;
+                               interrupt-controller;
+                               ngpios = <8>;
+                               bus-frequency = <12000000>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_sgpm_default>;
+                               status = "disabled";
+                       };
+
                        rtc: rtc@1e781000 {
                                compatible = "aspeed,ast2500-rtc";
                                reg = <0x1e781000 0x18>;
                                interrupts = <8>;
                                clocks = <&syscon ASPEED_CLK_APB>;
                                no-loopback-test;
+                               aspeed,sirq-polarity-sense = <&syscon 0x70 25>;
                                status = "disabled";
                        };
 
index 5b8bf58..045ce66 100644 (file)
                groups = "SD2";
        };
 
-       pinctrl_sd3_default: sd3_default {
-               function = "SD3";
-               groups = "SD3";
-       };
-
        pinctrl_emmc_default: emmc_default {
-               function = "SD3";
-               groups = "EMMC";
+               function = "EMMC";
+               groups = "EMMCG4";
        };
 
        pinctrl_sgpm1_default: sgpm1_default {
index 3a1422f..5f6142d 100644 (file)
        interrupt-parent = <&gic>;
 
        aliases {
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               i2c4 = &i2c4;
+               i2c5 = &i2c5;
+               i2c6 = &i2c6;
+               i2c7 = &i2c7;
+               i2c8 = &i2c8;
+               i2c9 = &i2c9;
+               i2c10 = &i2c10;
+               i2c11 = &i2c11;
+               i2c12 = &i2c12;
+               i2c13 = &i2c13;
+               i2c14 = &i2c14;
+               i2c15 = &i2c15;
+               serial0 = &uart1;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               serial3 = &uart4;
                serial4 = &uart5;
+               serial5 = &vuart1;
+               serial6 = &vuart2;
        };
 
 
                            <0x40466000 0x2000>;
                        };
 
+               fmc: spi@1e620000 {
+                       reg = < 0x1e620000 0xc4
+                               0x20000000 0x10000000 >;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "aspeed,ast2600-fmc";
+                       clocks = <&syscon ASPEED_CLK_AHB>;
+                       status = "disabled";
+                       interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+                       flash@0 {
+                               reg = < 0 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+                       flash@1 {
+                               reg = < 1 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+                       flash@2 {
+                               reg = < 2 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+               };
+
+               spi1: spi@1e630000 {
+                       reg = < 0x1e630000 0xc4
+                               0x30000000 0x10000000 >;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "aspeed,ast2600-spi";
+                       clocks = <&syscon ASPEED_CLK_AHB>;
+                       status = "disabled";
+                       flash@0 {
+                               reg = < 0 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+                       flash@1 {
+                               reg = < 1 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+               };
+
+               spi2: spi@1e631000 {
+                       reg = < 0x1e631000 0xc4
+                               0x50000000 0x10000000 >;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "aspeed,ast2600-spi";
+                       clocks = <&syscon ASPEED_CLK_AHB>;
+                       status = "disabled";
+                       flash@0 {
+                               reg = < 0 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+                       flash@1 {
+                               reg = < 1 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+                       flash@2 {
+                               reg = < 2 >;
+                               compatible = "jedec,spi-nor";
+                               spi-max-frequency = <50000000>;
+                               status = "disabled";
+                       };
+
+                       fsim0: fsi@1e79b000 {
+                               compatible = "aspeed,ast2600-fsi-master", "fsi-master";
+                               reg = <0x1e79b000 0x94>;
+                               interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_fsi1_default>;
+                               clocks = <&syscon ASPEED_CLK_GATE_FSICLK>;
+                               status = "disabled";
+                       };
+
+                       fsim1: fsi@1e79b100 {
+                               compatible = "aspeed,ast2600-fsi-master", "fsi-master";
+                               reg = <0x1e79b100 0x94>;
+                               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_fsi2_default>;
+                               clocks = <&syscon ASPEED_CLK_GATE_FSICLK>;
+                               status = "disabled";
+                       };
+               };
+
                mdio0: mdio@1e650000 {
                        compatible = "aspeed,ast2600-mdio";
                        reg = <0x1e650000 0x8>;
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_mdio1_default>;
                };
 
                mdio1: mdio@1e650008 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_mdio2_default>;
                };
 
                mdio2: mdio@1e650010 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_mdio3_default>;
                };
 
                mdio3: mdio@1e650018 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_mdio4_default>;
                };
 
                mac0: ftgmac@1e660000 {
                                quality = <100>;
                        };
 
+                       gpio0: gpio@1e780000 {
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               compatible = "aspeed,ast2600-gpio";
+                               reg = <0x1e780000 0x800>;
+                               interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 0 208>;
+                               ngpios = <208>;
+                               clocks = <&syscon ASPEED_CLK_APB2>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio1: gpio@1e780800 {
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               compatible = "aspeed,ast2600-gpio";
+                               reg = <0x1e780800 0x800>;
+                               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 208 36>;
+                               ngpios = <36>;
+                               clocks = <&syscon ASPEED_CLK_APB1>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
                        rtc: rtc@1e781000 {
                                compatible = "aspeed,ast2600-rtc";
                                reg = <0x1e781000 0x18>;
                                status = "disabled";
                        };
 
+                       timer: timer@1e782000 {
+                               compatible = "aspeed,ast2600-timer";
+                               reg = <0x1e782000 0x90>;
+                               interrupts-extended = <&gic  GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+                                               <&gic  GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_APB1>;
+                               clock-names = "PCLK";
+                        };
+
+                       uart1: serial@1e783000 {
+                               compatible = "ns16550a";
+                               reg = <0x1e783000 0x20>;
+                               reg-shift = <2>;
+                               reg-io-width = <4>;
+                               interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>;
+                               resets = <&lpc_reset 4>;
+                               no-loopback-test;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>;
+                               status = "disabled";
+                       };
+
                        uart5: serial@1e784000 {
                                compatible = "ns16550a";
                                reg = <0x1e784000 0x1000>;
                                status = "disabled";
                        };
 
+                       lpc: lpc@1e789000 {
+                               compatible = "aspeed,ast2600-lpc", "simple-mfd";
+                               reg = <0x1e789000 0x1000>;
+
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges = <0x0 0x1e789000 0x1000>;
+
+                               lpc_bmc: lpc-bmc@0 {
+                                       compatible = "aspeed,ast2600-lpc-bmc", "simple-mfd", "syscon";
+                                       reg = <0x0 0x80>;
+                                       reg-io-width = <4>;
+
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       ranges = <0x0 0x0 0x80>;
+
+                                       kcs1: kcs1@0 {
+                                               compatible = "aspeed,ast2600-kcs-bmc";
+                                               interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                                               kcs_chan = <1>;
+                                               status = "disabled";
+                                       };
+                                       kcs2: kcs2@0 {
+                                               compatible = "aspeed,ast2600-kcs-bmc";
+                                               interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+                                               kcs_chan = <2>;
+                                               status = "disabled";
+                                       };
+                                       kcs3: kcs3@0 {
+                                               compatible = "aspeed,ast2600-kcs-bmc";
+                                               interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+                                               kcs_chan = <3>;
+                                               status = "disabled";
+                                       };
+                               };
+
+                               lpc_host: lpc-host@80 {
+                                       compatible = "aspeed,ast2600-lpc-host", "simple-mfd", "syscon";
+                                       reg = <0x80 0x1e0>;
+                                       reg-io-width = <4>;
+
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       ranges = <0x0 0x80 0x1e0>;
+
+                                       kcs4: kcs4@0 {
+                                               compatible = "aspeed,ast2600-kcs-bmc";
+                                               interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+                                               kcs_chan = <4>;
+                                               status = "disabled";
+                                       };
+
+                                       lpc_ctrl: lpc-ctrl@0 {
+                                               compatible = "aspeed,ast2600-lpc-ctrl";
+                                               reg = <0x0 0x80>;
+                                               clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+                                               status = "disabled";
+                                       };
+
+                                       lpc_snoop: lpc-snoop@0 {
+                                               compatible = "aspeed,ast2600-lpc-snoop";
+                                               reg = <0x0 0x80>;
+                                               interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+                                               status = "disabled";
+                                       };
+
+                                       lhc: lhc@20 {
+                                               compatible = "aspeed,ast2600-lhc";
+                                               reg = <0x20 0x24 0x48 0x8>;
+                                       };
+
+                                       lpc_reset: reset-controller@18 {
+                                               compatible = "aspeed,ast2600-lpc-reset";
+                                               reg = <0x18 0x4>;
+                                               #reset-cells = <1>;
+                                       };
+
+                                       ibt: ibt@c0 {
+                                               compatible = "aspeed,ast2600-ibt-bmc";
+                                               reg = <0xc0 0x18>;
+                                               interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                                               status = "disabled";
+                                       };
+                               };
+                       };
+
                        sdc: sdc@1e740000 {
                                compatible = "aspeed,ast2600-sd-controller";
                                reg = <0x1e740000 0x100>;
                                };
                        };
 
-                       emmc: sdc@1e750000 {
+                       emmc_controller: sdc@1e750000 {
                                compatible = "aspeed,ast2600-sd-controller";
                                reg = <0x1e750000 0x100>;
                                #address-cells = <1>;
                                clocks = <&syscon ASPEED_CLK_GATE_EMMCCLK>;
                                status = "disabled";
 
-                               sdhci@1e750100 {
+                               emmc: sdhci@1e750100 {
                                        compatible = "aspeed,ast2600-sdhci";
                                        reg = <0x100 0x100>;
                                        sdhci,auto-cmd12;
                                        pinctrl-0 = <&pinctrl_emmc_default>;
                                };
                        };
+
+                       vuart1: serial@1e787000 {
+                               compatible = "aspeed,ast2500-vuart";
+                               reg = <0x1e787000 0x40>;
+                               reg-shift = <2>;
+                               interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_APB1>;
+                               no-loopback-test;
+                               status = "disabled";
+                       };
+
+                       vuart2: serial@1e788000 {
+                               compatible = "aspeed,ast2500-vuart";
+                               reg = <0x1e788000 0x40>;
+                               reg-shift = <2>;
+                               interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_APB1>;
+                               no-loopback-test;
+                               status = "disabled";
+                       };
+
+                       uart2: serial@1e78d000 {
+                               compatible = "ns16550a";
+                               reg = <0x1e78d000 0x20>;
+                               reg-shift = <2>;
+                               reg-io-width = <4>;
+                               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_GATE_UART2CLK>;
+                               resets = <&lpc_reset 5>;
+                               no-loopback-test;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
+                               status = "disabled";
+                       };
+
+                       uart3: serial@1e78e000 {
+                               compatible = "ns16550a";
+                               reg = <0x1e78e000 0x20>;
+                               reg-shift = <2>;
+                               reg-io-width = <4>;
+                               interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_GATE_UART3CLK>;
+                               resets = <&lpc_reset 6>;
+                               no-loopback-test;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_txd3_default &pinctrl_rxd3_default>;
+                               status = "disabled";
+                       };
+
+                       uart4: serial@1e78f000 {
+                               compatible = "ns16550a";
+                               reg = <0x1e78f000 0x20>;
+                               reg-shift = <2>;
+                               reg-io-width = <4>;
+                               interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_GATE_UART4CLK>;
+                               resets = <&lpc_reset 7>;
+                               no-loopback-test;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_txd4_default &pinctrl_rxd4_default>;
+                               status = "disabled";
+                       };
+
+                       i2c: bus@1e78a000 {
+                               compatible = "simple-bus";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges = <0 0x1e78a000 0x1000>;
+                       };
+
                };
        };
 };
 
 #include "aspeed-g6-pinctrl.dtsi"
+
+&i2c {
+       i2c0: i2c-bus@80 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x80 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c1_default>;
+               status = "disabled";
+       };
+
+       i2c1: i2c-bus@100 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x100 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c2_default>;
+               status = "disabled";
+       };
+
+       i2c2: i2c-bus@180 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x180 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c3_default>;
+               status = "disabled";
+       };
+
+       i2c3: i2c-bus@200 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x200 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c4_default>;
+               status = "disabled";
+       };
+
+       i2c4: i2c-bus@280 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x280 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c5_default>;
+               status = "disabled";
+       };
+
+       i2c5: i2c-bus@300 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x300 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c6_default>;
+               status = "disabled";
+       };
+
+       i2c6: i2c-bus@380 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x380 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c7_default>;
+               status = "disabled";
+       };
+
+       i2c7: i2c-bus@400 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x400 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c8_default>;
+               status = "disabled";
+       };
+
+       i2c8: i2c-bus@480 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x480 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c9_default>;
+               status = "disabled";
+       };
+
+       i2c9: i2c-bus@500 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x500 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c10_default>;
+               status = "disabled";
+       };
+
+       i2c10: i2c-bus@580 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x580 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c11_default>;
+               status = "disabled";
+       };
+
+       i2c11: i2c-bus@600 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x600 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c12_default>;
+               status = "disabled";
+       };
+
+       i2c12: i2c-bus@680 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x680 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c13_default>;
+               status = "disabled";
+       };
+
+       i2c13: i2c-bus@700 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x700 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c14_default>;
+               status = "disabled";
+       };
+
+       i2c14: i2c-bus@780 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x780 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c15_default>;
+               status = "disabled";
+       };
+
+       i2c15: i2c-bus@800 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #interrupt-cells = <1>;
+               reg = <0x800 0x80>;
+               compatible = "aspeed,ast2600-i2c-bus";
+               clocks = <&syscon ASPEED_CLK_APB2>;
+               resets = <&syscon ASPEED_RESET_I2C>;
+               interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+               bus-frequency = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c16_default>;
+               status = "disabled";
+       };
+};
diff --git a/arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi
new file mode 100644 (file)
index 0000000..7a395ba
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2019 Facebook Inc.
+
+#include "aspeed-g5.dtsi"
+
+/ {
+       memory@80000000 {
+               reg = <0x80000000 0x40000000>;
+       };
+};
+
+/*
+ * Update reset type to "system" (full chip) to fix warm reboot hang issue
+ * when reset type is set to default ("soc", gated by reset mask registers).
+ */
+&wdt1 {
+       status = "okay";
+       aspeed,reset-type = "system";
+};
+
+&wdt2 {
+       status = "disabled";
+};
+
+&uart1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd1_default
+                    &pinctrl_rxd1_default>;
+};
+
+&uart3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd3_default
+                    &pinctrl_rxd3_default>;
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&fmc {
+       status = "okay";
+
+       fmc_flash0: flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "spi0.0";
+
+#include "facebook-bmc-flash-layout.dtsi"
+       };
+
+       fmc_flash1: flash@1 {
+               status = "okay";
+               m25p,fast-read;
+               label = "spi0.1";
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       flash1@0 {
+                               reg = <0x0 0x2000000>;
+                               label = "flash1";
+                       };
+               };
+       };
+};
+
+&mac1 {
+       status = "okay";
+       no-hw-checksum;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+};
+
+&rtc {
+       status = "okay";
+};
+
+&vhub {
+       status = "okay";
+};
+
+&sdmmc {
+       status = "okay";
+};
+
+&sdhci1 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sd2_default>;
+};
diff --git a/arch/arm/boot/dts/at91-kizbox2-2.dts b/arch/arm/boot/dts/at91-kizbox2-2.dts
new file mode 100644 (file)
index 0000000..cab8b35
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * at91-kizbox2-2.dts - Device Tree file for the Kizbox2 with
+ * two head board
+ *
+ * Copyright (C) 2015 Overkiz SAS
+ *
+ * Authors: Antoine Aubert <a.aubert@overkiz.com>
+ *         Kévin Raymond <k.raymond@overkiz.com>
+ */
+/dts-v1/;
+#include "at91-kizbox2-common.dtsi"
+
+/ {
+       model = "Overkiz Kizbox 2 with two heads";
+       compatible = "overkiz,kizbox2-2", "atmel,sama5d31",
+                    "atmel,sama5d3", "atmel,sama5";
+};
+
+&usart1 {
+       status = "okay";
+};
+
+&usart2 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/at91-kizbox2-common.dtsi b/arch/arm/boot/dts/at91-kizbox2-common.dtsi
new file mode 100644 (file)
index 0000000..af38253
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * at91-kizbox2_common.dtsi - Device Tree Include file for
+ * Overkiz Kizbox 2 family SoC
+ *
+ * Copyright (C) 2014-2018 Overkiz SAS
+ *
+ * Authors: Antoine Aubert <a.aubert@overkiz.com>
+ *          Gaël Portay <g.portay@overkiz.com>
+ *          Kévin Raymond <k.raymond@overkiz.com>
+ */
+#include "sama5d31.dtsi"
+
+/ {
+       chosen {
+               bootargs = "ubi.mtd=ubi";
+               stdout-path = &dbgu;
+       };
+
+       memory {
+               reg = <0x20000000 0x10000000>;
+       };
+
+       clocks {
+               slow_xtal {
+                       clock-frequency = <32768>;
+               };
+
+               main_xtal {
+                       clock-frequency = <12000000>;
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               prog {
+                       label = "PB_PROG";
+                       gpios = <&pioE 27 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x102>;
+                       wakeup-source;
+               };
+
+               reset {
+                       label = "PB_RST";
+                       gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x100>;
+                       wakeup-source;
+               };
+
+               user {
+                       label = "PB_USER";
+                       gpios = <&pioE 31 GPIO_ACTIVE_HIGH>;
+                       linux,code = <0x101>;
+                       wakeup-source;
+               };
+       };
+
+       pwm_leds {
+               compatible = "pwm-leds";
+
+               blue {
+                       label = "pwm:blue:user";
+                       pwms = <&pwm0 2 10000000 0>;
+                       max-brightness = <255>;
+                       linux,default-trigger = "none";
+               };
+
+               green {
+                       label = "pwm:green:user";
+                       pwms = <&pwm0 1 10000000 0>;
+                       max-brightness = <255>;
+                       linux,default-trigger = "default-on";
+               };
+
+               red {
+                       label = "pwm:red:user";
+                       pwms = <&pwm0 0 10000000 0>;
+                       max-brightness = <255>;
+                       linux,default-trigger = "default-on";
+               };
+       };
+};
+
+&i2c1 {
+       status = "okay";
+
+       pmic: act8865@5b {
+               compatible = "active-semi,act8865";
+               reg = <0x5b>;
+               status = "okay";
+
+               regulators {
+                       vcc_1v8_reg: DCDC_REG1 {
+                               regulator-name = "VCC_1V8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                       };
+
+                       vcc_1v2_reg: DCDC_REG2 {
+                               regulator-name = "VCC_1V2";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-always-on;
+                       };
+
+                       vcc_3v3_reg: DCDC_REG3 {
+                               regulator-name = "VCC_3V3";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vddfuse_reg: LDO_REG1 {
+                               regulator-name = "FUSE_2V5";
+                               regulator-min-microvolt = <2500000>;
+                               regulator-max-microvolt = <2500000>;
+                       };
+
+                       vddana_reg: LDO_REG2 {
+                               regulator-name = "VDDANA";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vled_reg: LDO_REG3 {
+                               regulator-name = "VLED";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       v3v8_rf_reg: LDO_REG4 {
+                               regulator-name = "V3V8_RF";
+                               regulator-min-microvolt = <3800000>;
+                               regulator-max-microvolt = <3800000>;
+                               regulator-always-on;
+                       };
+               };
+       };
+};
+
+&usart0 {
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&usart1 {
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&usart2 {
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&pwm0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm0_pwmh0_1
+                    &pinctrl_pwm0_pwmh1_1
+                    &pinctrl_pwm0_pwmh2_0>;
+       status = "okay";
+};
+
+&adc0 {
+       atmel,adc-vref = <3333>;
+       status = "okay";
+};
+
+&macb1 {
+       phy-mode = "rmii";
+       status = "okay";
+};
+
+&dbgu {
+       status = "okay";
+};
+
+&watchdog {
+       status = "okay";
+};
+
+&ebi {
+       pinctrl-0 = <&pinctrl_ebi_nand_addr>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&nand_controller {
+       status = "okay";
+
+       nand@3 {
+               reg = <0x3 0x0 0x2>;
+               atmel,rb = <0>;
+               nand-bus-width = <8>;
+               nand-ecc-mode = "hw";
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-on-flash-bbt;
+               label = "atmel_nand";
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       bootstrap@0 {
+                               label = "bootstrap";
+                               reg = <0x0 0x20000>;
+                       };
+
+                       ubi@20000 {
+                               label = "ubi";
+                               reg = <0x20000 0x7fe0000>;
+                       };
+               };
+       };
+};
+
+&usb1 {
+       status = "okay";
+};
+
+&usb2 {
+       status = "okay";
+};
+
+/* WMBUS (inverted with IO in the latest schematic) */
+&pinctrl_usart0 {
+       atmel,pins =
+               <AT91_PIOD 17 AT91_PERIPH_A AT91_PINCTRL_NONE
+                AT91_PIOD 18 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
+                AT91_PIOE 2 AT91_PERIPH_GPIO AT91_PINCTRL_MULTI_DRIVE>;
+};
+
+/* RTS */
+&pinctrl_usart1 {
+       atmel,pins =
+               <AT91_PIOB 28 AT91_PERIPH_A AT91_PINCTRL_NONE
+                AT91_PIOB 29 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
+                AT91_PIOE 7 AT91_PERIPH_GPIO AT91_PINCTRL_MULTI_DRIVE>;
+};
+
+/* IO (inverted with WMBUS in the latest schematic) */
+&pinctrl_usart2 {
+       atmel,pins =
+               <AT91_PIOE 25 AT91_PERIPH_B AT91_PINCTRL_NONE
+                AT91_PIOE 26 AT91_PERIPH_B AT91_PINCTRL_PULL_UP
+                AT91_PIOE 8 AT91_PERIPH_GPIO AT91_PINCTRL_MULTI_DRIVE>;
+};
diff --git a/arch/arm/boot/dts/at91-kizbox2.dts b/arch/arm/boot/dts/at91-kizbox2.dts
deleted file mode 100644 (file)
index 86d8218..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * at91-kizbox2.dts - Device Tree file for Overkiz Kizbox 2 board
- *
- * Copyright (C) 2014 Gaël PORTAY <g.portay@overkiz.com>
- */
-/dts-v1/;
-#include "sama5d31.dtsi"
-#include <dt-bindings/pwm/pwm.h>
-
-/ {
-       model = "Overkiz Kizbox 2";
-       compatible = "overkiz,kizbox2", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
-
-       chosen {
-               bootargs = "ubi.mtd=ubi";
-               stdout-path = &dbgu;
-       };
-
-       memory {
-               reg = <0x20000000 0x10000000>;
-       };
-
-       clocks {
-               slow_xtal {
-                       clock-frequency = <32768>;
-               };
-
-               main_xtal {
-                       clock-frequency = <12000000>;
-               };
-       };
-
-       ahb {
-               apb {
-                       i2c1: i2c@f0018000 {
-                               status = "okay";
-
-                               pmic: act8865@5b {
-                                       compatible = "active-semi,act8865";
-                                       reg = <0x5b>;
-                                       status = "okay";
-
-                                       regulators {
-                                               vcc_1v8_reg: DCDC_REG1 {
-                                                       regulator-name = "VCC_1V8";
-                                                       regulator-min-microvolt = <1800000>;
-                                                       regulator-max-microvolt = <1800000>;
-                                                       regulator-always-on;
-                                               };
-
-                                               vcc_1v2_reg: DCDC_REG2 {
-                                                       regulator-name = "VCC_1V2";
-                                                       regulator-min-microvolt = <1200000>;
-                                                       regulator-max-microvolt = <1200000>;
-                                                       regulator-always-on;
-                                               };
-
-                                               vcc_3v3_reg: DCDC_REG3 {
-                                                       regulator-name = "VCC_3V3";
-                                                       regulator-min-microvolt = <3300000>;
-                                                       regulator-max-microvolt = <3300000>;
-                                                       regulator-always-on;
-                                               };
-
-                                               vddfuse_reg: LDO_REG1 {
-                                                       regulator-name = "FUSE_2V5";
-                                                       regulator-min-microvolt = <2500000>;
-                                                       regulator-max-microvolt = <2500000>;
-                                               };
-
-                                               vddana_reg: LDO_REG2 {
-                                                       regulator-name = "VDDANA";
-                                                       regulator-min-microvolt = <3300000>;
-                                                       regulator-max-microvolt = <3300000>;
-                                                       regulator-always-on;
-                                               };
-
-                                               vled_reg: LDO_REG3 {
-                                                       regulator-name = "VLED";
-                                                       regulator-min-microvolt = <3300000>;
-                                                       regulator-max-microvolt = <3300000>;
-                                                       regulator-always-on;
-                                               };
-
-                                               v3v8_rf_reg: LDO_REG4 {
-                                                       regulator-name = "V3V8_RF";
-                                                       regulator-min-microvolt = <3800000>;
-                                                       regulator-max-microvolt = <3800000>;
-                                                       regulator-always-on;
-                                               };
-                                       };
-                               };
-                       };
-
-                       tcb0: timer@f0010000 {
-                               timer@0 {
-                                       compatible = "atmel,tcb-timer";
-                                       reg = <0>;
-                               };
-
-                               timer@1 {
-                                       compatible = "atmel,tcb-timer";
-                                       reg = <1>;
-                               };
-                       };
-
-                       usart0: serial@f001c000 {
-                               status = "okay";
-                       };
-
-                       usart1: serial@f0020000 {
-                               status = "okay";
-                       };
-
-                       pwm0: pwm@f002c000 {
-                               pinctrl-names = "default";
-                               pinctrl-0 = <&pinctrl_pwm0_pwmh0_1
-                                            &pinctrl_pwm0_pwmh1_1
-                                            &pinctrl_pwm0_pwmh2_0>;
-                               status = "okay";
-                       };
-
-                       adc0: adc@f8018000 {
-                               atmel,adc-vref = <3333>;
-                               status = "okay";
-                       };
-
-                       usart2: serial@f8020000 {
-                               status = "okay";
-                       };
-
-                       macb1: ethernet@f802c000 {
-                               phy-mode = "rmii";
-                               status = "okay";
-                       };
-
-                       dbgu: serial@ffffee00 {
-                               status = "okay";
-                       };
-
-                       watchdog@fffffe40 {
-                               status = "okay";
-                       };
-               };
-
-               usb1: ohci@600000 {
-                       status = "okay";
-               };
-
-               usb2: ehci@700000 {
-                       status = "okay";
-               };
-
-               ebi: ebi@10000000 {
-                       pinctrl-0 = <&pinctrl_ebi_nand_addr>;
-                       pinctrl-names = "default";
-                       status = "okay";
-
-                       nand_controller: nand-controller {
-                               status = "okay";
-
-                               nand@3 {
-                                       reg = <0x3 0x0 0x2>;
-                                       atmel,rb = <0>;
-                                       nand-bus-width = <8>;
-                                       nand-ecc-mode = "hw";
-                                       nand-ecc-strength = <4>;
-                                       nand-ecc-step-size = <512>;
-                                       nand-on-flash-bbt;
-                                       label = "atmel_nand";
-
-                                       partitions {
-                                               compatible = "fixed-partitions";
-                                               #address-cells = <1>;
-                                               #size-cells = <1>;
-
-                                               bootstrap@0 {
-                                                       label = "bootstrap";
-                                                       reg = <0x0 0x20000>;
-                                               };
-
-                                               ubi@20000 {
-                                                       label = "ubi";
-                                                       reg = <0x20000 0x7fe0000>;
-                                               };
-                                       };
-                               };
-                       };
-               };
-       };
-
-       gpio_keys {
-               compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               prog {
-                       label = "PB_PROG";
-                       gpios = <&pioE 27 GPIO_ACTIVE_LOW>;
-                       linux,code = <0x102>;
-                       wakeup-source;
-               };
-
-               reset {
-                       label = "PB_RST";
-                       gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
-                       linux,code = <0x100>;
-                       wakeup-source;
-               };
-
-               user {
-                       label = "PB_USER";
-                       gpios = <&pioE 31 GPIO_ACTIVE_HIGH>;
-                       linux,code = <0x101>;
-                       wakeup-source;
-               };
-       };
-
-       pwm_leds {
-               compatible = "pwm-leds";
-
-               blue {
-                       label = "pwm:blue:user";
-                       pwms = <&pwm0 2 10000000 0>;
-                       max-brightness = <255>;
-                       linux,default-trigger = "default-on";
-               };
-
-               green {
-                       label = "pwm:green:user";
-                       pwms = <&pwm0 1 10000000 0>;
-                       max-brightness = <255>;
-                       linux,default-trigger = "default-on";
-               };
-
-               red {
-                       label = "pwm:red:user";
-                       pwms = <&pwm0 0 10000000 0>;
-                       max-brightness = <255>;
-                       linux,default-trigger = "default-on";
-               };
-       };
-};
diff --git a/arch/arm/boot/dts/at91-kizbox3-hs.dts b/arch/arm/boot/dts/at91-kizbox3-hs.dts
new file mode 100644 (file)
index 0000000..8734e7f
--- /dev/null
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * at91-kizbox3-hs.dts - Device Tree file for Overkiz KIZBOX3-HS board
+ *
+ * Copyright (C) 2018 Overkiz SAS
+ *
+ * Authors: Dorian Rocipon <d.rocipon@overkiz.com>
+ *          Kevin Carli <k.carli@overkiz.com>
+ *          Mickael Gardet <m.gardet@overkiz.com>
+ */
+/dts-v1/;
+#include "at91-kizbox3_common.dtsi"
+
+/ {
+       model = "Overkiz KIZBOX3-HS";
+       compatible = "overkiz,kizbox3-hs", "atmel,sama5d2", "atmel,sama5";
+
+       pwm_leds {
+               status = "okay";
+
+               red {
+                       status = "okay";
+               };
+
+               green {
+                       status = "okay";
+               };
+
+               blue {
+                       status = "okay";
+               };
+
+               white {
+                       status = "okay";
+               };
+       };
+
+       leds  {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_led_red
+                            &pinctrl_led_white>;
+               status = "okay";
+
+               red {
+                       label = "pio:red:user";
+                       gpios = <&pioA PIN_PB1 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+
+               white {
+                       label = "pio:white:user";
+                       gpios = <&pioA PIN_PB8 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default" , "default", "default",
+                               "default", "default" ;
+               pinctrl-0 = <&pinctrl_key_gpio_default>;
+               pinctrl-1 = <&pinctrl_pio_rf &pinctrl_pio_wifi>;
+               pinctrl-2 = <&pinctrl_pio_io_boot
+                            &pinctrl_pio_io_reset
+                            &pinctrl_pio_io_test_radio>;
+               pinctrl-3 = <&pinctrl_pio_zbe_test_radio
+                            &pinctrl_pio_zbe_rst>;
+               pinctrl-4 = <&pinctrl_pio_input>;
+
+               SW1 {
+                       label = "SW1";
+                       gpios = <&pioA PIN_PA29 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x101>;
+                       wakeup-source;
+               };
+
+               SW2 {
+                       label = "SW2";
+                       gpios = <&pioA PIN_PA18 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x102>;
+                       wakeup-source;
+               };
+
+               SW3 {
+                       label = "SW3";
+                       gpios = <&pioA PIN_PA22 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x103>;
+                       wakeup-source;
+               };
+
+               SW7 {
+                       label = "SW7";
+                       gpios = <&pioA PIN_PA26 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x107>;
+                       wakeup-source;
+               };
+
+               SW8 {
+                       label = "SW8";
+                       gpios = <&pioA PIN_PA24 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x108>;
+                       wakeup-source;
+               };
+       };
+
+       gpios {
+               compatible = "gpio";
+               status = "okay";
+
+               rf_on {
+                       label = "rf on";
+                       gpio = <&pioA PIN_PC19 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               wifi_on {
+                       label = "wifi on";
+                       gpio = <&pioA PIN_PC20 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               zbe_test_radio {
+                       label = "zbe test radio";
+                       gpio = <&pioA PIN_PB21 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               zbe_rst {
+                       label = "zbe rst";
+                       gpio = <&pioA PIN_PB25 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               io_reset {
+                       label = "io reset";
+                       gpio = <&pioA PIN_PB30 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               io_test_radio {
+                       label = "io test radio";
+                       gpio = <&pioA PIN_PC9 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               io_boot_0 {
+                       label = "io boot 0";
+                       gpio = <&pioA PIN_PC11 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               io_boot_1 {
+                       label = "io boot 1";
+                       gpio = <&pioA PIN_PC17 GPIO_ACTIVE_HIGH>;
+                       output;
+                       init-low;
+               };
+
+               verbose_bootloader {
+                       label = "verbose bootloader";
+                       gpio = <&pioA PIN_PB11 GPIO_ACTIVE_HIGH>;
+                       input;
+               };
+
+                nail_bed_detection  {
+                       label = "nail bed detection";
+                       gpio = <&pioA PIN_PB12 GPIO_ACTIVE_HIGH>;
+                       input;
+               };
+
+                id_usba {
+                       label = "id usba";
+                       gpio = <&pioA PIN_PC0 GPIO_ACTIVE_LOW>;
+                       input;
+               };
+       };
+};
+
+&pioA {
+       pinctrl_key_gpio_default: key_gpio_default {
+               pinmux=  <PIN_PA22__GPIO>,
+               <PIN_PA24__GPIO>,
+               <PIN_PA26__GPIO>,
+               <PIN_PA29__GPIO>,
+               <PIN_PA18__GPIO>;
+               bias-disable;
+               };
+
+       pinctrl_gpio {
+               pinctrl_pio_rf: gpio_rf {
+                       pinmux = <PIN_PC19__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_pio_wifi: gpio_wifi {
+                       pinmux = <PIN_PC20__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_pio_io_boot: gpio_io_boot {
+                       pinmux =
+                       <PIN_PC11__GPIO>,
+                       <PIN_PC17__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_pio_io_test_radio: gpio_io_test_radio {
+                       pinmux = <PIN_PC9__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_pio_zbe_test_radio: gpio_zbe_test_radio {
+                       pinmux = <PIN_PB21__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_pio_zbe_rst: gpio_zbe_rst {
+                       pinmux = <PIN_PB25__GPIO>;
+                       bias-disable;
+               };
+               /* stm32 reset must be open drain (internal pull up) */
+               pinctrl_pio_io_reset: gpio_io_reset {
+                       pinmux = <PIN_PB30__GPIO>;
+                       bias-disable;
+                       drive-open-drain = <1>;
+                       output-low;
+               };
+               pinctrl_pio_input: gpio_input {
+                       pinmux =
+                       <PIN_PB11__GPIO>,
+                       <PIN_PB12__GPIO>,
+                       <PIN_PC0__GPIO>;
+                       bias-disable;
+               };
+       };
+
+       pinctrl_leds {
+               pinctrl_led_red: led_red {
+                       pinmux = <PIN_PB1__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_led_white: led_white {
+                       pinmux = <PIN_PB8__GPIO>;
+                       bias-disable;
+               };
+       };
+};
+
+&adc {
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&uart3 {
+       status = "okay";
+};
+
+&uart4 {
+       status = "okay";
+};
+
+&flx0 {
+       status = "okay";
+
+       uart5: serial@200  {
+                       status = "okay";
+       };
+};
+
+&flx3 {
+       status = "okay";
+       uart6: serial@200 {
+               status = "okay";
+       };
+};
+
+&flx4 {
+       status = "okay";
+
+       i2c2: i2c@600 {
+               status = "okay";
+       };
+};
+
+&usb0 {
+       status = "okay";
+};
+
+&usb1 {
+       status = "okay";
+};
+
+&usb2 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/at91-kizbox3_common.dtsi b/arch/arm/boot/dts/at91-kizbox3_common.dtsi
new file mode 100644 (file)
index 0000000..299e74d
--- /dev/null
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * at91-kizbox3.dts - Device Tree Include file for Overkiz Kizbox 3
+ * family SoC boards
+ *
+ * Copyright (C) 2018 Overkiz SAS
+ *
+ * Authors: Dorian Rocipon <d.rocipon@overkiz.com>
+ *          Kevin Carli <k.carli@overkiz.com>
+ *          Mickael Gardet <m.gardet@overkiz.com>
+ */
+/dts-v1/;
+#include "sama5d2.dtsi"
+#include "sama5d2-pinfunc.h"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+#include <dt-bindings/pinctrl/at91.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+       model = "Overkiz Kizbox3";
+       compatible = "overkiz,kizbox3", "atmel,sama5d2", "atmel,sama5";
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+               serial2 = &uart2;
+               serial3 = &uart3;
+               serial4 = &uart4;
+               serial5 = &uart5;
+               serial6 = &uart6;
+       };
+
+       chosen {
+               bootargs = "ubi.mtd=ubi";
+               stdout-path = "serial1:115200n8";
+       };
+
+       clocks {
+               slow_xtal {
+                       clock-frequency = <32768>;
+               };
+
+               main_xtal {
+                       clock-frequency = <12000000>;
+               };
+       };
+
+       vdd_adc_vddana: supply_3v3_ana {
+               compatible = "regulator-fixed";
+               regulator-name = "adc-vddana";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       vdd_adc_vref: supply_3v3_ref {
+               compatible = "regulator-fixed";
+               regulator-name = "adc-vref";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       pwm_leds {
+               compatible = "pwm-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pwm0_pwm_h0
+                            &pinctrl_pwm0_pwm_h1
+                            &pinctrl_pwm0_pwm_h2
+                            &pinctrl_pwm0_pwm_h3>;
+               status = "disabled";
+
+               red {
+                       label = "pwm:red:user";
+                       pwms = <&pwm0 0 10000000 0>;
+                       max-brightness = <255>;
+                       linux,default-trigger = "default-on";
+                       status = "disabled";
+               };
+
+               green {
+                       label = "pwm:green:user";
+                       pwms = <&pwm0 1 10000000 0>;
+                       max-brightness = <255>;
+                       linux,default-trigger = "default-on";
+                       status = "disabled";
+               };
+
+               blue {
+                       label = "pwm:blue:user";
+                       pwms = <&pwm0 2 10000000 0>;
+                       max-brightness = <255>;
+                       status = "disabled";
+               };
+
+               white {
+                       label = "pwm:white:user";
+                       pwms = <&pwm0 3 10000000 0>;
+                       max-brightness = <255>;
+                       status = "disabled";
+               };
+       };
+};
+
+&ebi {
+       status = "okay";
+};
+
+&nand_controller {
+       status = "okay";
+
+       nand@3 {
+               pinctrl-0 = <&pinctrl_ebi_nand_addr>;
+               pinctrl-names = "default";
+               reg = <0x3 0x0 0x800000>;
+
+               atmel,rb = <0>;
+               nand-bus-width = <8>;
+               nand-ecc-mode = "hw";
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-on-flash-bbt;
+               label = "atmel_nand";
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       bootstrap@0 {
+                               label = "bootstrap";
+                               reg = <0x0 0x20000>;
+                       };
+
+                       u-boot@20000 {
+                               label = "u-boot";
+                               reg = <0x20000 0x140000>;
+                       };
+
+                       u-boot-factory@160000 {
+                               label = "u-boot-factory";
+                               reg = <0x160000 0x140000>;
+                       };
+
+                       ubi@2A0000 {
+                               label = "ubi";
+                               reg = <0x2A0000 0x7D60000>;
+                       };
+               };
+
+       };
+};
+
+&rtc {
+       status = "okay";
+};
+
+&pioA {
+       pinctrl_ebi_nand_addr: ebi-addr-1 {
+               pinmux = <PIN_PA0__D0>,
+                       <PIN_PA1__D1>,
+                       <PIN_PA2__D2>,
+                       <PIN_PA3__D3>,
+                       <PIN_PA4__D4>,
+                       <PIN_PA5__D5>,
+                       <PIN_PA6__D6>,
+                       <PIN_PA7__D7>,
+                       <PIN_PA8__NWE_NANDWE>,
+                       <PIN_PA9__NCS3>,
+                       <PIN_PA10__A21_NANDALE>,
+                       <PIN_PA11__A22_NANDCLE>,
+                       <PIN_PA21__NANDRDY>;
+               bias-disable;
+       };
+
+       pinctrl_usart {
+               pinctrl_usart_0: usart0-0 {
+                       pinmux = < PIN_PB26__URXD0>, <PIN_PB27__UTXD0>;
+                       bias-disable;
+               };
+               pinctrl_usart_1: usart1-0 {
+                       pinmux = < PIN_PD2__URXD1>, <PIN_PD3__UTXD1>;
+                       bias-disable;
+               };
+               pinctrl_usart_2: usart2-0 {
+                       pinmux = < PIN_PD4__URXD2>, <PIN_PD5__UTXD2>;
+                       bias-disable;
+               };
+               pinctrl_usart_3: usart3-0 {
+                       pinmux = < PIN_PC12__URXD3>, <PIN_PC13__UTXD3>;
+                       bias-disable;
+               };
+               pinctrl_usart_4: usart4-0 {
+                       pinmux = < PIN_PB3__URXD4>, <PIN_PB4__UTXD4>;
+                       bias-disable;
+               };
+               pinctrl_flx0_default: flx0_usart_default {
+                       pinmux = <PIN_PB28__FLEXCOM0_IO0>, //TX
+                       <PIN_PB29__FLEXCOM0_IO1>; //RX
+                       bias-disable;
+               };
+               pinctrl_flx3_default: flx3_usart_default {
+                       pinmux = <PIN_PB22__FLEXCOM3_IO1>, //RX
+                       <PIN_PB23__FLEXCOM3_IO0>; //TX
+                       bias-disable;
+               };
+       };
+
+       pinctrl_flx4_default: flx4_i2c2_default {
+               pinmux = <PIN_PD12__FLEXCOM4_IO0>, //DATA
+               <PIN_PD13__FLEXCOM4_IO1>; //CLK
+               bias-disable;
+               drive-open-drain = <1>;
+       };
+
+       pinctrl_pwm0 {
+               pinctrl_pwm0_pwm_h0: pwm0_pwm_h0 {
+                       pinmux = <PIN_PA30__PWMH0>;
+                       bias-disable;
+               };
+               pinctrl_pwm0_pwm_h1: pwm0_pwmh1 {
+                       pinmux = <PIN_PB0__PWMH1>;
+                       bias-disable;
+               };
+               pinctrl_pwm0_pwm_h2: pwm0_pwm_h2 {
+                       pinmux = <PIN_PB5__PWMH2>;
+                       bias-disable;
+               };
+               pinctrl_pwm0_pwm_h3: pwm0_pwm_h3 {
+                       pinmux = <PIN_PB7__PWMH3>;
+                       bias-disable;
+               };
+       };
+
+       pinctrl_adc {
+               pinctrl_adc2: adc2 {
+                       pinmux = <PIN_PD21__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_adc3: adc3 {
+                       pinmux = <PIN_PD22__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_adc4: adc4 {
+                       pinmux = <PIN_PD23__GPIO>;
+                       bias-disable;
+               };
+               pinctrl_adc5: adc5 {
+                       pinmux = <PIN_PD24__GPIO>;
+                       bias-disable;
+               };
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart_0>;
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+/* debug uart */
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart_1>;
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart_2>;
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart_3>;
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart_4>;
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
+       status = "disabled";
+};
+
+&flx0 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+       status = "disabled";
+
+       uart5: serial@200  {
+               compatible = "atmel,at91sam9260-usart";
+               reg = <0x200 0x400>;
+               interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>;
+               dmas = <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(11))>,
+                      <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(12))>;
+               dma-names = "tx", "rx";
+               clocks = <&pmc PMC_TYPE_PERIPHERAL 19>;
+               clock-names = "usart";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flx0_default>;
+               atmel,fifo-size = <32>;
+               atmel,use-dma-rx;
+               atmel,use-dma-tx;
+               status = "disabled";
+       };
+};
+
+&flx3 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+       status = "disabled";
+
+       uart6: serial@200 {
+               compatible = "atmel,at91sam9260-usart";
+               reg = <0x200 0x400>;
+               interrupts = <22 IRQ_TYPE_LEVEL_HIGH 7>;
+               dmas = <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(17))>,
+                      <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(18))>;
+               dma-names = "tx", "rx";
+               clocks = <&pmc PMC_TYPE_PERIPHERAL 22>;
+               clock-names = "usart";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flx3_default>;
+               atmel,fifo-size = <32>;
+               atmel,use-dma-rx;
+               atmel,use-dma-tx;
+               status = "disabled";
+       };
+};
+
+&flx4 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+       status = "disabled";
+
+       i2c2: i2c@600 {
+               compatible = "atmel,sama5d2-i2c";
+               reg = <0x600 0x200>;
+               interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>;
+               dmas = <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(19))>,
+                      <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(20))>;
+               dma-names = "tx", "rx";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&pmc PMC_TYPE_PERIPHERAL 23>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flx4_default>;
+               atmel,fifo-size = <16>;
+               status = "disabled";
+       };
+};
+
+&pwm0 {
+       status = "okay";
+};
+
+&shutdown_controller {
+       atmel,shdwc-debouncer = <976>;
+       atmel,wakeup-rtc-timer;
+
+       input@0 {
+               reg = <0>;
+               atmel,wakeup-type = "low";
+       };
+};
+
+&watchdog {
+       status = "okay";
+};
+
+&adc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_adc2
+                    &pinctrl_adc3
+                    &pinctrl_adc4
+                    &pinctrl_adc5>;
+
+       vddana-supply = <&vdd_adc_vddana>;
+       vref-supply = <&vdd_adc_vref>;
+       status = "disabled";
+};
+
+&securam {
+       export;
+
+       /* export overkiz u-boot mode/version and factory */
+       uboot@1400 {
+               reg = <0x1400 0x20>;
+               export;
+       };
+};
index 89f0c99..fca5716 100644 (file)
@@ -53,6 +53,7 @@
 
                sdmmc0: sdio-host@a0000000 {
                        bus-width = <8>;
+                       mmc-ddr-3_3v;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_sdmmc0_default>;
                        status = "okay";
index 808e399..9d0a7fb 100644 (file)
                                        pinctrl-names = "default";
                                        pinctrl-0 = <&pinctrl_flx4_default>;
                                        atmel,fifo-size = <16>;
+                                       i2c-analog-filter;
+                                       i2c-digital-filter;
+                                       i2c-digital-filter-width-ns = <35>;
                                        status = "okay";
                                };
                        };
                                dmas = <0>, <0>;
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_i2c1_default>;
+                               i2c-analog-filter;
+                               i2c-digital-filter;
+                               i2c-digital-filter-width-ns = <35>;
                                status = "okay";
 
                                at24@54 {
index fdfc37d..924d949 100644 (file)
@@ -49,6 +49,7 @@
                        };
 
                        i2c0: i2c@f8014000 {
+                               i2c-digital-filter;
                                status = "okay";
                        };
 
index e0c0291..e051504 100644 (file)
                                label = "rearview key";
                                linux,code = <KEY_CAMERA>;
                                gpios = <&gpio_1 3 GPIO_ACTIVE_LOW>;
-                               debounce_interval = <100>;
+                               debounce-interval = <100>;
                        };
                };
 
index e4d4973..6142c67 100644 (file)
                        clock-frequency = <100000>;
                };
 
-               watchdog@39000 {
+               watchdog: watchdog@39000 {
                        compatible = "arm,sp805", "arm,primecell";
                        reg = <0x39000 0x1000>;
                        interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
new file mode 100644 (file)
index 0000000..cccc1cc
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+#include "bcm2711.dtsi"
+#include "bcm2835-rpi.dtsi"
+#include "bcm283x-rpi-usb-peripheral.dtsi"
+
+/ {
+       compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+       model = "Raspberry Pi 4 Model B";
+
+       chosen {
+               /* 8250 auxiliary UART instead of pl011 */
+               stdout-path = "serial1:115200n8";
+       };
+
+       /* Will be filled by the bootloader */
+       memory@0 {
+               device_type = "memory";
+               reg = <0 0 0>;
+       };
+
+       leds {
+               act {
+                       gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+               };
+
+               pwr {
+                       label = "PWR";
+                       gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       wifi_pwrseq: wifi-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+       };
+
+       sd_io_1v8_reg: sd_io_1v8_reg {
+               compatible = "regulator-gpio";
+               regulator-name = "vdd-sd-io";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+               regulator-settling-time-us = <5000>;
+               gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
+               states = <1800000 0x1
+                         3300000 0x0>;
+               status = "okay";
+       };
+};
+
+&firmware {
+       expgpio: gpio {
+               compatible = "raspberrypi,firmware-gpio";
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "BT_ON",
+                                 "WL_ON",
+                                 "PWR_LED_OFF",
+                                 "GLOBAL_RESET",
+                                 "VDD_SD_IO_SEL",
+                                 "CAM_GPIO",
+                                 "",
+                                 "";
+               status = "okay";
+       };
+};
+
+&pwm1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
+       status = "okay";
+};
+
+/* SDHCI is used to control the SDIO for wireless */
+&sdhci {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&emmc_gpio34>;
+       bus-width = <4>;
+       non-removable;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+       };
+};
+
+/* EMMC2 is used to drive the SD card */
+&emmc2 {
+       vqmmc-supply = <&sd_io_1v8_reg>;
+       broken-cd;
+       status = "okay";
+};
+
+/* uart0 communicates with the BT module */
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               max-speed = <2000000>;
+               shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+/* uart1 is mapped to the pin header */
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_gpio14>;
+       status = "okay";
+};
+
+&vchiq {
+       interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+};
diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi
new file mode 100644 (file)
index 0000000..ac83dac
--- /dev/null
@@ -0,0 +1,844 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "bcm283x.dtsi"
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/bcm2835-pm.h>
+
+/ {
+       compatible = "brcm,bcm2711";
+
+       #address-cells = <2>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gicv2>;
+
+       soc {
+               /*
+                * Defined ranges:
+                *   Common BCM283x peripherals
+                *   BCM2711-specific peripherals
+                *   ARM-local peripherals
+                */
+               ranges = <0x7e000000  0x0 0xfe000000  0x01800000>,
+                        <0x7c000000  0x0 0xfc000000  0x02000000>,
+                        <0x40000000  0x0 0xff800000  0x00800000>;
+               /* Emulate a contiguous 30-bit address range for DMA */
+               dma-ranges = <0xc0000000  0x0 0x00000000  0x3c000000>;
+
+               /*
+                * This node is the provider for the enable-method for
+                * bringing up secondary cores.
+                */
+               local_intc: local_intc@40000000 {
+                       compatible = "brcm,bcm2836-l1-intc";
+                       reg = <0x40000000 0x100>;
+               };
+
+               gicv2: interrupt-controller@40041000 {
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       compatible = "arm,gic-400";
+                       reg =   <0x40041000 0x1000>,
+                               <0x40042000 0x2000>,
+                               <0x40044000 0x2000>,
+                               <0x40046000 0x2000>;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
+                                                IRQ_TYPE_LEVEL_HIGH)>;
+               };
+
+               dma: dma@7e007000 {
+                       compatible = "brcm,bcm2835-dma";
+                       reg = <0x7e007000 0xb00>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+                                    /* DMA lite 7 - 10 */
+                                    <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "dma0",
+                                         "dma1",
+                                         "dma2",
+                                         "dma3",
+                                         "dma4",
+                                         "dma5",
+                                         "dma6",
+                                         "dma7",
+                                         "dma8",
+                                         "dma9",
+                                         "dma10";
+                       #dma-cells = <1>;
+                       brcm,dma-channel-mask = <0x07f5>;
+               };
+
+               pm: watchdog@7e100000 {
+                       compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+                       #power-domain-cells = <1>;
+                       #reset-cells = <1>;
+                       reg = <0x7e100000 0x114>,
+                             <0x7e00a000 0x24>,
+                             <0x7ec11000 0x20>;
+                       clocks = <&clocks BCM2835_CLOCK_V3D>,
+                                <&clocks BCM2835_CLOCK_PERI_IMAGE>,
+                                <&clocks BCM2835_CLOCK_H264>,
+                                <&clocks BCM2835_CLOCK_ISP>;
+                       clock-names = "v3d", "peri_image", "h264", "isp";
+                       system-power-controller;
+               };
+
+               rng@7e104000 {
+                       interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+
+                       /* RNG is incompatible with brcm,bcm2835-rng */
+                       status = "disabled";
+               };
+
+               uart2: serial@7e201400 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x7e201400 0x200>;
+                       interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_UART>,
+                                <&clocks BCM2835_CLOCK_VPU>;
+                       clock-names = "uartclk", "apb_pclk";
+                       arm,primecell-periphid = <0x00241011>;
+                       status = "disabled";
+               };
+
+               uart3: serial@7e201600 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x7e201600 0x200>;
+                       interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_UART>,
+                                <&clocks BCM2835_CLOCK_VPU>;
+                       clock-names = "uartclk", "apb_pclk";
+                       arm,primecell-periphid = <0x00241011>;
+                       status = "disabled";
+               };
+
+               uart4: serial@7e201800 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x7e201800 0x200>;
+                       interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_UART>,
+                                <&clocks BCM2835_CLOCK_VPU>;
+                       clock-names = "uartclk", "apb_pclk";
+                       arm,primecell-periphid = <0x00241011>;
+                       status = "disabled";
+               };
+
+               uart5: serial@7e201a00 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x7e201a00 0x200>;
+                       interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_UART>,
+                                <&clocks BCM2835_CLOCK_VPU>;
+                       clock-names = "uartclk", "apb_pclk";
+                       arm,primecell-periphid = <0x00241011>;
+                       status = "disabled";
+               };
+
+               spi3: spi@7e204600 {
+                       compatible = "brcm,bcm2835-spi";
+                       reg = <0x7e204600 0x0200>;
+                       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               spi4: spi@7e204800 {
+                       compatible = "brcm,bcm2835-spi";
+                       reg = <0x7e204800 0x0200>;
+                       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               spi5: spi@7e204a00 {
+                       compatible = "brcm,bcm2835-spi";
+                       reg = <0x7e204a00 0x0200>;
+                       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               spi6: spi@7e204c00 {
+                       compatible = "brcm,bcm2835-spi";
+                       reg = <0x7e204c00 0x0200>;
+                       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c3: i2c@7e205600 {
+                       compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+                       reg = <0x7e205600 0x200>;
+                       interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c4: i2c@7e205800 {
+                       compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+                       reg = <0x7e205800 0x200>;
+                       interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c5: i2c@7e205a00 {
+                       compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+                       reg = <0x7e205a00 0x200>;
+                       interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c6: i2c@7e205c00 {
+                       compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+                       reg = <0x7e205c00 0x200>;
+                       interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               pwm1: pwm@7e20c800 {
+                       compatible = "brcm,bcm2835-pwm";
+                       reg = <0x7e20c800 0x28>;
+                       clocks = <&clocks BCM2835_CLOCK_PWM>;
+                       assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
+                       assigned-clock-rates = <10000000>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               emmc2: emmc2@7e340000 {
+                       compatible = "brcm,bcm2711-emmc2";
+                       reg = <0x7e340000 0x100>;
+                       interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clocks BCM2711_CLOCK_EMMC2>;
+                       status = "disabled";
+               };
+
+               hvs@7e400000 {
+                       interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+               };
+       };
+
+       arm-pmu {
+               compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>;
+               /* This only applies to the ARMv7 stub */
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       cpus: cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       reg = <0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x000000d8>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       reg = <1>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x000000e0>;
+               };
+
+               cpu2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       reg = <2>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x000000e8>;
+               };
+
+               cpu3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       reg = <3>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x000000f0>;
+               };
+       };
+};
+
+&clk_osc {
+       clock-frequency = <54000000>;
+};
+
+&clocks {
+       compatible = "brcm,bcm2711-cprman";
+};
+
+&cpu_thermal {
+       coefficients = <(-487) 410040>;
+};
+
+&dsi0 {
+       interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&dsi1 {
+       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&gpio {
+       compatible = "brcm,bcm2711-gpio";
+       interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+
+       gpclk0_gpio49: gpclk0_gpio49 {
+               pin-gpclk {
+                       pins = "gpio49";
+                       function = "alt1";
+                       bias-disable;
+               };
+       };
+       gpclk1_gpio50: gpclk1_gpio50 {
+               pin-gpclk {
+                       pins = "gpio50";
+                       function = "alt1";
+                       bias-disable;
+               };
+       };
+       gpclk2_gpio51: gpclk2_gpio51 {
+               pin-gpclk {
+                       pins = "gpio51";
+                       function = "alt1";
+                       bias-disable;
+               };
+       };
+
+       i2c0_gpio46: i2c0_gpio46 {
+               pin-sda {
+                       function = "alt0";
+                       pins = "gpio46";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt0";
+                       pins = "gpio47";
+                       bias-disable;
+               };
+       };
+       i2c1_gpio46: i2c1_gpio46 {
+               pin-sda {
+                       function = "alt1";
+                       pins = "gpio46";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt1";
+                       pins = "gpio47";
+                       bias-disable;
+               };
+       };
+       i2c3_gpio2: i2c3_gpio2 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio2";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio3";
+                       bias-disable;
+               };
+       };
+       i2c3_gpio4: i2c3_gpio4 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio4";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio5";
+                       bias-disable;
+               };
+       };
+       i2c4_gpio6: i2c4_gpio6 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio6";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio7";
+                       bias-disable;
+               };
+       };
+       i2c4_gpio8: i2c4_gpio8 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio8";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio9";
+                       bias-disable;
+               };
+       };
+       i2c5_gpio10: i2c5_gpio10 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio10";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio11";
+                       bias-disable;
+               };
+       };
+       i2c5_gpio12: i2c5_gpio12 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio12";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio13";
+                       bias-disable;
+               };
+       };
+       i2c6_gpio0: i2c6_gpio0 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio0";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio1";
+                       bias-disable;
+               };
+       };
+       i2c6_gpio22: i2c6_gpio22 {
+               pin-sda {
+                       function = "alt5";
+                       pins = "gpio22";
+                       bias-pull-up;
+               };
+               pin-scl {
+                       function = "alt5";
+                       pins = "gpio23";
+                       bias-disable;
+               };
+       };
+       i2c_slave_gpio8: i2c_slave_gpio8 {
+               pins-i2c-slave {
+                       pins = "gpio8",
+                              "gpio9",
+                              "gpio10",
+                              "gpio11";
+                       function = "alt3";
+               };
+       };
+
+       jtag_gpio48: jtag_gpio48 {
+               pins-jtag {
+                       pins = "gpio48",
+                              "gpio49",
+                              "gpio50",
+                              "gpio51",
+                              "gpio52",
+                              "gpio53";
+                       function = "alt4";
+               };
+       };
+
+       mii_gpio28: mii_gpio28 {
+               pins-mii {
+                       pins = "gpio28",
+                              "gpio29",
+                              "gpio30",
+                              "gpio31";
+                       function = "alt4";
+               };
+       };
+       mii_gpio36: mii_gpio36 {
+               pins-mii {
+                       pins = "gpio36",
+                              "gpio37",
+                              "gpio38",
+                              "gpio39";
+                       function = "alt5";
+               };
+       };
+
+       pcm_gpio50: pcm_gpio50 {
+               pins-pcm {
+                       pins = "gpio50",
+                              "gpio51",
+                              "gpio52",
+                              "gpio53";
+                       function = "alt2";
+               };
+       };
+
+       pwm0_0_gpio12: pwm0_0_gpio12 {
+               pin-pwm {
+                       pins = "gpio12";
+                       function = "alt0";
+                       bias-disable;
+               };
+       };
+       pwm0_0_gpio18: pwm0_0_gpio18 {
+               pin-pwm {
+                       pins = "gpio18";
+                       function = "alt5";
+                       bias-disable;
+               };
+       };
+       pwm1_0_gpio40: pwm1_0_gpio40 {
+               pin-pwm {
+                       pins = "gpio40";
+                       function = "alt0";
+                       bias-disable;
+               };
+       };
+       pwm0_1_gpio13: pwm0_1_gpio13 {
+               pin-pwm {
+                       pins = "gpio13";
+                       function = "alt0";
+                       bias-disable;
+               };
+       };
+       pwm0_1_gpio19: pwm0_1_gpio19 {
+               pin-pwm {
+                       pins = "gpio19";
+                       function = "alt5";
+                       bias-disable;
+               };
+       };
+       pwm1_1_gpio41: pwm1_1_gpio41 {
+               pin-pwm {
+                       pins = "gpio41";
+                       function = "alt0";
+                       bias-disable;
+               };
+       };
+       pwm0_1_gpio45: pwm0_1_gpio45 {
+               pin-pwm {
+                       pins = "gpio45";
+                       function = "alt0";
+                       bias-disable;
+               };
+       };
+       pwm0_0_gpio52: pwm0_0_gpio52 {
+               pin-pwm {
+                       pins = "gpio52";
+                       function = "alt1";
+                       bias-disable;
+               };
+       };
+       pwm0_1_gpio53: pwm0_1_gpio53 {
+               pin-pwm {
+                       pins = "gpio53";
+                       function = "alt1";
+                       bias-disable;
+               };
+       };
+
+       rgmii_gpio35: rgmii_gpio35 {
+               pin-start-stop {
+                       pins = "gpio35";
+                       function = "alt4";
+               };
+               pin-rx-ok {
+                       pins = "gpio36";
+                       function = "alt4";
+               };
+       };
+       rgmii_irq_gpio34: rgmii_irq_gpio34 {
+               pin-irq {
+                       pins = "gpio34";
+                       function = "alt5";
+               };
+       };
+       rgmii_irq_gpio39: rgmii_irq_gpio39 {
+               pin-irq {
+                       pins = "gpio39";
+                       function = "alt4";
+               };
+       };
+       rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
+               pins-mdio {
+                       pins = "gpio28",
+                              "gpio29";
+                       function = "alt5";
+               };
+       };
+       rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
+               pins-mdio {
+                       pins = "gpio37",
+                              "gpio38";
+                       function = "alt4";
+               };
+       };
+
+       spi0_gpio46: spi0_gpio46 {
+               pins-spi {
+                       pins = "gpio46",
+                              "gpio47",
+                              "gpio48",
+                              "gpio49";
+                       function = "alt2";
+               };
+       };
+       spi2_gpio46: spi2_gpio46 {
+               pins-spi {
+                       pins = "gpio46",
+                              "gpio47",
+                              "gpio48",
+                              "gpio49",
+                              "gpio50";
+                       function = "alt5";
+               };
+       };
+       spi3_gpio0: spi3_gpio0 {
+               pins-spi {
+                       pins = "gpio0",
+                              "gpio1",
+                              "gpio2",
+                              "gpio3";
+                       function = "alt3";
+               };
+       };
+       spi4_gpio4: spi4_gpio4 {
+               pins-spi {
+                       pins = "gpio4",
+                              "gpio5",
+                              "gpio6",
+                              "gpio7";
+                       function = "alt3";
+               };
+       };
+       spi5_gpio12: spi5_gpio12 {
+               pins-spi {
+                       pins = "gpio12",
+                              "gpio13",
+                              "gpio14",
+                              "gpio15";
+                       function = "alt3";
+               };
+       };
+       spi6_gpio18: spi6_gpio18 {
+               pins-spi {
+                       pins = "gpio18",
+                              "gpio19",
+                              "gpio20",
+                              "gpio21";
+                       function = "alt3";
+               };
+       };
+
+       uart2_gpio0: uart2_gpio0 {
+               pin-tx {
+                       pins = "gpio0";
+                       function = "alt4";
+                       bias-disable;
+               };
+               pin-rx {
+                       pins = "gpio1";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+       };
+       uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
+               pin-cts {
+                       pins = "gpio2";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+               pin-rts {
+                       pins = "gpio3";
+                       function = "alt4";
+                       bias-disable;
+               };
+       };
+       uart3_gpio4: uart3_gpio4 {
+               pin-tx {
+                       pins = "gpio4";
+                       function = "alt4";
+                       bias-disable;
+               };
+               pin-rx {
+                       pins = "gpio5";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+       };
+       uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
+               pin-cts {
+                       pins = "gpio6";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+               pin-rts {
+                       pins = "gpio7";
+                       function = "alt4";
+                       bias-disable;
+               };
+       };
+       uart4_gpio8: uart4_gpio8 {
+               pin-tx {
+                       pins = "gpio8";
+                       function = "alt4";
+                       bias-disable;
+               };
+               pin-rx {
+                       pins = "gpio9";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+       };
+       uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
+               pin-cts {
+                       pins = "gpio10";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+               pin-rts {
+                       pins = "gpio11";
+                       function = "alt4";
+                       bias-disable;
+               };
+       };
+       uart5_gpio12: uart5_gpio12 {
+               pin-tx {
+                       pins = "gpio12";
+                       function = "alt4";
+                       bias-disable;
+               };
+               pin-rx {
+                       pins = "gpio13";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+       };
+       uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
+               pin-cts {
+                       pins = "gpio14";
+                       function = "alt4";
+                       bias-pull-up;
+               };
+               pin-rts {
+                       pins = "gpio15";
+                       function = "alt4";
+                       bias-disable;
+               };
+       };
+};
+
+&i2c0 {
+       compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+       interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&i2c1 {
+       compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+       interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&mailbox {
+       interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&sdhci {
+       interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&sdhost {
+       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&spi {
+       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&spi1 {
+       interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&spi2 {
+       interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&system_timer {
+       interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&txp {
+       interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart0 {
+       interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart1 {
+       interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&usb {
+       interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&vec {
+       interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+};
diff --git a/arch/arm/boot/dts/bcm2835-common.dtsi b/arch/arm/boot/dts/bcm2835-common.dtsi
new file mode 100644 (file)
index 0000000..fe1ab40
--- /dev/null
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* This include file covers the common peripherals and configuration between
+ * bcm2835, bcm2836 and bcm2837 implementations.
+ */
+
+/ {
+       interrupt-parent = <&intc>;
+
+       soc {
+               dma: dma@7e007000 {
+                       compatible = "brcm,bcm2835-dma";
+                       reg = <0x7e007000 0xf00>;
+                       interrupts = <1 16>,
+                                    <1 17>,
+                                    <1 18>,
+                                    <1 19>,
+                                    <1 20>,
+                                    <1 21>,
+                                    <1 22>,
+                                    <1 23>,
+                                    <1 24>,
+                                    <1 25>,
+                                    <1 26>,
+                                    /* dma channel 11-14 share one irq */
+                                    <1 27>,
+                                    <1 27>,
+                                    <1 27>,
+                                    <1 27>,
+                                    /* unused shared irq for all channels */
+                                    <1 28>;
+                       interrupt-names = "dma0",
+                                         "dma1",
+                                         "dma2",
+                                         "dma3",
+                                         "dma4",
+                                         "dma5",
+                                         "dma6",
+                                         "dma7",
+                                         "dma8",
+                                         "dma9",
+                                         "dma10",
+                                         "dma11",
+                                         "dma12",
+                                         "dma13",
+                                         "dma14",
+                                         "dma-shared-all";
+                       #dma-cells = <1>;
+                       brcm,dma-channel-mask = <0x7f35>;
+               };
+
+               intc: interrupt-controller@7e00b200 {
+                       compatible = "brcm,bcm2835-armctrl-ic";
+                       reg = <0x7e00b200 0x200>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               pm: watchdog@7e100000 {
+                       compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+                       #power-domain-cells = <1>;
+                       #reset-cells = <1>;
+                       reg = <0x7e100000 0x114>,
+                             <0x7e00a000 0x24>;
+                       clocks = <&clocks BCM2835_CLOCK_V3D>,
+                                <&clocks BCM2835_CLOCK_PERI_IMAGE>,
+                                <&clocks BCM2835_CLOCK_H264>,
+                                <&clocks BCM2835_CLOCK_ISP>;
+                       clock-names = "v3d", "peri_image", "h264", "isp";
+                       system-power-controller;
+               };
+
+               pixelvalve@7e206000 {
+                       compatible = "brcm,bcm2835-pixelvalve0";
+                       reg = <0x7e206000 0x100>;
+                       interrupts = <2 13>; /* pwa0 */
+               };
+
+               pixelvalve@7e207000 {
+                       compatible = "brcm,bcm2835-pixelvalve1";
+                       reg = <0x7e207000 0x100>;
+                       interrupts = <2 14>; /* pwa1 */
+               };
+
+               thermal: thermal@7e212000 {
+                       compatible = "brcm,bcm2835-thermal";
+                       reg = <0x7e212000 0x8>;
+                       clocks = <&clocks BCM2835_CLOCK_TSENS>;
+                       #thermal-sensor-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c2: i2c@7e805000 {
+                       compatible = "brcm,bcm2835-i2c";
+                       reg = <0x7e805000 0x1000>;
+                       interrupts = <2 21>;
+                       clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "okay";
+               };
+
+               pixelvalve@7e807000 {
+                       compatible = "brcm,bcm2835-pixelvalve2";
+                       reg = <0x7e807000 0x100>;
+                       interrupts = <2 10>; /* pixelvalve */
+               };
+
+               hdmi: hdmi@7e902000 {
+                       compatible = "brcm,bcm2835-hdmi";
+                       reg = <0x7e902000 0x600>,
+                             <0x7e808000 0x100>;
+                       interrupts = <2 8>, <2 9>;
+                       ddc = <&i2c2>;
+                       clocks = <&clocks BCM2835_PLLH_PIX>,
+                                <&clocks BCM2835_CLOCK_HSM>;
+                       clock-names = "pixel", "hdmi";
+                       dmas = <&dma 17>;
+                       dma-names = "audio-rx";
+                       status = "disabled";
+               };
+
+               v3d: v3d@7ec00000 {
+                       compatible = "brcm,bcm2835-v3d";
+                       reg = <0x7ec00000 0x1000>;
+                       interrupts = <1 10>;
+                       power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
+               };
+
+               vc4: gpu {
+                       compatible = "brcm,bcm2835-vc4";
+               };
+       };
+};
+
+&cpu_thermal {
+       thermal-sensors = <&thermal>;
+};
+
+&gpio {
+       i2c_slave_gpio18: i2c_slave_gpio18 {
+               brcm,pins = <18 19 20 21>;
+               brcm,function = <BCM2835_FSEL_ALT3>;
+       };
+
+       jtag_gpio4: jtag_gpio4 {
+               brcm,pins = <4 5 6 12 13>;
+               brcm,function = <BCM2835_FSEL_ALT5>;
+       };
+
+       pwm0_gpio12: pwm0_gpio12 {
+               brcm,pins = <12>;
+               brcm,function = <BCM2835_FSEL_ALT0>;
+       };
+       pwm0_gpio18: pwm0_gpio18 {
+               brcm,pins = <18>;
+               brcm,function = <BCM2835_FSEL_ALT5>;
+       };
+       pwm0_gpio40: pwm0_gpio40 {
+               brcm,pins = <40>;
+               brcm,function = <BCM2835_FSEL_ALT0>;
+       };
+       pwm1_gpio13: pwm1_gpio13 {
+               brcm,pins = <13>;
+               brcm,function = <BCM2835_FSEL_ALT0>;
+       };
+       pwm1_gpio19: pwm1_gpio19 {
+               brcm,pins = <19>;
+               brcm,function = <BCM2835_FSEL_ALT5>;
+       };
+       pwm1_gpio41: pwm1_gpio41 {
+               brcm,pins = <41>;
+               brcm,function = <BCM2835_FSEL_ALT0>;
+       };
+       pwm1_gpio45: pwm1_gpio45 {
+               brcm,pins = <45>;
+               brcm,function = <BCM2835_FSEL_ALT0>;
+       };
+};
+
+&i2s {
+       dmas = <&dma 2>, <&dma 3>;
+       dma-names = "tx", "rx";
+};
+
+&sdhost {
+       dmas = <&dma 13>;
+       dma-names = "rx-tx";
+};
+
+&spi {
+       dmas = <&dma 6>, <&dma 7>;
+       dma-names = "tx", "rx";
+};
index 6c6a7f6..394c8a7 100644 (file)
        clock-frequency = <100000>;
 };
 
-&i2c2 {
-       status = "okay";
-};
-
 &usb {
        power-domains = <&power RPI_POWER_DOMAIN_USB>;
 };
index a5c3824..53bf457 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "bcm283x.dtsi"
+#include "bcm2835-common.dtsi"
 
 / {
        compatible = "brcm,bcm2835";
index c933e84..82d6c46 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "bcm283x.dtsi"
+#include "bcm2835-common.dtsi"
 
 / {
        compatible = "brcm,bcm2836";
index beb6c50..9e95fee 100644 (file)
@@ -1,4 +1,5 @@
 #include "bcm283x.dtsi"
+#include "bcm2835-common.dtsi"
 
 / {
        compatible = "brcm,bcm2837";
diff --git a/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi
new file mode 100644 (file)
index 0000000..0ff0e9e
--- /dev/null
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+&usb {
+       dr_mode = "peripheral";
+       g-rx-fifo-size = <256>;
+       g-np-tx-fifo-size = <32>;
+       g-tx-fifo-size = <256 256 512 512 512 768 768>;
+};
index 2d191fc..3caaa57 100644 (file)
@@ -18,7 +18,6 @@
 / {
        compatible = "brcm,bcm2835";
        model = "BCM2835";
-       interrupt-parent = <&intc>;
        #address-cells = <1>;
        #size-cells = <1>;
 
@@ -36,8 +35,6 @@
                        polling-delay-passive = <0>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&thermal>;
-
                        trips {
                                cpu-crit {
                                        temperature     = <80000>;
@@ -56,7 +53,7 @@
                #address-cells = <1>;
                #size-cells = <1>;
 
-               timer@7e003000 {
+               system_timer: timer@7e003000 {
                        compatible = "brcm,bcm2835-system-timer";
                        reg = <0x7e003000 0x1000>;
                        interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
                        clock-frequency = <1000000>;
                };
 
-               txp@7e004000 {
+               txp: txp@7e004000 {
                        compatible = "brcm,bcm2835-txp";
                        reg = <0x7e004000 0x20>;
                        interrupts = <1 11>;
                };
 
-               dma: dma@7e007000 {
-                       compatible = "brcm,bcm2835-dma";
-                       reg = <0x7e007000 0xf00>;
-                       interrupts = <1 16>,
-                                    <1 17>,
-                                    <1 18>,
-                                    <1 19>,
-                                    <1 20>,
-                                    <1 21>,
-                                    <1 22>,
-                                    <1 23>,
-                                    <1 24>,
-                                    <1 25>,
-                                    <1 26>,
-                                    /* dma channel 11-14 share one irq */
-                                    <1 27>,
-                                    <1 27>,
-                                    <1 27>,
-                                    <1 27>,
-                                    /* unused shared irq for all channels */
-                                    <1 28>;
-                       interrupt-names = "dma0",
-                                         "dma1",
-                                         "dma2",
-                                         "dma3",
-                                         "dma4",
-                                         "dma5",
-                                         "dma6",
-                                         "dma7",
-                                         "dma8",
-                                         "dma9",
-                                         "dma10",
-                                         "dma11",
-                                         "dma12",
-                                         "dma13",
-                                         "dma14",
-                                         "dma-shared-all";
-                       #dma-cells = <1>;
-                       brcm,dma-channel-mask = <0x7f35>;
-               };
-
-               intc: interrupt-controller@7e00b200 {
-                       compatible = "brcm,bcm2835-armctrl-ic";
-                       reg = <0x7e00b200 0x200>;
-                       interrupt-controller;
-                       #interrupt-cells = <2>;
-               };
-
-               pm: watchdog@7e100000 {
-                       compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-                       #power-domain-cells = <1>;
-                       #reset-cells = <1>;
-                       reg = <0x7e100000 0x114>,
-                             <0x7e00a000 0x24>;
-                       clocks = <&clocks BCM2835_CLOCK_V3D>,
-                                <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-                                <&clocks BCM2835_CLOCK_H264>,
-                                <&clocks BCM2835_CLOCK_ISP>;
-                       clock-names = "v3d", "peri_image", "h264", "isp";
-                       system-power-controller;
-               };
-
                clocks: cprman@7e101000 {
                        compatible = "brcm,bcm2835-cprman";
                        #clock-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
-                       /* Defines pin muxing groups according to
-                        * BCM2835-ARM-Peripherals.pdf page 102.
+                       /* Defines common pin muxing groups
                         *
                         * While each pin can have its mux selected
                         * for various functions individually, some
                                brcm,pins = <44 45>;
                                brcm,function = <BCM2835_FSEL_ALT2>;
                        };
-                       i2c_slave_gpio18: i2c_slave_gpio18 {
-                               brcm,pins = <18 19 20 21>;
-                               brcm,function = <BCM2835_FSEL_ALT3>;
-                       };
 
-                       jtag_gpio4: jtag_gpio4 {
-                               brcm,pins = <4 5 6 12 13>;
-                               brcm,function = <BCM2835_FSEL_ALT5>;
-                       };
                        jtag_gpio22: jtag_gpio22 {
                                brcm,pins = <22 23 24 25 26 27>;
                                brcm,function = <BCM2835_FSEL_ALT4>;
                                brcm,function = <BCM2835_FSEL_ALT2>;
                        };
 
-                       pwm0_gpio12: pwm0_gpio12 {
-                               brcm,pins = <12>;
-                               brcm,function = <BCM2835_FSEL_ALT0>;
-                       };
-                       pwm0_gpio18: pwm0_gpio18 {
-                               brcm,pins = <18>;
-                               brcm,function = <BCM2835_FSEL_ALT5>;
-                       };
-                       pwm0_gpio40: pwm0_gpio40 {
-                               brcm,pins = <40>;
-                               brcm,function = <BCM2835_FSEL_ALT0>;
-                       };
-                       pwm1_gpio13: pwm1_gpio13 {
-                               brcm,pins = <13>;
-                               brcm,function = <BCM2835_FSEL_ALT0>;
-                       };
-                       pwm1_gpio19: pwm1_gpio19 {
-                               brcm,pins = <19>;
-                               brcm,function = <BCM2835_FSEL_ALT5>;
-                       };
-                       pwm1_gpio41: pwm1_gpio41 {
-                               brcm,pins = <41>;
-                               brcm,function = <BCM2835_FSEL_ALT0>;
-                       };
-                       pwm1_gpio45: pwm1_gpio45 {
-                               brcm,pins = <45>;
-                               brcm,function = <BCM2835_FSEL_ALT0>;
-                       };
-
                        sdhost_gpio48: sdhost_gpio48 {
                                brcm,pins = <48 49 50 51 52 53>;
                                brcm,function = <BCM2835_FSEL_ALT0>;
                };
 
                uart0: serial@7e201000 {
-                       compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+                       compatible = "arm,pl011", "arm,primecell";
                        reg = <0x7e201000 0x200>;
                        interrupts = <2 25>;
                        clocks = <&clocks BCM2835_CLOCK_UART>,
                        reg = <0x7e202000 0x100>;
                        interrupts = <2 24>;
                        clocks = <&clocks BCM2835_CLOCK_VPU>;
-                       dmas = <&dma 13>;
-                       dma-names = "rx-tx";
                        status = "disabled";
                };
 
                        compatible = "brcm,bcm2835-i2s";
                        reg = <0x7e203000 0x24>;
                        clocks = <&clocks BCM2835_CLOCK_PCM>;
-
-                       dmas = <&dma 2>,
-                              <&dma 3>;
-                       dma-names = "tx", "rx";
                        status = "disabled";
                };
 
                        reg = <0x7e204000 0x200>;
                        interrupts = <2 22>;
                        clocks = <&clocks BCM2835_CLOCK_VPU>;
-                       dmas = <&dma 6>, <&dma 7>;
-                       dma-names = "tx", "rx";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                        status = "disabled";
                };
 
-               pixelvalve@7e206000 {
-                       compatible = "brcm,bcm2835-pixelvalve0";
-                       reg = <0x7e206000 0x100>;
-                       interrupts = <2 13>; /* pwa0 */
-               };
-
-               pixelvalve@7e207000 {
-                       compatible = "brcm,bcm2835-pixelvalve1";
-                       reg = <0x7e207000 0x100>;
-                       interrupts = <2 14>; /* pwa1 */
-               };
-
                dpi: dpi@7e208000 {
                        compatible = "brcm,bcm2835-dpi";
                        reg = <0x7e208000 0x8c>;
 
                };
 
-               thermal: thermal@7e212000 {
-                       compatible = "brcm,bcm2835-thermal";
-                       reg = <0x7e212000 0x8>;
-                       clocks = <&clocks BCM2835_CLOCK_TSENS>;
-                       #thermal-sensor-cells = <0>;
-                       status = "disabled";
-               };
-
                aux: aux@7e215000 {
                        compatible = "brcm,bcm2835-aux";
                        #clock-cells = <1>;
                        status = "disabled";
                };
 
-               i2c2: i2c@7e805000 {
-                       compatible = "brcm,bcm2835-i2c";
-                       reg = <0x7e805000 0x1000>;
-                       interrupts = <2 21>;
-                       clocks = <&clocks BCM2835_CLOCK_VPU>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       status = "disabled";
-               };
-
                vec: vec@7e806000 {
                        compatible = "brcm,bcm2835-vec";
                        reg = <0x7e806000 0x1000>;
                        status = "disabled";
                };
 
-               pixelvalve@7e807000 {
-                       compatible = "brcm,bcm2835-pixelvalve2";
-                       reg = <0x7e807000 0x100>;
-                       interrupts = <2 10>; /* pixelvalve */
-               };
-
-               hdmi: hdmi@7e902000 {
-                       compatible = "brcm,bcm2835-hdmi";
-                       reg = <0x7e902000 0x600>,
-                             <0x7e808000 0x100>;
-                       interrupts = <2 8>, <2 9>;
-                       ddc = <&i2c2>;
-                       clocks = <&clocks BCM2835_PLLH_PIX>,
-                                <&clocks BCM2835_CLOCK_HSM>;
-                       clock-names = "pixel", "hdmi";
-                       dmas = <&dma 17>;
-                       dma-names = "audio-rx";
-                       status = "disabled";
-               };
-
                usb: usb@7e980000 {
                        compatible = "brcm,bcm2835-usb";
                        reg = <0x7e980000 0x10000>;
                        phys = <&usbphy>;
                        phy-names = "usb2-phy";
                };
-
-               v3d: v3d@7ec00000 {
-                       compatible = "brcm,bcm2835-v3d";
-                       reg = <0x7ec00000 0x1000>;
-                       interrupts = <1 10>;
-                       power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
-               };
-
-               vc4: gpu {
-                       compatible = "brcm,bcm2835-vc4";
-               };
        };
 
        clocks {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                /* The oscillator is the root of the clock tree. */
-               clk_osc: clock@3 {
+               clk_osc: clk-osc {
                        compatible = "fixed-clock";
-                       reg = <3>;
                        #clock-cells = <0>;
                        clock-output-names = "osc";
                        clock-frequency = <19200000>;
                };
 
-               clk_usb: clock@4 {
+               clk_usb: clk-usb {
                        compatible = "fixed-clock";
-                       reg = <4>;
                        #clock-cells = <0>;
                        clock-output-names = "otg";
                        clock-frequency = <480000000>;
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
new file mode 100644 (file)
index 0000000..3343253
--- /dev/null
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2019 Legrand AV Inc.
+ */
+
+/dts-v1/;
+
+#include "bcm47094.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+/ {
+       compatible = "luxul,xwc-2000-v1", "brcm,bcm47094", "brcm,bcm4708";
+       model = "Luxul XWC-2000 V1";
+
+       chosen {
+               bootargs = "earlycon";
+       };
+
+       memory {
+               reg = <0x00000000 0x08000000
+                      0x88000000 0x18000000>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               status  {
+                       label = "bcm53xx:green:status";
+                       gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "timer";
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               restart {
+                       label = "Reset";
+                       linux,code = <KEY_RESTART>;
+                       gpios = <&chipcommon 19 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&spi_nor {
+       status = "okay";
+};
index 2e8a397..3081b04 100644 (file)
                                status = "disabled";
                        };
 
-                       crypto_sram: sa-sram@ffffe000 {
+                       crypto_sram: sram@ffffe000 {
                                compatible = "mmio-sram";
                                reg = <0xffffe000 0x800>;
                                clocks = <&gate_clk 15>;
index 37e0487..bbf1c6d 100644 (file)
 
                target-module@f4000 {                   /* 0x4a0f4000, ap 23 04.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox1";
                        reg = <0xf4000 0x4>,
                              <0xf4010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@90000 {                   /* 0x48090000, ap 55 12.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "rng";
                        reg = <0x91fe0 0x4>,
                              <0x91fe4 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@b2000 {                   /* 0x480b2000, ap 37 52.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "hdq1w";
                        reg = <0xb2000 0x4>,
                              <0xb2014 0x4>,
                              <0xb2018 0x4>;
 
                target-module@2000 {                    /* 0x48802000, ap 95 7c.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox13";
                        reg = <0x2000 0x4>,
                              <0x2010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@3a000 {                   /* 0x4883a000, ap 33 3e.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox2";
                        reg = <0x3a000 0x4>,
                              <0x3a010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@3c000 {                   /* 0x4883c000, ap 35 3a.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox3";
                        reg = <0x3c000 0x4>,
                              <0x3c010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@3e000 {                   /* 0x4883e000, ap 37 46.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox4";
                        reg = <0x3e000 0x4>,
                              <0x3e010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@40000 {                   /* 0x48840000, ap 39 64.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox5";
                        reg = <0x40000 0x4>,
                              <0x40010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@42000 {                   /* 0x48842000, ap 41 4e.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox6";
                        reg = <0x42000 0x4>,
                              <0x42010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@44000 {                   /* 0x48844000, ap 43 42.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox7";
                        reg = <0x44000 0x4>,
                              <0x44010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@46000 {                   /* 0x48846000, ap 45 48.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox8";
                        reg = <0x46000 0x4>,
                              <0x46010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@5e000 {                   /* 0x4885e000, ap 69 6c.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox9";
                        reg = <0x5e000 0x4>,
                              <0x5e010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@60000 {                   /* 0x48860000, ap 71 4a.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox10";
                        reg = <0x60000 0x4>,
                              <0x60010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@62000 {                   /* 0x48862000, ap 73 74.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox11";
                        reg = <0x62000 0x4>,
                              <0x62010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@64000 {                   /* 0x48864000, ap 67 52.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox12";
                        reg = <0x64000 0x4>,
                              <0x64010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@4000 {                    /* 0x4ae14000, ap 7 28.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "wd_timer2";
                        reg = <0x4000 0x4>,
                              <0x4010 0x4>,
                              <0x4014 0x4>;
index 953f0ff..73e5011 100644 (file)
 
 #include "dra7-l4.dtsi"
 #include "dra7xx-clocks.dtsi"
+
+&prm {
+       prm_dsp1: prm@400 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x400 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_ipu: prm@500 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x500 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_core: prm@700 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x700 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_iva: prm@f00 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0xf00 0x100>;
+       };
+
+       prm_dsp2: prm@1b00 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1b00 0x40>;
+               #reset-cells = <1>;
+       };
+
+       prm_eve1: prm@1b40 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1b40 0x40>;
+       };
+
+       prm_eve2: prm@1b80 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1b80 0x40>;
+       };
+
+       prm_eve3: prm@1bc0 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1bc0 0x40>;
+       };
+
+       prm_eve4: prm@1c00 {
+               compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1c00 0x60>;
+       };
+};
diff --git a/arch/arm/boot/dts/e60k02.dtsi b/arch/arm/boot/dts/e60k02.dtsi
new file mode 100644 (file)
index 0000000..6472b05
--- /dev/null
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Andreas Kemnade
+ * based on works
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * and
+ * Copyright (C) 2014 Ricoh Electronic Devices Co., Ltd
+ *
+ * Netronix E60K02 board common.
+ * This board is equipped with different SoCs and
+ * found in ebook-readers like the Kobo Clara HD (with i.MX6SLL) and
+ * the Tolino Shine 3 (with i.MX6SL)
+ */
+#include <dt-bindings/input/input.h>
+
+/ {
+
+       chosen {
+               stdout-path = &uart1;
+       };
+
+       gpio_keys: gpio-keys {
+               compatible = "gpio-keys";
+
+               power {
+                       label = "Power";
+                       gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+                       wakeup-source;
+               };
+
+               cover {
+                       label = "Cover";
+                       gpios = <&gpio5 12 GPIO_ACTIVE_LOW>;
+                       linux,code = <SW_LID>;
+                       linux,input-type = <EV_SW>;
+                       wakeup-source;
+               };
+       };
+
+       leds: leds {
+               compatible = "gpio-leds";
+
+               on {
+                       label = "e60k02:white:on";
+                       gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "timer";
+               };
+       };
+
+       memory {
+               reg = <0x80000000 0x20000000>;
+       };
+
+       reg_wifi: regulator-wifi {
+               compatible = "regulator-fixed";
+               regulator-name = "SD3_SPWR";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+               gpio = <&gpio4 29 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       wifi_pwrseq: wifi_pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               post-power-on-delay-ms = <20>;
+               reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+       };
+};
+
+
+&i2c1 {
+       clock-frequency = <100000>;
+       status = "okay";
+
+       lm3630a: backlight@36 {
+               reg = <0x36>;
+               compatible = "ti,lm3630a";
+               enable-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@0 {
+                       reg = <0>;
+                       led-sources = <0>;
+                       label = "backlight_warm";
+                       default-brightness = <0>;
+                       max-brightness = <255>;
+               };
+
+               led@1 {
+                       reg = <1>;
+                       led-sources = <1>;
+                       label = "backlight_cold";
+                       default-brightness = <0>;
+                       max-brightness = <255>;
+               };
+       };
+};
+
+&i2c2 {
+       clock-frequency = <100000>;
+       status = "okay";
+
+       /* TODO: CYTTSP5 touch controller at 0x24 */
+
+       /* TODO: TPS65185 PMIC for E Ink at 0x68 */
+
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       status = "okay";
+
+       ricoh619: pmic@32 {
+               compatible = "ricoh,rc5t619";
+               reg = <0x32>;
+               system-power-controller;
+
+               regulators {
+                       dcdc1_reg: DCDC1 {
+                               regulator-name = "DCDC1";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <900000>;
+                                       regulator-suspend-min-microvolt = <900000>;
+                               };
+                       };
+
+                       /* Core3_3V3 */
+                       dcdc2_reg: DCDC2 {
+                               regulator-name = "DCDC2";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <3300000>;
+                                       regulator-suspend-min-microvolt = <3300000>;
+                               };
+                       };
+
+                       dcdc3_reg: DCDC3 {
+                               regulator-name = "DCDC3";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <1140000>;
+                                       regulator-suspend-min-microvolt = <1140000>;
+                               };
+                       };
+
+                       /* Core4_1V2 */
+                       dcdc4_reg: DCDC4 {
+                               regulator-name = "DCDC4";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <1140000>;
+                                       regulator-suspend-min-microvolt = <1140000>;
+                               };
+                       };
+
+                       /* Core4_1V8 */
+                       dcdc5_reg: DCDC5 {
+                               regulator-name = "DCDC5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <1700000>;
+                                       regulator-suspend-min-microvolt = <1700000>;
+                               };
+                       };
+
+                       /* IR_3V3 */
+                       ldo1_reg: LDO1  {
+                               regulator-name = "LDO1";
+                               regulator-boot-on;
+                       };
+
+                       /* Core1_3V3 */
+                       ldo2_reg: LDO2  {
+                               regulator-name = "LDO2";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <3000000>;
+                                       regulator-suspend-min-microvolt = <3000000>;
+                               };
+                       };
+
+                       /* Core5_1V2 */
+                       ldo3_reg: LDO3  {
+                               regulator-name = "LDO3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       ldo4_reg: LDO4 {
+                               regulator-name = "LDO4";
+                               regulator-boot-on;
+                       };
+
+                       /* SPD_3V3 */
+                       ldo5_reg: LDO5 {
+                               regulator-name = "LDO5";
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       /* DDR_0V6 */
+                       ldo6_reg: LDO6 {
+                               regulator-name = "LDO6";
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       /* VDD_PWM */
+                       ldo7_reg: LDO7 {
+                               regulator-name = "LDO7";
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       /* ldo_1v8 */
+                       ldo8_reg: LDO8 {
+                               regulator-name = "LDO8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       ldo9_reg: LDO9 {
+                               regulator-name = "LDO9";
+                               regulator-boot-on;
+                       };
+
+                       ldo10_reg: LDO10 {
+                               regulator-name = "LDO10";
+                               regulator-boot-on;
+                       };
+
+                       ldortc1_reg: LDORTC1  {
+                               regulator-name = "LDORTC1";
+                               regulator-boot-on;
+                       };
+
+                       ldortc2_reg: LDORTC2 {
+                               regulator-name = "LDORTC2";
+                               regulator-boot-on;
+                       };
+               };
+       };
+};
+
+&snvs_rtc {
+       /* we are using the rtc in the pmic, not disabled in imx6sll.dtsi */
+       status = "disabled";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&usdhc2 {
+       non-removable;
+       status = "okay";
+};
+
+&usdhc3 {
+       vmmc-supply = <&reg_wifi>;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       cap-power-off-card;
+       non-removable;
+       status = "okay";
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       disable-over-current;
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       status = "okay";
+};
index 67d8601..96678dd 100644 (file)
                interrupt-controller;
                #interrupt-cells = <2>;
        };
+
        gpio1: gpio@e0050080 {
                compatible = "renesas,em-gio";
                reg = <0xe0050080 0x2c>, <0xe00500c0 0x20>;
                interrupt-controller;
                #interrupt-cells = <2>;
        };
+
        gpio2: gpio@e0050100 {
                compatible = "renesas,em-gio";
                reg = <0xe0050100 0x2c>, <0xe0050140 0x20>;
                interrupt-controller;
                #interrupt-cells = <2>;
        };
+
        gpio3: gpio@e0050180 {
                compatible = "renesas,em-gio";
                reg = <0xe0050180 0x2c>, <0xe00501c0 0x20>;
                interrupt-controller;
                #interrupt-cells = <2>;
        };
+
        gpio4: gpio@e0050200 {
                compatible = "renesas,em-gio";
                reg = <0xe0050200 0x2c>, <0xe0050240 0x20>;
index 7848184..b016b0b 100644 (file)
                #size-cells = <1>;
                ranges;
 
-               sysram@2020000 {
+               sram@2020000 {
                        compatible = "mmio-sram";
                        reg = <0x02020000 0x40000>;
                        #address-cells = <1>;
                                        (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
                };
 
-               mct@10050000 {
+               timer@10050000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x10050000 0x800>;
                        interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
                sysmmu_jpeg: sysmmu@11a60000 {
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x11a60000 0x1000>;
-                       interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "sysmmu", "master";
                        clocks = <&cmu CLK_SMMUJPEG>, <&cmu CLK_JPEG>;
                        power-domains = <&pd_cam>;
                sysmmu_fimd0: sysmmu@11e20000 {
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x11e20000 0x1000>;
-                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "sysmmu", "master";
                        clocks = <&cmu CLK_SMMUFIMD0>, <&cmu CLK_FIMD0>;
                        power-domains = <&pd_lcd0>;
                sysmmu_mfc: sysmmu@13620000 {
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x13620000 0x1000>;
-                       interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "sysmmu", "master";
                        clocks = <&cmu CLK_SMMUMFC_L>, <&cmu CLK_MFC>;
                        power-domains = <&pd_mfc>;
index 433f109..d2779a7 100644 (file)
                        syscon = <&pmu_system_controller>;
                };
 
-               pd_mfc: mfc-power-domain@10023c40 {
+               pd_mfc: power-domain@10023c40 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023C40 0x20>;
                        #power-domain-cells = <0>;
                        label = "MFC";
                };
 
-               pd_g3d: g3d-power-domain@10023c60 {
+               pd_g3d: power-domain@10023c60 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023C60 0x20>;
                        #power-domain-cells = <0>;
                        label = "G3D";
                };
 
-               pd_lcd0: lcd0-power-domain@10023c80 {
+               pd_lcd0: power-domain@10023c80 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023C80 0x20>;
                        #power-domain-cells = <0>;
                        label = "LCD0";
                };
 
-               pd_tv: tv-power-domain@10023c20 {
+               pd_tv: power-domain@10023c20 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023C20 0x20>;
                        #power-domain-cells = <0>;
                        label = "TV";
                };
 
-               pd_cam: cam-power-domain@10023c00 {
+               pd_cam: power-domain@10023c00 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023C00 0x20>;
                        #power-domain-cells = <0>;
                        label = "CAM";
                };
 
-               pd_gps: gps-power-domain@10023ce0 {
+               pd_gps: power-domain@10023ce0 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023CE0 0x20>;
                        #power-domain-cells = <0>;
                        label = "GPS";
                };
 
-               pd_gps_alive: gps-alive-power-domain@10023d00 {
+               pd_gps_alive: power-domain@10023d00 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023D00 0x20>;
                        #power-domain-cells = <0>;
index f220716..554819a 100644 (file)
@@ -72,7 +72,7 @@
        };
 
        soc: soc {
-               sysram: sysram@2020000 {
+               sysram: sram@2020000 {
                        compatible = "mmio-sram";
                        reg = <0x02020000 0x20000>;
                        #address-cells = <1>;
@@ -90,7 +90,7 @@
                        };
                };
 
-               pd_lcd1: lcd1-power-domain@10023ca0 {
+               pd_lcd1: power-domain@10023ca0 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023CA0 0x20>;
                        #power-domain-cells = <0>;
                        arm,data-latency = <2 2 1>;
                };
 
-               mct: mct@10050000 {
+               mct: timer@10050000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x10050000 0x800>;
-                       interrupt-parent = <&mct_map>;
-                       interrupts = <0>, <1>, <2>, <3>, <4>, <5>;
                        clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
                        clock-names = "fin_pll", "mct";
-
-                       mct_map: mct-map {
-                               #interrupt-cells = <1>;
-                               #address-cells = <0>;
-                               #size-cells = <0>;
-                               interrupt-map =
-                                       <0 &gic 0 57 IRQ_TYPE_LEVEL_HIGH>,
-                                       <1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>,
-                                       <2 &combiner 12 6>,
-                                       <3 &combiner 12 7>,
-                                       <4 &gic 0 42 IRQ_TYPE_LEVEL_HIGH>,
-                                       <5 &gic 0 48 IRQ_TYPE_LEVEL_HIGH>;
-                       };
+                       interrupts-extended = <&gic GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&combiner 12 6>,
+                                             <&combiner 12 7>,
+                                             <&gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
                };
 
                watchdog: watchdog@10060000 {
index d20db2d..5022aa5 100644 (file)
                        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
                };
 
-               sysram@2020000 {
+               sram@2020000 {
                        compatible = "mmio-sram";
                        reg = <0x02020000 0x40000>;
                        #address-cells = <1>;
                        };
                };
 
-               pd_isp: isp-power-domain@10023ca0 {
+               pd_isp: power-domain@10023ca0 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023CA0 0x20>;
                        #power-domain-cells = <0>;
                        clock-names = "aclk200", "aclk400_mcuisp";
                };
 
-               mct@10050000 {
+               timer@10050000 {
                        compatible = "samsung,exynos4412-mct";
                        reg = <0x10050000 0x800>;
-                       interrupt-parent = <&mct_map>;
-                       interrupts = <0>, <1>, <2>, <3>, <4>;
                        clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
                        clock-names = "fin_pll", "mct";
-
-                       mct_map: mct-map {
-                               #interrupt-cells = <1>;
-                               #address-cells = <0>;
-                               #size-cells = <0>;
-                               interrupt-map =
-                                       <0 &gic 0 57 IRQ_TYPE_LEVEL_HIGH>,
-                                       <1 &combiner 12 5>,
-                                       <2 &combiner 12 6>,
-                                       <3 &combiner 12 7>,
-                                       <4 &gic 1 12 IRQ_TYPE_LEVEL_HIGH>;
-                       };
+                       interrupts-extended = <&gic GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&combiner 12 5>,
+                                             <&combiner 12 6>,
+                                             <&combiner 12 7>,
+                                             <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_HIGH>;
                };
 
                watchdog: watchdog@10060000 {
index 67f9b45..4801ca7 100644 (file)
@@ -35,8 +35,8 @@
                #size-cells = <1>;
                ranges;
 
-               chipid@10000000 {
-                       compatible = "samsung,exynos4210-chipid";
+               chipid: chipid@10000000 {
+                       compatible = "samsung,exynos4210-chipid", "syscon";
                        reg = <0x10000000 0x100>;
                };
 
index 6fcb78a..d6c85ef 100644 (file)
@@ -11,6 +11,7 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/clock/samsung,s2mps11.h>
+#include <dt-bindings/sound/samsung-i2s.h>
 #include "exynos5250.dtsi"
 
 / {
                };
        };
 
+       sound {
+               compatible = "samsung,arndale-wm1811";
+               samsung,audio-cpu = <&i2s0>;
+               samsung,audio-codec = <&wm1811>;
+       };
+
        fixed-rate-clocks {
                xxti {
                        compatible = "samsung,clock-xxti";
        };
 };
 
+&clock {
+       assigned-clocks = <&clock CLK_FOUT_EPLL>;
+       assigned-clock-rates = <49152000>;
+};
+
+&clock_audss {
+       assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>;
+       assigned-clock-parents = <&clock CLK_FOUT_EPLL>;
+};
+
 &cpu0 {
        cpu0-supply = <&buck2_reg>;
 };
 &i2c_3 {
        status = "okay";
 
-       wm1811a@1a {
+       wm1811: codec@1a {
                compatible = "wlf,wm1811";
                reg = <0x1a>;
+               clocks = <&i2s0 CLK_I2S_CDCLK>;
+               clock-names = "MCLK1";
 
                AVDD2-supply = <&main_dc_reg>;
                CPVDD-supply = <&main_dc_reg>;
 };
 
 &i2s0 {
+       assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>;
+       assigned-clock-parents = <&clock_audss EXYNOS_I2S_BUS>;
        status = "okay";
 };
 
+&i2s0_bus {
+       samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+};
+
 &mali {
        mali-supply = <&buck4_reg>;
        status = "okay";
index fc966c1..e1f0215 100644 (file)
        };
 
        soc: soc {
-               sysram@2020000 {
+               sram@2020000 {
                        compatible = "mmio-sram";
                        reg = <0x02020000 0x30000>;
                        #address-cells = <1>;
                        power-domains = <&pd_mau>;
                };
 
-               mct@101c0000 {
+               timer@101c0000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x101C0000 0x800>;
-                       interrupt-controller;
-                       #interrupt-cells = <2>;
-                       interrupt-parent = <&mct_map>;
-                       interrupts = <0 0>, <1 0>, <2 0>, <3 0>,
-                                    <4 0>, <5 0>;
                        clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
                        clock-names = "fin_pll", "mct";
-
-                       mct_map: mct-map {
-                               #interrupt-cells = <2>;
-                               #address-cells = <0>;
-                               #size-cells = <0>;
-                               interrupt-map = <0x0 0 &combiner 23 3>,
-                                               <0x1 0 &combiner 23 4>,
-                                               <0x2 0 &combiner 25 2>,
-                                               <0x3 0 &combiner 25 3>,
-                                               <0x4 0 &gic 0 120 IRQ_TYPE_LEVEL_HIGH>,
-                                               <0x5 0 &gic 0 121 IRQ_TYPE_LEVEL_HIGH>;
-                       };
+                       interrupts-extended = <&combiner 23 3>,
+                                             <&combiner 23 4>,
+                                             <&combiner 25 2>,
+                                             <&combiner 25 3>,
+                                             <&gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
                };
 
                pinctrl_0: pinctrl@11400000 {
                        compatible = "samsung,s5pv210-i2s";
                        status = "disabled";
                        reg = <0x03830000 0x100>;
-                       dmas = <&pdma0 10
-                               &pdma0 9
-                               &pdma0 8>;
+                       dmas = <&pdma0 10>,
+                               <&pdma0 9>,
+                               <&pdma0 8>;
                        dma-names = "tx", "rx", "tx-sec";
                        clocks = <&clock_audss EXYNOS_I2S_BUS>,
                                <&clock_audss EXYNOS_I2S_BUS>,
                        compatible = "samsung,s3c6410-i2s";
                        status = "disabled";
                        reg = <0x12D60000 0x100>;
-                       dmas = <&pdma1 12
-                               &pdma1 11>;
+                       dmas = <&pdma1 12>,
+                               <&pdma1 11>;
                        dma-names = "tx", "rx";
                        clocks = <&clock CLK_I2S1>, <&clock CLK_DIV_I2S1>;
                        clock-names = "iis", "i2s_opclk0";
                        compatible = "samsung,s3c6410-i2s";
                        status = "disabled";
                        reg = <0x12D70000 0x100>;
-                       dmas = <&pdma0 12
-                               &pdma0 11>;
+                       dmas = <&pdma0 12>,
+                               <&pdma0 11>;
                        dma-names = "tx", "rx";
                        clocks = <&clock CLK_I2S2>, <&clock CLK_DIV_I2S2>;
                        clock-names = "iis", "i2s_opclk0";
index 3581b57..b0811db 100644 (file)
                        reg = <0x10000000 0x100>;
                };
 
-               mct: mct@100b0000 {
+               mct: timer@100b0000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x100B0000 0x1000>;
                        clocks = <&fin_pll>, <&clock_peri PERI_CLK_MCT>;
index e6f78b1..a4b03d4 100644 (file)
                audi2s0: i2s@3830000 {
                        compatible = "samsung,exynos5420-i2s";
                        reg = <0x03830000 0x100>;
-                       dmas = <&pdma0 10
-                               &pdma0 9
-                               &pdma0 8>;
+                       dmas = <&pdma0 10>,
+                               <&pdma0 9>,
+                               <&pdma0 8>;
                        dma-names = "tx", "rx", "tx-sec";
                        clocks = <&clock_audss EXYNOS_I2S_BUS>,
                                <&clock_audss EXYNOS_I2S_BUS>,
index 9eb48ca..2bcbdf8 100644 (file)
        status = "okay";
 };
 
+&timer {
+       arm,cpu-registers-not-fw-configured;
+};
+
 &tmu_cpu0 {
        vtmu-supply = <&ldo10_reg>;
 };
index 7d51e0f..d39907a 100644 (file)
                };
 
                clock: clock-controller@10010000 {
-                       compatible = "samsung,exynos5420-clock";
+                       compatible = "samsung,exynos5420-clock", "syscon";
                        reg = <0x10010000 0x30000>;
                        #clock-cells = <1>;
                };
                        status = "disabled";
                };
 
+               dmc: memory-controller@10c20000 {
+                       compatible = "samsung,exynos5422-dmc";
+                       reg = <0x10c20000 0x10000>, <0x10c30000 0x10000>;
+                       interrupt-parent = <&combiner>;
+                       interrupts = <16 0>, <16 1>;
+                       interrupt-names = "drex_0", "drex_1";
+                       clocks = <&clock CLK_FOUT_SPLL>,
+                                <&clock CLK_MOUT_SCLK_SPLL>,
+                                <&clock CLK_FF_DOUT_SPLL2>,
+                                <&clock CLK_FOUT_BPLL>,
+                                <&clock CLK_MOUT_BPLL>,
+                                <&clock CLK_SCLK_BPLL>,
+                                <&clock CLK_MOUT_MX_MSPLL_CCORE>,
+                                <&clock CLK_MOUT_MCLK_CDREX>;
+                       clock-names = "fout_spll",
+                                     "mout_sclk_spll",
+                                     "ff_dout_spll2",
+                                     "fout_bpll",
+                                     "mout_bpll",
+                                     "sclk_bpll",
+                                     "mout_mx_mspll_ccore",
+                                     "mout_mclk_cdrex";
+                       samsung,syscon-clk = <&clock>;
+                       status = "disabled";
+               };
+
                nocp_mem0_0: nocp@10ca1000 {
                        compatible = "samsung,exynos5420-nocp";
                        reg = <0x10CA1000 0x200>;
                        status = "disabled";
                };
 
+               ppmu_dmc0_0: ppmu@10d00000 {
+                       compatible = "samsung,exynos-ppmu";
+                       reg = <0x10d00000 0x2000>;
+                       clocks = <&clock CLK_PCLK_PPMU_DREX0_0>;
+                       clock-names = "ppmu";
+                       events {
+                               ppmu_event3_dmc0_0: ppmu-event3-dmc0_0 {
+                                       event-name = "ppmu-event3-dmc0_0";
+                               };
+                       };
+               };
+
+               ppmu_dmc0_1: ppmu@10d10000 {
+                       compatible = "samsung,exynos-ppmu";
+                       reg = <0x10d10000 0x2000>;
+                       clocks = <&clock CLK_PCLK_PPMU_DREX0_1>;
+                       clock-names = "ppmu";
+                       events {
+                               ppmu_event3_dmc0_1: ppmu-event3-dmc0_1 {
+                                       event-name = "ppmu-event3-dmc0_1";
+                               };
+                       };
+               };
+
+               ppmu_dmc1_0: ppmu@10d60000 {
+                       compatible = "samsung,exynos-ppmu";
+                       reg = <0x10d60000 0x2000>;
+                       clocks = <&clock CLK_PCLK_PPMU_DREX1_0>;
+                       clock-names = "ppmu";
+                       events {
+                               ppmu_event3_dmc1_0: ppmu-event3-dmc1_0 {
+                                       event-name = "ppmu-event3-dmc1_0";
+                               };
+                       };
+               };
+
+               ppmu_dmc1_1: ppmu@10d70000 {
+                       compatible = "samsung,exynos-ppmu";
+                       reg = <0x10d70000 0x2000>;
+                       clocks = <&clock CLK_PCLK_PPMU_DREX1_1>;
+                       clock-names = "ppmu";
+                       events {
+                               ppmu_event3_dmc1_1: ppmu-event3-dmc1_1 {
+                                       event-name = "ppmu-event3-dmc1_1";
+                               };
+                       };
+               };
+
                gsc_pd: power-domain@10044000 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10044000 0x20>;
                i2s0: i2s@3830000 {
                        compatible = "samsung,exynos5420-i2s";
                        reg = <0x03830000 0x100>;
-                       dmas = <&adma 0
-                               &adma 2
-                               &adma 1>;
+                       dmas = <&adma 0>,
+                               <&adma 2>,
+                               <&adma 1>;
                        dma-names = "tx", "rx", "tx-sec";
                        clocks = <&clock_audss EXYNOS_I2S_BUS>,
                                <&clock_audss EXYNOS_I2S_BUS>,
                i2s1: i2s@12d60000 {
                        compatible = "samsung,exynos5420-i2s";
                        reg = <0x12D60000 0x100>;
-                       dmas = <&pdma1 12
-                               &pdma1 11>;
+                       dmas = <&pdma1 12>,
+                               <&pdma1 11>;
                        dma-names = "tx", "rx";
                        clocks = <&clock CLK_I2S1>, <&clock CLK_SCLK_I2S1>;
                        clock-names = "iis", "i2s_opclk0";
                i2s2: i2s@12d70000 {
                        compatible = "samsung,exynos5420-i2s";
                        reg = <0x12D70000 0x100>;
-                       dmas = <&pdma0 12
-                               &pdma0 11>;
+                       dmas = <&pdma0 12>,
+                               <&pdma0 11>;
                        dma-names = "tx", "rx";
                        clocks = <&clock CLK_I2S2>, <&clock CLK_SCLK_I2S2>;
                        clock-names = "iis", "i2s_opclk0";
index 829147e..059fa32 100644 (file)
                        clock-frequency = <24000000>;
                };
        };
+
+       dmc_opp_table: opp_table2 {
+               compatible = "operating-points-v2";
+
+               opp00 {
+                       opp-hz = /bits/ 64 <165000000>;
+                       opp-microvolt = <875000>;
+               };
+               opp01 {
+                       opp-hz = /bits/ 64 <206000000>;
+                       opp-microvolt = <875000>;
+               };
+               opp02 {
+                       opp-hz = /bits/ 64 <275000000>;
+                       opp-microvolt = <875000>;
+               };
+               opp03 {
+                       opp-hz = /bits/ 64 <413000000>;
+                       opp-microvolt = <887500>;
+               };
+               opp04 {
+                       opp-hz = /bits/ 64 <543000000>;
+                       opp-microvolt = <937500>;
+               };
+               opp05 {
+                       opp-hz = /bits/ 64 <633000000>;
+                       opp-microvolt = <1012500>;
+               };
+               opp06 {
+                       opp-hz = /bits/ 64 <728000000>;
+                       opp-microvolt = <1037500>;
+               };
+               opp07 {
+                       opp-hz = /bits/ 64 <825000000>;
+                       opp-microvolt = <1050000>;
+               };
+       };
+
+       samsung_K3QF2F20DB: lpddr3 {
+               compatible      = "samsung,K3QF2F20DB", "jedec,lpddr3";
+               density         = <16384>;
+               io-width        = <32>;
+               #address-cells  = <1>;
+               #size-cells     = <0>;
+
+               tRFC-min-tck            = <17>;
+               tRRD-min-tck            = <2>;
+               tRPab-min-tck           = <2>;
+               tRPpb-min-tck           = <2>;
+               tRCD-min-tck            = <3>;
+               tRC-min-tck             = <6>;
+               tRAS-min-tck            = <5>;
+               tWTR-min-tck            = <2>;
+               tWR-min-tck             = <7>;
+               tRTP-min-tck            = <2>;
+               tW2W-C2C-min-tck        = <0>;
+               tR2R-C2C-min-tck        = <0>;
+               tWL-min-tck             = <8>;
+               tDQSCK-min-tck          = <5>;
+               tRL-min-tck             = <14>;
+               tFAW-min-tck            = <5>;
+               tXSR-min-tck            = <12>;
+               tXP-min-tck             = <2>;
+               tCKE-min-tck            = <2>;
+               tCKESR-min-tck          = <2>;
+               tMRD-min-tck            = <5>;
+
+               timings_samsung_K3QF2F20DB_800mhz: lpddr3-timings@800000000 {
+                       compatible      = "jedec,lpddr3-timings";
+                       /* workaround: 'reg' shows max-freq */
+                       reg             = <800000000>;
+                       min-freq        = <100000000>;
+                       tRFC            = <65000>;
+                       tRRD            = <6000>;
+                       tRPab           = <12000>;
+                       tRPpb           = <12000>;
+                       tRCD            = <10000>;
+                       tRC             = <33750>;
+                       tRAS            = <23000>;
+                       tWTR            = <3750>;
+                       tWR             = <7500>;
+                       tRTP            = <3750>;
+                       tW2W-C2C        = <0>;
+                       tR2R-C2C        = <0>;
+                       tFAW            = <25000>;
+                       tXSR            = <70000>;
+                       tXP             = <3750>;
+                       tCKE            = <3750>;
+                       tCKESR          = <3750>;
+                       tMRD            = <7000>;
+               };
+       };
 };
 
 &adc {
        cpu-supply = <&buck2_reg>;
 };
 
+&dmc {
+       devfreq-events = <&ppmu_event3_dmc0_0>, <&ppmu_event3_dmc0_1>,
+                       <&ppmu_event3_dmc1_0>, <&ppmu_event3_dmc1_1>;
+       device-handle = <&samsung_K3QF2F20DB>;
+       operating-points-v2 = <&dmc_opp_table>;
+       vdd-supply = <&buck1_reg>;
+       status = "okay";
+};
+
 &hsi2c_4 {
        status = "okay";
 
        };
 };
 
+&ppmu_dmc0_0 {
+       status = "okay";
+};
+
+&ppmu_dmc0_1 {
+       status = "okay";
+};
+
+&ppmu_dmc1_0 {
+       status = "okay";
+};
+
+&ppmu_dmc1_1 {
+       status = "okay";
+};
+
 &tmu_cpu0 {
        vtmu-supply = <&ldo7_reg>;
 };
index c19b5a5..a31ca2e 100644 (file)
        status = "disabled";
 };
 
+&chipid {
+       samsung,asv-bin = <2>;
+};
+
 &pwm {
        /*
         * PWM 0 -- fan
index 9c3b63b..f78dee8 100644 (file)
                status = "disabled";
        };
 
+       timer: timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               clock-frequency = <24000000>;
+       };
+
        soc: soc {
-               sysram@2020000 {
+               sram@2020000 {
                        compatible = "mmio-sram";
                        reg = <0x02020000 0x54000>;
                        #address-cells = <1>;
                        };
                };
 
-               mct: mct@101c0000 {
+               mct: timer@101c0000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x101c0000 0xb00>;
-                       interrupt-parent = <&mct_map>;
-                       interrupts = <0>, <1>, <2>, <3>, <4>, <5>, <6>, <7>,
-                                       <8>, <9>, <10>, <11>;
-
-                       mct_map: mct-map {
-                               #interrupt-cells = <1>;
-                               #address-cells = <0>;
-                               #size-cells = <0>;
-                               interrupt-map = <0 &combiner 23 3>,
-                                               <1 &combiner 23 4>,
-                                               <2 &combiner 25 2>,
-                                               <3 &combiner 25 3>,
-                                               <4 &gic 0 120 IRQ_TYPE_LEVEL_HIGH>,
-                                               <5 &gic 0 121 IRQ_TYPE_LEVEL_HIGH>,
-                                               <6 &gic 0 122 IRQ_TYPE_LEVEL_HIGH>,
-                                               <7 &gic 0 123 IRQ_TYPE_LEVEL_HIGH>,
-                                               <8 &gic 0 128 IRQ_TYPE_LEVEL_HIGH>,
-                                               <9 &gic 0 129 IRQ_TYPE_LEVEL_HIGH>,
-                                               <10 &gic 0 130 IRQ_TYPE_LEVEL_HIGH>,
-                                               <11 &gic 0 131 IRQ_TYPE_LEVEL_HIGH>;
-                       };
+                       interrupts-extended = <&combiner 23 3>,
+                                             <&combiner 23 4>,
+                                             <&combiner 25 2>,
+                                             <&combiner 25 3>,
+                                             <&gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
                };
 
                watchdog: watchdog@101d0000 {
index 4398f2d..60ca3d6 100644 (file)
        status = "okay";
 };
 
+&timer {
+       arm,cpu-registers-not-fw-configured;
+};
+
 &tmu_cpu0 {
        vtmu-supply = <&ldo10_reg>;
 };
index de639ee..16177d8 100644 (file)
@@ -17,7 +17,7 @@
 };
 
 &clock {
-       compatible = "samsung,exynos5800-clock";
+       compatible = "samsung,exynos5800-clock", "syscon";
 };
 
 &cluster_a15_opp_table {
index 3652f55..f3464cf 100644 (file)
                        status = "disabled";
                };
 
-               iram: iram@ffff4c00 {
+               iram: sram@ffff4c00 {
                        compatible = "mmio-sram";
                        reg = <0xffff4c00 0xb400>;
                };
index d7f6fb7..6b62f07 100644 (file)
@@ -55,7 +55,7 @@
                interrupt-parent = <&avic>;
                ranges;
 
-               iram: iram@1fffc000 {
+               iram: sram@1fffc000 {
                        compatible = "mmio-sram";
                        reg = <0x1fffc000 0x4000>;
                        #address-cells = <1>;
index 0a4b9a5..dea86b9 100644 (file)
                interrupt-parent = <&tzic>;
                ranges;
 
-               iram: iram@1ffe0000 {
+               iram: sram@1ffe0000 {
                        compatible = "mmio-sram";
                        reg = <0x1ffe0000 0x20000>;
                };
index f00dda3..9b4efcd 100644 (file)
 
        display0: disp0 {
                compatible = "fsl,imx-parallel-display";
-               interface-pix-fmt = "rgb565";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_ipu_disp0>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
-               display-timings {
-                       claawvga {
-                               native-mode;
-                               clock-frequency = <27000000>;
-                               hactive = <800>;
-                               vactive = <480>;
-                               hback-porch = <40>;
-                               hfront-porch = <60>;
-                               vback-porch = <10>;
-                               vfront-porch = <10>;
-                               hsync-len = <20>;
-                               vsync-len = <10>;
-                               hsync-active = <0>;
-                               vsync-active = <0>;
-                               de-active = <1>;
-                               pixelclk-active = <0>;
-                       };
-               };
 
-               port {
+               port@0 {
+                       reg = <0>;
+
                        display0_in: endpoint {
                                remote-endpoint = <&ipu_di0_disp0>;
                        };
                };
+
+               port@1 {
+                       reg = <1>;
+
+                       display_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
        };
 
        gpio-keys {
                };
        };
 
+       panel {
+               compatible = "sii,43wvf1g";
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&display_out>;
+                       };
+               };
+       };
+
        regulators {
                compatible = "simple-bus";
                #address-cells = <1>;
index ee6263d..f34993a 100644 (file)
        };
 
        /*
-        * UART mode pin header configration
+        * UART mode pin header configuration
         * 3 - GPIO5[26], pull-down 100K
         * 4 - GPIO5[27], pull-down 100K
         * 5 - TX, pull-up 100K
index 6632e99..3dcce34 100644 (file)
@@ -1,49 +1,6 @@
-/*
- * Copyright 2015 Armadeus Systems
- *
- * 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.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this file; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright 2015 Armadeus Systems <support@armadeus.com>
 
 /dts-v1/;
 #include "imx6dl.dtsi"
index 9a5d6c9..cd07562 100644 (file)
 &i2c3 {
        status = "okay";
 
+       /*
+        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
+        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
+        */
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pcap_1>;
+               reg = <0x4a>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;         /* SODIMM 28 */
+               reset-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;     /* SODIMM 30 */
+               status = "disabled";
+       };
+
        /* M41T0M6 real time clock on carrier board */
        rtc_i2c: rtc@68 {
                compatible = "st,m41t0";
        };
 };
 
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <
+               &pinctrl_weim_gpio_1 &pinctrl_weim_gpio_2
+               &pinctrl_weim_gpio_3 &pinctrl_weim_gpio_4
+               &pinctrl_weim_gpio_5 &pinctrl_weim_gpio_6
+               &pinctrl_usbh_oc_1 &pinctrl_usbc_id_1
+       >;
+
+       pinctrl_pcap_1: pcap1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_9__GPIO1_IO09   0x1b0b0 /* SODIMM 28 */
+                       MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0 /* SODIMM 30 */
+               >;
+       };
+
+       pinctrl_mxt_ts: mxttsgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_CS1__GPIO2_IO24  0x130b0 /* SODIMM 107 */
+                       MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x130b0 /* SODIMM 106 */
+               >;
+       };
+};
+
 &ipu1_di0_disp0 {
        remote-endpoint = <&lcd_display_in>;
 };
index e8d800f..80ed5f1 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/pwm/pwm.h>
 
 / {
        clock-frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c3>;
-       status = "disabled";
+       status = "okay";
 
        oled: oled@3d {
                compatible = "solomon,ssd1305fb-i2c";
                vcc-supply = <&sw2_reg>;
                status = "disabled";
        };
+
+       touchkeys: keys@5a {
+               compatible = "fsl,mpr121-touchkey";
+               reg = <0x5a>;
+               vdd-supply = <&sw2_reg>;
+               autorepeat;
+               linux,keycodes = <KEY_1>, <KEY_2>, <KEY_3>, <KEY_4>, <KEY_5>,
+                               <KEY_6>, <KEY_7>, <KEY_8>, <KEY_9>,
+                               <KEY_BACKSPACE>, <KEY_0>, <KEY_ENTER>;
+               poll-interval = <50>;
+               status = "disabled";
+       };
 };
 
 &iomuxc {
                >;
        };
 
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__UART2_TX_DATA        0x1b098
+                       MX6QDL_PAD_GPIO_8__UART2_RX_DATA        0x1b098
+               >;
+       };
+
        pinctrl_usbh1: usbh1grp {
                fsl,pins = <
                        MX6QDL_PAD_EIM_D30__USB_H1_OC   0x1b098
        status = "okay";
 };
 
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
 &usbh1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usbh1>;
index f979270..6010d3d 100644 (file)
        status = "okay";
 };
 
-&i2c3 {
-       status = "okay";
-};
-
 &leds {
        status = "okay";
 };
        status = "okay";
 };
 
+&touchkeys {
+       status = "okay";
+};
+
 &usdhc3 {
        status = "okay";
 };
index 2ed1031..008312e 100644 (file)
@@ -64,6 +64,7 @@
                                396000  1175000
                        >;
                        clock-latency = <61036>; /* two CLK32 periods */
+                       #cooling-cells = <2>;
                        clocks = <&clks IMX6QDL_CLK_ARM>,
                                 <&clks IMX6QDL_CLK_PLL2_PFD2_396M>,
                                 <&clks IMX6QDL_CLK_STEP>,
index 0edd304..4665e15 100644 (file)
 &i2c1 {
        status = "okay";
 
+       /*
+        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
+        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
+        */
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               reg = <0x4a>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
+               reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */
+               status = "disabled";
+       };
+
        pcie-switch@58 {
                compatible = "plx,pex8605";
                reg = <0x58>;
index b94bb68..a3fa04a 100644 (file)
 &i2c1 {
        status = "okay";
 
+       /*
+        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
+        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
+        */
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               reg = <0x4a>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
+               reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */
+               status = "disabled";
+       };
+
        /* M41T0M6 real time clock on carrier board */
        rtc_i2c: rtc@68 {
                compatible = "st,m41t0";
index 302fd6a..5ba49d0 100644 (file)
 &i2c1 {
        status = "okay";
 
+       /*
+        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
+        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
+        */
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               reg = <0x4a>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
+               reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */
+               status = "disabled";
+       };
+
        eeprom@50 {
                compatible = "atmel,24c02";
                reg = <0x50>;
index 07a36bb..664b0af 100644 (file)
@@ -1,49 +1,6 @@
-/*
- * Copyright 2015 Armadeus Systems
- *
- * 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.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this file; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright 2015 Armadeus Systems <support@armadeus.com>
 
 /dts-v1/;
 #include "imx6q.dtsi"
index 9c61e3b..5219553 100644 (file)
        status = "okay";
 };
 
+&can1 {
+       status = "okay";
+};
+
+&can2 {
+       status = "disabled";
+};
+
 &hdmi {
        ddc-i2c-bus = <&i2c2>;
        status = "okay";
index 387801d..845cfad 100644 (file)
 &can1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_flexcan1>;
-       status = "okay";
 };
 
 &can2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_flexcan2>;
-       status = "okay";
 };
 
 &ecspi1 {
index ecc3989..d5d4690 100644 (file)
        sound-digital {
                compatible = "simple-audio-card";
                simple-audio-card,name = "tda1997x-audio";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&sound_codec>;
+               simple-audio-card,frame-master = <&sound_codec>;
 
-               simple-audio-card,dai-link@0 {
-                       format = "i2s";
-
-                       cpu {
-                               sound-dai = <&ssi2>;
-                       };
+               sound_cpu: simple-audio-card,cpu {
+                       sound-dai = <&ssi2>;
+               };
 
-                       codec {
-                               bitclock-master;
-                               frame-master;
-                               sound-dai = <&hdmi_receiver>;
-                       };
+               sound_codec: simple-audio-card,codec {
+                       sound-dai = <&hdmi_receiver>;
                };
        };
 };
index d038f41..9d3be1c 100644 (file)
@@ -73,6 +73,7 @@
                                396000  1175000
                        >;
                        clock-latency = <61036>; /* two CLK32 periods */
+                       #cooling-cells = <2>;
                        clocks = <&clks IMX6QDL_CLK_ARM>,
                                 <&clks IMX6QDL_CLK_PLL2_PFD2_396M>,
                                 <&clks IMX6QDL_CLK_STEP>,
                                396000  1175000
                        >;
                        clock-latency = <61036>; /* two CLK32 periods */
+                       #cooling-cells = <2>;
                        clocks = <&clks IMX6QDL_CLK_ARM>,
                                 <&clks IMX6QDL_CLK_PLL2_PFD2_396M>,
                                 <&clks IMX6QDL_CLK_STEP>,
                                396000  1175000
                        >;
                        clock-latency = <61036>; /* two CLK32 periods */
+                       #cooling-cells = <2>;
                        clocks = <&clks IMX6QDL_CLK_ARM>,
                                 <&clks IMX6QDL_CLK_PLL2_PFD2_396M>,
                                 <&clks IMX6QDL_CLK_STEP>,
index 7c4ad54..ff1287e 100644 (file)
 };
 
 &can1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan1>;
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&pinctrl_flexcan1_default>;
+       pinctrl-1 = <&pinctrl_flexcan1_sleep>;
        status = "disabled";
 };
 
 &can2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan2>;
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&pinctrl_flexcan2_default>;
+       pinctrl-1 = <&pinctrl_flexcan2_sleep>;
        status = "disabled";
 };
 
 /* I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
 &i2c1 {
        clock-frequency = <100000>;
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_gpio>;
+       scl-gpios = <&gpio5 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "disabled";
 };
 
  */
 &i2c2 {
        clock-frequency = <100000>;
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c2>;
+       pinctrl-1 = <&pinctrl_i2c2_gpio>;
+       scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 
        pmic: pfuze100@8 {
  */
 &i2c3 {
        clock-frequency = <100000>;
-       pinctrl-names = "default", "recovery";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c3>;
-       pinctrl-1 = <&pinctrl_i2c3_recovery>;
+       pinctrl-1 = <&pinctrl_i2c3_gpio>;
        scl-gpios = <&gpio3 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio3 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "disabled";
                >;
        };
 
-       pinctrl_flexcan1: flexcan1grp {
+       pinctrl_flexcan1_default: flexcan1defgrp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b0
                        MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x1b0b0
                >;
        };
 
-       pinctrl_flexcan2: flexcan2grp {
+       pinctrl_flexcan1_sleep: flexcan1slpgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x0
+                       MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x0
+               >;
+       };
+
+       pinctrl_flexcan2_default: flexcan2defgrp {
                fsl,pins = <
                        MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0
                        MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0
                >;
        };
+       pinctrl_flexcan2_sleep: flexcan2slpgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x0
+                       MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x0
+               >;
+       };
 
        pinctrl_gpio_bl_on: gpioblon {
                fsl,pins = <
                >;
        };
 
+       pinctrl_i2c1_gpio: i2c1gpiogrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x4001b8b1
+                       MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x4001b8b1
+               >;
+       };
+
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
                        MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
                >;
        };
 
+       pinctrl_i2c2_gpio: i2c2gpiogrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x4001b8b1
+               >;
+       };
+
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
                        MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
                >;
        };
 
-       pinctrl_i2c3_recovery: i2c3recoverygrp {
+       pinctrl_i2c3_gpio: i2c3gpiogrp {
                fsl,pins = <
                        MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x4001b8b1
                        MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x4001b8b1
index 4738c3c..b78ed79 100644 (file)
@@ -1,66 +1,56 @@
-/*
- * Copyright 2015 Armadeus Systems
- *
- * 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.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this file; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright 2015 Armadeus Systems <support@armadeus.com>
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
+/ {
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               vin-supply = <&reg_3p3v>;
+       };
+
+       usdhc1_pwrseq: usdhc1-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
+               post-power-on-delay-ms = <15>;
+               power-off-delay-us = <70>;
+       };
+};
+
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
        phy-mode = "rgmii-id";
        phy-reset-duration = <10>;
        phy-reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
+       phy-handle = <&ethphy1>;
        status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1: ethernet-phy@1 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <1>;
+                       interrupt-parent = <&gpio1>;
+                       interrupts = <28 IRQ_TYPE_LEVEL_LOW>;
+                       status = "okay";
+               };
+       };
 };
 
 /* Bluetooth */
 &uart2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2>;
+       uart-has-rtscts;
        status = "okay";
 };
 
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
+       bus-width = <4>;
+       mmc-pwrseq = <&usdhc1_pwrseq>;
+       vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_1p8v>;
+       cap-power-off-card;
+       keep-power-in-suspend;
        non-removable;
        status = "okay";
 
 };
 
 &iomuxc {
-       apf6 {
-               pinctrl_enet: enetgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b8b0
-                               MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
-                               MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x1b0b0
-                               MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24       0x130b0
-                               MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28       0x130b0
-                               MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x1b030
-                               MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x1b030
-                               MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x1b030
-                               MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x1b030
-                               MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x1b030
-                               MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x1b030
-                               MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x13030
-                               MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x1b030
-                               MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x13030
-                               MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1f030
-                               MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1f030
-                               MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x13030
-                       >;
-               };
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b8b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x1b0b0
+                       MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24       0x130b0
+                       MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28       0x130b0
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x1b030
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x1b030
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x1b030
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x1b030
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x1b030
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x1b030
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x13030
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x1b030
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x13030
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1f030
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1f030
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x13030
+               >;
+       };
 
-               pinctrl_uart2: uart2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA      0x1b0b0
-                               MX6QDL_PAD_SD4_DAT5__UART2_RTS_B        0x1b0b0
-                               MX6QDL_PAD_SD4_DAT6__UART2_CTS_B        0x1b0b0
-                               MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA      0x1b0b0
-                               MX6QDL_PAD_SD4_DAT3__GPIO2_IO11         0x130b0 /* BT_EN */
-                       >;
-               };
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA      0x1b0b0
+                       MX6QDL_PAD_SD4_DAT5__UART2_RTS_B        0x1b0b0
+                       MX6QDL_PAD_SD4_DAT6__UART2_CTS_B        0x1b0b0
+                       MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA      0x1b0b0
+                       MX6QDL_PAD_SD4_DAT3__GPIO2_IO11         0x130b0 /* BT_EN */
+               >;
+       };
 
-               pinctrl_usdhc1: usdhc1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD1_CMD__SD1_CMD     0x17059
-                               MX6QDL_PAD_SD1_CLK__SD1_CLK     0x10059
-                               MX6QDL_PAD_SD1_DAT0__SD1_DATA0  0x17059
-                               MX6QDL_PAD_SD1_DAT1__SD1_DATA1  0x17059
-                               MX6QDL_PAD_SD1_DAT2__SD1_DATA2  0x17059
-                               MX6QDL_PAD_SD1_DAT3__SD1_DATA3  0x17059
-                               MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x1b0b0 /* WL_EN */
-                               MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0 /* WL_IRQ */
-                       >;
-               };
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CMD__SD1_CMD     0x17059
+                       MX6QDL_PAD_SD1_CLK__SD1_CLK     0x10059
+                       MX6QDL_PAD_SD1_DAT0__SD1_DATA0  0x17059
+                       MX6QDL_PAD_SD1_DAT1__SD1_DATA1  0x17059
+                       MX6QDL_PAD_SD1_DAT2__SD1_DATA2  0x17059
+                       MX6QDL_PAD_SD1_DAT3__SD1_DATA3  0x17059
+                       MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x130b0 /* WL_EN */
+                       MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x130b0 /* WL_IRQ */
+               >;
+       };
 
-               pinctrl_usdhc3: usdhc3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD3_CMD__SD3_CMD     0x17059
-                               MX6QDL_PAD_SD3_CLK__SD3_CLK     0x10059
-                               MX6QDL_PAD_SD3_DAT0__SD3_DATA0  0x17059
-                               MX6QDL_PAD_SD3_DAT1__SD3_DATA1  0x17059
-                               MX6QDL_PAD_SD3_DAT2__SD3_DATA2  0x17059
-                               MX6QDL_PAD_SD3_DAT3__SD3_DATA3  0x17059
-                               MX6QDL_PAD_SD3_DAT4__SD3_DATA4  0x17059
-                               MX6QDL_PAD_SD3_DAT5__SD3_DATA5  0x17059
-                               MX6QDL_PAD_SD3_DAT6__SD3_DATA6  0x17059
-                               MX6QDL_PAD_SD3_DAT7__SD3_DATA7  0x17059
-                       >;
-               };
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD     0x17059
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK     0x10059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0  0x17059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1  0x17059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2  0x17059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3  0x17059
+                       MX6QDL_PAD_SD3_DAT4__SD3_DATA4  0x17059
+                       MX6QDL_PAD_SD3_DAT5__SD3_DATA5  0x17059
+                       MX6QDL_PAD_SD3_DAT6__SD3_DATA6  0x17059
+                       MX6QDL_PAD_SD3_DAT7__SD3_DATA7  0x17059
+               >;
        };
 };
index 9fc1fa4..b8e74ab 100644 (file)
@@ -1,49 +1,6 @@
-/*
- * Copyright 2015 Armadeus Systems
- *
- * 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.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this file; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright 2015 Armadeus Systems <support@armadeus.com>
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
                stdout-path = &uart4;
        };
 
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm3 0 191000>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <0>;
+               power-supply = <&reg_5v>;
+       };
+
        disp0 {
                compatible = "fsl,imx-parallel-display";
-               interface-pix-fmt = "bgr666";
                pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_ipu1_disp1>;
-
-               display-timings {
-                       lw700 {
-                               clock-frequency = <33000033>;
-                               hactive = <800>;
-                               vactive = <480>;
-                               hback-porch = <96>;
-                               hfront-porch = <96>;
-                               vback-porch = <20>;
-                               vfront-porch = <21>;
-                               hsync-len = <64>;
-                               vsync-len = <4>;
-                               hsync-active = <1>;
-                               vsync-active = <1>;
-                               de-active = <1>;
-                               pixelclk-active = <1>;
-                       };
-               };
+               pinctrl-0 = <&pinctrl_ipu1_disp0>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
 
-               port {
                        display_in: endpoint {
                                remote-endpoint = <&ipu1_di0_disp0>;
                        };
                };
+
+               port@1 {
+                       reg = <1>;
+
+                       display_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
        };
 
        gpio-keys {
                };
        };
 
+       panel {
+               compatible = "armadeus,st0700-adapt";
+               power-supply = <&reg_3p3v>;
+               backlight = <&backlight>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&display_out>;
+                       };
+               };
+       };
+
        reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "3P3V";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                regulator-always-on;
+               vin-supply = <&reg_5v>;
        };
 
-       reg_usbh1_vbus: regulator-usb-h1-vbus {
+       reg_5v: regulator-5v {
                compatible = "regulator-fixed";
-               regulator-name = "usb_h1_vbus";
+               regulator-name = "5V";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                regulator-always-on;
 &can2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_flexcan2>;
+       xceiver-supply = <&reg_5v>;
        status = "okay";
 };
 
                VDDA-supply = <&reg_3p3v>;
                VDDIO-supply = <&reg_3p3v>;
        };
+
+       rtc@6f {
+               compatible = "microchip,mcp7940x";
+               reg = <0x6f>;
+       };
 };
 
 &i2c3 {
 };
 
 &usbh1 {
-       vbus-supply = <&reg_usbh1_vbus>;
+       vbus-supply = <&reg_5v>;
        phy_type = "utmi";
        status = "okay";
 };
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gpios>;
 
-       apf6dev {
-               pinctrl_audmux: audmuxgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT4__AUD3_TXC  0x1b0b0
-                               MX6QDL_PAD_CSI0_DAT5__AUD3_TXD  0x1b0b0
-                               MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b0b0
-                               MX6QDL_PAD_CSI0_DAT7__AUD3_RXD  0x1b0b0
-                               MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x130b0
-                       >;
-               };
+       pinctrl_audmux: audmuxgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT4__AUD3_TXC  0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT5__AUD3_TXD  0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT7__AUD3_RXD  0x1b0b0
+                       MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x130b0
+               >;
+       };
 
-               pinctrl_ecspi1: ecspi1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1
-                               MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1
-                               MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1
-                               MX6QDL_PAD_KEY_ROW1__GPIO4_IO09  0x1b0b0
-                               MX6QDL_PAD_KEY_ROW2__GPIO4_IO11  0x1b0b0
-                               MX6QDL_PAD_KEY_COL2__GPIO4_IO10  0x1b0b0
-                       >;
-               };
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1
+                       MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1
+                       MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1
+                       MX6QDL_PAD_KEY_ROW1__GPIO4_IO09  0x1b0b0
+                       MX6QDL_PAD_KEY_ROW2__GPIO4_IO11  0x1b0b0
+                       MX6QDL_PAD_KEY_COL2__GPIO4_IO10  0x1b0b0
+               >;
+       };
 
-               pinctrl_flexcan2: flexcan2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0
-                               MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0
-                       >;
-               };
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0
+                       MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0
+               >;
+       };
 
-               pinctrl_gpio_keys: gpiokeysgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0
-                       >;
-               };
+       pinctrl_gpio_keys: gpiokeysgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0
+               >;
+       };
 
-               pinctrl_gpio_leds: gpioledsgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x130b0
-                       >;
-               };
+       pinctrl_gpio_leds: gpioledsgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x130b0
+               >;
+       };
 
-               pinctrl_gpios: gpiosgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_DI0_PIN4__GPIO4_IO20         0x100b1
-                               MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12      0x100b1
-                               MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13      0x100b1
-                               MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14      0x100b1
-                               MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15      0x100b1
-                               MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16      0x100b1
-                               MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17      0x100b1
-                               MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18      0x100b1
-                               MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21       0x100b1
-                       >;
-               };
+       pinctrl_gpios: gpiosgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DI0_PIN4__GPIO4_IO20         0x100b1
+                       MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12      0x100b1
+                       MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13      0x100b1
+                       MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14      0x100b1
+                       MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15      0x100b1
+                       MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16      0x100b1
+                       MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17      0x100b1
+                       MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18      0x100b1
+                       MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21       0x100b1
+               >;
+       };
 
-               pinctrl_gsm: gsmgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_4__GPIO1_IO04  0x130b0 /* GSM_POKIN */
-                               MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x130b0 /* GSM_PWR_EN */
-                       >;
-               };
+       pinctrl_gsm: gsmgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_4__GPIO1_IO04  0x130b0 /* GSM_POKIN */
+                       MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x130b0 /* GSM_PWR_EN */
+               >;
+       };
 
-               pinctrl_i2c1: i2c1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
-                               MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
-                       >;
-               };
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
+                       MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
+               >;
+       };
 
-               pinctrl_i2c2: i2c2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
-                               MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
-                       >;
-               };
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+               >;
+       };
 
-               pinctrl_i2c3: i2c3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
-                               MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
-                       >;
-               };
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+                       MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
+               >;
+       };
 
-               pinctrl_ipu1_disp1: ipu1disp1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK      0x100b1
-                               MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15            0x100b1
-                               MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02             0x100b1
-                               MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03             0x100b1
-                               MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00        0x100b1
-                               MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01        0x100b1
-                               MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02        0x100b1
-                               MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03        0x100b1
-                               MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04        0x100b1
-                               MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05        0x100b1
-                               MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06        0x100b1
-                               MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07        0x100b1
-                               MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08        0x100b1
-                               MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09        0x100b1
-                               MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10       0x100b1
-                               MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11       0x100b1
-                               MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12       0x100b1
-                               MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13       0x100b1
-                               MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14       0x100b1
-                               MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15       0x100b1
-                               MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16       0x100b1
-                               MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17       0x100b1
-                       >;
-               };
+       pinctrl_ipu1_disp0: ipu1disp0grp {
+               fsl,pins = <
+                       MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK      0x100b1
+                       MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15            0x100b1
+                       MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02             0x100b1
+                       MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03             0x100b1
+                       MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00        0x100b1
+                       MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01        0x100b1
+                       MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02        0x100b1
+                       MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03        0x100b1
+                       MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04        0x100b1
+                       MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05        0x100b1
+                       MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06        0x100b1
+                       MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07        0x100b1
+                       MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08        0x100b1
+                       MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09        0x100b1
+                       MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10       0x100b1
+                       MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11       0x100b1
+                       MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12       0x100b1
+                       MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13       0x100b1
+                       MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14       0x100b1
+                       MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15       0x100b1
+                       MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16       0x100b1
+                       MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17       0x100b1
+               >;
+       };
 
-               pinctrl_pcie: pciegrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x130b0
-                       >;
-               };
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x130b0
+               >;
+       };
 
-               pinctrl_pwm3: pwm3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
-                       >;
-               };
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+               >;
+       };
 
-               pinctrl_uart1: uart1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b0
-                               MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b0
-                       >;
-               };
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b0
+               >;
+       };
 
-               pinctrl_uart3: uart3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_EIM_D23__UART3_CTS_B   0x1b0b0
-                               MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b0
-                               MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b0
-                               MX6QDL_PAD_EIM_D31__UART3_RTS_B   0x1b0b0
-                       >;
-               };
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D23__UART3_CTS_B   0x1b0b0
+                       MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b0
+                       MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b0
+                       MX6QDL_PAD_EIM_D31__UART3_RTS_B   0x1b0b0
+               >;
+       };
 
-               pinctrl_uart4: uart4grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b0
-                               MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b0
-                       >;
-               };
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b0
+               >;
+       };
 
-               pinctrl_usbotg: usbotggrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x1b0b0
-                       >;
-               };
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x1b0b0
+               >;
+       };
 
-               pinctrl_usdhc2: usdhc2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD2_CMD__SD2_CMD    0x17059
-                               MX6QDL_PAD_SD2_CLK__SD2_CLK    0x10059
-                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
-                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
-                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
-                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
-                       >;
-               };
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_CMD__SD2_CMD    0x17059
+                       MX6QDL_PAD_SD2_CLK__SD2_CLK    0x10059
+                       MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+                       MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+                       MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+                       MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+               >;
+       };
 
-               pinctrl_spdif: spdifgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x1b0b0
-                       >;
-               };
+       pinctrl_spdif: spdifgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x1b0b0
+               >;
+       };
 
-               pinctrl_touchscreen: touchscreengrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x1b0b0
-                       >;
-               };
+       pinctrl_touchscreen: touchscreengrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x1b0b0
+               >;
        };
 };
index 019dda6..d03dff2 100644 (file)
  */
 &i2c2 {
        clock-frequency = <100000>;
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c2>;
+       pinctrl-0 = <&pinctrl_i2c2_gpio>;
+       scl-gpios = <&gpio2 30 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio3 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 
        pmic: pfuze100@8 {
  */
 &i2c3 {
        clock-frequency = <100000>;
-       pinctrl-names = "default", "recovery";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c3>;
-       pinctrl-1 = <&pinctrl_i2c3_recovery>;
+       pinctrl-1 = <&pinctrl_i2c3_gpio>;
        scl-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "disabled";
 };
 
 &iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh_oc_1>;
+
        pinctrl_audmux: audmuxgrp {
                fsl,pins = <
                        MX6QDL_PAD_KEY_COL0__AUD5_TXC   0x130b0
                >;
        };
 
+       pinctrl_i2c2_gpio: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x4001b8b1
+                       MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x4001b8b1
+               >;
+       };
+
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
                >;
        };
 
-       pinctrl_i2c3_recovery: i2c3recoverygrp {
+       pinctrl_i2c3_gpio: i2c3gpiogrp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x4001b8b1
                        MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x4001b8b1
                >;
        };
 
+       pinctrl_usbh_oc_1: usbhoc1grp {
+               fsl,pins = <
+                       /* USBH_OC */
+                       MX6QDL_PAD_EIM_D30__GPIO3_IO30          0x1b0b0
+               >;
+       };
+
        pinctrl_spdif: spdifgrp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0
                >;
        };
 
+       pinctrl_usbc_id_1: usbc_id-1 {
+               fsl,pins = <
+                       /* USBC_ID */
+                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02         0x1b0b0
+               >;
+       };
+
        pinctrl_usdhc1: usdhc1grp {
                fsl,pins = <
                        MX6QDL_PAD_SD1_CMD__SD1_CMD     0x17071
index c23ba22..c38e86e 100644 (file)
        sound-digital {
                compatible = "simple-audio-card";
                simple-audio-card,name = "tda1997x-audio";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&sound_codec>;
+               simple-audio-card,frame-master = <&sound_codec>;
 
-               simple-audio-card,dai-link@0 {
-                       format = "i2s";
-
-                       cpu {
-                               sound-dai = <&ssi2>;
-                       };
+               sound_cpu: simple-audio-card,cpu {
+                       sound-dai = <&ssi2>;
+               };
 
-                       codec {
-                               bitclock-master;
-                               frame-master;
-                               sound-dai = <&hdmi_receiver>;
-                       };
+               sound_codec: simple-audio-card,codec {
+                       sound-dai = <&hdmi_receiver>;
                };
        };
 };
index 97f1659..de514eb 100644 (file)
        pinctrl-0 = <&pinctrl_i2c2>;
        status = "okay";
 
+       pca9535: gpio-expander@27 {
+               compatible = "nxp,pca9535";
+               reg = <0x27>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pca9535>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+       };
+
        eeprom@57 {
                compatible = "atmel,24c02";
                reg = <0x57>;
                        >;
                };
 
+               pinctrl_pca9535: pca9535grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_NANDF_CS3__GPIO6_IO16        0x17059
+                  >;
+               };
+
                pinctrl_uart1: uart1grp {
                        fsl,pins = <
                                MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA    0x1b0b1
index 776bfc7..828dd20 100644 (file)
                        >;
                };
 
+               pinctrl_usbotg: usbotg {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+                               MX6QDL_PAD_EIM_D22__USB_OTG_PWR 0x17059
+                               MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x17059
+                       >;
+               };
+
                pinctrl_usdhc3: usdhc3grp {
                        fsl,pins = <
                                MX6QDL_PAD_SD3_CMD__SD3_CMD             0x17059
        status = "okay";
 };
 
+&usbotg {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       status = "okay";
+};
+
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
index 2cfb411..c070893 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
        phy-mode = "rgmii-id";
+       phy-handle = <&ethphy>;
        phy-reset-gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
        status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy: ethernet-phy@1 {
+                       reg = <1>;
+               };
+       };
 };
 
 &mipi_csi {
index 93be00a..a2a4f33 100644 (file)
                compatible = "fsl,mma8451";
                reg = <0x1c>;
                interrupt-parent = <&gpio1>;
-               interrupt-names = "int1", "int2";
-               interrupts = <18 IRQ_TYPE_LEVEL_LOW>, <20 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-names = "INT2";
+               interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&reg_3p3v>;
+               vddio-supply = <&reg_3p3v>;
        };
 
        hpa2: amp@60 {
 &iomuxc {
        pinctrl_accel: accelgrp {
                fsl,pins = <
-                       MX6QDL_PAD_SD1_CMD__GPIO1_IO18          0x4001b000
                        MX6QDL_PAD_SD1_CLK__GPIO1_IO20          0x4001b000
                >;
        };
index 3a96b55..59c54e6 100644 (file)
                        anatop: anatop@20c8000 {
                                compatible = "fsl,imx6sl-anatop",
                                             "fsl,imx6q-anatop",
-                                            "syscon", "simple-bus";
+                                            "syscon", "simple-mfd";
                                reg = <0x020c8000 0x1000>;
                                interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>,
                                             <0 54 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/arch/arm/boot/dts/imx6sll-kobo-clarahd.dts b/arch/arm/boot/dts/imx6sll-kobo-clarahd.dts
new file mode 100644 (file)
index 0000000..7214d1c
--- /dev/null
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Device tree for the Kobo Clara HD ebook reader
+ *
+ * Name on mainboard is: 37NB-E60K00+4A4
+ * Serials start with: E60K02 (a number also seen in
+ * vendor kernel sources)
+ *
+ * This mainboard seems to be equipped with different SoCs.
+ * In the Kobo Clara HD ebook reader it is an i.MX6SLL
+ *
+ * Copyright 2019 Andreas Kemnade
+ * based on works
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "imx6sll.dtsi"
+#include "e60k02.dtsi"
+
+/ {
+       model = "Kobo Clara HD";
+       compatible = "kobo,clarahd", "fsl,imx6sll";
+};
+
+&clks {
+       assigned-clocks = <&clks IMX6SLL_CLK_PLL4_AUDIO_DIV>;
+       assigned-clock-rates = <393216000>;
+};
+
+&cpu0 {
+       arm-supply = <&dcdc3_reg>;
+       soc-supply = <&dcdc1_reg>;
+};
+
+&gpio_keys {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio_keys>;
+};
+
+&i2c1 {
+       pinctrl-names = "default","sleep";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_sleep>;
+};
+
+&i2c2 {
+       pinctrl-names = "default","sleep";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       pinctrl-1 = <&pinctrl_i2c2_sleep>;
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       pinctrl_gpio_keys: gpio-keysgrp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD1_DATA1__GPIO5_IO08        0x17059 /* PWR_SW */
+                       MX6SLL_PAD_SD1_DATA4__GPIO5_IO12        0x17059 /* HALL_EN */
+               >;
+       };
+
+       pinctrl_hog: hoggrp {
+               fsl,pins = <
+                       MX6SLL_PAD_LCD_DATA00__GPIO2_IO20       0x79
+                       MX6SLL_PAD_LCD_DATA01__GPIO2_IO21       0x79
+                       MX6SLL_PAD_LCD_DATA02__GPIO2_IO22       0x79
+                       MX6SLL_PAD_LCD_DATA03__GPIO2_IO23       0x79
+                       MX6SLL_PAD_LCD_DATA04__GPIO2_IO24       0x79
+                       MX6SLL_PAD_LCD_DATA05__GPIO2_IO25       0x79
+                       MX6SLL_PAD_LCD_DATA06__GPIO2_IO26       0x79
+                       MX6SLL_PAD_LCD_DATA07__GPIO2_IO27       0x79
+                       MX6SLL_PAD_LCD_DATA08__GPIO2_IO28       0x79
+                       MX6SLL_PAD_LCD_DATA09__GPIO2_IO29       0x79
+                       MX6SLL_PAD_LCD_DATA10__GPIO2_IO30       0x79
+                       MX6SLL_PAD_LCD_DATA11__GPIO2_IO31       0x79
+                       MX6SLL_PAD_LCD_DATA12__GPIO3_IO00       0x79
+                       MX6SLL_PAD_LCD_DATA13__GPIO3_IO01       0x79
+                       MX6SLL_PAD_LCD_DATA14__GPIO3_IO02       0x79
+                       MX6SLL_PAD_LCD_DATA15__GPIO3_IO03       0x79
+                       MX6SLL_PAD_LCD_DATA16__GPIO3_IO04       0x79
+                       MX6SLL_PAD_LCD_DATA17__GPIO3_IO05       0x79
+                       MX6SLL_PAD_LCD_DATA18__GPIO3_IO06       0x79
+                       MX6SLL_PAD_LCD_DATA19__GPIO3_IO07       0x79
+                       MX6SLL_PAD_LCD_DATA20__GPIO3_IO08       0x79
+                       MX6SLL_PAD_LCD_DATA21__GPIO3_IO09       0x79
+                       MX6SLL_PAD_LCD_DATA22__GPIO3_IO10       0x79
+                       MX6SLL_PAD_LCD_DATA23__GPIO3_IO11       0x79
+                       MX6SLL_PAD_LCD_CLK__GPIO2_IO15          0x79
+                       MX6SLL_PAD_LCD_ENABLE__GPIO2_IO16       0x79
+                       MX6SLL_PAD_LCD_HSYNC__GPIO2_IO17        0x79
+                       MX6SLL_PAD_LCD_VSYNC__GPIO2_IO18        0x79
+                       MX6SLL_PAD_LCD_RESET__GPIO2_IO19        0x79
+                       MX6SLL_PAD_KEY_COL3__GPIO3_IO30         0x79
+                       MX6SLL_PAD_KEY_ROW7__GPIO4_IO07         0x79
+                       MX6SLL_PAD_ECSPI2_MOSI__GPIO4_IO13      0x79
+                       MX6SLL_PAD_KEY_COL5__GPIO4_IO02         0x79
+                       MX6SLL_PAD_KEY_ROW6__GPIO4_IO05         0x79
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6SLL_PAD_I2C1_SCL__I2C1_SCL   0x4001f8b1
+                       MX6SLL_PAD_I2C1_SDA__I2C1_SDA   0x4001f8b1
+               >;
+       };
+
+       pinctrl_i2c1_sleep: i2c1grp-sleep {
+               fsl,pins = <
+                       MX6SLL_PAD_I2C1_SCL__I2C1_SCL   0x400108b1
+                       MX6SLL_PAD_I2C1_SDA__I2C1_SDA   0x400108b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6SLL_PAD_I2C2_SCL__I2C2_SCL   0x4001f8b1
+                       MX6SLL_PAD_I2C2_SDA__I2C2_SDA   0x4001f8b1
+               >;
+       };
+
+       pinctrl_i2c2_sleep: i2c2grp-sleep {
+               fsl,pins = <
+                       MX6SLL_PAD_I2C2_SCL__I2C2_SCL   0x400108b1
+                       MX6SLL_PAD_I2C2_SDA__I2C2_SDA   0x400108b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6SLL_PAD_REF_CLK_24M__I2C3_SCL 0x4001f8b1
+                       MX6SLL_PAD_REF_CLK_32K__I2C3_SDA 0x4001f8b1
+               >;
+       };
+
+       pinctrl_led: ledgrp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD1_DATA6__GPIO5_IO07 0x17059
+               >;
+       };
+
+       pinctrl_lm3630a_bl_gpio: lm3630a-bl-gpiogrp {
+               fsl,pins = <
+                       MX6SLL_PAD_EPDC_PWR_CTRL3__GPIO2_IO10   0x10059 /* HWEN */
+               >;
+       };
+
+       pinctrl_ricoh_gpio: ricoh-gpiogrp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD1_CLK__GPIO5_IO15  0x1b8b1 /* ricoh619 chg */
+                       MX6SLL_PAD_SD1_DATA0__GPIO5_IO11 0x1b8b1 /* ricoh619 irq */
+                       MX6SLL_PAD_KEY_COL2__GPIO3_IO28 0x1b8b1 /* ricoh619 bat_low_int */
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6SLL_PAD_UART1_TXD__UART1_DCE_TX 0x1b0b1
+                       MX6SLL_PAD_UART1_RXD__UART1_DCE_RX 0x1b0b1
+               >;
+       };
+
+       pinctrl_usbotg1: usbotg1grp {
+               fsl,pins = <
+                       MX6SLL_PAD_EPDC_PWR_COM__USB_OTG1_ID 0x17059
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD2_CMD__SD2_CMD             0x17059
+                       MX6SLL_PAD_SD2_CLK__SD2_CLK             0x13059
+                       MX6SLL_PAD_SD2_DATA0__SD2_DATA0         0x17059
+                       MX6SLL_PAD_SD2_DATA1__SD2_DATA1         0x17059
+                       MX6SLL_PAD_SD2_DATA2__SD2_DATA2         0x17059
+                       MX6SLL_PAD_SD2_DATA3__SD2_DATA3         0x17059
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2grp-100mhz {
+               fsl,pins = <
+                       MX6SLL_PAD_SD2_CMD__SD2_CMD             0x170b9
+                       MX6SLL_PAD_SD2_CLK__SD2_CLK             0x130b9
+                       MX6SLL_PAD_SD2_DATA0__SD2_DATA0         0x170b9
+                       MX6SLL_PAD_SD2_DATA1__SD2_DATA1         0x170b9
+                       MX6SLL_PAD_SD2_DATA2__SD2_DATA2         0x170b9
+                       MX6SLL_PAD_SD2_DATA3__SD2_DATA3         0x170b9
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2grp-200mhz {
+               fsl,pins = <
+                       MX6SLL_PAD_SD2_CMD__SD2_CMD             0x170f9
+                       MX6SLL_PAD_SD2_CLK__SD2_CLK             0x130f9
+                       MX6SLL_PAD_SD2_DATA0__SD2_DATA0         0x170f9
+                       MX6SLL_PAD_SD2_DATA1__SD2_DATA1         0x170f9
+                       MX6SLL_PAD_SD2_DATA2__SD2_DATA2         0x170f9
+                       MX6SLL_PAD_SD2_DATA3__SD2_DATA3         0x170f9
+               >;
+       };
+
+       pinctrl_usdhc2_sleep: usdhc2grp-sleep {
+               fsl,pins = <
+                       MX6SLL_PAD_SD2_CMD__GPIO5_IO04          0x100f9
+                       MX6SLL_PAD_SD2_CLK__GPIO5_IO05          0x100f9
+                       MX6SLL_PAD_SD2_DATA0__GPIO5_IO01        0x100f9
+                       MX6SLL_PAD_SD2_DATA1__GPIO4_IO30        0x100f9
+                       MX6SLL_PAD_SD2_DATA2__GPIO5_IO03        0x100f9
+                       MX6SLL_PAD_SD2_DATA3__GPIO4_IO28        0x100f9
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD3_CMD__SD3_CMD     0x11059
+                       MX6SLL_PAD_SD3_CLK__SD3_CLK     0x11059
+                       MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x11059
+                       MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x11059
+                       MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x11059
+                       MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x11059
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3grp-100mhz {
+               fsl,pins = <
+                       MX6SLL_PAD_SD3_CMD__SD3_CMD     0x170b9
+                       MX6SLL_PAD_SD3_CLK__SD3_CLK     0x170b9
+                       MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x170b9
+                       MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x170b9
+                       MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x170b9
+                       MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170b9
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3grp-200mhz {
+               fsl,pins = <
+                       MX6SLL_PAD_SD3_CMD__SD3_CMD     0x170f9
+                       MX6SLL_PAD_SD3_CLK__SD3_CLK     0x170f9
+                       MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x170f9
+                       MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x170f9
+                       MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x170f9
+                       MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170f9
+               >;
+       };
+
+       pinctrl_usdhc3_sleep: usdhc3grp-sleep {
+               fsl,pins = <
+                       MX6SLL_PAD_SD3_CMD__GPIO5_IO21  0x100c1
+                       MX6SLL_PAD_SD3_CLK__GPIO5_IO18  0x100c1
+                       MX6SLL_PAD_SD3_DATA0__GPIO5_IO19        0x100c1
+                       MX6SLL_PAD_SD3_DATA1__GPIO5_IO20        0x100c1
+                       MX6SLL_PAD_SD3_DATA2__GPIO5_IO16        0x100c1
+                       MX6SLL_PAD_SD3_DATA3__GPIO5_IO17        0x100c1
+               >;
+       };
+
+       pinctrl_wifi_power: wifi-powergrp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD2_DATA6__GPIO4_IO29        0x10059         /* WIFI_3V3_ON */
+               >;
+       };
+
+       pinctrl_wifi_reset: wifi-resetgrp {
+               fsl,pins = <
+                       MX6SLL_PAD_SD2_DATA7__GPIO5_IO00        0x10059         /* WIFI_RST */
+               >;
+       };
+};
+
+&leds {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_led>;
+};
+
+&lm3630a {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lm3630a_bl_gpio>;
+};
+
+&reg_wifi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wifi_power>;
+};
+
+&ricoh619 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ricoh_gpio>;
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+};
+
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz","sleep";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+       pinctrl-3 = <&pinctrl_usdhc2_sleep>;
+};
+
+&usdhc3 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz","sleep";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+       pinctrl-3 = <&pinctrl_usdhc3_sleep>;
+};
+
+&wifi_pwrseq {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wifi_reset>;
+};
index 13c7ba7..85aa8bb 100644 (file)
                        anatop: anatop@20c8000 {
                                compatible = "fsl,imx6sll-anatop",
                                             "fsl,imx6q-anatop",
-                                            "syscon", "simple-bus";
+                                            "syscon", "simple-mfd";
                                reg = <0x020c8000 0x4000>;
                                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
index 531a52c..59bad60 100644 (file)
 
                        anatop: anatop@20c8000 {
                                compatible = "fsl,imx6sx-anatop", "fsl,imx6q-anatop",
-                                            "syscon", "simple-bus";
+                                            "syscon", "simple-mfd";
                                reg = <0x020c8000 0x1000>;
                                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
index c2a9dd5..1506eb1 100644 (file)
                enable-active-high;
        };
 
+       reg_sensors: regulator-sensors {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_sensors_reg>;
+               regulator-name = "sensors-supply";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio5 2 GPIO_ACTIVE_LOW>;
+       };
+
        reg_can_3v3: regulator-can-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "can-3v3";
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
 
-       mag3110@e {
+       magnetometer@e {
                compatible = "fsl,mag3110";
                reg = <0x0e>;
+               vdd-supply = <&reg_sensors>;
+               vddio-supply = <&reg_sensors>;
        };
 };
 
 
 &usbotg1 {
        dr_mode = "otg";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usb_otg1>;
        status = "okay";
 };
 
                >;
        };
 
+       pinctrl_sensors_reg: sensorsreggrp {
+               fsl,pins = <
+                       MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02      0x1b0b0
+               >;
+       };
+
        pinctrl_pwm1: pwm1grp {
                fsl,pins = <
                        MX6UL_PAD_GPIO1_IO08__PWM1_OUT   0x110b0
                >;
        };
 
+       pinctrl_usb_otg1: usbotg1grp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID    0x17059
+               >;
+       };
+
        pinctrl_usdhc1: usdhc1grp {
                fsl,pins = <
                        MX6UL_PAD_SD1_CMD__USDHC1_CMD           0x17059
diff --git a/arch/arm/boot/dts/imx6ul-imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/imx6ul-imx6ull-opos6ul.dtsi
new file mode 100644 (file)
index 0000000..f2386dc
--- /dev/null
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+//
+// Copyright 2019 Armadeus Systems <support@armadeus.com>
+
+/ {
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0>; /* will be filled by U-Boot */
+       };
+
+       reg_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       usdhc3_pwrseq: usdhc3-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpio2 9 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet1>;
+       phy-mode = "rmii";
+       phy-reset-duration = <1>;
+       phy-reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+       phy-handle = <&ethphy1>;
+       phy-supply = <&reg_3v3>;
+       status = "okay";
+
+       mdio: mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1: ethernet-phy@1 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <1>;
+                       interrupt-parent = <&gpio4>;
+                       interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+                       status = "okay";
+               };
+       };
+};
+
+/* Bluetooth */
+&uart8 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart8>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+/* eMMC */
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       bus-width = <8>;
+       no-1-8-v;
+       non-removable;
+       status = "okay";
+};
+
+/* WiFi */
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       bus-width = <4>;
+       no-1-8-v;
+       non-removable;
+       mmc-pwrseq = <&usdhc3_pwrseq>;
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       brcmf: wifi@1 {
+               compatible = "brcm,bcm4329-fmac";
+               reg = <1>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-names = "host-wake";
+       };
+};
+
+&iomuxc {
+       pinctrl_enet1: enet1grp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO06__ENET1_MDIO        0x1b0b0
+                       MX6UL_PAD_GPIO1_IO07__ENET1_MDC         0x1b0b0
+                       MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER      0x130b0
+                       MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN      0x130b0
+                       MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x130b0
+                       MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x130b0
+                       MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
+                       MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
+                       MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN      0x1b0b0
+                       /* INT# */
+                       MX6UL_PAD_NAND_DQS__GPIO4_IO16          0x1b0b0
+                       /* RST# */
+                       MX6UL_PAD_NAND_DATA00__GPIO4_IO02       0x130b0
+                       MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b031
+               >;
+       };
+
+       pinctrl_uart8: uart8grp {
+               fsl,pins = <
+                       MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX     0x1b0b0
+                       MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX  0x1b0b0
+                       MX6UL_PAD_ENET2_RX_ER__UART8_DCE_RTS    0x1b0b0
+                       MX6UL_PAD_ENET2_TX_CLK__UART8_DCE_CTS   0x1b0b0
+                       /* BT_REG_ON */
+                       MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10       0x130b0
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX6UL_PAD_SD1_CMD__USDHC1_CMD           0x17059
+                       MX6UL_PAD_SD1_CLK__USDHC1_CLK           0x10059
+                       MX6UL_PAD_SD1_DATA0__USDHC1_DATA0       0x17059
+                       MX6UL_PAD_SD1_DATA1__USDHC1_DATA1       0x17059
+                       MX6UL_PAD_SD1_DATA2__USDHC1_DATA2       0x17059
+                       MX6UL_PAD_SD1_DATA3__USDHC1_DATA3       0x17059
+                       MX6UL_PAD_NAND_READY_B__USDHC1_DATA4    0x17059
+                       MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5      0x17059
+                       MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6      0x17059
+                       MX6UL_PAD_NAND_CLE__USDHC1_DATA7        0x17059
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6UL_PAD_LCD_DATA18__USDHC2_CMD        0x1b0b0
+                       MX6UL_PAD_LCD_DATA19__USDHC2_CLK        0x100b0
+                       MX6UL_PAD_LCD_DATA20__USDHC2_DATA0      0x1b0b0
+                       MX6UL_PAD_LCD_DATA21__USDHC2_DATA1      0x1b0b0
+                       MX6UL_PAD_LCD_DATA22__USDHC2_DATA2      0x1b0b0
+                       MX6UL_PAD_LCD_DATA23__USDHC2_DATA3      0x1b0b0
+                       /* WL_REG_ON */
+                       MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09    0x130b0
+                       /* WL_IRQ */
+                       MX6UL_PAD_ENET2_RX_DATA0__GPIO2_IO08    0x1b0b0
+               >;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6ul-imx6ull-opos6uldev.dtsi b/arch/arm/boot/dts/imx6ul-imx6ull-opos6uldev.dtsi
new file mode 100644 (file)
index 0000000..1896635
--- /dev/null
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+//
+// Copyright 2019 Armadeus Systems <support@armadeus.com>
+
+/ {
+       chosen {
+               stdout-path = &uart1;
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm3 0 191000>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <7>;
+               power-supply = <&reg_5v>;
+               status = "okay";
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_keys>;
+
+               user-button {
+                       label = "User button";
+                       gpios = <&gpio2 11 GPIO_ACTIVE_LOW>;
+                       linux,code = <BTN_MISC>;
+                       wakeup-source;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user-led {
+                       label = "User";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_led>;
+                       gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       onewire {
+               compatible = "w1-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_w1>;
+               gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+       };
+
+       panel: panel {
+               compatible = "armadeus,st0700-adapt";
+               power-supply = <&reg_3v3>;
+               backlight = <&backlight>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&lcdif_out>;
+                       };
+               };
+       };
+
+       reg_5v: regulator-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       reg_usbotg1_vbus: regulator-usbotg1vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usbotg1vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbotg1_vbus>;
+               gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_usbotg2_vbus: regulator-usbotg2vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usbotg2vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbotg2_vbus>;
+               gpio = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+};
+
+&adc1 {
+       vref-supply = <&reg_3v3>;
+       status = "okay";
+};
+
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       xceiver-supply = <&reg_5v>;
+       status = "okay";
+};
+
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       xceiver-supply = <&reg_5v>;
+       status = "okay";
+};
+
+&ecspi4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi4>;
+       cs-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>, <&gpio4 3 GPIO_ACTIVE_LOW>;
+       status = "okay";
+
+       spidev0: spi@0 {
+               compatible = "spidev";
+               reg = <0>;
+               spi-max-frequency = <5000000>;
+       };
+
+       spidev1: spi@1 {
+               compatible = "spidev";
+               reg = <1>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&lcdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lcdif>;
+       status = "okay";
+
+       port {
+               lcdif_out: endpoint {
+                       remote-endpoint = <&panel_in>;
+               };
+       };
+};
+
+&pwm3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm3>;
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "disabled";
+};
+
+&tsc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_tsc>;
+       xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+       measure-delay-time = <0xffff>;
+       pre-charge-time = <0xffff>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg1_id>;
+       vbus-supply = <&reg_usbotg1_vbus>;
+       dr_mode = "otg";
+       disable-over-current;
+       status = "okay";
+};
+
+&usbotg2 {
+       vbus-supply = <&reg_usbotg2_vbus>;
+       dr_mode = "host";
+       disable-over-current;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpios>;
+
+       pinctrl_ecspi4: ecspi4grp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_DATA04__ECSPI4_SCLK      0x1b0b0
+                       MX6UL_PAD_NAND_DATA05__ECSPI4_MOSI      0x1b0b0
+                       MX6UL_PAD_NAND_DATA06__ECSPI4_MISO      0x1b0b0
+                       MX6UL_PAD_NAND_DATA01__GPIO4_IO03       0x1b0b0
+                       MX6UL_PAD_NAND_DATA07__GPIO4_IO09       0x1b0b0
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX      0x0b0b0
+                       MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX      0x0b0b0
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX      0x0b0b0
+                       MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX      0x0b0b0
+               >;
+       };
+
+       pinctrl_gpios: gpiosgrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x0b0b0
+                       MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25     0x0b0b0
+                       MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24     0x0b0b0
+                       MX6UL_PAD_NAND_RE_B__GPIO4_IO00         0x0b0b0
+                       MX6UL_PAD_GPIO1_IO08__GPIO1_IO08        0x0b0b0
+                       MX6UL_PAD_UART1_CTS_B__GPIO1_IO18       0x0b0b0
+                       MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x0b0b0
+                       MX6UL_PAD_NAND_WE_B__GPIO4_IO01         0x0b0b0
+               >;
+       };
+
+       pinctrl_gpio_keys: gpiokeysgrp {
+               fsl,pins = <
+                       MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11    0x0b0b0
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART4_RX_DATA__I2C1_SDA       0x4001b8b0
+                       MX6UL_PAD_UART4_TX_DATA__I2C1_SCL       0x4001b8b0
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART5_RX_DATA__I2C2_SDA       0x4001b8b0
+                       MX6UL_PAD_UART5_TX_DATA__I2C2_SCL       0x4001b8b0
+               >;
+       };
+
+       pinctrl_lcdif: lcdifgrp {
+               fsl,pins = <
+                       MX6UL_PAD_LCD_CLK__LCDIF_CLK        0x100b1
+                       MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x100b1
+                       MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x100b1
+                       MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x100b1
+                       MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x100b1
+                       MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x100b1
+                       MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x100b1
+                       MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x100b1
+                       MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x100b1
+                       MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x100b1
+                       MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x100b1
+                       MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x100b1
+                       MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x100b1
+                       MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x100b1
+                       MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x100b1
+                       MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x100b1
+                       MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x100b1
+                       MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x100b1
+                       MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x100b1
+                       MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x100b1
+                       MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x100b1
+                       MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x100b1
+               >;
+       };
+
+       pinctrl_led: ledgrp {
+               fsl,pins = <
+                       MX6UL_PAD_LCD_RESET__GPIO3_IO04         0x0b0b0
+               >;
+       };
+
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_ALE__PWM3_OUT            0x1b0b0
+               >;
+       };
+
+       pinctrl_tsc: tscgrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO01__GPIO1_IO01       0xb0
+                       MX6UL_PAD_GPIO1_IO02__GPIO1_IO02       0xb0
+                       MX6UL_PAD_GPIO1_IO03__GPIO1_IO03       0xb0
+                       MX6UL_PAD_GPIO1_IO04__GPIO1_IO04       0xb0
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX   0x1b0b1
+                       MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX   0x1b0b1
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX   0x1b0b1
+                       MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX   0x1b0b1
+               >;
+       };
+
+       pinctrl_usbotg1_id: usbotg1idgrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID    0x1b0b0
+               >;
+       };
+
+       pinctrl_usbotg1_vbus: usbotg1vbusgrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO05__GPIO1_IO05        0x1b0b0
+               >;
+       };
+};
index 0205fd5..5a3e06d 100644 (file)
 /dts-v1/;
 
 #include "imx6ul-kontron-n6310-som.dtsi"
+#include "imx6ul-kontron-n6x1x-s.dtsi"
 
 / {
        model = "Kontron N6310 S";
        compatible = "kontron,imx6ul-n6310-s", "kontron,imx6ul-n6310-som",
                     "fsl,imx6ul";
-
-       gpio-leds {
-               compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpio_leds>;
-
-               led1 {
-                       label = "debug-led1";
-                       gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
-                       default-state = "off";
-                       linux,default-trigger = "heartbeat";
-               };
-
-               led2 {
-                       label = "debug-led2";
-                       gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
-                       default-state = "off";
-               };
-
-               led3 {
-                       label = "debug-led3";
-                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
-                       default-state = "off";
-               };
-       };
-
-       pwm-beeper {
-               compatible = "pwm-beeper";
-               pwms = <&pwm8 0 5000>;
-       };
-
-       reg_3v3: regulator-3v3 {
-               compatible = "regulator-fixed";
-               regulator-name = "3v3";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
-
-       reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
-               compatible = "regulator-fixed";
-               regulator-name = "usb_otg1_vbus";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-       };
-
-       reg_vref_adc: regulator-vref-adc {
-               compatible = "regulator-fixed";
-               regulator-name = "vref-adc";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
-};
-
-&adc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_adc1>;
-       num-channels = <3>;
-       vref-supply = <&reg_vref_adc>;
-       status = "okay";
-};
-
-&can2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan2>;
-       status = "okay";
-};
-
-&ecspi1 {
-       cs-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi1>;
-       status = "okay";
-
-       eeprom@0 {
-               compatible = "anvo,anv32e61w", "atmel,at25";
-               reg = <0>;
-               spi-max-frequency = <20000000>;
-               spi-cpha;
-               spi-cpol;
-               pagesize = <1>;
-               size = <8192>;
-               address-width = <16>;
-       };
-};
-
-&fec1 {
-       pinctrl-0 = <&pinctrl_enet1>;
-       /delete-node/ mdio;
-};
-
-&fec2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_mdio>;
-       phy-mode = "rmii";
-       phy-handle = <&ethphy2>;
-       status = "okay";
-
-       mdio {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               ethphy1: ethernet-phy@1 {
-                       reg = <1>;
-                       micrel,led-mode = <0>;
-                       clocks = <&clks IMX6UL_CLK_ENET_REF>;
-                       clock-names = "rmii-ref";
-               };
-
-               ethphy2: ethernet-phy@2 {
-                       reg = <2>;
-                       micrel,led-mode = <0>;
-                       clocks = <&clks IMX6UL_CLK_ENET2_REF>;
-                       clock-names = "rmii-ref";
-               };
-       };
-};
-
-&i2c1 {
-       clock-frequency = <100000>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c1>;
-       status = "okay";
-};
-
-&i2c4 {
-       clock-frequency = <100000>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c4>;
-       status = "okay";
-
-       rtc@32 {
-               compatible = "epson,rx8900";
-               reg = <0x32>;
-       };
-};
-
-&pwm8 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_pwm8>;
-       status = "okay";
-};
-
-&snvs_poweroff {
-       status = "okay";
-};
-
-&uart1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart1>;
-       status = "okay";
-};
-
-&uart2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart2>;
-       linux,rs485-enabled-at-boot-time;
-       rs485-rx-during-tx;
-       rs485-rts-active-low;
-       uart-has-rtscts;
-       status = "okay";
-};
-
-&uart3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart3>;
-       fsl,uart-has-rtscts;
-       status = "okay";
-};
-
-&uart4 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart4>;
-       status = "okay";
-};
-
-&usbotg1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usbotg1>;
-       dr_mode = "otg";
-       srp-disable;
-       hnp-disable;
-       adp-disable;
-       vbus-supply = <&reg_usb_otg1_vbus>;
-       status = "okay";
-};
-
-&usbotg2 {
-       dr_mode = "host";
-       disable-over-current;
-       status = "okay";
-};
-
-&usdhc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
-       keep-power-in-suspend;
-       wakeup-source;
-       vmmc-supply = <&reg_3v3>;
-       voltage-ranges = <3300 3300>;
-       no-1-8-v;
-       status = "okay";
-};
-
-&usdhc2 {
-       pinctrl-names = "default", "state_100mhz", "state_200mhz";
-       pinctrl-0 = <&pinctrl_usdhc2>;
-       pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
-       pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
-       non-removable;
-       keep-power-in-suspend;
-       wakeup-source;
-       vmmc-supply = <&reg_3v3>;
-       voltage-ranges = <3300 3300>;
-       no-1-8-v;
-       status = "okay";
-};
-
-&wdog1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_wdog>;
-       fsl,ext-reset-output;
-       status = "okay";
-};
-
-&iomuxc {
-       pinctrl-0 = <&pinctrl_reset_out &pinctrl_gpio>;
-
-       pinctrl_adc1: adc1grp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO02__GPIO1_IO02        0xb0
-                       MX6UL_PAD_GPIO1_IO03__GPIO1_IO03        0xb0
-                       MX6UL_PAD_GPIO1_IO08__GPIO1_IO08        0xb0
-               >;
-       };
-
-       /* FRAM */
-       pinctrl_ecspi1: ecspi1grp {
-               fsl,pins = <
-                       MX6UL_PAD_CSI_DATA07__ECSPI1_MISO       0x100b1
-                       MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI       0x100b1
-                       MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK       0x100b1
-                       MX6UL_PAD_CSI_DATA05__GPIO4_IO26        0x100b1 /* ECSPI1-CS1 */
-               >;
-       };
-
-       pinctrl_enet2: enet2grp {
-               fsl,pins = <
-                       MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN      0x1b0b0
-                       MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER      0x1b0b0
-                       MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
-                       MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
-                       MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN      0x1b0b0
-                       MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
-                       MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
-                       MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2  0x4001b009
-               >;
-       };
-
-       pinctrl_enet2_mdio: enet2mdiogrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO07__ENET2_MDC         0x1b0b0
-                       MX6UL_PAD_GPIO1_IO06__ENET2_MDIO        0x1b0b0
-               >;
-       };
-
-       pinctrl_flexcan2: flexcan2grp{
-               fsl,pins = <
-                       MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX      0x1b020
-                       MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX      0x1b020
-               >;
-       };
-
-       pinctrl_gpio: gpiogrp {
-               fsl,pins = <
-                       MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05      0x1b0b0 /* DOUT1 */
-                       MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04      0x1b0b0 /* DIN1 */
-                       MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01      0x1b0b0 /* DOUT2 */
-                       MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00      0x1b0b0 /* DIN2 */
-               >;
-       };
-
-       pinctrl_gpio_leds: gpioledsgrp {
-               fsl,pins = <
-                       MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30     0x1b0b0 /* LED H14 */
-                       MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03      0x1b0b0 /* LED H15 */
-                       MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02      0x1b0b0 /* LED H16 */
-               >;
-       };
-
-       pinctrl_i2c1: i2c1grp {
-               fsl,pins = <
-                       MX6UL_PAD_CSI_PIXCLK__I2C1_SCL          0x4001b8b0
-                       MX6UL_PAD_CSI_MCLK__I2C1_SDA            0x4001b8b0
-               >;
-       };
-
-       pinctrl_i2c4: i2c4grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART2_TX_DATA__I2C4_SCL       0x4001f8b0
-                       MX6UL_PAD_UART2_RX_DATA__I2C4_SDA       0x4001f8b0
-               >;
-       };
-
-       pinctrl_pwm8: pwm8grp {
-               fsl,pins = <
-                       MX6UL_PAD_CSI_HSYNC__PWM8_OUT           0x110b0
-               >;
-       };
-
-       pinctrl_uart1: uart1grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX   0x1b0b1
-                       MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX   0x1b0b1
-               >;
-       };
-
-       pinctrl_uart2: uart2grp {
-               fsl,pins = <
-                       MX6UL_PAD_NAND_DATA04__UART2_DCE_TX     0x1b0b1
-                       MX6UL_PAD_NAND_DATA05__UART2_DCE_RX     0x1b0b1
-                       MX6UL_PAD_NAND_DATA06__UART2_DCE_CTS    0x1b0b1
-                       /*
-                        * mux unused RTS to make sure it doesn't cause
-                        * any interrupts when it is undefined
-                        */
-                       MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS    0x1b0b1
-               >;
-       };
-
-       pinctrl_uart3: uart3grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX   0x1b0b1
-                       MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX   0x1b0b1
-                       MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS    0x1b0b1
-                       MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS    0x1b0b1
-               >;
-       };
-
-       pinctrl_uart4: uart4grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX   0x1b0b1
-                       MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX   0x1b0b1
-               >;
-       };
-
-       pinctrl_usbotg1: usbotg1 {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO04__GPIO1_IO04        0x1b0b0
-               >;
-       };
-
-       pinctrl_usdhc1: usdhc1grp {
-               fsl,pins = <
-                       MX6UL_PAD_SD1_CMD__USDHC1_CMD           0x17059
-                       MX6UL_PAD_SD1_CLK__USDHC1_CLK           0x10059
-                       MX6UL_PAD_SD1_DATA0__USDHC1_DATA0       0x17059
-                       MX6UL_PAD_SD1_DATA1__USDHC1_DATA1       0x17059
-                       MX6UL_PAD_SD1_DATA2__USDHC1_DATA2       0x17059
-                       MX6UL_PAD_SD1_DATA3__USDHC1_DATA3       0x17059
-                       MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x100b1 /* SD1_CD */
-               >;
-       };
-
-       pinctrl_usdhc2: usdhc2grp {
-               fsl,pins = <
-                       MX6UL_PAD_NAND_RE_B__USDHC2_CLK         0x10059
-                       MX6UL_PAD_NAND_WE_B__USDHC2_CMD         0x17059
-                       MX6UL_PAD_NAND_DATA00__USDHC2_DATA0     0x17059
-                       MX6UL_PAD_NAND_DATA01__USDHC2_DATA1     0x17059
-                       MX6UL_PAD_NAND_DATA02__USDHC2_DATA2     0x17059
-                       MX6UL_PAD_NAND_DATA03__USDHC2_DATA3     0x17059
-               >;
-       };
-
-       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
-               fsl,pins = <
-                       MX6UL_PAD_NAND_RE_B__USDHC2_CLK         0x100b9
-                       MX6UL_PAD_NAND_WE_B__USDHC2_CMD         0x170b9
-                       MX6UL_PAD_NAND_DATA00__USDHC2_DATA0     0x170b9
-                       MX6UL_PAD_NAND_DATA01__USDHC2_DATA1     0x170b9
-                       MX6UL_PAD_NAND_DATA02__USDHC2_DATA2     0x170b9
-                       MX6UL_PAD_NAND_DATA03__USDHC2_DATA3     0x170b9
-               >;
-       };
-
-       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
-               fsl,pins = <
-                       MX6UL_PAD_NAND_RE_B__USDHC2_CLK         0x100f9
-                       MX6UL_PAD_NAND_WE_B__USDHC2_CMD         0x170f9
-                       MX6UL_PAD_NAND_DATA00__USDHC2_DATA0     0x170f9
-                       MX6UL_PAD_NAND_DATA01__USDHC2_DATA1     0x170f9
-                       MX6UL_PAD_NAND_DATA02__USDHC2_DATA2     0x170f9
-                       MX6UL_PAD_NAND_DATA03__USDHC2_DATA3     0x170f9
-               >;
-       };
-
-       pinctrl_wdog: wdoggrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO09__WDOG1_WDOG_ANY    0x30b0
-               >;
-       };
 };
index a896b23..47d3ce5 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #include "imx6ul.dtsi"
-#include <dt-bindings/gpio/gpio.h>
+#include "imx6ul-kontron-n6x1x-som-common.dtsi"
 
 / {
        model = "Kontron N6310 SOM";
        };
 };
 
-&ecspi2 {
-       cs-gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi2>;
-       status = "okay";
-
-       spi-flash@0 {
-               compatible = "mxicy,mx25v8035f", "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-               reg = <0>;
-       };
-};
-
-&fec1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_mdio>;
-       phy-mode = "rmii";
-       phy-handle = <&ethphy1>;
-       status = "okay";
-
-       mdio {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               ethphy1: ethernet-phy@1 {
-                       reg = <1>;
-                       micrel,led-mode = <0>;
-                       clocks = <&clks IMX6UL_CLK_ENET_REF>;
-                       clock-names = "rmii-ref";
-               };
-       };
-};
-
-&fec2 {
-       phy-mode = "rmii";
-       status = "disabled";
-};
-
 &qspi {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_qspi>;
-       status = "okay";
-
        spi-flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                };
        };
 };
-
-&iomuxc {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_reset_out>;
-
-       pinctrl_ecspi2: ecspi2grp {
-               fsl,pins = <
-                       MX6UL_PAD_CSI_DATA03__ECSPI2_MISO      0x100b1
-                       MX6UL_PAD_CSI_DATA02__ECSPI2_MOSI      0x100b1
-                       MX6UL_PAD_CSI_DATA00__ECSPI2_SCLK      0x100b1
-                       MX6UL_PAD_CSI_DATA01__GPIO4_IO22       0x100b1
-               >;
-       };
-
-       pinctrl_enet1: enet1grp {
-               fsl,pins = <
-                       MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN      0x1b0b0
-                       MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER      0x1b0b0
-                       MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
-                       MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
-                       MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN      0x1b0b0
-                       MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
-                       MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
-                       MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b009
-               >;
-       };
-
-       pinctrl_enet1_mdio: enet1mdiogrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO07__ENET1_MDC         0x1b0b0
-                       MX6UL_PAD_GPIO1_IO06__ENET1_MDIO        0x1b0b0
-               >;
-       };
-
-       pinctrl_qspi: qspigrp {
-               fsl,pins = <
-                       MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK        0x70a1
-                       MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00   0x70a1
-                       MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01     0x70a1
-                       MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02     0x70a1
-                       MX6UL_PAD_NAND_CLE__QSPI_A_DATA03       0x70a1
-                       MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B        0x70a1
-               >;
-       };
-
-       pinctrl_reset_out: rstoutgrp {
-               fsl,pins = <
-                       MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09      0x1b0b0
-               >;
-       };
-};
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6311-s.dts b/arch/arm/boot/dts/imx6ul-kontron-n6311-s.dts
new file mode 100644 (file)
index 0000000..239a1af
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ */
+
+/dts-v1/;
+
+#include "imx6ul-kontron-n6311-som.dtsi"
+#include "imx6ul-kontron-n6x1x-s.dtsi"
+
+/ {
+       model = "Kontron N6311 S";
+       compatible = "kontron,imx6ul-n6311-s", "kontron,imx6ul-n6311-som",
+                    "fsl,imx6ul";
+};
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6311-som.dtsi b/arch/arm/boot/dts/imx6ul-kontron-n6311-som.dtsi
new file mode 100644 (file)
index 0000000..a095a76
--- /dev/null
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ */
+
+#include "imx6ul.dtsi"
+#include "imx6ul-kontron-n6x1x-som-common.dtsi"
+
+/ {
+       model = "Kontron N6311 SOM";
+       compatible = "kontron,imx6ul-n6311-som", "fsl,imx6ul";
+
+       memory@80000000 {
+               reg = <0x80000000 0x20000000>;
+               device_type = "memory";
+       };
+};
+
+&qspi {
+       spi-flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spi-nand";
+               spi-max-frequency = <104000000>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
+               reg = <0>;
+
+               partition@0 {
+                       label = "ubi1";
+                       reg = <0x00000000 0x08000000>;
+               };
+
+               partition@8000000 {
+                       label = "ubi2";
+                       reg = <0x08000000 0x18000000>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6x1x-s.dtsi b/arch/arm/boot/dts/imx6ul-kontron-n6x1x-s.dtsi
new file mode 100644 (file)
index 0000000..f05e918
--- /dev/null
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ * Copyright (c) 2019 Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_leds>;
+
+               led1 {
+                       label = "debug-led1";
+                       gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+                       linux,default-trigger = "heartbeat";
+               };
+
+               led2 {
+                       label = "debug-led2";
+                       gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+
+               led3 {
+                       label = "debug-led3";
+                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+       };
+
+       pwm-beeper {
+               compatible = "pwm-beeper";
+               pwms = <&pwm8 0 5000>;
+       };
+
+       reg_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       reg_5v: regulator-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_otg1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_vref_adc: regulator-vref-adc {
+               compatible = "regulator-fixed";
+               regulator-name = "vref-adc";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+};
+
+&adc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_adc1>;
+       num-channels = <3>;
+       vref-supply = <&reg_vref_adc>;
+       status = "okay";
+};
+
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       status = "okay";
+};
+
+&ecspi1 {
+       cs-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       status = "okay";
+
+       eeprom@0 {
+               compatible = "anvo,anv32e61w", "atmel,at25";
+               reg = <0>;
+               spi-max-frequency = <20000000>;
+               spi-cpha;
+               spi-cpol;
+               pagesize = <1>;
+               size = <8192>;
+               address-width = <16>;
+       };
+};
+
+&fec1 {
+       pinctrl-0 = <&pinctrl_enet1>;
+       /delete-node/ mdio;
+};
+
+&fec2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_mdio>;
+       phy-mode = "rmii";
+       phy-handle = <&ethphy2>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1: ethernet-phy@1 {
+                       reg = <1>;
+                       micrel,led-mode = <0>;
+                       clocks = <&clks IMX6UL_CLK_ENET_REF>;
+                       clock-names = "rmii-ref";
+               };
+
+               ethphy2: ethernet-phy@2 {
+                       reg = <2>;
+                       micrel,led-mode = <0>;
+                       clocks = <&clks IMX6UL_CLK_ENET2_REF>;
+                       clock-names = "rmii-ref";
+               };
+       };
+};
+
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&i2c4 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       status = "okay";
+
+       rtc@32 {
+               compatible = "epson,rx8900";
+               reg = <0x32>;
+       };
+};
+
+&pwm8 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm8>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       linux,rs485-enabled-at-boot-time;
+       rs485-rx-during-tx;
+       rs485-rts-active-low;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       fsl,uart-has-rtscts;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       status = "okay";
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg1>;
+       dr_mode = "otg";
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       over-current-active-low;
+       vbus-supply = <&reg_usb_otg1_vbus>;
+       status = "okay";
+};
+
+&usbotg2 {
+       dr_mode = "host";
+       disable-over-current;
+       vbus-supply = <&reg_5v>;
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
+       keep-power-in-suspend;
+       wakeup-source;
+       vmmc-supply = <&reg_3v3>;
+       voltage-ranges = <3300 3300>;
+       no-1-8-v;
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+       non-removable;
+       keep-power-in-suspend;
+       wakeup-source;
+       vmmc-supply = <&reg_3v3>;
+       voltage-ranges = <3300 3300>;
+       no-1-8-v;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-0 = <&pinctrl_reset_out &pinctrl_gpio>;
+
+       pinctrl_adc1: adc1grp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO02__GPIO1_IO02        0xb0
+                       MX6UL_PAD_GPIO1_IO03__GPIO1_IO03        0xb0
+                       MX6UL_PAD_GPIO1_IO08__GPIO1_IO08        0xb0
+               >;
+       };
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX6UL_PAD_CSI_DATA07__ECSPI1_MISO       0x100b1
+                       MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI       0x100b1
+                       MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK       0x100b1
+                       MX6UL_PAD_CSI_DATA05__GPIO4_IO26        0x100b1 /* ECSPI1-CS1 */
+               >;
+       };
+
+       pinctrl_enet2: enet2grp {
+               fsl,pins = <
+                       MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN      0x1b0b0
+                       MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER      0x1b0b0
+                       MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
+                       MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
+                       MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN      0x1b0b0
+                       MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
+                       MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
+                       MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2  0x4001b009
+               >;
+       };
+
+       pinctrl_enet2_mdio: enet2mdiogrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO07__ENET2_MDC         0x1b0b0
+                       MX6UL_PAD_GPIO1_IO06__ENET2_MDIO        0x1b0b0
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp{
+               fsl,pins = <
+                       MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX      0x1b020
+                       MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX      0x1b020
+               >;
+       };
+
+       pinctrl_gpio: gpiogrp {
+               fsl,pins = <
+                       MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05      0x1b0b0 /* DOUT1 */
+                       MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04      0x1b0b0 /* DIN1 */
+                       MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01      0x1b0b0 /* DOUT2 */
+                       MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00      0x1b0b0 /* DIN2 */
+               >;
+       };
+
+       pinctrl_gpio_leds: gpioledsgrp {
+               fsl,pins = <
+                       MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30     0x1b0b0 /* LED H14 */
+                       MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03      0x1b0b0 /* LED H15 */
+                       MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02      0x1b0b0 /* LED H16 */
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6UL_PAD_CSI_PIXCLK__I2C1_SCL          0x4001b8b0
+                       MX6UL_PAD_CSI_MCLK__I2C1_SDA            0x4001b8b0
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART2_TX_DATA__I2C4_SCL       0x4001f8b0
+                       MX6UL_PAD_UART2_RX_DATA__I2C4_SDA       0x4001f8b0
+               >;
+       };
+
+       pinctrl_pwm8: pwm8grp {
+               fsl,pins = <
+                       MX6UL_PAD_CSI_HSYNC__PWM8_OUT           0x110b0
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX   0x1b0b1
+                       MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX   0x1b0b1
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_DATA04__UART2_DCE_TX     0x1b0b1
+                       MX6UL_PAD_NAND_DATA05__UART2_DCE_RX     0x1b0b1
+                       MX6UL_PAD_NAND_DATA06__UART2_DCE_CTS    0x1b0b1
+                       /*
+                        * mux unused RTS to make sure it doesn't cause
+                        * any interrupts when it is undefined
+                        */
+                       MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS    0x1b0b1
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX   0x1b0b1
+                       MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX   0x1b0b1
+                       MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS    0x1b0b1
+                       MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS    0x1b0b1
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX   0x1b0b1
+                       MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX   0x1b0b1
+               >;
+       };
+
+       pinctrl_usbotg1: usbotg1 {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO04__GPIO1_IO04        0x1b0b0
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX6UL_PAD_SD1_CMD__USDHC1_CMD           0x17059
+                       MX6UL_PAD_SD1_CLK__USDHC1_CLK           0x10059
+                       MX6UL_PAD_SD1_DATA0__USDHC1_DATA0       0x17059
+                       MX6UL_PAD_SD1_DATA1__USDHC1_DATA1       0x17059
+                       MX6UL_PAD_SD1_DATA2__USDHC1_DATA2       0x17059
+                       MX6UL_PAD_SD1_DATA3__USDHC1_DATA3       0x17059
+                       MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x100b1 /* SD1_CD */
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_RE_B__USDHC2_CLK         0x10059
+                       MX6UL_PAD_NAND_WE_B__USDHC2_CMD         0x17059
+                       MX6UL_PAD_NAND_DATA00__USDHC2_DATA0     0x17059
+                       MX6UL_PAD_NAND_DATA01__USDHC2_DATA1     0x17059
+                       MX6UL_PAD_NAND_DATA02__USDHC2_DATA2     0x17059
+                       MX6UL_PAD_NAND_DATA03__USDHC2_DATA3     0x17059
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_RE_B__USDHC2_CLK         0x100b9
+                       MX6UL_PAD_NAND_WE_B__USDHC2_CMD         0x170b9
+                       MX6UL_PAD_NAND_DATA00__USDHC2_DATA0     0x170b9
+                       MX6UL_PAD_NAND_DATA01__USDHC2_DATA1     0x170b9
+                       MX6UL_PAD_NAND_DATA02__USDHC2_DATA2     0x170b9
+                       MX6UL_PAD_NAND_DATA03__USDHC2_DATA3     0x170b9
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_RE_B__USDHC2_CLK         0x100f9
+                       MX6UL_PAD_NAND_WE_B__USDHC2_CMD         0x170f9
+                       MX6UL_PAD_NAND_DATA00__USDHC2_DATA0     0x170f9
+                       MX6UL_PAD_NAND_DATA01__USDHC2_DATA1     0x170f9
+                       MX6UL_PAD_NAND_DATA02__USDHC2_DATA2     0x170f9
+                       MX6UL_PAD_NAND_DATA03__USDHC2_DATA3     0x170f9
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO09__WDOG1_WDOG_ANY    0x30b0
+               >;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6x1x-som-common.dtsi b/arch/arm/boot/dts/imx6ul-kontron-n6x1x-som-common.dtsi
new file mode 100644 (file)
index 0000000..a17af4d
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ * Copyright (c) 2019 Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       chosen {
+               stdout-path = &uart4;
+       };
+};
+
+&ecspi2 {
+       cs-gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       status = "okay";
+
+       spi-flash@0 {
+               compatible = "mxicy,mx25v8035f", "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+               reg = <0>;
+       };
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_mdio>;
+       phy-mode = "rmii";
+       phy-handle = <&ethphy1>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1: ethernet-phy@1 {
+                       reg = <1>;
+                       micrel,led-mode = <0>;
+                       clocks = <&clks IMX6UL_CLK_ENET_REF>;
+                       clock-names = "rmii-ref";
+               };
+       };
+};
+
+&fec2 {
+       phy-mode = "rmii";
+       status = "disabled";
+};
+
+&qspi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_reset_out>;
+
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX6UL_PAD_CSI_DATA03__ECSPI2_MISO      0x100b1
+                       MX6UL_PAD_CSI_DATA02__ECSPI2_MOSI      0x100b1
+                       MX6UL_PAD_CSI_DATA00__ECSPI2_SCLK      0x100b1
+                       MX6UL_PAD_CSI_DATA01__GPIO4_IO22       0x100b1
+               >;
+       };
+
+       pinctrl_enet1: enet1grp {
+               fsl,pins = <
+                       MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN      0x1b0b0
+                       MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER      0x1b0b0
+                       MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
+                       MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
+                       MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN      0x1b0b0
+                       MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
+                       MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
+                       MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b009
+               >;
+       };
+
+       pinctrl_enet1_mdio: enet1mdiogrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO07__ENET1_MDC         0x1b0b0
+                       MX6UL_PAD_GPIO1_IO06__ENET1_MDIO        0x1b0b0
+               >;
+       };
+
+       pinctrl_qspi: qspigrp {
+               fsl,pins = <
+                       MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK        0x70a1
+                       MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00   0x70a1
+                       MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01     0x70a1
+                       MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02     0x70a1
+                       MX6UL_PAD_NAND_CLE__QSPI_A_DATA03       0x70a1
+                       MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B        0x70a1
+               >;
+       };
+
+       pinctrl_reset_out: rstoutgrp {
+               fsl,pins = <
+                       MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09      0x1b0b0
+               >;
+       };
+};
index cf7faf4..6ce84f9 100644 (file)
@@ -1,193 +1,6 @@
-/*
- * Copyright 2017 Armadeus Systems <support@armadeus.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.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this file; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+//
+// Copyright 2017 Armadeus Systems <support@armadeus.com>
 
 #include "imx6ul.dtsi"
-
-/ {
-       memory@80000000 {
-               device_type = "memory";
-               reg = <0x80000000 0>; /* will be filled by U-Boot */
-       };
-
-       reg_3v3: regulator-3v3 {
-               compatible = "regulator-fixed";
-               regulator-name = "3V3";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
-
-       usdhc3_pwrseq: usdhc3-pwrseq {
-               compatible = "mmc-pwrseq-simple";
-               reset-gpios = <&gpio2 9 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&fec1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_enet1>;
-       phy-mode = "rmii";
-       phy-reset-duration = <1>;
-       phy-reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
-       phy-handle = <&ethphy1>;
-       phy-supply = <&reg_3v3>;
-       status = "okay";
-
-       mdio: mdio {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               ethphy1: ethernet-phy@1 {
-                       compatible = "ethernet-phy-ieee802.3-c22";
-                       reg = <1>;
-                       interrupt-parent = <&gpio4>;
-                       interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
-                       status = "okay";
-               };
-       };
-};
-
-/* Bluetooth */
-&uart8 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart8>;
-       uart-has-rtscts;
-       status = "okay";
-};
-
-/* eMMC */
-&usdhc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc1>;
-       bus-width = <8>;
-       no-1-8-v;
-       non-removable;
-       status = "okay";
-};
-
-/* WiFi */
-&usdhc2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc2>;
-       bus-width = <4>;
-       no-1-8-v;
-       non-removable;
-       mmc-pwrseq = <&usdhc3_pwrseq>;
-       status = "okay";
-
-       #address-cells = <1>;
-       #size-cells = <0>;
-
-       brcmf: wifi@1 {
-               compatible = "brcm,bcm4329-fmac";
-               reg = <1>;
-               interrupt-parent = <&gpio2>;
-               interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-               interrupt-names = "host-wake";
-       };
-};
-
-&iomuxc {
-       pinctrl_enet1: enet1grp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO06__ENET1_MDIO        0x1b0b0
-                       MX6UL_PAD_GPIO1_IO07__ENET1_MDC         0x1b0b0
-                       MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER      0x130b0
-                       MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN      0x130b0
-                       MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x130b0
-                       MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x130b0
-                       MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
-                       MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
-                       MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN      0x1b0b0
-                       /* INT# */
-                       MX6UL_PAD_NAND_DQS__GPIO4_IO16          0x1b0b0
-                       /* RST# */
-                       MX6UL_PAD_NAND_DATA00__GPIO4_IO02       0x130b0
-                       MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b031
-               >;
-       };
-
-       pinctrl_uart8: uart8grp {
-               fsl,pins = <
-                       MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX     0x1b0b0
-                       MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX  0x1b0b0
-                       MX6UL_PAD_ENET2_RX_ER__UART8_DCE_RTS    0x1b0b0
-                       MX6UL_PAD_ENET2_TX_CLK__UART8_DCE_CTS   0x1b0b0
-                       /* BT_REG_ON */
-                       MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10       0x130b0
-               >;
-       };
-
-       pinctrl_usdhc1: usdhc1grp {
-               fsl,pins = <
-                       MX6UL_PAD_SD1_CMD__USDHC1_CMD           0x17059
-                       MX6UL_PAD_SD1_CLK__USDHC1_CLK           0x10059
-                       MX6UL_PAD_SD1_DATA0__USDHC1_DATA0       0x17059
-                       MX6UL_PAD_SD1_DATA1__USDHC1_DATA1       0x17059
-                       MX6UL_PAD_SD1_DATA2__USDHC1_DATA2       0x17059
-                       MX6UL_PAD_SD1_DATA3__USDHC1_DATA3       0x17059
-                       MX6UL_PAD_NAND_READY_B__USDHC1_DATA4    0x17059
-                       MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5      0x17059
-                       MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6      0x17059
-                       MX6UL_PAD_NAND_CLE__USDHC1_DATA7        0x17059
-               >;
-       };
-
-       pinctrl_usdhc2: usdhc2grp {
-               fsl,pins = <
-                       MX6UL_PAD_LCD_DATA18__USDHC2_CMD        0x1b0b0
-                       MX6UL_PAD_LCD_DATA19__USDHC2_CLK        0x100b0
-                       MX6UL_PAD_LCD_DATA20__USDHC2_DATA0      0x1b0b0
-                       MX6UL_PAD_LCD_DATA21__USDHC2_DATA1      0x1b0b0
-                       MX6UL_PAD_LCD_DATA22__USDHC2_DATA2      0x1b0b0
-                       MX6UL_PAD_LCD_DATA23__USDHC2_DATA3      0x1b0b0
-                       /* WL_REG_ON */
-                       MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09    0x130b0
-                       /* WL_IRQ */
-                       MX6UL_PAD_ENET2_RX_DATA0__GPIO2_IO08    0x1b0b0
-               >;
-       };
-};
+#include "imx6ul-imx6ull-opos6ul.dtsi"
index 8ecdb9a..375b98d 100644 (file)
-/*
- * Copyright 2017 Armadeus Systems <support@armadeus.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.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this file; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+//
+// Copyright 2017 Armadeus Systems <support@armadeus.com>
 
 /dts-v1/;
 #include "imx6ul-opos6ul.dtsi"
+#include "imx6ul-imx6ull-opos6uldev.dtsi"
 
 / {
-       model = "Armadeus Systems OPOS6UL SoM on OPOS6ULDev board";
-       compatible = "armadeus,opos6uldev", "armadeus,opos6ul", "fsl,imx6ul";
-
-       chosen {
-               stdout-path = &uart1;
-       };
-
-       backlight: backlight {
-               compatible = "pwm-backlight";
-               pwms = <&pwm3 0 191000>;
-               brightness-levels = <0 4 8 16 32 64 128 255>;
-               default-brightness-level = <7>;
-               power-supply = <&reg_5v>;
-               status = "okay";
-       };
-
-       gpio-keys {
-               compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpio_keys>;
-
-               user-button {
-                       label = "User button";
-                       gpios = <&gpio2 11 GPIO_ACTIVE_LOW>;
-                       linux,code = <BTN_MISC>;
-                       wakeup-source;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               user-led {
-                       label = "User";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_led>;
-                       gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
-                       linux,default-trigger = "heartbeat";
-               };
-       };
-
-       onewire {
-               compatible = "w1-gpio";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_w1>;
-               gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
-       };
-
-       panel: panel {
-               compatible = "armadeus,st0700-adapt";
-               power-supply = <&reg_3v3>;
-               backlight = <&backlight>;
-
-               port {
-                       panel_in: endpoint {
-                               remote-endpoint = <&lcdif_out>;
-                       };
-               };
-       };
-
-       reg_5v: regulator-5v {
-               compatible = "regulator-fixed";
-               regulator-name = "5V";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-       };
-
-       reg_usbotg1_vbus: regulator-usbotg1vbus {
-               compatible = "regulator-fixed";
-               regulator-name = "usbotg1vbus";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_usbotg1_vbus>;
-               gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-       };
-
-       reg_usbotg2_vbus: regulator-usbotg2vbus {
-               compatible = "regulator-fixed";
-               regulator-name = "usbotg2vbus";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_usbotg2_vbus>;
-               gpio = <&gpio5 9 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-       };
-};
-
-&adc1 {
-       vref-supply = <&reg_3v3>;
-       status = "okay";
-};
-
-&can1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan1>;
-       xceiver-supply = <&reg_5v>;
-       status = "okay";
-};
-
-&can2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan2>;
-       xceiver-supply = <&reg_5v>;
-       status = "okay";
-};
-
-&ecspi4 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi4>;
-       cs-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>, <&gpio4 3 GPIO_ACTIVE_LOW>;
-       status = "okay";
-
-       spidev0: spi@0 {
-               compatible = "spidev";
-               reg = <0>;
-               spi-max-frequency = <5000000>;
-       };
-
-       spidev1: spi@1 {
-               compatible = "spidev";
-               reg = <1>;
-               spi-max-frequency = <5000000>;
-       };
-};
-
-&i2c1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c1>;
-       clock_frequency = <400000>;
-       status = "okay";
-};
-
-&i2c2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c2>;
-       clock_frequency = <400000>;
-       status = "okay";
-};
-
-&lcdif {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_lcdif>;
-       status = "okay";
-
-       port {
-               lcdif_out: endpoint {
-                       remote-endpoint = <&panel_in>;
-               };
-       };
-};
-
-&pwm3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_pwm3>;
-       status = "okay";
-};
-
-&snvs_pwrkey {
-       status = "disabled";
-};
-
-&tsc {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_tsc>;
-       xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
-       measure-delay-time = <0xffff>;
-       pre-charge-time = <0xffff>;
-       status = "okay";
-};
-
-&uart1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart1>;
-       status = "okay";
-};
-
-&uart2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart2>;
-       status = "okay";
-};
-
-&usbotg1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usbotg1_id>;
-       vbus-supply = <&reg_usbotg1_vbus>;
-       dr_mode = "otg";
-       disable-over-current;
-       status = "okay";
-};
-
-&usbotg2 {
-       vbus-supply = <&reg_usbotg2_vbus>;
-       dr_mode = "host";
-       disable-over-current;
-       status = "okay";
+       model = "Armadeus Systems OPOS6UL SoM (i.MX6UL) on OPOS6ULDev board";
+       compatible = "armadeus,imx6ul-opos6uldev", "armadeus,imx6ul-opos6ul", "fsl,imx6ul";
 };
 
 &iomuxc {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpios>;
+       pinctrl-0 = <&pinctrl_gpios>, <&pinctrl_tamper_gpios>;
 
-       pinctrl_ecspi4: ecspi4grp {
+       pinctrl_tamper_gpios: tampergpiosgrp {
                fsl,pins = <
-                       MX6UL_PAD_NAND_DATA04__ECSPI4_SCLK      0x1b0b0
-                       MX6UL_PAD_NAND_DATA05__ECSPI4_MOSI      0x1b0b0
-                       MX6UL_PAD_NAND_DATA06__ECSPI4_MISO      0x1b0b0
-                       MX6UL_PAD_NAND_DATA01__GPIO4_IO03       0x1b0b0
-                       MX6UL_PAD_NAND_DATA07__GPIO4_IO09       0x1b0b0
-               >;
-       };
-
-       pinctrl_flexcan1: flexcan1grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX      0x0b0b0
-                       MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX      0x0b0b0
-               >;
-       };
-
-       pinctrl_flexcan2: flexcan2grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX      0x0b0b0
-                       MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX      0x0b0b0
-               >;
-       };
-
-       pinctrl_gpios: gpiosgrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x0b0b0
-                       MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25     0x0b0b0
-                       MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24     0x0b0b0
-                       MX6UL_PAD_NAND_RE_B__GPIO4_IO00         0x0b0b0
-                       MX6UL_PAD_GPIO1_IO08__GPIO1_IO08        0x0b0b0
-                       MX6UL_PAD_UART1_CTS_B__GPIO1_IO18       0x0b0b0
-                       MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x0b0b0
-                       MX6UL_PAD_NAND_WE_B__GPIO4_IO01         0x0b0b0
                        MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00      0x0b0b0
                        MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02      0x0b0b0
                        MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03      0x0b0b0
                >;
        };
 
-       pinctrl_gpio_keys: gpiokeysgrp {
-               fsl,pins = <
-                       MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11    0x0b0b0
-               >;
-       };
-
-       pinctrl_i2c1: i2c1grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART4_RX_DATA__I2C1_SDA       0x4001b8b0
-                       MX6UL_PAD_UART4_TX_DATA__I2C1_SCL       0x4001b8b0
-               >;
-       };
-
-       pinctrl_i2c2: i2c2grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART5_RX_DATA__I2C2_SDA       0x4001b8b0
-                       MX6UL_PAD_UART5_TX_DATA__I2C2_SCL       0x4001b8b0
-               >;
-       };
-
-       pinctrl_lcdif: lcdifgrp {
-               fsl,pins = <
-                       MX6UL_PAD_LCD_CLK__LCDIF_CLK        0x100b1
-                       MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x100b1
-                       MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x100b1
-                       MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x100b1
-                       MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x100b1
-                       MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x100b1
-                       MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x100b1
-                       MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x100b1
-                       MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x100b1
-                       MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x100b1
-                       MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x100b1
-                       MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x100b1
-                       MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x100b1
-                       MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x100b1
-                       MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x100b1
-                       MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x100b1
-                       MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x100b1
-                       MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x100b1
-                       MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x100b1
-                       MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x100b1
-                       MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x100b1
-                       MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x100b1
-               >;
-       };
-
-       pinctrl_led: ledgrp {
-               fsl,pins = <
-                       MX6UL_PAD_LCD_RESET__GPIO3_IO04         0x0b0b0
-               >;
-       };
-
-       pinctrl_pwm3: pwm3grp {
-               fsl,pins = <
-                       MX6UL_PAD_NAND_ALE__PWM3_OUT            0x1b0b0
-               >;
-       };
-
-       pinctrl_tsc: tscgrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO01__GPIO1_IO01       0xb0
-                       MX6UL_PAD_GPIO1_IO02__GPIO1_IO02       0xb0
-                       MX6UL_PAD_GPIO1_IO03__GPIO1_IO03       0xb0
-                       MX6UL_PAD_GPIO1_IO04__GPIO1_IO04       0xb0
-               >;
-       };
-
-       pinctrl_uart1: uart1grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX   0x1b0b1
-                       MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX   0x1b0b1
-               >;
-       };
-
-       pinctrl_uart2: uart2grp {
-               fsl,pins = <
-                       MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX   0x1b0b1
-                       MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX   0x1b0b1
-               >;
-       };
-
-       pinctrl_usbotg1_id: usbotg1idgrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID    0x1b0b0
-               >;
-       };
-
-       pinctrl_usbotg1_vbus: usbotg1vbusgrp {
-               fsl,pins = <
-                       MX6UL_PAD_GPIO1_IO05__GPIO1_IO05        0x1b0b0
-               >;
-       };
-
        pinctrl_usbotg2_vbus: usbotg2vbusgrp {
                fsl,pins = <
                        MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09      0x1b0b0
index 41f3b7f..88f631c 100644 (file)
@@ -20,7 +20,7 @@
         * Set the minimum memory size here and
         * let the bootloader set the real size.
         */
-       memory {
+       memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x8000000>;
        };
index f008036..d9fdca1 100644 (file)
 
                        anatop: anatop@20c8000 {
                                compatible = "fsl,imx6ul-anatop", "fsl,imx6q-anatop",
-                                            "syscon", "simple-bus";
+                                            "syscon", "simple-mfd";
                                reg = <0x020c8000 0x1000>;
                                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
                                clocks = <&clks IMX6UL_CLK_GPT2_BUS>,
                                         <&clks IMX6UL_CLK_GPT2_SERIAL>;
                                clock-names = "ipg", "per";
+                               status = "disabled";
                        };
 
                        sdma: sdma@20ec000 {
index b6147c7..a78849f 100644 (file)
@@ -8,6 +8,20 @@
                stdout-path = "serial0:115200n8";
        };
 
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_snvs_gpiokeys>;
+
+               power {
+                       label = "Wake-Up";
+                       gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+                       linux,code = <KEY_WAKEUP>;
+                       debounce-interval = <10>;
+                       wakeup-source;
+               };
+       };
+
        /* fixed crystal dedicated to mcp2515 */
        clk16m: clk16m {
                compatible = "fixed-clock";
index fb213be..95a11b8 100644 (file)
@@ -15,7 +15,7 @@
 &iomuxc {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3
-               &pinctrl_gpio4 &pinctrl_gpio5 &pinctrl_gpio6>;
+               &pinctrl_gpio4 &pinctrl_gpio5 &pinctrl_gpio6 &pinctrl_gpio7>;
 };
 
 &iomuxc_snvs {
index 038d8c9..a054543 100644 (file)
@@ -26,7 +26,7 @@
 &iomuxc {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3
-               &pinctrl_gpio4 &pinctrl_gpio5>;
+               &pinctrl_gpio4 &pinctrl_gpio5 &pinctrl_gpio7>;
 
 };
 
index d56728f..6d850d9 100644 (file)
        vref-supply = <&reg_module_3v3_avdd>;
 };
 
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       status = "disabled";
+};
+
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       status = "disabled";
+};
+
 /* Colibri SPI */
 &ecspi1 {
        cs-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>;
@@ -62,8 +74,9 @@
 };
 
 &fec2 {
-       pinctrl-names = "default";
+       pinctrl-names = "default", "sleep";
        pinctrl-0 = <&pinctrl_enet2>;
+       pinctrl-1 = <&pinctrl_enet2_sleep>;
        phy-mode = "rmii";
        phy-handle = <&ethphy1>;
        status = "okay";
        assigned-clock-rates = <0>, <198000000>;
 };
 
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+};
+
 &iomuxc {
        pinctrl_can_int: canint-grp {
                fsl,pins = <
                >;
        };
 
+       pinctrl_enet2_sleep: enet2sleepgrp {
+               fsl,pins = <
+                       MX6UL_PAD_GPIO1_IO06__GPIO1_IO06        0x0
+                       MX6UL_PAD_GPIO1_IO07__GPIO1_IO07        0x0
+                       MX6UL_PAD_ENET2_RX_DATA0__GPIO2_IO08    0x0
+                       MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09    0x0
+                       MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10       0x0
+                       MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15       0x0
+                       MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2  0x4001b031
+                       MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11    0x0
+                       MX6UL_PAD_ENET2_TX_DATA1__GPIO2_IO12    0x0
+                       MX6UL_PAD_ENET2_TX_EN__GPIO2_IO13       0x0
+               >;
+       };
+
        pinctrl_ecspi1_cs: ecspi1-cs-grp {
                fsl,pins = <
                        MX6UL_PAD_LCD_DATA21__GPIO3_IO26        0x000a0
                >;
        };
 
+       pinctrl_flexcan1: flexcan1-grp {
+               fsl,pins = <
+                       MX6UL_PAD_ENET1_RX_DATA0__FLEXCAN1_TX   0x1b020
+                       MX6UL_PAD_ENET1_RX_DATA1__FLEXCAN1_RX   0x1b020
+               >;
+       };
+
        pinctrl_flexcan2: flexcan2-grp {
                fsl,pins = <
                        MX6UL_PAD_ENET1_TX_DATA0__FLEXCAN2_RX   0x1b020
 
        pinctrl_gpio1: gpio1-grp {
                fsl,pins = <
-                       MX6UL_PAD_ENET1_RX_DATA0__GPIO2_IO00    0x74 /* SODIMM 55 */
-                       MX6UL_PAD_ENET1_RX_DATA1__GPIO2_IO01    0x74 /* SODIMM 63 */
                        MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25     0X14 /* SODIMM 77 */
                        MX6UL_PAD_JTAG_TCK__GPIO1_IO14          0x14 /* SODIMM 99 */
                        MX6UL_PAD_NAND_CE1_B__GPIO4_IO14        0x14 /* SODIMM 133 */
                >;
        };
 
+       pinctrl_gpio7: gpio7-grp { /* CAN1 */
+               fsl,pins = <
+                       MX6UL_PAD_ENET1_RX_DATA0__GPIO2_IO00    0x74 /* SODIMM 55 */
+                       MX6UL_PAD_ENET1_RX_DATA1__GPIO2_IO01    0x74 /* SODIMM 63 */
+               >;
+       };
+
        pinctrl_gpmi_nand: gpmi-nand-grp {
                fsl,pins = <
                        MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00   0x100a9
                        MX6UL_PAD_GPIO1_IO03__OSC32K_32K_OUT    0x14
                >;
        };
+
+       pinctrl_wdog: wdog-grp {
+               fsl,pins = <
+                       MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY    0x30b0
+               >;
+       };
 };
 
 &iomuxc_snvs {
 
        pinctrl_snvs_ad7879_int: snvs-ad7879-int-grp { /* TOUCH Interrupt */
                fsl,pins = <
-                       MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07     0x1b0b0
+                       MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07     0x100b0
                >;
        };
 
        pinctrl_snvs_reg_sd: snvs-reg-sd-grp {
                fsl,pins = <
-                       MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09     0x4001b8b0
+                       MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09     0x400100b0
                >;
        };
 
        pinctrl_snvs_usbc_det: snvs-usbc-det-grp {
                fsl,pins = <
-                       MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02     0x1b0b0
+                       MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02     0x130b0
                >;
        };
 
diff --git a/arch/arm/boot/dts/imx6ull-kontron-n6411-s.dts b/arch/arm/boot/dts/imx6ull-kontron-n6411-s.dts
new file mode 100644 (file)
index 0000000..57588a5
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2019 Kontron Electronics GmbH
+ */
+
+/dts-v1/;
+
+#include "imx6ull-kontron-n6411-som.dtsi"
+#include "imx6ul-kontron-n6x1x-s.dtsi"
+
+/ {
+       model = "Kontron N6411 S";
+       compatible = "kontron,imx6ull-n6411-s", "kontron,imx6ull-n6411-som",
+                    "fsl,imx6ull";
+};
diff --git a/arch/arm/boot/dts/imx6ull-kontron-n6411-som.dtsi b/arch/arm/boot/dts/imx6ull-kontron-n6411-som.dtsi
new file mode 100644 (file)
index 0000000..b7e9842
--- /dev/null
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ */
+
+#include "imx6ull.dtsi"
+#include "imx6ul-kontron-n6x1x-som-common.dtsi"
+
+/ {
+       model = "Kontron N6411 SOM";
+       compatible = "kontron,imx6ull-n6311-som", "fsl,imx6ull";
+
+       memory@80000000 {
+               reg = <0x80000000 0x20000000>;
+               device_type = "memory";
+       };
+};
+
+&qspi {
+       spi-flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spi-nand";
+               spi-max-frequency = <104000000>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
+               reg = <0>;
+
+               partition@0 {
+                       label = "ubi1";
+                       reg = <0x00000000 0x08000000>;
+               };
+
+               partition@8000000 {
+                       label = "ubi2";
+                       reg = <0x08000000 0x18000000>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/imx6ull-opos6ul.dtsi
new file mode 100644 (file)
index 0000000..155f941
--- /dev/null
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+//
+// Copyright 2019 Armadeus Systems <support@armadeus.com>
+
+#include "imx6ull.dtsi"
+#include "imx6ul-imx6ull-opos6ul.dtsi"
diff --git a/arch/arm/boot/dts/imx6ull-opos6uldev.dts b/arch/arm/boot/dts/imx6ull-opos6uldev.dts
new file mode 100644 (file)
index 0000000..198fdb7
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+//
+// Copyright 2019 Armadeus Systems <support@armadeus.com>
+
+/dts-v1/;
+#include "imx6ull-opos6ul.dtsi"
+#include "imx6ul-imx6ull-opos6uldev.dtsi"
+
+/ {
+       model = "Armadeus Systems OPOS6UL SoM (i.MX6ULL) on OPOS6ULDev board";
+       compatible = "armadeus,imx6ull-opos6uldev", "armadeus,imx6ull-opos6ul", "fsl,imx6ull";
+};
+
+&iomuxc_snvs {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_tamper_gpios>;
+
+       pinctrl_tamper_gpios: tampergpiosgrp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07     0x0b0b0
+                       MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08     0x0b0b0
+               >;
+       };
+
+       pinctrl_usbotg2_vbus: usbotg2vbusgrp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09     0x1b0b0
+               >;
+       };
+
+       pinctrl_w1: w1grp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01     0x0b0b0
+               >;
+       };
+};
index 3f27461..6aa123c 100644 (file)
                clock-frequency = <16000000>;
        };
 
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiokeys>;
+
+               power {
+                       label = "Wake-Up";
+                       gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+                       linux,code = <KEY_WAKEUP>;
+                       debounce-interval = <10>;
+                       wakeup-source;
+               };
+       };
+
        panel: panel {
                compatible = "edt,et057090dhu";
                backlight = <&bl>;
 &i2c4 {
        status = "okay";
 
+       /*
+        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
+        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
+        */
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiotouch>;
+               reg = <0x4a>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;         /* SODIMM 28 */
+               reset-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;     /* SODIMM 30 */
+               status = "disabled";
+       };
+
        /* M41T0M6 real time clock on carrier board */
        rtc: m41t0m6@68 {
                compatible = "st,m41t0";
        vmmc-supply = <&reg_3v3>;
        status = "okay";
 };
+
+&iomuxc {
+       pinctrl_gpiotouch: touchgpios {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO09__GPIO1_IO9          0x74
+                       MX7D_PAD_GPIO1_IO10__GPIO1_IO10         0x14
+               >;
+       };
+};
index 917eb0b..d05be3f 100644 (file)
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_cd_usdhc1>;
-       no-1-8-v;
        cd-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
        disable-wp;
        vqmmc-supply = <&reg_LDO2>;
                >;
        };
 
+       pinctrl_usdhc1_100mhz: usdhc1grp_100mhz {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CMD__SD1_CMD       0x5a
+                       MX7D_PAD_SD1_CLK__SD1_CLK       0x1a
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0   0x5a
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1   0x5a
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2   0x5a
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3   0x5a
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1grp_200mhz {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CMD__SD1_CMD       0x5b
+                       MX7D_PAD_SD1_CLK__SD1_CLK       0x1b
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0   0x5b
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1   0x5b
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2   0x5b
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3   0x5b
+               >;
+       };
+
        pinctrl_usdhc3: usdhc3grp {
                fsl,pins = <
                        MX7D_PAD_SD3_CMD__SD3_CMD               0x59
 
        pinctrl_gpio_lpsr: gpio1-grp {
                fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO01__GPIO1_IO1     0x59
                        MX7D_PAD_LPSR_GPIO1_IO02__GPIO1_IO2     0x59
                        MX7D_PAD_LPSR_GPIO1_IO03__GPIO1_IO3     0x59
                >;
        };
 
+       pinctrl_gpiokeys: gpiokeysgrp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO01__GPIO1_IO1     0x19
+               >;
+       };
+
        pinctrl_i2c1: i2c1-grp {
                fsl,pins = <
                        MX7D_PAD_LPSR_GPIO1_IO05__I2C1_SDA      0x4000007f
index 9c8dd32..d8acd7c 100644 (file)
@@ -22,6 +22,7 @@
                        reg = <1>;
                        clock-frequency = <996000000>;
                        operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
                        cpu-idle-states = <&cpu_sleep_wait>;
                };
        };
@@ -43,7 +44,8 @@
                        opp-hz = /bits/ 64 <792000000>;
                        opp-microvolt = <1000000>;
                        clock-latency-ns = <150000>;
-                       opp-supported-hw = <0xf>, <0xf>;
+                       opp-supported-hw = <0xd>, <0xf>;
+                       opp-suspend;
                };
 
                opp-996000000 {
@@ -51,6 +53,7 @@
                        opp-microvolt = <1100000>;
                        clock-latency-ns = <150000>;
                        opp-supported-hw = <0xc>, <0xf>;
+                       opp-suspend;
                };
 
                opp-1200000000 {
@@ -58,6 +61,7 @@
                        opp-microvolt = <1225000>;
                        clock-latency-ns = <150000>;
                        opp-supported-hw = <0x8>, <0xf>;
+                       opp-suspend;
                };
        };
 
index e2e604d..1b812f4 100644 (file)
 
                        anatop: anatop@30360000 {
                                compatible = "fsl,imx7d-anatop", "fsl,imx6q-anatop",
-                                       "syscon", "simple-bus";
+                                       "syscon", "simple-mfd";
                                reg = <0x30360000 0x10000>;
                                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
                                        <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
index 4245b33..a863a2b 100644 (file)
@@ -77,6 +77,8 @@
 };
 
 &usdhc0 {
+       assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC0>;
+       assigned-clock-parents = <&scg1 IMX7ULP_CLK_APLL_PFD1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc0>;
        cd-gpios = <&gpio_ptc 10 GPIO_ACTIVE_LOW>;
index 6859a3a..d37a192 100644 (file)
                #clock-cells = <0>;
        };
 
-       mpll: clock-mpll {
-               compatible = "fixed-clock";
-               clock-frequency = <480000000>;
-               clock-output-names = "mpll";
-               #clock-cells = <0>;
-       };
-
        ahbbridge0: bus@40000000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                                 <&scg1 IMX7ULP_CLK_NIC1_DIV>,
                                 <&pcc2 IMX7ULP_CLK_USDHC0>;
                        clock-names = "ipg", "ahb", "per";
-                       assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC0>;
-                       assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>;
                        bus-width = <4>;
                        fsl,tuning-start-tap = <20>;
                        fsl,tuning-step = <2>;
                                 <&scg1 IMX7ULP_CLK_NIC1_DIV>,
                                 <&pcc2 IMX7ULP_CLK_USDHC1>;
                        clock-names = "ipg", "ahb", "per";
-                       assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC1>;
-                       assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>;
                        bus-width = <4>;
                        fsl,tuning-start-tap = <20>;
                        fsl,tuning-step = <2>;
                        compatible = "fsl,imx7ulp-scg1";
                        reg = <0x403e0000 0x10000>;
                        clocks = <&rosc>, <&sosc>, <&sirc>,
-                                <&firc>, <&upll>, <&mpll>;
+                                <&firc>, <&upll>;
                        clock-names = "rosc", "sosc", "sirc",
-                                     "firc", "upll", "mpll";
+                                     "firc", "upll";
                        #clock-cells = <1>;
                };
 
+               wdog1: watchdog@403d0000 {
+                       compatible = "fsl,imx7ulp-wdt";
+                       reg = <0x403d0000 0x10000>;
+                       interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
+                       assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
+                       assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
+                       timeout-sec = <40>;
+               };
+
                pcc2: clock-controller@403f0000 {
                        compatible = "fsl,imx7ulp-pcc2";
                        reg = <0x403f0000 0x10000>;
                                 <&scg1 IMX7ULP_CLK_APLL_PFD0>,
                                 <&scg1 IMX7ULP_CLK_UPLL>,
                                 <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
-                                <&scg1 IMX7ULP_CLK_MIPI_PLL>,
                                 <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
                                 <&scg1 IMX7ULP_CLK_ROSC>,
                                 <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
                        clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
                                      "apll_pfd2", "apll_pfd1", "apll_pfd0",
-                                     "upll", "sosc_bus_clk", "mpll",
+                                     "upll", "sosc_bus_clk",
                                      "firc_bus_clk", "rosc", "spll_bus_clk";
                        assigned-clocks = <&pcc2 IMX7ULP_CLK_LPTPM5>;
                        assigned-clock-parents = <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>;
                                 <&scg1 IMX7ULP_CLK_APLL_PFD0>,
                                 <&scg1 IMX7ULP_CLK_UPLL>,
                                 <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
-                                <&scg1 IMX7ULP_CLK_MIPI_PLL>,
                                 <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
                                 <&scg1 IMX7ULP_CLK_ROSC>,
                                 <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
                        clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
                                      "apll_pfd2", "apll_pfd1", "apll_pfd0",
-                                     "upll", "sosc_bus_clk", "mpll",
+                                     "upll", "sosc_bus_clk",
                                      "firc_bus_clk", "rosc", "spll_bus_clk";
                };
        };
index 457515b..0397c34 100644 (file)
@@ -408,4 +408,31 @@ clocks {
                reg-names = "control", "domain";
                domain-id = <0>;
        };
+
+       /*
+        * Below are set of fixed, input clocks definitions,
+        * for which real frequencies have to be defined in board files.
+        * Those clocks can be used as reference clocks for some HW modules
+        * (as cpts, for example) by configuring corresponding clock muxes.
+        */
+       timi0: timi0 {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+               clock-output-names = "timi0";
+       };
+
+       timi1: timi1 {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+               clock-output-names = "timi1";
+       };
+
+       tsrefclk: tsrefclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+               clock-output-names = "tsrefclk";
+       };
 };
index f759215..cf30e00 100644 (file)
@@ -71,4 +71,24 @@ clocks {
                reg-names = "control", "domain";
                domain-id = <29>;
        };
+
+       /*
+        * Below are set of fixed, input clocks definitions,
+        * for which real frequencies have to be defined in board files.
+        * Those clocks can be used as reference clocks for some HW modules
+        * (as cpts, for example) by configuring corresponding clock muxes.
+        */
+       tsipclka: tsipclka {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+               clock-output-names = "tsipclka";
+       };
+
+       tsipclkb: tsipclkb {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+               clock-output-names = "tsipclkb";
+       };
 };
index 1db17ec..ad15e77 100644 (file)
@@ -135,8 +135,8 @@ netcp: netcp@24000000 {
        /* NetCP address range */
        ranges = <0 0x24000000 0x1000000>;
 
-       clocks = <&clkpa>, <&clkcpgmac>, <&chipclk12>;
-       clock-names = "pa_clk", "ethss_clk", "cpts";
+       clocks = <&clkpa>, <&clkcpgmac>;
+       clock-names = "pa_clk", "ethss_clk";
        dma-coherent;
 
        ti,navigator-dmas = <&dma_gbe 0>,
@@ -156,6 +156,23 @@ netcp: netcp@24000000 {
                        tx-queue = <896>;
                        tx-channel = "nettx";
 
+                       cpts {
+                               clocks = <&cpts_refclk_mux>;
+                               clock-names = "cpts";
+
+                               cpts_refclk_mux: cpts-refclk-mux {
+                                       #clock-cells = <0>;
+                                       clocks = <&chipclk12>, <&chipclk13>,
+                                                <&timi0>, <&timi1>,
+                                                <&tsipclka>, <&tsrefclk>,
+                                                <&tsipclkb>;
+                                       ti,mux-tbl = <0x0>, <0x1>, <0x2>,
+                                               <0x3>, <0x4>, <0x8>, <0xC>;
+                                       assigned-clocks = <&cpts_refclk_mux>;
+                                       assigned-clock-parents = <&chipclk12>;
+                               };
+                       };
+
                        interfaces {
                                gbe0: interface-0 {
                                        slave-port = <0>;
index e203145..d5a6c1f 100644 (file)
@@ -152,8 +152,8 @@ netcp: netcp@2000000 {
        /* NetCP address range */
        ranges  = <0 0x2000000 0x100000>;
 
-       clocks = <&clkpa>, <&clkcpgmac>, <&chipclk12>;
-       clock-names = "pa_clk", "ethss_clk", "cpts";
+       clocks = <&clkpa>, <&clkcpgmac>;
+       clock-names = "pa_clk", "ethss_clk";
        dma-coherent;
 
        ti,navigator-dmas = <&dma_gbe 22>,
@@ -175,6 +175,22 @@ netcp: netcp@2000000 {
                        tx-queue = <648>;
                        tx-channel = "nettx";
 
+                       cpts {
+                               clocks = <&cpts_refclk_mux>;
+                               clock-names = "cpts";
+
+                               cpts_refclk_mux: cpts-refclk-mux {
+                                       #clock-cells = <0>;
+                                       clocks = <&chipclk12>, <&chipclk13>,
+                                                <&timi0>, <&timi1>,
+                                                <&tsrefclk>;
+                                       ti,mux-tbl = <0x0>, <0x1>, <0x2>,
+                                               <0x3>, <0x8>;
+                                       assigned-clocks = <&cpts_refclk_mux>;
+                                       assigned-clock-parents = <&chipclk12>;
+                               };
+                       };
+
                        interfaces {
                                gbe0: interface-0 {
                                        slave-port = <0>;
index a2e47ba..c1f9826 100644 (file)
@@ -134,8 +134,8 @@ netcp: netcp@26000000 {
        /* NetCP address range */
        ranges = <0 0x26000000 0x1000000>;
 
-       clocks = <&clkpa>, <&clkcpgmac>, <&chipclk12>;
-       clock-names = "pa_clk", "ethss_clk", "cpts";
+       clocks = <&clkpa>, <&clkcpgmac>;
+       clock-names = "pa_clk", "ethss_clk";
        dma-coherent;
 
        ti,navigator-dmas = <&dma_gbe 0>,
@@ -155,6 +155,22 @@ netcp: netcp@26000000 {
                        tx-queue = <896>;
                        tx-channel = "nettx";
 
+                       cpts {
+                               clocks = <&cpts_refclk_mux>;
+                               clock-names = "cpts";
+
+                               cpts_refclk_mux: cpts-refclk-mux {
+                                       #clock-cells = <0>;
+                                       clocks = <&chipclk12>, <&chipclk13>,
+                                                <&timi0>, <&timi1>,
+                                                <&tsrefclk>;
+                                       ti,mux-tbl = <0x0>, <0x1>, <0x2>,
+                                               <0x3>, <0x8>;
+                                       assigned-clocks = <&cpts_refclk_mux>;
+                                       assigned-clock-parents = <&chipclk12>;
+                               };
+                       };
+
                        interfaces {
                                gbe0: interface-0 {
                                        slave-port = <0>;
index c97ed29..217bd37 100644 (file)
 
                        rs5c372: rs5c372@32 {
                                status = "disabled";
-                               compatible = "ricoh,rs5c372";
+                               compatible = "ricoh,rs5c372a";
                                reg = <0x32>;
                        };
 
index 07ac99b..cdb89b3 100644 (file)
 #include "logicpd-torpedo-37xx-devkit.dts"
 
 &lcd0 {
-
-       label = "28";
-
-       panel-timing {
-               clock-frequency = <9000000>;
-               hactive = <480>;
-               vactive = <272>;
-               hfront-porch = <3>;
-               hback-porch = <2>;
-               hsync-len = <42>;
-               vback-porch = <3>;
-               vfront-porch = <2>;
-               vsync-len = <11>;
-               hsync-active = <1>;
-               vsync-active = <1>;
-               de-active = <1>;
-               pixelclk-active = <0>;
-       };
+       /* To make it work, set CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=4 */
+       compatible = "logicpd,type28";
 };
index 18c27e8..5532db0 100644 (file)
        };
 };
 
+&uart2 {
+       /delete-property/dma-names;
+       bluetooth {
+               compatible = "ti,wl1283-st";
+               enable-gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>; /* gpio 162 */
+               max-speed = <3000000>;
+       };
+};
+
+/* The DM3730 has a faster L3 than OMAP35, so increase pixel clock */
+&mt9p031_out {
+       pixel-clock-frequency = <90000000>;
+};
+
 &omap3_pmx_core {
        mmc3_pins: pinmux_mm3_pins {
                pinctrl-single,pins = <
index 449cc76..184e462 100644 (file)
 &dss {
        status = "ok";
        vdds_dsi-supply = <&vpll2>;
+       vdda_video-supply = <&vpll2>;
        pinctrl-names = "default";
        pinctrl-0 = <&dss_dpi_pins1>;
        port {
index 506b118..3a52285 100644 (file)
        };
 };
 
+/* The Torpedo doesn't route the USB host pins */
+&usbhshost {
+       status = "disabled";
+};
+
 &gpmc {
        ranges = <0 0 0x30000000 0x1000000>;    /* CS0: 16MB for NAND */
 
diff --git a/arch/arm/boot/dts/mmp3-dell-ariel.dts b/arch/arm/boot/dts/mmp3-dell-ariel.dts
new file mode 100644 (file)
index 0000000..c1947b5
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Dell Wyse 3020 a.k.a. "Ariel" a.k.a. Tx0D (T00D, T10D)
+ *
+ * Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+/dts-v1/;
+#include "mmp3.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       model = "Dell Ariel";
+       compatible = "dell,wyse-ariel", "marvell,mmp3";
+
+       aliases {
+               serial2 = &uart3;
+       };
+
+       chosen {
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+               ranges;
+               bootargs = "earlyprintk=ttyS2,115200 console=ttyS2,115200";
+       };
+
+       memory@0 {
+               linux,usable-memory = <0x0 0x7f600000>;
+               available = <0x7f700000 0x7ff00000 0x00000000 0x7f600000>;
+               reg = <0x0 0x80000000>;
+               device_type = "memory";
+       };
+};
+
+&uart3 {
+       status = "okay";
+};
+
+&rtc {
+       status = "okay";
+};
+
+&usb_otg0 {
+       status = "okay";
+};
+
+&usb_otg_phy0 {
+       status = "okay";
+};
+
+&mmc3 {
+       status = "okay";
+       max-frequency = <50000000>;
+       status = "okay";
+       bus-width = <8>;
+       non-removable;
+       cap-mmc-highspeed;
+};
+
+&twsi1 {
+       status = "okay";
+
+       rtc@68 {
+               compatible = "dallas,ds1338";
+               reg = <0x68>;
+               status = "okay";
+       };
+};
+
+&twsi3 {
+       status = "okay";
+};
+
+&twsi4 {
+       status = "okay";
+};
+
+&ssp3 {
+       status = "okay";
+       cs-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
+
+       firmware-flash@0 {
+               compatible = "st,m25p80", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               m25p,fast-read;
+       };
+};
+
+&ssp4 {
+       cs-gpios = <&gpio 56 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/mmp3.dtsi b/arch/arm/boot/dts/mmp3.dtsi
new file mode 100644 (file)
index 0000000..d9762de
--- /dev/null
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ *  Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <dt-bindings/clock/marvell,mmp2.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               enable-method = "marvell,mmp3-smp";
+
+               cpu@0 {
+                       compatible = "marvell,pj4b";
+                       device_type = "cpu";
+                       next-level-cache = <&l2>;
+                       reg = <0>;
+               };
+
+               cpu@1 {
+                       compatible = "marvell,pj4b";
+                       device_type = "cpu";
+                       next-level-cache = <&l2>;
+                       reg = <1>;
+               };
+       };
+
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+               axi@d4200000 {
+                       compatible = "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0xd4200000 0x00200000>;
+                       ranges;
+
+                       interrupt-controller@d4282000 {
+                               compatible = "marvell,mmp3-intc";
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0xd4282000 0x1000>,
+                                     <0xd4284000 0x100>;
+                               mrvl,intc-nr-irqs = <64>;
+                       };
+
+                       pmic_mux: interrupt-controller@d4282150 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x150 0x4>, <0x168 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <4>;
+                       };
+
+                       rtc_mux: interrupt-controller@d4282154 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x154 0x4>, <0x16c 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <2>;
+                       };
+
+                       hsi3_mux: interrupt-controller@d42821bc {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x1bc 0x4>, <0x1a4 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <3>;
+                       };
+
+                       gpu_mux: interrupt-controller@d42821c0 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x1c0 0x4>, <0x1a8 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <3>;
+                       };
+
+                       twsi_mux: interrupt-controller@d4282158 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x158 0x4>, <0x170 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <5>;
+                       };
+
+                       hsi2_mux: interrupt-controller@d42821c4 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x1c4 0x4>, <0x1ac 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <2>;
+                       };
+
+                       dxo_mux: interrupt-controller@d42821c8 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x1c8 0x4>, <0x1b0 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <2>;
+                       };
+
+                       misc1_mux: interrupt-controller@d428215c {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x15c 0x4>, <0x174 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <31>;
+                       };
+
+                       ci_mux: interrupt-controller@d42821cc {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x1cc 0x4>, <0x1b4 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <2>;
+                       };
+
+                       ssp_mux: interrupt-controller@d4282160 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x160 0x4>, <0x178 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <2>;
+                       };
+
+                       hsi1_mux: interrupt-controller@d4282184 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x184 0x4>, <0x17c 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <4>;
+                       };
+
+                       misc2_mux: interrupt-controller@d4282188 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x188 0x4>, <0x180 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <20>;
+                       };
+
+                       hsi0_mux: interrupt-controller@d42821d0 {
+                               compatible = "mrvl,mmp2-mux-intc";
+                               interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x1d0 0x4>, <0x1b8 0x4>;
+                               reg-names = "mux status", "mux mask";
+                               mrvl,intc-nr-irqs = <5>;
+                       };
+
+                       usb_otg_phy0: usb-otg-phy@d4207000 {
+                               compatible = "marvell,mmp3-usb-phy";
+                               reg = <0xd4207000 0x40>;
+                               #phy-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       usb_otg0: usb-otg@d4208000 {
+                               compatible = "marvell,pxau2o-ehci";
+                               reg = <0xd4208000 0x200>;
+                               interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_USB>;
+                               clock-names = "USBCLK";
+                               phys = <&usb_otg_phy0>;
+                               phy-names = "usb";
+                               status = "disabled";
+                       };
+
+                       mmc1: mmc@d4280000 {
+                               compatible = "mrvl,pxav3-mmc";
+                               reg = <0xd4280000 0x120>;
+                               clocks = <&soc_clocks MMP2_CLK_SDH0>;
+                               clock-names = "io";
+                               interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                       };
+
+                       mmc2: mmc@d4280800 {
+                               compatible = "mrvl,pxav3-mmc";
+                               reg = <0xd4280800 0x120>;
+                               clocks = <&soc_clocks MMP2_CLK_SDH1>;
+                               clock-names = "io";
+                               interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                       };
+
+                       mmc3: mmc@d4281000 {
+                               compatible = "mrvl,pxav3-mmc";
+                               reg = <0xd4281000 0x120>;
+                               clocks = <&soc_clocks MMP2_CLK_SDH2>;
+                               clock-names = "io";
+                               interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                       };
+
+                       mmc4: mmc@d4281800 {
+                               compatible = "mrvl,pxav3-mmc";
+                               reg = <0xd4281800 0x120>;
+                               clocks = <&soc_clocks MMP2_CLK_SDH3>;
+                               clock-names = "io";
+                               interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                       };
+
+                       camera0: camera@d420a000 {
+                               compatible = "marvell,mmp2-ccic";
+                               reg = <0xd420a000 0x800>;
+                               interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_CCIC0>;
+                               clock-names = "axi";
+                               #clock-cells = <0>;
+                               clock-output-names = "mclk";
+                               status = "disabled";
+                       };
+
+                       camera1: camera@d420a800 {
+                               compatible = "marvell,mmp2-ccic";
+                               reg = <0xd420a800 0x800>;
+                               interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_CCIC1>;
+                               clock-names = "axi";
+                               #clock-cells = <0>;
+                               clock-output-names = "mclk";
+                               status = "disabled";
+                       };
+               };
+
+               apb@d4000000 {
+                       compatible = "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0xd4000000 0x00200000>;
+                       ranges;
+
+                       timer: timer@d4014000 {
+                               compatible = "mrvl,mmp-timer";
+                               reg = <0xd4014000 0x100>;
+                               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_TIMER>;
+                       };
+
+                       uart1: uart@d4030000 {
+                               compatible = "mrvl,mmp-uart";
+                               reg = <0xd4030000 0x1000>;
+                               interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_UART0>;
+                               resets = <&soc_clocks MMP2_CLK_UART0>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       uart2: uart@d4017000 {
+                               compatible = "mrvl,mmp-uart";
+                               reg = <0xd4017000 0x1000>;
+                               interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_UART1>;
+                               resets = <&soc_clocks MMP2_CLK_UART1>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       uart3: uart@d4018000 {
+                               compatible = "mrvl,mmp-uart";
+                               reg = <0xd4018000 0x1000>;
+                               interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_UART2>;
+                               resets = <&soc_clocks MMP2_CLK_UART2>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       uart4: uart@d4016000 {
+                               compatible = "mrvl,mmp-uart";
+                               reg = <0xd4016000 0x1000>;
+                               interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_UART3>;
+                               resets = <&soc_clocks MMP2_CLK_UART3>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       gpio: gpio@d4019000 {
+                               compatible = "marvell,mmp2-gpio";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               reg = <0xd4019000 0x1000>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "gpio_mux";
+                               clocks = <&soc_clocks MMP2_CLK_GPIO>;
+                               resets = <&soc_clocks MMP2_CLK_GPIO>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               ranges;
+
+                               gcb0: gpio@d4019000 {
+                                       reg = <0xd4019000 0x4>;
+                               };
+
+                               gcb1: gpio@d4019004 {
+                                       reg = <0xd4019004 0x4>;
+                               };
+
+                               gcb2: gpio@d4019008 {
+                                       reg = <0xd4019008 0x4>;
+                               };
+
+                               gcb3: gpio@d4019100 {
+                                       reg = <0xd4019100 0x4>;
+                               };
+
+                               gcb4: gpio@d4019104 {
+                                       reg = <0xd4019104 0x4>;
+                               };
+
+                               gcb5: gpio@d4019108 {
+                                       reg = <0xd4019108 0x4>;
+                               };
+                       };
+
+                       twsi1: i2c@d4011000 {
+                               compatible = "mrvl,mmp-twsi";
+                               reg = <0xd4011000 0x1000>;
+                               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&soc_clocks MMP2_CLK_TWSI0>;
+                               resets = <&soc_clocks MMP2_CLK_TWSI0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               mrvl,i2c-fast-mode;
+                               status = "disabled";
+                       };
+
+                       twsi2: i2c@d4031000 {
+                               compatible = "mrvl,mmp-twsi";
+                               reg = <0xd4031000 0x1000>;
+                               interrupt-parent = <&twsi_mux>;
+                               interrupts = <0>;
+                               clocks = <&soc_clocks MMP2_CLK_TWSI1>;
+                               resets = <&soc_clocks MMP2_CLK_TWSI1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       twsi3: i2c@d4032000 {
+                               compatible = "mrvl,mmp-twsi";
+                               reg = <0xd4032000 0x1000>;
+                               interrupt-parent = <&twsi_mux>;
+                               interrupts = <1>;
+                               clocks = <&soc_clocks MMP2_CLK_TWSI2>;
+                               resets = <&soc_clocks MMP2_CLK_TWSI2>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       twsi4: i2c@d4033000 {
+                               compatible = "mrvl,mmp-twsi";
+                               reg = <0xd4033000 0x1000>;
+                               interrupt-parent = <&twsi_mux>;
+                               interrupts = <2>;
+                               clocks = <&soc_clocks MMP2_CLK_TWSI3>;
+                               resets = <&soc_clocks MMP2_CLK_TWSI3>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+
+                       twsi5: i2c@d4033800 {
+                               compatible = "mrvl,mmp-twsi";
+                               reg = <0xd4033800 0x1000>;
+                               interrupt-parent = <&twsi_mux>;
+                               interrupts = <3>;
+                               clocks = <&soc_clocks MMP2_CLK_TWSI4>;
+                               resets = <&soc_clocks MMP2_CLK_TWSI4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       twsi6: i2c@d4034000 {
+                               compatible = "mrvl,mmp-twsi";
+                               reg = <0xd4034000 0x1000>;
+                               interrupt-parent = <&twsi_mux>;
+                               interrupts = <4>;
+                               clocks = <&soc_clocks MMP2_CLK_TWSI5>;
+                               resets = <&soc_clocks MMP2_CLK_TWSI5>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       rtc: rtc@d4010000 {
+                               compatible = "mrvl,mmp-rtc";
+                               reg = <0xd4010000 0x1000>;
+                               interrupts = <1 0>;
+                               interrupt-names = "rtc 1Hz", "rtc alarm";
+                               interrupt-parent = <&rtc_mux>;
+                               clocks = <&soc_clocks MMP2_CLK_RTC>;
+                               resets = <&soc_clocks MMP2_CLK_RTC>;
+                               status = "disabled";
+                       };
+
+                       ssp1: spi@d4035000 {
+                               compatible = "marvell,mmp2-ssp";
+                               reg = <0xd4035000 0x1000>;
+                               clocks = <&soc_clocks MMP2_CLK_SSP0>;
+                               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       ssp2: spi@d4036000 {
+                               compatible = "marvell,mmp2-ssp";
+                               reg = <0xd4036000 0x1000>;
+                               clocks = <&soc_clocks MMP2_CLK_SSP1>;
+                               interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       ssp3: spi@d4037000 {
+                               compatible = "marvell,mmp2-ssp";
+                               reg = <0xd4037000 0x1000>;
+                               clocks = <&soc_clocks MMP2_CLK_SSP2>;
+                               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       ssp4: spi@d4039000 {
+                               compatible = "marvell,mmp2-ssp";
+                               reg = <0xd4039000 0x1000>;
+                               clocks = <&soc_clocks MMP2_CLK_SSP3>;
+                               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               l2: l2-cache-controller@d0020000 {
+                       compatible = "marvell,tauros3-cache", "arm,pl310-cache";
+                       reg = <0xd0020000 0x1000>;
+                       cache-unified;
+                       cache-level = <2>;
+               };
+
+               soc_clocks: clocks@d4050000 {
+                       compatible = "marvell,mmp2-clock";
+                       reg = <0xd4050000 0x1000>,
+                             <0xd4282800 0x400>,
+                             <0xd4015000 0x1000>;
+                       reg-names = "mpmu", "apmu", "apbc";
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       #power-domain-cells = <1>;
+               };
+
+               snoop-control-unit@e0000000 {
+                       compatible = "arm,arm11mp-scu";
+                       reg = <0xe0000000 0x100>;
+               };
+
+               gic: interrupt-controller@e0001000 {
+                       compatible = "arm,arm11mp-gic";
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       reg = <0xe0001000 0x1000>,
+                             <0xe0000100 0x100>;
+               };
+
+               local-timer@e0000600 {
+                       compatible = "arm,arm11mp-twd-timer";
+                       interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
+                                                 IRQ_TYPE_EDGE_RISING)>;
+                       reg = <0xe0000600 0x20>;
+               };
+
+               watchdog@e0000620 {
+                       compatible = "arm,arm11mp-twd-wdt";
+                       reg = <0xe0000620 0x20>;
+                       interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) |
+                                                 IRQ_TYPE_EDGE_RISING)>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
new file mode 100644 (file)
index 0000000..da6b107
--- /dev/null
@@ -0,0 +1,786 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "omap443x.dtsi"
+#include "motorola-cpcap-mapphone.dtsi"
+
+/ {
+       chosen {
+               stdout-path = &uart3;
+       };
+
+       aliases {
+               display0 = &lcd0;
+               display1 = &hdmi0;
+       };
+
+       /*
+        * We seem to have only 1021 MB accessible, 1021 - 1022 is locked,
+        * then 1023 - 1024 seems to contain mbm.
+        */
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x3fd00000>;  /* 1021 MB */
+       };
+
+       /* Poweroff GPIO probably connected to CPCAP */
+       gpio-poweroff {
+               compatible = "gpio-poweroff";
+               pinctrl-0 = <&poweroff_gpio>;
+               pinctrl-names = "default";
+               gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;    /* gpio50 */
+       };
+
+       hdmi0: connector {
+               compatible = "hdmi-connector";
+               pinctrl-0 = <&hdmi_hpd_gpio>;
+               pinctrl-names = "default";
+               label = "hdmi";
+               type = "d";
+
+               hpd-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>;       /* gpio63 */
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_out>;
+                       };
+               };
+       };
+
+       /*
+        * HDMI 5V regulator probably sourced from battery. Let's keep
+        * keep this as always enabled for HDMI to work until we've
+        * figured what the encoder chip is.
+        */
+       hdmi_regulator: regulator-hdmi {
+               compatible = "regulator-fixed";
+               regulator-name = "hdmi";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio2 27 GPIO_ACTIVE_HIGH>;    /* gpio59 */
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       /* FS USB Host PHY on port 1 for mdm6600 */
+       fsusb1_phy: usb-phy@1 {
+               compatible = "motorola,mapphone-mdm6600";
+               pinctrl-0 = <&usb_mdm6600_pins>;
+               pinctrl-names = "default";
+               enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;     /* gpio_95 */
+               power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;     /* gpio_54 */
+               reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;     /* gpio_49 */
+               /* mode: gpio_148 gpio_149 */
+               motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>,
+                                     <&gpio5 21 GPIO_ACTIVE_HIGH>;
+               /* cmd: gpio_103 gpio_104 gpio_142 */
+               motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>,
+                                    <&gpio4 8 GPIO_ACTIVE_HIGH>,
+                                    <&gpio5 14 GPIO_ACTIVE_HIGH>;
+               /* status: gpio_52 gpio_53 gpio_55 */
+               motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>,
+                                       <&gpio2 21 GPIO_ACTIVE_HIGH>,
+                                       <&gpio2 23 GPIO_ACTIVE_HIGH>;
+               #phy-cells = <0>;
+       };
+
+       /* HS USB host TLL nop-phy on port 2 for w3glte */
+       hsusb2_phy: usb-phy@2 {
+               compatible = "usb-nop-xceiv";
+               #phy-cells = <0>;
+       };
+
+       /* LCD regulator from sw5 source */
+       lcd_regulator: regulator-lcd {
+               compatible = "regulator-fixed";
+               regulator-name = "lcd";
+               regulator-min-microvolt = <5050000>;
+               regulator-max-microvolt = <5050000>;
+               gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>;     /* gpio96 */
+               enable-active-high;
+               vin-supply = <&sw5>;
+       };
+
+       /* This is probably coming straight from the battery.. */
+       wl12xx_vmmc: regulator-wl12xx {
+               compatible = "regulator-fixed";
+               regulator-name = "vwl1271";
+               regulator-min-microvolt = <1650000>;
+               regulator-max-microvolt = <1650000>;
+               gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;    /* gpio94 */
+               startup-delay-us = <70000>;
+               enable-active-high;
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+
+               volume_down {
+                       label = "Volume Down";
+                       gpios = <&gpio5 26 GPIO_ACTIVE_LOW>; /* gpio154 */
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       linux,can-disable;
+                       /* Value above 7.95ms for no GPIO hardware debounce */
+                       debounce-interval = <10>;
+               };
+
+               slider {
+                       label = "Keypad Slide";
+                       gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; /* gpio122 */
+                       linux,input-type = <EV_SW>;
+                       linux,code = <SW_KEYPAD_SLIDE>;
+                       linux,can-disable;
+                       /* Value above 7.95ms for no GPIO hardware debounce */
+                       debounce-interval = <10>;
+               };
+       };
+
+       soundcard {
+               compatible = "audio-graph-card";
+               label = "Droid 4 Audio";
+
+               simple-graph-card,widgets =
+                       "Speaker", "Earpiece",
+                       "Speaker", "Loudspeaker",
+                       "Headphone", "Headphone Jack",
+                       "Microphone", "Internal Mic";
+
+               simple-graph-card,routing =
+                       "Earpiece", "EP",
+                       "Loudspeaker", "SPKR",
+                       "Headphone Jack", "HSL",
+                       "Headphone Jack", "HSR",
+                       "MICR", "Internal Mic";
+
+               dais = <&mcbsp2_port>, <&mcbsp3_port>;
+       };
+
+       pwm8: dmtimer-pwm-8 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&vibrator_direction_pin>;
+
+               compatible = "ti,omap-dmtimer-pwm";
+               #pwm-cells = <3>;
+               ti,timers = <&timer8>;
+               ti,clock-source = <0x01>;
+       };
+
+       pwm9: dmtimer-pwm-9 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&vibrator_enable_pin>;
+
+               compatible = "ti,omap-dmtimer-pwm";
+               #pwm-cells = <3>;
+               ti,timers = <&timer9>;
+               ti,clock-source = <0x01>;
+       };
+
+       vibrator {
+               compatible = "pwm-vibrator";
+               pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>;
+               pwm-names = "enable", "direction";
+               direction-duty-cycle-ns = <10000000>;
+       };
+};
+
+&dss {
+       status = "okay";
+};
+
+&dsi1 {
+       status = "okay";
+       vdd-supply = <&vcsi>;
+
+       port {
+               dsi1_out_ep: endpoint {
+                       remote-endpoint = <&lcd0_in>;
+                       lanes = <0 1 2 3 4 5>;
+               };
+       };
+
+       lcd0: display {
+               compatible = "panel-dsi-cm";
+               label = "lcd0";
+               vddi-supply = <&lcd_regulator>;
+               reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;      /* gpio101 */
+
+               width-mm = <50>;
+               height-mm = <89>;
+
+               panel-timing {
+                       clock-frequency = <0>;          /* Calculated by dsi */
+
+                       hback-porch = <2>;
+                       hactive = <540>;
+                       hfront-porch = <0>;
+                       hsync-len = <2>;
+
+                       vback-porch = <1>;
+                       vactive = <960>;
+                       vfront-porch = <0>;
+                       vsync-len = <1>;
+
+                       hsync-active = <0>;
+                       vsync-active = <0>;
+                       de-active = <1>;
+                       pixelclk-active = <1>;
+               };
+
+               port {
+                       lcd0_in: endpoint {
+                               remote-endpoint = <&dsi1_out_ep>;
+                       };
+               };
+       };
+};
+
+&hdmi {
+       status = "okay";
+       pinctrl-0 = <&dss_hdmi_pins>;
+       pinctrl-names = "default";
+       vdda-supply = <&vdac>;
+
+       port {
+               hdmi_out: endpoint {
+                       remote-endpoint = <&hdmi_connector_in>;
+                       lanes = <1 0 3 2 5 4 7 6>;
+               };
+       };
+};
+
+&i2c1 {
+       tmp105@48 {
+               compatible = "ti,tmp105";
+               reg = <0x48>;
+               pinctrl-0 = <&tmp105_irq>;
+               pinctrl-names = "default";
+               /* kpd_row0.gpio_178 */
+               interrupts-extended = <&gpio6 18 IRQ_TYPE_EDGE_FALLING
+                                      &omap4_pmx_core 0x14e>;
+               interrupt-names = "irq", "wakeup";
+               wakeup-source;
+       };
+};
+
+&keypad {
+       keypad,num-rows = <8>;
+       keypad,num-columns = <8>;
+       linux,keymap = <
+
+       /* Row 1 */
+       MATRIX_KEY(0, 2, KEY_1)
+       MATRIX_KEY(0, 6, KEY_2)
+       MATRIX_KEY(2, 3, KEY_3)
+       MATRIX_KEY(0, 7, KEY_4)
+       MATRIX_KEY(0, 4, KEY_5)
+       MATRIX_KEY(5, 5, KEY_6)
+       MATRIX_KEY(0, 1, KEY_7)
+       MATRIX_KEY(0, 5, KEY_8)
+       MATRIX_KEY(0, 0, KEY_9)
+       MATRIX_KEY(1, 6, KEY_0)
+
+       /* Row 2 */
+       MATRIX_KEY(3, 4, KEY_APOSTROPHE)
+       MATRIX_KEY(7, 6, KEY_Q)
+       MATRIX_KEY(7, 7, KEY_W)
+       MATRIX_KEY(7, 2, KEY_E)
+       MATRIX_KEY(1, 0, KEY_R)
+       MATRIX_KEY(4, 4, KEY_T)
+       MATRIX_KEY(1, 2, KEY_Y)
+       MATRIX_KEY(6, 7, KEY_U)
+       MATRIX_KEY(2, 2, KEY_I)
+       MATRIX_KEY(5, 6, KEY_O)
+       MATRIX_KEY(3, 7, KEY_P)
+       MATRIX_KEY(6, 5, KEY_BACKSPACE)
+
+       /* Row 3 */
+       MATRIX_KEY(5, 4, KEY_TAB)
+       MATRIX_KEY(5, 7, KEY_A)
+       MATRIX_KEY(2, 7, KEY_S)
+       MATRIX_KEY(7, 0, KEY_D)
+       MATRIX_KEY(2, 6, KEY_F)
+       MATRIX_KEY(6, 2, KEY_G)
+       MATRIX_KEY(6, 6, KEY_H)
+       MATRIX_KEY(1, 4, KEY_J)
+       MATRIX_KEY(3, 1, KEY_K)
+       MATRIX_KEY(2, 1, KEY_L)
+       MATRIX_KEY(4, 6, KEY_ENTER)
+
+       /* Row 4 */
+       MATRIX_KEY(3, 6, KEY_LEFTSHIFT)         /* KEY_CAPSLOCK */
+       MATRIX_KEY(6, 1, KEY_Z)
+       MATRIX_KEY(7, 4, KEY_X)
+       MATRIX_KEY(5, 1, KEY_C)
+       MATRIX_KEY(1, 7, KEY_V)
+       MATRIX_KEY(2, 4, KEY_B)
+       MATRIX_KEY(4, 1, KEY_N)
+       MATRIX_KEY(1, 1, KEY_M)
+       MATRIX_KEY(3, 5, KEY_COMMA)
+       MATRIX_KEY(5, 2, KEY_DOT)
+       MATRIX_KEY(6, 3, KEY_UP)
+       MATRIX_KEY(7, 3, KEY_OK)
+
+       /* Row 5 */
+       MATRIX_KEY(2, 5, KEY_LEFTCTRL)          /* KEY_LEFTSHIFT */
+       MATRIX_KEY(4, 5, KEY_LEFTALT)           /* SYM */
+       MATRIX_KEY(6, 0, KEY_MINUS)
+       MATRIX_KEY(4, 7, KEY_EQUAL)
+       MATRIX_KEY(1, 5, KEY_SPACE)
+       MATRIX_KEY(3, 2, KEY_SLASH)
+       MATRIX_KEY(4, 3, KEY_LEFT)
+       MATRIX_KEY(5, 3, KEY_DOWN)
+       MATRIX_KEY(3, 3, KEY_RIGHT)
+
+       /* Side buttons, KEY_VOLUMEDOWN and KEY_PWER are on CPCAP? */
+       MATRIX_KEY(5, 0, KEY_VOLUMEUP)
+       >;
+};
+
+&mmc1 {
+       vmmc-supply = <&vwlan2>;
+       bus-width = <4>;
+       cd-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; /* gpio176 */
+};
+
+&mmc2 {
+       vmmc-supply = <&vsdio>;
+       bus-width = <8>;
+       ti,non-removable;
+};
+
+&mmc3 {
+       vmmc-supply = <&wl12xx_vmmc>;
+       /* uart2_tx.sdmmc3_dat1 pad as wakeirq */
+       interrupts-extended = <&wakeupgen GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH
+                              &omap4_pmx_core 0xde>;
+       interrupt-names = "irq", "wakeup";
+       non-removable;
+       bus-width = <4>;
+       cap-power-off-card;
+       keep-power-in-suspend;
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       wlcore: wlcore@2 {
+               compatible = "ti,wl1285", "ti,wl1283";
+               reg = <2>;
+               /* gpio_100 with gpmc_wait2 pad as wakeirq */
+               interrupts-extended = <&gpio4 4 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&omap4_pmx_core 0x4e>;
+               interrupt-names = "irq", "wakeup";
+               ref-clock-frequency = <26000000>;
+               tcxo-clock-frequency = <26000000>;
+       };
+};
+
+&i2c1 {
+       led-controller@38 {
+               compatible = "ti,lm3532";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x38>;
+
+               enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
+
+               ramp-up-us = <1024>;
+               ramp-down-us = <8193>;
+
+               led@0 {
+                       reg = <0>;
+                       led-sources = <2>;
+                       ti,led-mode = <0>;
+                       label = ":backlight";
+                       linux,default-trigger = "backlight";
+               };
+
+               led@1 {
+                       reg = <1>;
+                       led-sources = <1>;
+                       ti,led-mode = <0>;
+                       label = ":kbd_backlight";
+               };
+       };
+};
+
+&i2c2 {
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               reg = <0x4a>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+
+               reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */
+
+               /* gpio_183 with sys_nirq2 pad as wakeup */
+               interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING>,
+                                     <&omap4_pmx_core 0x160>;
+               interrupt-names = "irq", "wakeup";
+               wakeup-source;
+       };
+
+       isl29030@44 {
+               compatible = "isil,isl29030";
+               reg = <0x44>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&als_proximity_pins>;
+
+               interrupt-parent = <&gpio6>;
+               interrupts = <17 IRQ_TYPE_LEVEL_LOW>; /* gpio177 */
+       };
+};
+
+&omap4_pmx_core {
+
+       /* hdmi_hpd.gpio_63 */
+       hdmi_hpd_gpio: pinmux_hdmi_hpd_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x098, PIN_INPUT | MUX_MODE3)
+               >;
+       };
+
+       /* hdmi_cec.hdmi_cec, hdmi_scl.hdmi_scl, hdmi_sda.hdmi_sda */
+       dss_hdmi_pins: pinmux_dss_hdmi_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x09a, PIN_INPUT | MUX_MODE0)
+               OMAP4_IOPAD(0x09c, PIN_INPUT | MUX_MODE0)
+               OMAP4_IOPAD(0x09e, PIN_INPUT | MUX_MODE0)
+               >;
+       };
+
+       /* gpmc_ncs0.gpio_50 */
+       poweroff_gpio: pinmux_poweroff_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x074, PIN_OUTPUT_PULLUP | MUX_MODE3)
+               >;
+       };
+
+       /* kpd_row0.gpio_178 */
+       tmp105_irq: pinmux_tmp105_irq {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x18e, PIN_INPUT_PULLUP | MUX_MODE3)
+               >;
+       };
+
+       usb_gpio_mux_sel1: pinmux_usb_gpio_mux_sel1_pins {
+               /* gpio_60 */
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x088, PIN_OUTPUT | MUX_MODE3)
+               >;
+       };
+
+       touchscreen_pins: pinmux_touchscreen_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3)
+               OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3)
+               >;
+       };
+
+       als_proximity_pins: pinmux_als_proximity_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x18c, PIN_INPUT_PULLUP | MUX_MODE3)
+               >;
+       };
+
+       usb_mdm6600_pins: pinmux_usb_mdm6600_pins {
+               pinctrl-single,pins = <
+               /* enable 0x4a1000d8 usbb1_ulpitll_dat7.gpio_95 ag16 */
+               OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3)
+
+               /* power 0x4a10007c gpmc_nwp.gpio_54 c25 */
+               OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3)
+
+               /* reset 0x4a100072 gpmc_a25.gpio_49 d20 */
+               OMAP4_IOPAD(0x072, PIN_OUTPUT | MUX_MODE3)
+
+               /* mode0/bpwake 0x4a10014e sdmmc5_dat1.gpio_148 af4 */
+               OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3)
+
+               /* mode1/apwake 0x4a100150 sdmmc5_dat2.gpio_149 ag3 */
+               OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3)
+
+               /* status0 0x4a10007e gpmc_clk.gpio_55 b22 */
+               OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3)
+
+               /* status1 0x4a10007a gpmc_ncs3.gpio_53 c22 */
+               OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3)
+
+               /* status2 0x4a100078 gpmc_ncs2.gpio_52 d21 */
+               OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3)
+
+               /* cmd0 0x4a100094 gpmc_ncs6.gpio_103 c24 */
+               OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3)
+
+               /* cmd1 0x4a100096 gpmc_ncs7.gpio_104 d24 */
+               OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3)
+
+               /* cmd2 0x4a100142 uart3_rts_sd.gpio_142 f28 */
+               OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3)
+               >;
+       };
+
+       usb_ulpi_pins: pinmux_usb_ulpi_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x196, MUX_MODE7)
+               OMAP4_IOPAD(0x198, MUX_MODE7)
+               OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1ba, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1bc, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE0)
+               OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE0)
+               >;
+       };
+
+       /* usb0_otg_dp and usb0_otg_dm */
+       usb_utmi_pins: pinmux_usb_utmi_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x196, PIN_INPUT | MUX_MODE0)
+               OMAP4_IOPAD(0x198, PIN_INPUT | MUX_MODE0)
+               OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1ba, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1bc, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE7)
+               >;
+       };
+
+       /*
+        * Note that the v3.0.8 stock userspace dynamically remuxes uart1
+        * rts pin probably for PM purposes to PIN_INPUT_PULLUP | MUX_MODE7
+        * when not used. If needed, we can add rts pin remux later based
+        * on power measurements.
+        */
+       uart1_pins: pinmux_uart1_pins {
+               pinctrl-single,pins = <
+               /* 0x4a10013c mcspi1_cs2.uart1_cts ag23 */
+               OMAP4_IOPAD(0x13c, PIN_INPUT_PULLUP | MUX_MODE1)
+
+               /* 0x4a10013e mcspi1_cs3.uart1_rts ah23 */
+               OMAP4_IOPAD(0x13e, MUX_MODE1)
+
+               /* 0x4a100140 uart3_cts_rctx.uart1_tx f27 */
+               OMAP4_IOPAD(0x140, PIN_OUTPUT | MUX_MODE1)
+
+               /* 0x4a1001ca dpm_emu14.uart1_rx aa3 */
+               OMAP4_IOPAD(0x1ca, PIN_INPUT_PULLUP | MUX_MODE2)
+               >;
+       };
+
+       /* uart3_tx_irtx and uart3_rx_irrx */
+       uart3_pins: pinmux_uart3_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x196, MUX_MODE7)
+               OMAP4_IOPAD(0x198, MUX_MODE7)
+               OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1ba, MUX_MODE2)
+               OMAP4_IOPAD(0x1bc, PIN_INPUT | MUX_MODE2)
+               OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE7)
+               OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE7)
+               >;
+       };
+
+       uart4_pins: pinmux_uart4_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x15c, PIN_INPUT | MUX_MODE0)               /* uart4_rx */
+               OMAP4_IOPAD(0x15e, PIN_OUTPUT | MUX_MODE0)              /* uart4_tx */
+               OMAP4_IOPAD(0x110, PIN_INPUT_PULLUP | MUX_MODE5)        /* uart4_cts */
+               OMAP4_IOPAD(0x112, PIN_OUTPUT_PULLUP | MUX_MODE5)       /* uart4_rts */
+               >;
+       };
+
+       mcbsp2_pins: pinmux_mcbsp2_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x0f6, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_clkx */
+               OMAP4_IOPAD(0x0f8, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_dr */
+               OMAP4_IOPAD(0x0fa, PIN_OUTPUT | MUX_MODE0)      /* abe_mcbsp2_dx */
+               OMAP4_IOPAD(0x0fc, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_fsx */
+               >;
+       };
+
+       mcbsp3_pins: pinmux_mcbsp3_pins {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x106, PIN_INPUT | MUX_MODE1)       /* abe_mcbsp3_dr */
+               OMAP4_IOPAD(0x108, PIN_OUTPUT | MUX_MODE1)      /* abe_mcbsp3_dx */
+               OMAP4_IOPAD(0x10a, PIN_INPUT | MUX_MODE1)       /* abe_mcbsp3_clkx */
+               OMAP4_IOPAD(0x10c, PIN_INPUT | MUX_MODE1)       /* abe_mcbsp3_fsx */
+               >;
+       };
+
+       vibrator_direction_pin: pinmux_vibrator_direction_pin {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1)      /* dmtimer8_pwm_evt (gpio_27) */
+               >;
+       };
+
+       vibrator_enable_pin: pinmux_vibrator_enable_pin {
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1)      /* dmtimer9_pwm_evt (gpio_28) */
+               >;
+       };
+};
+
+&omap4_pmx_wkup {
+       usb_gpio_mux_sel2: pinmux_usb_gpio_mux_sel2_pins {
+               /* gpio_wk0 */
+               pinctrl-single,pins = <
+               OMAP4_IOPAD(0x040, PIN_OUTPUT_PULLDOWN | MUX_MODE3)
+               >;
+       };
+};
+
+/* Configure pwm clock source for timers 8 & 9 */
+&timer8 {
+       assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>;
+       assigned-clock-parents = <&sys_clkin_ck>;
+};
+
+&timer9 {
+       assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>;
+       assigned-clock-parents = <&sys_clkin_ck>;
+};
+
+/*
+ * As uart1 is wired to mdm6600 with rts and cts, we can use the cts pin for
+ * uart1 wakeirq.
+ */
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_pins>;
+       interrupts-extended = <&wakeupgen GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH
+                              &omap4_pmx_core 0xfc>;
+};
+
+&uart3 {
+       interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
+                              &omap4_pmx_core 0x17c>;
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart4_pins>;
+
+       bluetooth {
+               compatible = "ti,wl1285-st";
+               enable-gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>; /* gpio 174 */
+               max-speed = <3686400>;
+       };
+};
+
+&usbhsohci {
+       phys = <&fsusb1_phy>;
+       phy-names = "usb";
+};
+
+&usbhsehci {
+       phys = <&hsusb2_phy>;
+};
+
+&usbhshost {
+       port1-mode = "ohci-phy-4pin-dpdm";
+       port2-mode = "ehci-tll";
+};
+
+/* Internal UTMI+ PHY used for OTG, CPCAP ULPI PHY for detection and charger */
+&usb_otg_hs {
+       interface-type = <1>;
+       mode = <3>;
+
+       /*
+        * Max 300 mA steps based on similar PMIC MC13783UG.pdf "Table 10-4.
+        * VBUS Regulator Main Characteristics". Binding uses 2 mA units.
+        */
+       power = <150>;
+};
+
+&i2c4 {
+       ak8975: magnetometer@c {
+               compatible = "asahi-kasei,ak8975";
+               reg = <0x0c>;
+
+               vdd-supply = <&vhvio>;
+
+               interrupt-parent = <&gpio6>;
+               interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */
+
+               rotation-matrix = "-1", "0", "0",
+                                 "0", "1", "0",
+                                 "0", "0", "-1";
+
+       };
+
+       lis3dh: accelerometer@18 {
+               compatible = "st,lis3dh-accel";
+               reg = <0x18>;
+
+               vdd-supply = <&vhvio>;
+
+               interrupt-parent = <&gpio2>;
+               interrupts = <2 IRQ_TYPE_EDGE_BOTH>; /* gpio34 */
+
+               rotation-matrix = "0", "-1", "0",
+                                 "1", "0", "0",
+                                 "0", "0", "1";
+       };
+};
+
+&mcbsp2 {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcbsp2_pins>;
+       status = "okay";
+
+       mcbsp2_port: port {
+               cpu_dai2: endpoint {
+                       dai-format = "i2s";
+                       remote-endpoint = <&cpcap_audio_codec0>;
+                       frame-master = <&cpcap_audio_codec0>;
+                       bitclock-master = <&cpcap_audio_codec0>;
+               };
+       };
+};
+
+&mcbsp3 {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcbsp3_pins>;
+       status = "okay";
+
+       mcbsp3_port: port {
+               cpu_dai3: endpoint {
+                       dai-format = "dsp_a";
+                       frame-master = <&cpcap_audio_codec1>;
+                       bitclock-master = <&cpcap_audio_codec1>;
+                       remote-endpoint = <&cpcap_audio_codec1>;
+               };
+       };
+};
+
+&cpcap_audio_codec0 {
+       remote-endpoint = <&cpu_dai2>;
+};
+
+&cpcap_audio_codec1 {
+       remote-endpoint = <&cpu_dai3>;
+};
index ba39740..7fda40a 100644 (file)
                                regulator-enable-ramp-delay = <216>;
                        };
                };
+
+               mt6323keys: mt6323keys {
+                       compatible = "mediatek,mt6323-keys";
+                       mediatek,long-press-mode = <1>;
+                       power-off-time-sec = <0>;
+
+                       power {
+                               linux,keycodes = <116>;
+                               wakeup-source;
+                       };
+
+                       home {
+                               linux,keycodes = <114>;
+                       };
+               };
+
+               codec: mt6397codec {
+                       compatible = "mediatek,mt6397-codec";
+               };
+
+               power-controller {
+                       compatible = "mediatek,mt6323-pwrc";
+               };
+
+               rtc {
+                       compatible = "mediatek,mt6323-rtc";
+               };
        };
 };
index d134ce1..5672325 100644 (file)
                interrupts = <17 IRQ_TYPE_EDGE_RISING>; /* gpio 177 */
        };
 };
+
+&uart2 {
+       bluetooth {
+               compatible = "ti,wl1835-st";
+               enable-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>; /* gpio 137 */
+               max-speed = <300000>;
+       };
+};
index 9ca1d0f..df6ba12 100644 (file)
                interrupts = <8 IRQ_TYPE_EDGE_RISING>; /* gpio 136 */
        };
 };
+
+&uart2 {
+       bluetooth {
+               compatible = "ti,wl1835-st";
+               enable-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>; /* gpio 137 */
+               max-speed = <300000>;
+       };
+};
index 6365988..a638e05 100644 (file)
        };
 };
 
+/* RNG not directly accessible on n900, see omap3-rom-rng instead */
+&rng_target {
+       status = "disabled";
+};
+
 &usb_otg_hs {
        interface-type = <0>;
        usb-phy = <&usb2_phy>;
index 4043ecb..5698a3e 100644 (file)
@@ -8,6 +8,7 @@
  * kind, whether express or implied.
  */
 
+#include <dt-bindings/bus/ti-sysc.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pinctrl/omap.h>
                        status = "disabled";
                };
 
+               /* Likely needs to be tagged disabled on HS devices */
+               rng_target: target-module@480a0000 {
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       reg = <0x480a003c 0x4>,
+                             <0x480a0040 0x4>,
+                             <0x480a0044 0x4>;
+                       reg-names = "rev", "sysc", "syss";
+                       ti,sysc-mask = <(SYSC_OMAP2_AUTOIDLE)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>;
+                       ti,syss-mask = <1>;
+                       clocks = <&rng_ick>;
+                       clock-names = "ick";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x480a0000 0x2000>;
+
+                       rng: rng@0 {
+                               compatible = "ti,omap2-rng";
+                               reg = <0x0 0x2000>;
+                               interrupts = <52>;
+                       };
+               };
+
                mcbsp2: mcbsp@49022000 {
                        compatible = "ti,omap3-mcbsp";
                        reg = <0x49022000 0xff>,
index 5e9d1af..21079cd 100644 (file)
                         <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
                         <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, <&icr_ick>,
                         <&des2_ick>, <&mspro_ick>, <&mailboxes_ick>,
-                        <&mspro_fck>;
+                        <&rng_ick>, <&mspro_fck>;
        };
 };
diff --git a/arch/arm/boot/dts/omap4-droid-bionic-xt875.dts b/arch/arm/boot/dts/omap4-droid-bionic-xt875.dts
new file mode 100644 (file)
index 0000000..ba5c35b
--- /dev/null
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/dts-v1/;
+
+#include "motorola-mapphone-common.dtsi"
+
+/ {
+       model = "Motorola Droid Bionic XT875";
+       compatible = "motorola,droid-bionic", "ti,omap4430", "ti,omap4";
+};
index a40fe8d..c0d2fd9 100644 (file)
@@ -1,784 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /dts-v1/;
 
-#include <dt-bindings/input/input.h>
-#include "omap443x.dtsi"
-#include "motorola-cpcap-mapphone.dtsi"
+#include "motorola-mapphone-common.dtsi"
 
 / {
        model = "Motorola Droid 4 XT894";
        compatible = "motorola,droid4", "ti,omap4430", "ti,omap4";
-
-       chosen {
-               stdout-path = &uart3;
-       };
-
-       aliases {
-               display0 = &lcd0;
-               display1 = &hdmi0;
-       };
-
-       /*
-        * We seem to have only 1021 MB accessible, 1021 - 1022 is locked,
-        * then 1023 - 1024 seems to contain mbm.
-        */
-       memory {
-               device_type = "memory";
-               reg = <0x80000000 0x3fd00000>;  /* 1021 MB */
-       };
-
-       /* Poweroff GPIO probably connected to CPCAP */
-       gpio-poweroff {
-               compatible = "gpio-poweroff";
-               pinctrl-0 = <&poweroff_gpio>;
-               pinctrl-names = "default";
-               gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;    /* gpio50 */
-       };
-
-       hdmi0: connector {
-               compatible = "hdmi-connector";
-               pinctrl-0 = <&hdmi_hpd_gpio>;
-               pinctrl-names = "default";
-               label = "hdmi";
-               type = "d";
-
-               hpd-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>;       /* gpio63 */
-
-               port {
-                       hdmi_connector_in: endpoint {
-                               remote-endpoint = <&hdmi_out>;
-                       };
-               };
-       };
-
-       /*
-        * HDMI 5V regulator probably sourced from battery. Let's keep
-        * keep this as always enabled for HDMI to work until we've
-        * figured what the encoder chip is.
-        */
-       hdmi_regulator: regulator-hdmi {
-               compatible = "regulator-fixed";
-               regulator-name = "hdmi";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               gpio = <&gpio2 27 GPIO_ACTIVE_HIGH>;    /* gpio59 */
-               enable-active-high;
-               regulator-always-on;
-       };
-
-       /* FS USB Host PHY on port 1 for mdm6600 */
-       fsusb1_phy: usb-phy@1 {
-               compatible = "motorola,mapphone-mdm6600";
-               pinctrl-0 = <&usb_mdm6600_pins>;
-               pinctrl-names = "default";
-               enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;     /* gpio_95 */
-               power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;     /* gpio_54 */
-               reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;     /* gpio_49 */
-               /* mode: gpio_148 gpio_149 */
-               motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>,
-                                     <&gpio5 21 GPIO_ACTIVE_HIGH>;
-               /* cmd: gpio_103 gpio_104 gpio_142 */
-               motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>,
-                                    <&gpio4 8 GPIO_ACTIVE_HIGH>,
-                                    <&gpio5 14 GPIO_ACTIVE_HIGH>;
-               /* status: gpio_52 gpio_53 gpio_55 */
-               motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>,
-                                       <&gpio2 21 GPIO_ACTIVE_HIGH>,
-                                       <&gpio2 23 GPIO_ACTIVE_HIGH>;
-               #phy-cells = <0>;
-       };
-
-       /* HS USB host TLL nop-phy on port 2 for w3glte */
-       hsusb2_phy: usb-phy@2 {
-               compatible = "usb-nop-xceiv";
-               #phy-cells = <0>;
-       };
-
-       /* LCD regulator from sw5 source */
-       lcd_regulator: regulator-lcd {
-               compatible = "regulator-fixed";
-               regulator-name = "lcd";
-               regulator-min-microvolt = <5050000>;
-               regulator-max-microvolt = <5050000>;
-               gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>;     /* gpio96 */
-               enable-active-high;
-               vin-supply = <&sw5>;
-       };
-
-       /* This is probably coming straight from the battery.. */
-       wl12xx_vmmc: regulator-wl12xx {
-               compatible = "regulator-fixed";
-               regulator-name = "vwl1271";
-               regulator-min-microvolt = <1650000>;
-               regulator-max-microvolt = <1650000>;
-               gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;    /* gpio94 */
-               startup-delay-us = <70000>;
-               enable-active-high;
-       };
-
-       gpio_keys {
-               compatible = "gpio-keys";
-
-               volume_down {
-                       label = "Volume Down";
-                       gpios = <&gpio5 26 GPIO_ACTIVE_LOW>; /* gpio154 */
-                       linux,code = <KEY_VOLUMEDOWN>;
-                       linux,can-disable;
-                       /* Value above 7.95ms for no GPIO hardware debounce */
-                       debounce-interval = <10>;
-               };
-
-               slider {
-                       label = "Keypad Slide";
-                       gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; /* gpio122 */
-                       linux,input-type = <EV_SW>;
-                       linux,code = <SW_KEYPAD_SLIDE>;
-                       linux,can-disable;
-                       /* Value above 7.95ms for no GPIO hardware debounce */
-                       debounce-interval = <10>;
-               };
-       };
-
-       soundcard {
-               compatible = "audio-graph-card";
-               label = "Droid 4 Audio";
-
-               simple-graph-card,widgets =
-                       "Speaker", "Earpiece",
-                       "Speaker", "Loudspeaker",
-                       "Headphone", "Headphone Jack",
-                       "Microphone", "Internal Mic";
-
-               simple-graph-card,routing =
-                       "Earpiece", "EP",
-                       "Loudspeaker", "SPKR",
-                       "Headphone Jack", "HSL",
-                       "Headphone Jack", "HSR",
-                       "MICR", "Internal Mic";
-
-               dais = <&mcbsp2_port>, <&mcbsp3_port>;
-       };
-
-       pwm8: dmtimer-pwm-8 {
-               pinctrl-names = "default";
-               pinctrl-0 = <&vibrator_direction_pin>;
-
-               compatible = "ti,omap-dmtimer-pwm";
-               #pwm-cells = <3>;
-               ti,timers = <&timer8>;
-               ti,clock-source = <0x01>;
-       };
-
-       pwm9: dmtimer-pwm-9 {
-               pinctrl-names = "default";
-               pinctrl-0 = <&vibrator_enable_pin>;
-
-               compatible = "ti,omap-dmtimer-pwm";
-               #pwm-cells = <3>;
-               ti,timers = <&timer9>;
-               ti,clock-source = <0x01>;
-       };
-
-       vibrator {
-               compatible = "pwm-vibrator";
-               pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>;
-               pwm-names = "enable", "direction";
-               direction-duty-cycle-ns = <10000000>;
-       };
-};
-
-&dss {
-       status = "okay";
-};
-
-&dsi1 {
-       status = "okay";
-       vdd-supply = <&vcsi>;
-
-       port {
-               dsi1_out_ep: endpoint {
-                       remote-endpoint = <&lcd0_in>;
-                       lanes = <0 1 2 3 4 5>;
-               };
-       };
-
-       lcd0: display {
-               compatible = "panel-dsi-cm";
-               label = "lcd0";
-               vddi-supply = <&lcd_regulator>;
-               reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;      /* gpio101 */
-
-               width-mm = <50>;
-               height-mm = <89>;
-
-               panel-timing {
-                       clock-frequency = <0>;          /* Calculated by dsi */
-
-                       hback-porch = <2>;
-                       hactive = <540>;
-                       hfront-porch = <0>;
-                       hsync-len = <2>;
-
-                       vback-porch = <1>;
-                       vactive = <960>;
-                       vfront-porch = <0>;
-                       vsync-len = <1>;
-
-                       hsync-active = <0>;
-                       vsync-active = <0>;
-                       de-active = <1>;
-                       pixelclk-active = <1>;
-               };
-
-               port {
-                       lcd0_in: endpoint {
-                               remote-endpoint = <&dsi1_out_ep>;
-                       };
-               };
-       };
-};
-
-&hdmi {
-       status = "okay";
-       pinctrl-0 = <&dss_hdmi_pins>;
-       pinctrl-names = "default";
-       vdda-supply = <&vdac>;
-
-       port {
-               hdmi_out: endpoint {
-                       remote-endpoint = <&hdmi_connector_in>;
-                       lanes = <1 0 3 2 5 4 7 6>;
-               };
-       };
-};
-
-&i2c1 {
-       tmp105@48 {
-               compatible = "ti,tmp105";
-               reg = <0x48>;
-               pinctrl-0 = <&tmp105_irq>;
-               pinctrl-names = "default";
-               /* kpd_row0.gpio_178 */
-               interrupts-extended = <&gpio6 18 IRQ_TYPE_EDGE_FALLING
-                                      &omap4_pmx_core 0x14e>;
-               interrupt-names = "irq", "wakeup";
-               wakeup-source;
-       };
-};
-
-&keypad {
-       keypad,num-rows = <8>;
-       keypad,num-columns = <8>;
-       linux,keymap = <
-
-       /* Row 1 */
-       MATRIX_KEY(0, 2, KEY_1)
-       MATRIX_KEY(0, 6, KEY_2)
-       MATRIX_KEY(2, 3, KEY_3)
-       MATRIX_KEY(0, 7, KEY_4)
-       MATRIX_KEY(0, 4, KEY_5)
-       MATRIX_KEY(5, 5, KEY_6)
-       MATRIX_KEY(0, 1, KEY_7)
-       MATRIX_KEY(0, 5, KEY_8)
-       MATRIX_KEY(0, 0, KEY_9)
-       MATRIX_KEY(1, 6, KEY_0)
-
-       /* Row 2 */
-       MATRIX_KEY(3, 4, KEY_APOSTROPHE)
-       MATRIX_KEY(7, 6, KEY_Q)
-       MATRIX_KEY(7, 7, KEY_W)
-       MATRIX_KEY(7, 2, KEY_E)
-       MATRIX_KEY(1, 0, KEY_R)
-       MATRIX_KEY(4, 4, KEY_T)
-       MATRIX_KEY(1, 2, KEY_Y)
-       MATRIX_KEY(6, 7, KEY_U)
-       MATRIX_KEY(2, 2, KEY_I)
-       MATRIX_KEY(5, 6, KEY_O)
-       MATRIX_KEY(3, 7, KEY_P)
-       MATRIX_KEY(6, 5, KEY_BACKSPACE)
-
-       /* Row 3 */
-       MATRIX_KEY(5, 4, KEY_TAB)
-       MATRIX_KEY(5, 7, KEY_A)
-       MATRIX_KEY(2, 7, KEY_S)
-       MATRIX_KEY(7, 0, KEY_D)
-       MATRIX_KEY(2, 6, KEY_F)
-       MATRIX_KEY(6, 2, KEY_G)
-       MATRIX_KEY(6, 6, KEY_H)
-       MATRIX_KEY(1, 4, KEY_J)
-       MATRIX_KEY(3, 1, KEY_K)
-       MATRIX_KEY(2, 1, KEY_L)
-       MATRIX_KEY(4, 6, KEY_ENTER)
-
-       /* Row 4 */
-       MATRIX_KEY(3, 6, KEY_LEFTSHIFT)         /* KEY_CAPSLOCK */
-       MATRIX_KEY(6, 1, KEY_Z)
-       MATRIX_KEY(7, 4, KEY_X)
-       MATRIX_KEY(5, 1, KEY_C)
-       MATRIX_KEY(1, 7, KEY_V)
-       MATRIX_KEY(2, 4, KEY_B)
-       MATRIX_KEY(4, 1, KEY_N)
-       MATRIX_KEY(1, 1, KEY_M)
-       MATRIX_KEY(3, 5, KEY_COMMA)
-       MATRIX_KEY(5, 2, KEY_DOT)
-       MATRIX_KEY(6, 3, KEY_UP)
-       MATRIX_KEY(7, 3, KEY_OK)
-
-       /* Row 5 */
-       MATRIX_KEY(2, 5, KEY_LEFTCTRL)          /* KEY_LEFTSHIFT */
-       MATRIX_KEY(4, 5, KEY_LEFTALT)           /* SYM */
-       MATRIX_KEY(6, 0, KEY_MINUS)
-       MATRIX_KEY(4, 7, KEY_EQUAL)
-       MATRIX_KEY(1, 5, KEY_SPACE)
-       MATRIX_KEY(3, 2, KEY_SLASH)
-       MATRIX_KEY(4, 3, KEY_LEFT)
-       MATRIX_KEY(5, 3, KEY_DOWN)
-       MATRIX_KEY(3, 3, KEY_RIGHT)
-
-       /* Side buttons, KEY_VOLUMEDOWN and KEY_PWER are on CPCAP? */
-       MATRIX_KEY(5, 0, KEY_VOLUMEUP)
-       >;
-};
-
-&mmc1 {
-       vmmc-supply = <&vwlan2>;
-       bus-width = <4>;
-       cd-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; /* gpio176 */
-};
-
-&mmc2 {
-       vmmc-supply = <&vsdio>;
-       bus-width = <8>;
-       ti,non-removable;
-};
-
-&mmc3 {
-       vmmc-supply = <&wl12xx_vmmc>;
-       /* uart2_tx.sdmmc3_dat1 pad as wakeirq */
-       interrupts-extended = <&wakeupgen GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH
-                              &omap4_pmx_core 0xde>;
-       interrupt-names = "irq", "wakeup";
-       non-removable;
-       bus-width = <4>;
-       cap-power-off-card;
-       keep-power-in-suspend;
-
-       #address-cells = <1>;
-       #size-cells = <0>;
-       wlcore: wlcore@2 {
-               compatible = "ti,wl1285", "ti,wl1283";
-               reg = <2>;
-               /* gpio_100 with gpmc_wait2 pad as wakeirq */
-               interrupts-extended = <&gpio4 4 IRQ_TYPE_LEVEL_HIGH>,
-                                     <&omap4_pmx_core 0x4e>;
-               interrupt-names = "irq", "wakeup";
-               ref-clock-frequency = <26000000>;
-               tcxo-clock-frequency = <26000000>;
-       };
-};
-
-&i2c1 {
-       led-controller@38 {
-               compatible = "ti,lm3532";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <0x38>;
-
-               enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
-
-               ramp-up-us = <1024>;
-               ramp-down-us = <8193>;
-
-               led@0 {
-                       reg = <0>;
-                       led-sources = <2>;
-                       ti,led-mode = <0>;
-                       label = ":backlight";
-                       linux,default-trigger = "backlight";
-               };
-
-               led@1 {
-                       reg = <1>;
-                       led-sources = <1>;
-                       ti,led-mode = <0>;
-                       label = ":kbd_backlight";
-               };
-       };
-};
-
-&i2c2 {
-       touchscreen@4a {
-               compatible = "atmel,maxtouch";
-               reg = <0x4a>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&touchscreen_pins>;
-
-               reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */
-
-               /* gpio_183 with sys_nirq2 pad as wakeup */
-               interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING>,
-                                     <&omap4_pmx_core 0x160>;
-               interrupt-names = "irq", "wakeup";
-               wakeup-source;
-       };
-
-       isl29030@44 {
-               compatible = "isil,isl29030";
-               reg = <0x44>;
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&als_proximity_pins>;
-
-               interrupt-parent = <&gpio6>;
-               interrupts = <17 IRQ_TYPE_LEVEL_LOW>; /* gpio177 */
-       };
-};
-
-&omap4_pmx_core {
-
-       /* hdmi_hpd.gpio_63 */
-       hdmi_hpd_gpio: pinmux_hdmi_hpd_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x098, PIN_INPUT | MUX_MODE3)
-               >;
-       };
-
-       /* hdmi_cec.hdmi_cec, hdmi_scl.hdmi_scl, hdmi_sda.hdmi_sda */
-       dss_hdmi_pins: pinmux_dss_hdmi_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x09a, PIN_INPUT | MUX_MODE0)
-               OMAP4_IOPAD(0x09c, PIN_INPUT | MUX_MODE0)
-               OMAP4_IOPAD(0x09e, PIN_INPUT | MUX_MODE0)
-               >;
-       };
-
-       /* gpmc_ncs0.gpio_50 */
-       poweroff_gpio: pinmux_poweroff_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x074, PIN_OUTPUT_PULLUP | MUX_MODE3)
-               >;
-       };
-
-       /* kpd_row0.gpio_178 */
-       tmp105_irq: pinmux_tmp105_irq {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x18e, PIN_INPUT_PULLUP | MUX_MODE3)
-               >;
-       };
-
-       usb_gpio_mux_sel1: pinmux_usb_gpio_mux_sel1_pins {
-               /* gpio_60 */
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x088, PIN_OUTPUT | MUX_MODE3)
-               >;
-       };
-
-       touchscreen_pins: pinmux_touchscreen_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3)
-               OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3)
-               >;
-       };
-
-       als_proximity_pins: pinmux_als_proximity_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x18c, PIN_INPUT_PULLUP | MUX_MODE3)
-               >;
-       };
-
-       usb_mdm6600_pins: pinmux_usb_mdm6600_pins {
-               pinctrl-single,pins = <
-               /* enable 0x4a1000d8 usbb1_ulpitll_dat7.gpio_95 ag16 */
-               OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3)
-
-               /* power 0x4a10007c gpmc_nwp.gpio_54 c25 */
-               OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3)
-
-               /* reset 0x4a100072 gpmc_a25.gpio_49 d20 */
-               OMAP4_IOPAD(0x072, PIN_OUTPUT | MUX_MODE3)
-
-               /* mode0/bpwake 0x4a10014e sdmmc5_dat1.gpio_148 af4 */
-               OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3)
-
-               /* mode1/apwake 0x4a100150 sdmmc5_dat2.gpio_149 ag3 */
-               OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3)
-
-               /* status0 0x4a10007e gpmc_clk.gpio_55 b22 */
-               OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3)
-
-               /* status1 0x4a10007a gpmc_ncs3.gpio_53 c22 */
-               OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3)
-
-               /* status2 0x4a100078 gpmc_ncs2.gpio_52 d21 */
-               OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3)
-
-               /* cmd0 0x4a100094 gpmc_ncs6.gpio_103 c24 */
-               OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3)
-
-               /* cmd1 0x4a100096 gpmc_ncs7.gpio_104 d24 */
-               OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3)
-
-               /* cmd2 0x4a100142 uart3_rts_sd.gpio_142 f28 */
-               OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3)
-               >;
-       };
-
-       usb_ulpi_pins: pinmux_usb_ulpi_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x196, MUX_MODE7)
-               OMAP4_IOPAD(0x198, MUX_MODE7)
-               OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1ba, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1bc, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE0)
-               OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE0)
-               >;
-       };
-
-       /* usb0_otg_dp and usb0_otg_dm */
-       usb_utmi_pins: pinmux_usb_utmi_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x196, PIN_INPUT | MUX_MODE0)
-               OMAP4_IOPAD(0x198, PIN_INPUT | MUX_MODE0)
-               OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1ba, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1bc, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE7)
-               >;
-       };
-
-       /*
-        * Note that the v3.0.8 stock userspace dynamically remuxes uart1
-        * rts pin probably for PM purposes to PIN_INPUT_PULLUP | MUX_MODE7
-        * when not used. If needed, we can add rts pin remux later based
-        * on power measurements.
-        */
-       uart1_pins: pinmux_uart1_pins {
-               pinctrl-single,pins = <
-               /* 0x4a10013c mcspi1_cs2.uart1_cts ag23 */
-               OMAP4_IOPAD(0x13c, PIN_INPUT_PULLUP | MUX_MODE1)
-
-               /* 0x4a10013e mcspi1_cs3.uart1_rts ah23 */
-               OMAP4_IOPAD(0x13e, MUX_MODE1)
-
-               /* 0x4a100140 uart3_cts_rctx.uart1_tx f27 */
-               OMAP4_IOPAD(0x140, PIN_OUTPUT | MUX_MODE1)
-
-               /* 0x4a1001ca dpm_emu14.uart1_rx aa3 */
-               OMAP4_IOPAD(0x1ca, PIN_INPUT_PULLUP | MUX_MODE2)
-               >;
-       };
-
-       /* uart3_tx_irtx and uart3_rx_irrx */
-       uart3_pins: pinmux_uart3_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x196, MUX_MODE7)
-               OMAP4_IOPAD(0x198, MUX_MODE7)
-               OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1ba, MUX_MODE2)
-               OMAP4_IOPAD(0x1bc, PIN_INPUT | MUX_MODE2)
-               OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE7)
-               OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE7)
-               >;
-       };
-
-       uart4_pins: pinmux_uart4_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x15c, PIN_INPUT | MUX_MODE0)               /* uart4_rx */
-               OMAP4_IOPAD(0x15e, PIN_OUTPUT | MUX_MODE0)              /* uart4_tx */
-               OMAP4_IOPAD(0x110, PIN_INPUT_PULLUP | MUX_MODE5)        /* uart4_cts */
-               OMAP4_IOPAD(0x112, PIN_OUTPUT_PULLUP | MUX_MODE5)       /* uart4_rts */
-               >;
-       };
-
-       mcbsp2_pins: pinmux_mcbsp2_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x0f6, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_clkx */
-               OMAP4_IOPAD(0x0f8, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_dr */
-               OMAP4_IOPAD(0x0fa, PIN_OUTPUT | MUX_MODE0)      /* abe_mcbsp2_dx */
-               OMAP4_IOPAD(0x0fc, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_fsx */
-               >;
-       };
-
-       mcbsp3_pins: pinmux_mcbsp3_pins {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x106, PIN_INPUT | MUX_MODE1)       /* abe_mcbsp3_dr */
-               OMAP4_IOPAD(0x108, PIN_OUTPUT | MUX_MODE1)      /* abe_mcbsp3_dx */
-               OMAP4_IOPAD(0x10a, PIN_INPUT | MUX_MODE1)       /* abe_mcbsp3_clkx */
-               OMAP4_IOPAD(0x10c, PIN_INPUT | MUX_MODE1)       /* abe_mcbsp3_fsx */
-               >;
-       };
-
-       vibrator_direction_pin: pinmux_vibrator_direction_pin {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1)      /* dmtimer8_pwm_evt (gpio_27) */
-               >;
-       };
-
-       vibrator_enable_pin: pinmux_vibrator_enable_pin {
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1)      /* dmtimer9_pwm_evt (gpio_28) */
-               >;
-       };
-};
-
-&omap4_pmx_wkup {
-       usb_gpio_mux_sel2: pinmux_usb_gpio_mux_sel2_pins {
-               /* gpio_wk0 */
-               pinctrl-single,pins = <
-               OMAP4_IOPAD(0x040, PIN_OUTPUT_PULLDOWN | MUX_MODE3)
-               >;
-       };
-};
-
-/* Configure pwm clock source for timers 8 & 9 */
-&timer8 {
-       assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>;
-       assigned-clock-parents = <&sys_clkin_ck>;
-};
-
-&timer9 {
-       assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>;
-       assigned-clock-parents = <&sys_clkin_ck>;
-};
-
-/*
- * As uart1 is wired to mdm6600 with rts and cts, we can use the cts pin for
- * uart1 wakeirq.
- */
-&uart1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&uart1_pins>;
-       interrupts-extended = <&wakeupgen GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH
-                              &omap4_pmx_core 0xfc>;
-};
-
-&uart3 {
-       interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
-                              &omap4_pmx_core 0x17c>;
-};
-
-&uart4 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&uart4_pins>;
-
-       bluetooth {
-               compatible = "ti,wl1285-st";
-               enable-gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>; /* gpio 174 */
-               max-speed = <3686400>;
-       };
-};
-
-&usbhsohci {
-       phys = <&fsusb1_phy>;
-       phy-names = "usb";
-};
-
-&usbhsehci {
-       phys = <&hsusb2_phy>;
-};
-
-&usbhshost {
-       port1-mode = "ohci-phy-4pin-dpdm";
-       port2-mode = "ehci-tll";
-};
-
-/* Internal UTMI+ PHY used for OTG, CPCAP ULPI PHY for detection and charger */
-&usb_otg_hs {
-       interface-type = <1>;
-       mode = <3>;
-       power = <50>;
-};
-
-&i2c4 {
-       ak8975: magnetometer@c {
-               compatible = "asahi-kasei,ak8975";
-               reg = <0x0c>;
-
-               vdd-supply = <&vhvio>;
-
-               interrupt-parent = <&gpio6>;
-               interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */
-
-               rotation-matrix = "-1", "0", "0",
-                                 "0", "1", "0",
-                                 "0", "0", "-1";
-
-       };
-
-       lis3dh: accelerometer@18 {
-               compatible = "st,lis3dh-accel";
-               reg = <0x18>;
-
-               vdd-supply = <&vhvio>;
-
-               interrupt-parent = <&gpio2>;
-               interrupts = <2 IRQ_TYPE_EDGE_BOTH>; /* gpio34 */
-
-               rotation-matrix = "0", "-1", "0",
-                                 "1", "0", "0",
-                                 "0", "0", "1";
-       };
-};
-
-&mcbsp2 {
-       #sound-dai-cells = <0>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&mcbsp2_pins>;
-       status = "okay";
-
-       mcbsp2_port: port {
-               cpu_dai2: endpoint {
-                       dai-format = "i2s";
-                       remote-endpoint = <&cpcap_audio_codec0>;
-                       frame-master = <&cpcap_audio_codec0>;
-                       bitclock-master = <&cpcap_audio_codec0>;
-               };
-       };
-};
-
-&mcbsp3 {
-       #sound-dai-cells = <0>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&mcbsp3_pins>;
-       status = "okay";
-
-       mcbsp3_port: port {
-               cpu_dai3: endpoint {
-                       dai-format = "dsp_a";
-                       frame-master = <&cpcap_audio_codec1>;
-                       bitclock-master = <&cpcap_audio_codec1>;
-                       remote-endpoint = <&cpcap_audio_codec1>;
-               };
-       };
-};
-
-&cpcap_audio_codec0 {
-       remote-endpoint = <&cpu_dai2>;
-};
-
-&cpcap_audio_codec1 {
-       remote-endpoint = <&cpu_dai3>;
 };
index 8e6662b..6c892fc 100644 (file)
@@ -86,7 +86,6 @@
 
                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 |
 
                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 |
 
                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 |
 
                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";
index d60d5e0..83f803b 100644 (file)
 
                target-module@2b000 {                   /* 0x4a0ab000, ap 84 12.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "usb_otg_hs";
                        reg = <0x2b400 0x4>,
                              <0x2b404 0x4>,
                              <0x2b408 0x4>;
 
                target-module@74000 {                   /* 0x4a0f4000, ap 27 24.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox";
                        reg = <0x74000 0x4>,
                              <0x74010 0x4>;
                        reg-names = "rev", "sysc";
                        ranges = <0x0 0x6000 0x2000>;
 
                        prm: prm@0 {
-                               compatible = "ti,omap4-prm";
+                               compatible = "ti,omap4-prm", "simple-bus";
                                reg = <0x0 0x2000>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
                                #address-cells = <1>;
 
                gpio1_target: target-module@0 {                 /* 0x4a310000, ap 5 14.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio1";
                        reg = <0x0 0x4>,
                              <0x10 0x4>,
                              <0x114 0x4>;
 
                target-module@55000 {                   /* 0x48055000, ap 15 0c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio2";
                        reg = <0x55000 0x4>,
                              <0x55010 0x4>,
                              <0x55114 0x4>;
 
                target-module@57000 {                   /* 0x48057000, ap 17 16.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio3";
                        reg = <0x57000 0x4>,
                              <0x57010 0x4>,
                              <0x57114 0x4>;
 
                target-module@59000 {                   /* 0x48059000, ap 19 10.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio4";
                        reg = <0x59000 0x4>,
                              <0x59010 0x4>,
                              <0x59114 0x4>;
 
                target-module@5b000 {                   /* 0x4805b000, ap 21 12.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio5";
                        reg = <0x5b000 0x4>,
                              <0x5b010 0x4>,
                              <0x5b114 0x4>;
 
                target-module@5d000 {                   /* 0x4805d000, ap 23 14.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio6";
                        reg = <0x5d000 0x4>,
                              <0x5d010 0x4>,
                              <0x5d114 0x4>;
 
                target-module@96000 {                   /* 0x48096000, ap 37 26.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "mcbsp4";
                        reg = <0x9608c 0x4>;
                        reg-names = "sysc";
                        ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
 
                target-module@98000 {                   /* 0x48098000, ap 49 22.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi1";
                        reg = <0x98000 0x4>,
                              <0x98010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@9a000 {                   /* 0x4809a000, ap 51 2c.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi2";
                        reg = <0x9a000 0x4>,
                              <0x9a010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@b2000 {                   /* 0x480b2000, ap 65 3c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "hdq1w";
                        reg = <0xb2000 0x4>,
                              <0xb2014 0x4>,
                              <0xb2018 0x4>;
 
                target-module@b8000 {                   /* 0x480b8000, ap 69 58.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi3";
                        reg = <0xb8000 0x4>,
                              <0xb8010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@ba000 {                   /* 0x480ba000, ap 71 32.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi4";
                        reg = <0xba000 0x4>,
                              <0xba010 0x4>;
                        reg-names = "rev", "sysc";
index 7cc95bc..a0a747b 100644 (file)
                l4_abe: interconnect@40100000 {
                };
 
-               ocmcram: ocmcram@40304000 {
+               ocmcram: sram@40304000 {
                        compatible = "mmio-sram";
                        reg = <0x40304000 0xa000>; /* 40k */
                };
 #include "omap4-l4.dtsi"
 #include "omap4-l4-abe.dtsi"
 #include "omap44xx-clocks.dtsi"
+
+&prm {
+       prm_tesla: prm@400 {
+               compatible = "ti,omap4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x400 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_core: prm@700 {
+               compatible = "ti,omap4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x700 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_ivahd: prm@f00 {
+               compatible = "ti,omap4-prm-inst", "ti,omap-prm-inst";
+               reg = <0xf00 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_device: prm@1b00 {
+               compatible = "ti,omap4-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1b00 0x40>;
+               #reset-cells = <1>;
+       };
+};
index dc9d053..23aa907 100644 (file)
@@ -86,7 +86,6 @@
 
                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 |
 
                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 |
 
                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 |
index 0960348..25aacf1 100644 (file)
 
                target-module@74000 {                   /* 0x4a0f4000, ap 25 04.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mailbox";
                        reg = <0x74000 0x4>,
                              <0x74010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@20000 {                   /* 0x48020000, ap 3 04.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart3";
                        reg = <0x20050 0x4>,
                              <0x20054 0x4>,
                              <0x20058 0x4>;
 
                target-module@51000 {                   /* 0x48051000, ap 45 2e.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio7";
                        reg = <0x51000 0x4>,
                              <0x51010 0x4>,
                              <0x51114 0x4>;
 
                target-module@53000 {                   /* 0x48053000, ap 35 36.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio8";
                        reg = <0x53000 0x4>,
                              <0x53010 0x4>,
                              <0x53114 0x4>;
 
                target-module@55000 {                   /* 0x48055000, ap 13 0e.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio2";
                        reg = <0x55000 0x4>,
                              <0x55010 0x4>,
                              <0x55114 0x4>;
 
                target-module@57000 {                   /* 0x48057000, ap 15 06.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio3";
                        reg = <0x57000 0x4>,
                              <0x57010 0x4>,
                              <0x57114 0x4>;
 
                target-module@59000 {                   /* 0x48059000, ap 17 16.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio4";
                        reg = <0x59000 0x4>,
                              <0x59010 0x4>,
                              <0x59114 0x4>;
 
                target-module@5b000 {                   /* 0x4805b000, ap 19 1e.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio5";
                        reg = <0x5b000 0x4>,
                              <0x5b010 0x4>,
                              <0x5b114 0x4>;
 
                target-module@5d000 {                   /* 0x4805d000, ap 21 26.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio6";
                        reg = <0x5d000 0x4>,
                              <0x5d010 0x4>,
                              <0x5d114 0x4>;
 
                target-module@60000 {                   /* 0x48060000, ap 23 24.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c3";
                        reg = <0x60000 0x8>,
                              <0x60010 0x8>,
                              <0x60090 0x8>;
 
                target-module@66000 {                   /* 0x48066000, ap 63 4c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart5";
                        reg = <0x66050 0x4>,
                              <0x66054 0x4>,
                              <0x66058 0x4>;
 
                target-module@68000 {                   /* 0x48068000, ap 53 54.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart6";
                        reg = <0x68050 0x4>,
                              <0x68054 0x4>,
                              <0x68058 0x4>;
 
                target-module@6a000 {                   /* 0x4806a000, ap 24 0a.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart1";
                        reg = <0x6a050 0x4>,
                              <0x6a054 0x4>,
                              <0x6a058 0x4>;
 
                target-module@6c000 {                   /* 0x4806c000, ap 26 22.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart2";
                        reg = <0x6c050 0x4>,
                              <0x6c054 0x4>,
                              <0x6c058 0x4>;
 
                target-module@6e000 {                   /* 0x4806e000, ap 28 44.1 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart4";
                        reg = <0x6e050 0x4>,
                              <0x6e054 0x4>,
                              <0x6e058 0x4>;
 
                target-module@70000 {                   /* 0x48070000, ap 30 14.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c1";
                        reg = <0x70000 0x8>,
                              <0x70010 0x8>,
                              <0x70090 0x8>;
 
                target-module@72000 {                   /* 0x48072000, ap 32 1c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c2";
                        reg = <0x72000 0x8>,
                              <0x72010 0x8>,
                              <0x72090 0x8>;
 
                target-module@7a000 {                   /* 0x4807a000, ap 81 2c.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c4";
                        reg = <0x7a000 0x8>,
                              <0x7a010 0x8>,
                              <0x7a090 0x8>;
 
                target-module@7c000 {                   /* 0x4807c000, ap 83 34.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "i2c5";
                        reg = <0x7c000 0x8>,
                              <0x7c010 0x8>,
                              <0x7c090 0x8>;
 
                target-module@98000 {                   /* 0x48098000, ap 47 08.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi1";
                        reg = <0x98000 0x4>,
                              <0x98010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@9a000 {                   /* 0x4809a000, ap 49 10.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi2";
                        reg = <0x9a000 0x4>,
                              <0x9a010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@9c000 {                   /* 0x4809c000, ap 51 3a.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc1";
                        reg = <0x9c000 0x4>,
                              <0x9c010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@ad000 {                   /* 0x480ad000, ap 61 20.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc3";
                        reg = <0xad000 0x4>,
                              <0xad010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@b4000 {                   /* 0x480b4000, ap 65 42.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc2";
                        reg = <0xb4000 0x4>,
                              <0xb4010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@b8000 {                   /* 0x480b8000, ap 67 32.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi3";
                        reg = <0xb8000 0x4>,
                              <0xb8010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@ba000 {                   /* 0x480ba000, ap 69 18.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mcspi4";
                        reg = <0xba000 0x4>,
                              <0xba010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@d1000 {                   /* 0x480d1000, ap 71 28.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc4";
                        reg = <0xd1000 0x4>,
                              <0xd1010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@d5000 {                   /* 0x480d5000, ap 73 30.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc5";
                        reg = <0xd5000 0x4>,
                              <0xd5010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@0 {                       /* 0x4ae10000, ap 5 10.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "gpio1";
                        reg = <0x0 0x4>,
                              <0x10 0x4>,
                              <0x114 0x4>;
 
                target-module@4000 {                    /* 0x4ae14000, ap 7 14.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "wd_timer2";
                        reg = <0x4000 0x4>,
                              <0x4010 0x4>,
                              <0x4014 0x4>;
index 1fb7937..1f6ad1d 100644 (file)
                l4_abe: interconnect@40100000 {
                };
 
-               ocmcram: ocmcram@40300000 {
+               ocmcram: sram@40300000 {
                        compatible = "mmio-sram";
                        reg = <0x40300000 0x20000>; /* 128k */
                };
 
 #include "omap5-l4-abe.dtsi"
 #include "omap54xx-clocks.dtsi"
+
+&prm {
+       prm_dsp: prm@400 {
+               compatible = "ti,omap5-prm-inst", "ti,omap-prm-inst";
+               reg = <0x400 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_core: prm@700 {
+               compatible = "ti,omap5-prm-inst", "ti,omap-prm-inst";
+               reg = <0x700 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_iva: prm@1200 {
+               compatible = "ti,omap5-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1200 0x100>;
+               #reset-cells = <1>;
+       };
+
+       prm_device: prm@1c00 {
+               compatible = "ti,omap5-prm-inst", "ti,omap-prm-inst";
+               reg = <0x1c00 0x100>;
+               #reset-cells = <1>;
+       };
+};
diff --git a/arch/arm/boot/dts/openbmc-flash-layout-128.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-128.dtsi
new file mode 100644 (file)
index 0000000..05101a3
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+partitions {
+       compatible = "fixed-partitions";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       u-boot@0 {
+               reg = <0x0 0xe0000>; // 896KB
+               label = "u-boot";
+       };
+
+       u-boot-env@e0000 {
+               reg = <0xe0000 0x20000>; // 128KB
+               label = "u-boot-env";
+       };
+
+       kernel@100000 {
+               reg = <0x100000 0x900000>; // 9MB
+               label = "kernel";
+       };
+
+       rofs@a00000 {
+               reg = <0xa00000 0x5600000>; // 86MB
+               label = "rofs";
+       };
+
+       rwfs@6000000 {
+               reg = <0x6000000 0x2000000>; // 32MB
+               label = "rwfs";
+       };
+};
index 56f5159..8ef26da 100644 (file)
                        interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               sdhci: sdhci@7824900 {
+                       compatible = "qcom,sdhci-msm-v4";
+                       reg = <0x7824900 0x11c>, <0x7824000 0x800>;
+                       interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "hc_irq", "pwr_irq";
+                       bus-width = <8>;
+                       clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_DCD_XO_CLK>;
+                       clock-names = "core", "iface", "xo";
+                       status = "disabled";
+               };
+
                blsp_dma: dma@7884000 {
                        compatible = "qcom,bam-v1.7.0";
                        reg = <0x07884000 0x23000>;
index bf402ae..2616039 100644 (file)
                                                regulator-max-microvolt = <2950000>;
 
                                                regulator-boot-on;
+                                               regulator-system-load = <200000>;
+                                               regulator-allow-set-load;
                                        };
 
                                        l21 {
                        };
                };
 
-               sdhc2_cd_pin_a: sdhc2-cd-pin-active {
-                       pins = "gpio62";
-                       function = "gpio";
-
-                       drive-strength = <2>;
-                       bias-disable;
-               };
-
                sdhc2_pin_a: sdhc2-pin-active {
                        clk {
                                pins = "sdc2_clk";
                bus-width = <4>;
 
                pinctrl-names = "default";
-               pinctrl-0 = <&sdhc2_pin_a>, <&sdhc2_cd_pin_a>;
+               pinctrl-0 = <&sdhc2_pin_a>;
        };
 
        usb@f9a55000 {
                        };
                };
        };
+
+       imem@fe805000 {
+               status = "okay";
+
+               reboot-mode {
+                       mode-normal     = <0x77665501>;
+                       mode-bootloader = <0x77665500>;
+                       mode-recovery   = <0x77665502>;
+               };
+       };
 };
 
 &spmi_bus {
index 369e58f..9a84eb0 100644 (file)
                                };
                        };
                };
+
+               q6-dsp-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 1>;
+
+                       trips {
+                               q6_dsp_alert0: trip-point0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               modemtx-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 2>;
+
+                       trips {
+                               modemtx_alert0: trip-point0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               video-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 3>;
+
+                       trips {
+                               video_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               wlan-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 4>;
+
+                       trips {
+                               wlan_alert0: trip-point0 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               gpu-thermal-top {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 9>;
+
+                       trips {
+                               gpu1_alert0: trip-point0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               gpu-thermal-bottom {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 10>;
+
+                       trips {
+                               gpu2_alert0: trip-point0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
        };
 
        cpu-pmu {
                        nvmem-cells = <&tsens_calib>, <&tsens_backup>;
                        nvmem-cell-names = "calib", "calib_backup";
                        #qcom,sensors = <11>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
                                clock-names = "iface";
                        };
                };
+
+               imem@fe805000 {
+                       status = "disabled";
+                       compatible = "syscon", "simple-mfd";
+                       reg = <0xfe805000 0x1000>;
+
+                       reboot-mode {
+                               compatible = "syscon-reboot-mode";
+                               offset = <0x65c>;
+                       };
+               };
        };
 
        smd {
index f198480..c1f2012 100644 (file)
                                qcom,vs-soft-start-strength = <0>;
                                regulator-initial-mode = <1>;
                        };
+
+                       pm8941_5vs2: 5vs2 {
+                               regulator-enable-ramp-delay = <1000>;
+                               regulator-pull-down;
+                               regulator-over-current-protection;
+                               qcom,ocp-max-retries = <10>;
+                               qcom,ocp-retry-delay = <30>;
+                               qcom,vs-soft-start-strength = <0>;
+                               regulator-initial-mode = <1>;
+                       };
                };
        };
 };
index 83cc619..6ec2cf7 100644 (file)
                #size-cells = <0>;
        };
 
-        /*
-         * IIC2 and I2C2 may be switched using pinmux.
-         * A fallback to GPIO is also provided.
-         */
+       /*
+        * IIC2 and I2C2 may be switched using pinmux.
+        * A fallback to GPIO is also provided.
+        */
        i2chdmi: i2c-12 {
                compatible = "i2c-demux-pinctrl";
                i2c-parent = <&iic2>, <&i2c2>, <&gpioi2c2>;
index 42f3313..48fbeb6 100644 (file)
                compatible = "gpio-keys";
 
                key-1 {
-                       gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_1>;
-                       label = "SW2-1";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_1>;
+                       label = "SW2-1";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-2 {
-                       gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_2>;
-                       label = "SW2-2";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_2>;
+                       label = "SW2-2";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-3 {
-                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_3>;
-                       label = "SW2-3";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_3>;
+                       label = "SW2-3";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-4 {
-                       gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_4>;
-                       label = "SW2-4";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_4>;
+                       label = "SW2-4";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-a {
-                       gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_A>;
-                       label = "SW30";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_A>;
+                       label = "SW30";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-b {
-                       gpios = <&gpio7 1 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_B>;
-                       label = "SW31";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_B>;
+                       label = "SW31";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-c {
-                       gpios = <&gpio7 2 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_C>;
-                       label = "SW32";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_C>;
+                       label = "SW32";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-d {
-                       gpios = <&gpio7 3 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_D>;
-                       label = "SW33";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 3 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_D>;
+                       label = "SW33";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-e {
-                       gpios = <&gpio7 4 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_E>;
-                       label = "SW34";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 4 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_E>;
+                       label = "SW34";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-f {
-                       gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_F>;
-                       label = "SW35";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_F>;
+                       label = "SW35";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
                key-g {
-                       gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_G>;
-                       label = "SW36";
-                       wakeup-source;
-                       debounce-interval = <20>;
+                       gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_G>;
+                       label = "SW36";
+                       wakeup-source;
+                       debounce-interval = <20>;
                };
        };
 
index 19cde89..f30d6ec 100644 (file)
                ranges;
        };
 
+       modem@10000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x10000000 0xfffffff>;
+
+               gpioc@1a08000 {
+                       compatible = "rda,8810pl-gpio";
+                       reg = <0x1a08000 0x1000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       ngpios = <32>;
+               };
+       };
+
        apb@20800000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                                     <17 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hwtimer", "ostimer";
                };
+
+               gpioa@30000 {
+                       compatible = "rda,8810pl-gpio";
+                       reg = <0x30000 0x1000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       ngpios = <32>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               gpiob@31000 {
+                       compatible = "rda,8810pl-gpio";
+                       reg = <0x31000 0x1000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       ngpios = <32>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               gpiod@32000 {
+                       compatible = "rda,8810pl-gpio";
+                       reg = <0x32000 0x1000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       ngpios = <32>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+               };
        };
 
        apb@20a00000 {
index c776321..c70182c 100644 (file)
 
                hdmi {
                        hdmi_ctl: hdmi-ctl {
-                               rockchip,pins = <1 RK_PB0  1 &pcfg_pull_none>,
-                                               <1 RK_PB1  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>;
                        };
index 9f9e2bf..44bb5e6 100644 (file)
        };
 
        emmc {
-                       emmc_reset: emmc-reset {
-                               rockchip,pins = <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
-                       };
+               emmc_reset: emmc-reset {
+                       rockchip,pins = <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
        };
 
        gmac {
                phy_rst: phy-rst {
-                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO  &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 };
index 81e4e95..0aeef23 100644 (file)
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO \
-                                       &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                dvs_1: dvs-1 {
-                       rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO \
-                                       &pcfg_pull_down>;
+                       rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO \
-                                       &pcfg_pull_down>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 RK_PC4 1 \
-                                       &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
        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>;
+                                       <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 445270a..51208d1 100644 (file)
@@ -17,6 +17,7 @@
                rockchip,hp-det-gpios = <&gpio6 RK_PA5 GPIO_ACTIVE_HIGH>;
                rockchip,mic-det-gpios = <&gpio6 RK_PB3 GPIO_ACTIVE_LOW>;
                rockchip,headset-codec = <&headsetcodec>;
+               rockchip,hdmi-codec = <&hdmi>;
        };
 };
 
index b12e061..300a7e3 100644 (file)
 
        backlight: backlight {
                compatible = "pwm-backlight";
-               brightness-levels = <
-                         0   1   2   3   4   5   6   7
-                         8   9  10  11  12  13  14  15
-                        16  17  18  19  20  21  22  23
-                        24  25  26  27  28  29  30  31
-                        32  33  34  35  36  37  38  39
-                        40  41  42  43  44  45  46  47
-                        48  49  50  51  52  53  54  55
-                        56  57  58  59  60  61  62  63
-                        64  65  66  67  68  69  70  71
-                        72  73  74  75  76  77  78  79
-                        80  81  82  83  84  85  86  87
-                        88  89  90  91  92  93  94  95
-                        96  97  98  99 100 101 102 103
-                       104 105 106 107 108 109 110 111
-                       112 113 114 115 116 117 118 119
-                       120 121 122 123 124 125 126 127
-                       128 129 130 131 132 133 134 135
-                       136 137 138 139 140 141 142 143
-                       144 145 146 147 148 149 150 151
-                       152 153 154 155 156 157 158 159
-                       160 161 162 163 164 165 166 167
-                       168 169 170 171 172 173 174 175
-                       176 177 178 179 180 181 182 183
-                       184 185 186 187 188 189 190 191
-                       192 193 194 195 196 197 198 199
-                       200 201 202 203 204 205 206 207
-                       208 209 210 211 212 213 214 215
-                       216 217 218 219 220 221 222 223
-                       224 225 226 227 228 229 230 231
-                       232 233 234 235 236 237 238 239
-                       240 241 242 243 244 245 246 247
-                       248 249 250 251 252 253 254 255>;
+               brightness-levels = <0 255>;
+               num-interpolated-steps = <255>;
                default-brightness-level = <128>;
                enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
index 8038620..a4966e5 100644 (file)
 
 &backlight {
        /* Jaq panel PWM must be >= 3%, so start non-zero brightness at 8 */
-       brightness-levels = <
-                 0
-                 8   9  10  11  12  13  14  15
-                16  17  18  19  20  21  22  23
-                24  25  26  27  28  29  30  31
-                32  33  34  35  36  37  38  39
-                40  41  42  43  44  45  46  47
-                48  49  50  51  52  53  54  55
-                56  57  58  59  60  61  62  63
-                64  65  66  67  68  69  70  71
-                72  73  74  75  76  77  78  79
-                80  81  82  83  84  85  86  87
-                88  89  90  91  92  93  94  95
-                96  97  98  99 100 101 102 103
-               104 105 106 107 108 109 110 111
-               112 113 114 115 116 117 118 119
-               120 121 122 123 124 125 126 127
-               128 129 130 131 132 133 134 135
-               136 137 138 139 140 141 142 143
-               144 145 146 147 148 149 150 151
-               152 153 154 155 156 157 158 159
-               160 161 162 163 164 165 166 167
-               168 169 170 171 172 173 174 175
-               176 177 178 179 180 181 182 183
-               184 185 186 187 188 189 190 191
-               192 193 194 195 196 197 198 199
-               200 201 202 203 204 205 206 207
-               208 209 210 211 212 213 214 215
-               216 217 218 219 220 221 222 223
-               224 225 226 227 228 229 230 231
-               232 233 234 235 236 237 238 239
-               240 241 242 243 244 245 246 247
-               248 249 250 251 252 253 254 255>;
+       brightness-levels = <0 8 255>;
+       num-interpolated-steps = <247>;
 };
 
 &rk808 {
index aa352d4..06a6a95 100644 (file)
                regulator-boot-on;
                vin-supply = <&vcc33_sys>;
        };
+
+       sound {
+               compatible = "rockchip,rockchip-audio-max98090";
+               rockchip,model = "VEYRON-HDMI";
+               rockchip,hdmi-codec = <&hdmi>;
+               rockchip,i2s-controller = <&i2s>;
+       };
 };
 
 &cpu_thermal {
index 55955b0..c833716 100644 (file)
 
 &backlight {
        /* Minnie panel PWM must be >= 1%, so start non-zero brightness at 3 */
-       brightness-levels = <
-                         0   3   4   5   6   7
-                         8   9  10  11  12  13  14  15
-                        16  17  18  19  20  21  22  23
-                        24  25  26  27  28  29  30  31
-                        32  33  34  35  36  37  38  39
-                        40  41  42  43  44  45  46  47
-                        48  49  50  51  52  53  54  55
-                        56  57  58  59  60  61  62  63
-                        64  65  66  67  68  69  70  71
-                        72  73  74  75  76  77  78  79
-                        80  81  82  83  84  85  86  87
-                        88  89  90  91  92  93  94  95
-                        96  97  98  99 100 101 102 103
-                       104 105 106 107 108 109 110 111
-                       112 113 114 115 116 117 118 119
-                       120 121 122 123 124 125 126 127
-                       128 129 130 131 132 133 134 135
-                       136 137 138 139 140 141 142 143
-                       144 145 146 147 148 149 150 151
-                       152 153 154 155 156 157 158 159
-                       160 161 162 163 164 165 166 167
-                       168 169 170 171 172 173 174 175
-                       176 177 178 179 180 181 182 183
-                       184 185 186 187 188 189 190 191
-                       192 193 194 195 196 197 198 199
-                       200 201 202 203 204 205 206 207
-                       208 209 210 211 212 213 214 215
-                       216 217 218 219 220 221 222 223
-                       224 225 226 227 228 229 230 231
-                       232 233 234 235 236 237 238 239
-                       240 241 242 243 244 245 246 247
-                       248 249 250 251 252 253 254 255>;
+       brightness-levels = <0 3 255>;
+       num-interpolated-steps = <252>;
 };
 
 &i2c_tunnel {
index 2755720..bebb230 100644 (file)
 
 &backlight {
        /* Tiger panel PWM must be >= 1%, so start non-zero brightness at 3 */
-       brightness-levels = <
-                 0   3   4   5   6   7
-                 8   9  10  11  12  13  14  15
-                16  17  18  19  20  21  22  23
-                24  25  26  27  28  29  30  31
-                32  33  34  35  36  37  38  39
-                40  41  42  43  44  45  46  47
-                48  49  50  51  52  53  54  55
-                56  57  58  59  60  61  62  63
-                64  65  66  67  68  69  70  71
-                72  73  74  75  76  77  78  79
-                80  81  82  83  84  85  86  87
-                88  89  90  91  92  93  94  95
-                96  97  98  99 100 101 102 103
-               104 105 106 107 108 109 110 111
-               112 113 114 115 116 117 118 119
-               120 121 122 123 124 125 126 127
-               128 129 130 131 132 133 134 135
-               136 137 138 139 140 141 142 143
-               144 145 146 147 148 149 150 151
-               152 153 154 155 156 157 158 159
-               160 161 162 163 164 165 166 167
-               168 169 170 171 172 173 174 175
-               176 177 178 179 180 181 182 183
-               184 185 186 187 188 189 190 191
-               192 193 194 195 196 197 198 199
-               200 201 202 203 204 205 206 207
-               208 209 210 211 212 213 214 215
-               216 217 218 219 220 221 222 223
-               224 225 226 227 228 229 230 231
-               232 233 234 235 236 237 238 239
-               240 241 242 243 244 245 246 247
-               248 249 250 251 252 253 254 255>;
+       brightness-levels = <0 3 255>;
+       num-interpolated-steps = <252>;
 };
 
 &backlight_regulator {
index cc893e1..415c75f 100644 (file)
 
        vopb: vop@ff930000 {
                compatible = "rockchip,rk3288-vop";
-               reg = <0x0 0xff930000 0x0 0x19c>;
+               reg = <0x0 0xff930000 0x0 0x19c>, <0x0 0xff931000 0x0 0x1000>;
                interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
                clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
 
        vopl: vop@ff940000 {
                compatible = "rockchip,rk3288-vop";
-               reg = <0x0 0xff940000 0x0 0x19c>;
+               reg = <0x0 0xff940000 0x0 0x19c>, <0x0 0xff941000 0x0 0x1000>;
                interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
                clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
                clocks = <&cru PCLK_EFUSE256>;
                clock-names = "pclk_efuse";
 
+               cpu_id: cpu-id@7 {
+                       reg = <0x07 0x10>;
+               };
                cpu_leakage: cpu_leakage@17 {
                        reg = <0x17 0x1>;
                };
index 0e159c8..1aeac33 100644 (file)
        };
 };
 
+&clocks {
+       clocks = <&fin_pll>;
+};
+
 &sdhci0 {
        pinctrl-names = "default";
        pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
index a9a5689..3bf6c45 100644 (file)
        };
 };
 
+&clocks {
+       clocks = <&fin_pll>;
+};
+
 &sdhci0 {
        pinctrl-names = "default";
        pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
index 2e2c1a7..5652048 100644 (file)
                                #clock-cells = <0>;
                        };
 
-                       rtc@f80480b0 {
+                       rtc: rtc@f80480b0 {
                                compatible = "atmel,at91rm9200-rtc";
                                reg = <0xf80480b0 0x30>;
                                interrupts = <74 IRQ_TYPE_LEVEL_HIGH 7>;
index b4c0a76..2b64564 100644 (file)
@@ -19,7 +19,7 @@
                m25p,fast-read;
                cdns,page-size = <256>;
                cdns,block-size = <16>;
-               cdns,read-delay = <4>;
+               cdns,read-delay = <3>;
                cdns,tshsl-ns = <50>;
                cdns,tsd2d-ns = <50>;
                cdns,tchsh-ns = <4>;
index ba08624..58288aa 100644 (file)
@@ -60,7 +60,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@00000000 {
                device_type = "memory";
                reg = <0x00000000 0x2000000>;
        };
        status = "okay";
        pinctrl-0 = <&ltdc_pins>;
        pinctrl-names = "default";
-       dma-ranges;
 
        port {
                ltdc_out_rgb: endpoint {
index 2b16648..fcc804e 100644 (file)
@@ -55,7 +55,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@c0000000 {
                device_type = "memory";
                reg = <0xc0000000 0x2000000>;
        };
@@ -95,7 +95,6 @@
 
        joystick {
                compatible = "gpio-keys";
-               #size-cells = <0>;
                pinctrl-0 = <&joystick_pins>;
                pinctrl-names = "default";
                button-0 {
index e19d0fe..30c0f67 100644 (file)
@@ -59,7 +59,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@90000000 {
                device_type = "memory";
                reg = <0x90000000 0x800000>;
        };
index a3ff049..f3ce477 100644 (file)
@@ -60,7 +60,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@00000000 {
                device_type = "memory";
                reg = <0x00000000 0x1000000>;
        };
 };
 
 &ltdc {
-       dma-ranges;
        status = "okay";
 
        port {
index 5ae5213..be002e8 100644 (file)
@@ -8,7 +8,6 @@
                dsi: dsi@40016c00 {
                        compatible = "st,stm32-dsi";
                        reg = <0x40016c00 0x800>;
-                       interrupts = <92>;
                        resets = <&rcc STM32F4_APB2_RESET(DSI)>;
                        reset-names = "apb";
                        clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>;
index 0ba9c5b..569d23c 100644 (file)
@@ -55,7 +55,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@c0000000 {
                device_type = "memory";
                reg = <0xC0000000 0x800000>;
        };
index 6f1d0ac..1626e00 100644 (file)
@@ -55,7 +55,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@c0000000 {
                device_type = "memory";
                reg = <0xC0000000 0x1000000>;
        };
index 3acd2e9..e446d31 100644 (file)
@@ -53,7 +53,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@d0000000 {
                device_type = "memory";
                reg = <0xd0000000 0x2000000>;
        };
index e4d3c58..8f39817 100644 (file)
@@ -53,7 +53,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@d0000000 {
                device_type = "memory";
                reg = <0xd0000000 0x2000000>;
        };
index 0a3a7d6..3d1ecb4 100644 (file)
                                status = "disabled";
                        };
 
+                       adc12_ain_pins_a: adc12-ain-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('C', 3, ANALOG)>, /* ADC1 in13 */
+                                                <STM32_PINMUX('F', 12, ANALOG)>, /* ADC1 in6 */
+                                                <STM32_PINMUX('F', 13, ANALOG)>, /* ADC2 in2 */
+                                                <STM32_PINMUX('F', 14, ANALOG)>; /* ADC2 in6 */
+                               };
+                       };
+
+                       adc12_usb_cc_pins_a: adc12-usb-cc-pins-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('A', 4, ANALOG)>, /* ADC12 in18 */
+                                                <STM32_PINMUX('A', 5, ANALOG)>; /* ADC12 in19 */
+                               };
+                       };
+
                        cec_pins_a: cec-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('A', 15, AF4)>;
                                };
                        };
 
+                       dac_ch1_pins_a: dac-ch1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('A', 4, ANALOG)>;
+                               };
+                       };
+
+                       dac_ch2_pins_a: dac-ch2 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('A', 5, ANALOG)>;
+                               };
+                       };
+
                        dcmi_pins_a: dcmi-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('H', 8,  AF13)>,/* DCMI_HSYNC */
index 2e4742c..628c74a 100644 (file)
                                regulator-name = "vbus_otg";
                                interrupts = <IT_OCP_OTG 0>;
                                interrupt-parent = <&pmic>;
-                               regulator-active-discharge;
                        };
 
                        vbus_sw: pwr_sw2 {
                                regulator-name = "vbus_sw";
                                interrupts = <IT_OCP_SWOUT 0>;
                                interrupt-parent = <&pmic>;
-                               regulator-active-discharge;
+                               regulator-active-discharge = <1>;
                        };
                };
 
        status = "okay";
 };
 
+&pwr_regulators {
+       vdd-supply = <&vdd>;
+       vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
 &rng1 {
        status = "okay";
 };
index 0615d1c..984a47c 100644 (file)
@@ -25,6 +25,7 @@
        };
 
        memory@c0000000 {
+               device_type = "memory";
                reg = <0xc0000000 0x20000000>;
        };
 
                        "Playback" , "MCLK",
                        "Capture" , "MCLK",
                        "MICL" , "Mic Bias";
-               dais = <&sai2a_port &sai2b_port>;
+               dais = <&sai2a_port &sai2b_port &i2s2_port>;
+               status = "okay";
+       };
+};
+
+&adc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&adc12_ain_pins_a>, <&adc12_usb_cc_pins_a>;
+       vdd-supply = <&vdd>;
+       vdda-supply = <&vdd>;
+       vref-supply = <&vrefbuf>;
+       status = "disabled";
+       adc1: adc@0 {
+               /*
+                * Type-C USB_PWR_CC1 & USB_PWR_CC2 on in18 & in19.
+                * Use at least 5 * RC time, e.g. 5 * (Rp + Rd) * C:
+                * 5 * (56 + 47kOhms) * 5pF => 2.5us.
+                * Use arbitrary margin here (e.g. 5us).
+                */
+               st,min-sample-time-nsecs = <5000>;
+               /* AIN connector, USB Type-C CC1 & CC2 */
+               st,adc-channels = <0 1 6 13 18 19>;
+               status = "okay";
+       };
+       adc2: adc@100 {
+               /* AIN connector, USB Type-C CC1 & CC2 */
+               st,adc-channels = <0 1 2 6 18 19>;
+               st,min-sample-time-nsecs = <5000>;
                status = "okay";
        };
 };
                reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>;
                interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
                interrupt-parent = <&gpiog>;
-               pinctrl-names = "default", "sleep";
-               pinctrl-0 = <&ltdc_pins_a>;
-               pinctrl-1 = <&ltdc_pins_sleep_a>;
+               #sound-dai-cells = <0>;
                status = "okay";
 
                ports {
                                        remote-endpoint = <&ltdc_ep0_out>;
                                };
                        };
+
+                       port@3 {
+                               reg = <3>;
+                               sii9022_tx_endpoint: endpoint {
+                                       remote-endpoint = <&i2s2_endpoint>;
+                               };
+                       };
                };
        };
 
 
                        vddcore: buck1 {
                                regulator-name = "vddcore";
-                               regulator-min-microvolt = <800000>;
+                               regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1350000>;
                                regulator-always-on;
                                regulator-initial-mode = <0>;
                         vbus_sw: pwr_sw2 {
                                regulator-name = "vbus_sw";
                                interrupts = <IT_OCP_SWOUT 0>;
-                               regulator-active-discharge;
+                               regulator-active-discharge = <1>;
                         };
                };
 
        };
 };
 
+&i2s2 {
+       clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>;
+       clock-names = "pclk", "i2sclk", "x8k", "x11k";
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&i2s2_pins_a>;
+       pinctrl-1 = <&i2s2_pins_sleep_a>;
+       status = "okay";
+
+       i2s2_port: port {
+               i2s2_endpoint: endpoint {
+                       remote-endpoint = <&sii9022_tx_endpoint>;
+                       format = "i2s";
+                       mclk-fs = <256>;
+               };
+       };
+};
+
 &ipcc {
        status = "okay";
 };
 };
 
 &ltdc {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&ltdc_pins_a>;
+       pinctrl-1 = <&ltdc_pins_sleep_a>;
        status = "okay";
 
        port {
        status = "okay";
 };
 
+&pwr_regulators {
+       vdd-supply = <&vdd>;
+       vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
 &rng1 {
        status = "okay";
 };
        pinctrl-0 = <&uart4_pins_a>;
        status = "okay";
 };
+
+&vrefbuf {
+       regulator-min-microvolt = <2500000>;
+       regulator-max-microvolt = <2500000>;
+       vdda-supply = <&vdd>;
+       status = "okay";
+};
index 20ea601..d26adcb 100644 (file)
 / {
        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 {
        };
 };
 
+&i2c1 {
+       touchscreen@38 {
+               compatible = "focaltech,ft6236";
+               reg = <0x38>;
+               interrupts = <2 2>;
+               interrupt-parent = <&gpiof>;
+               interrupt-controller;
+               touchscreen-size-x = <480>;
+               touchscreen-size-y = <800>;
+               status = "okay";
+       };
+};
+
 &ltdc {
        status = "okay";
 
index 1d426ea..b8cc0fb 100644 (file)
                serial0 = &uart4;
        };
 
-       reg11: reg11 {
-               compatible = "regulator-fixed";
-               regulator-name = "reg11";
-               regulator-min-microvolt = <1100000>;
-               regulator-max-microvolt = <1100000>;
-               regulator-always-on;
-       };
-
-       reg18: reg18 {
-               compatible = "regulator-fixed";
-               regulator-name = "reg18";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
-               regulator-always-on;
-       };
-
        sd_switch: regulator-sd_switch {
                compatible = "regulator-gpio";
                regulator-name = "sd_switch";
 
                gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>;
                gpios-states = <0>;
-               states = <1800000 0x1 2900000 0x0>;
+               states = <1800000 0x1>,
+                        <2900000 0x0>;
+       };
+};
+
+&dac {
+       pinctrl-names = "default";
+       pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>;
+       vref-supply = <&vdda>;
+       status = "disabled";
+       dac1: dac@1 {
+               status = "okay";
+       };
+       dac2: dac@2 {
+               status = "okay";
        };
 };
 
 
                        vddcore: buck1 {
                                regulator-name = "vddcore";
-                               regulator-min-microvolt = <800000>;
+                               regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1350000>;
                                regulator-always-on;
                                regulator-initial-mode = <0>;
                         vbus_sw: pwr_sw2 {
                                regulator-name = "vbus_sw";
                                interrupts = <IT_OCP_SWOUT 0>;
-                               regulator-active-discharge;
+                               regulator-active-discharge = <1>;
                         };
                };
 
        status = "okay";
 };
 
+&pwr_regulators {
+       vdd-supply = <&vdd>;
+       vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
 &rng1 {
        status = "okay";
 };
index 91fc0a3..3789312 100644 (file)
@@ -32,7 +32,6 @@
 
        joystick {
                compatible = "gpio-keys";
-               #size-cells = <0>;
                pinctrl-0 = <&joystick_pins>;
                pinctrl-names = "default";
                button-0 {
 
 &usbh_ehci {
        phys = <&usbphyc_port0>;
-       phy-names = "usb";
        status = "okay";
 };
 
 &usbotg_hs {
        dr_mode = "peripheral";
        phys = <&usbphyc_port1 0>;
-       phy-names = "usb2-phy";
        status = "okay";
 };
 
index f98e037..ed8b258 100644 (file)
                        #reset-cells = <1>;
                };
 
+               pwr_regulators: pwr@50001000 {
+                       compatible = "st,stm32mp1,pwr-reg";
+                       reg = <0x50001000 0x10>;
+
+                       reg11: reg11 {
+                               regulator-name = "reg11";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                       };
+
+                       reg18: reg18 {
+                               regulator-name = "reg18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                       };
+
+                       usb33: usb33 {
+                               regulator-name = "usb33";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+               };
+
                exti: interrupt-controller@5000d000 {
                        compatible = "st,stm32mp1-exti", "syscon";
                        interrupt-controller;
index 7033a12..d6bb82c 100644 (file)
 &i2c1 {
        status = "okay";
 
-       at24@50 {
+       eeprom@50 {
                compatible = "atmel,24c16";
                pagesize = <16>;
                reg = <0x50>;
index ac76380..2cf34ae 100644 (file)
                                 <&ccu CLK_PLL_VIDEO1_2X>;
                        clock-names = "ahb", "mod", "ddc", "pll-0", "pll-1";
                        resets = <&ccu RST_AHB1_HDMI>;
-                       reset-names = "ahb";
                        dma-names = "ddc-tx", "ddc-rx", "audio-tx";
                        dmas = <&dma 13>, <&dma 13>, <&dma 14>;
                        status = "disabled";
index 3bec3e0..2fd31a0 100644 (file)
        status = "okay";
 };
 
+&i2c0 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       touchscreen@38 {
+               compatible = "edt,edt-ft5x06";
+               reg = <0x38>;
+               interrupt-parent = <&r_pio>;
+               interrupts = <0 7 IRQ_TYPE_EDGE_FALLING>; /* PL7 */
+               reset-gpios = <&pio 3 5 GPIO_ACTIVE_LOW>; /* PD5 */
+               vcc-supply = <&reg_ldo_io0>;
+               touchscreen-size-x = <1024>;
+               touchscreen-size-y = <600>;
+       };
+};
+
 &i2c1 {
        clock-frequency = <400000>;
        status = "okay";
index 74bb053..53c38de 100644 (file)
                        reg = <0x1c14000 0x400>;
                };
 
+               crypto: crypto@1c15000 {
+                       compatible = "allwinner,sun8i-a83t-crypto";
+                       reg = <0x01c15000 0x1000>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&ccu RST_BUS_SS>;
+                       clocks = <&ccu CLK_BUS_SS>, <&ccu CLK_SS>;
+                       clock-names = "bus", "mod";
+               };
+
                usb_otg: usb@1c19000 {
                        compatible = "allwinner,sun8i-a83t-musb",
                                     "allwinner,sun8i-a33-musb";
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-duo2.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-duo2.dts
new file mode 100644 (file)
index 0000000..c73f599
--- /dev/null
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Karl Palsson <karlp@tweak.net.au>
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "FriendlyARM NanoPi Duo2";
+       compatible = "friendlyarm,nanopi-duo2", "allwinner,sun8i-h3";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               pwr {
+                       label = "nanopi:red:pwr";
+                       gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+                       default-state = "on";
+               };
+
+               status {
+                       label = "nanopi:green:status";
+                       gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */
+               };
+       };
+
+       r_gpio_keys {
+               compatible = "gpio-keys";
+
+               k1 {
+                       label = "k1";
+                       linux,code = <BTN_0>;
+                       gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; /* PL3 */
+               };
+       };
+
+       reg_vdd_cpux: vdd-cpux-regulator {
+               compatible = "regulator-gpio";
+               regulator-name = "vdd-cpux";
+               regulator-min-microvolt = <1100000>;
+               regulator-max-microvolt = <1300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-ramp-delay = <50>; /* 4ms */
+
+               enable-active-high;
+               enable-gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
+               gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+               gpios-states = <0x1>;
+               states = <1100000 0x0
+                         1300000 0x1>;
+       };
+
+       reg_vcc_dram: vcc-dram {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc-dram";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               regulator-always-on;
+               regulator-boot-on;
+               enable-active-high;
+               gpio = <&r_pio 0 9 GPIO_ACTIVE_HIGH>; /* PL9 */
+               vin-supply = <&reg_vcc5v0>;
+        };
+
+       reg_vdd_sys: vdd-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd-sys";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-always-on;
+               regulator-boot-on;
+               enable-active-high;
+               gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
+               vin-supply = <&reg_vcc5v0>;
+        };
+
+       wifi_pwrseq: wifi_pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+               clocks = <&rtc 1>;
+               clock-names = "ext_clock";
+       };
+
+};
+
+&cpu0 {
+       cpu-supply = <&reg_vdd_cpux>;
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&mmc0 {
+       bus-width = <4>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+       status = "okay";
+       vmmc-supply = <&reg_vcc3v3>;
+};
+
+&mmc1 {
+       vmmc-supply = <&reg_vcc3v3>;
+       vqmmc-supply = <&reg_vcc3v3>;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       bus-width = <4>;
+       non-removable;
+       status = "okay";
+
+       sdio_wifi: sdio_wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+               interrupt-parent = <&pio>;
+               interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+               interrupt-names = "host-wake";
+       };
+};
+
+&ohci0 {
+       status = "okay";
+};
+
+&reg_usb0_vbus {
+       gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
+       status = "okay";
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pa_pins>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pins>, <&uart2_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 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+               host-wakeup-gpios = <&pio 0 7 GPIO_ACTIVE_HIGH>; /* PA7 */
+               shutdown-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+       };
+};
+
+&usb_otg {
+       status = "okay";
+       dr_mode = "otg";
+};
+
+&usbphy {
+       usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+       usb0_vbus-supply = <&reg_usb0_vbus>;
+       status = "okay";
+};
index e37c30e..fe773c7 100644 (file)
        };
 
        soc {
+               deinterlace: deinterlace@1400000 {
+                       compatible = "allwinner,sun8i-h3-deinterlace";
+                       reg = <0x01400000 0x20000>;
+                       clocks = <&ccu CLK_BUS_DEINTERLACE>,
+                                <&ccu CLK_DEINTERLACE>,
+                                <&ccu CLK_DRAM_DEINTERLACE>;
+                       clock-names = "bus", "mod", "ram";
+                       resets = <&ccu RST_BUS_DEINTERLACE>;
+                       interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+                       interconnects = <&mbus 9>;
+                       interconnect-names = "dma-mem";
+               };
+
                syscon: system-control@1c00000 {
                        compatible = "allwinner,sun8i-h3-system-control";
                        reg = <0x01c00000 0x1000>;
                        allwinner,sram = <&ve_sram 1>;
                };
 
+               crypto: crypto@1c15000 {
+                       compatible = "allwinner,sun8i-h3-crypto";
+                       reg = <0x01c15000 0x1000>;
+                       interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+                       clock-names = "bus", "mod";
+                       resets = <&ccu RST_BUS_CE>;
+               };
+
                mali: gpu@1c40000 {
                        compatible = "allwinner,sun8i-h3-mali", "arm,mali-400";
                        reg = <0x01c40000 0x10000>;
index c9c2688..421dfbb 100644 (file)
                        #phy-cells = <1>;
                };
 
+               crypto: crypto@1c15000 {
+                       compatible = "allwinner,sun8i-r40-crypto";
+                       reg = <0x01c15000 0x1000>;
+                       interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+                       clock-names = "bus", "mod";
+                       resets = <&ccu RST_BUS_CE>;
+               };
+
                ehci1: usb@1c19000 {
                        compatible = "allwinner,sun8i-r40-ehci", "generic-ehci";
                        reg = <0x01c19000 0x100>;
index b9b6fb0..1d900f5 100644 (file)
                        reg = <0x01700000 0x100>;
                };
 
+               crypto: crypto@1c02000 {
+                       compatible = "allwinner,sun9i-a80-crypto";
+                       reg = <0x01c02000 0x1000>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&ccu RST_BUS_SS>;
+                       clocks = <&ccu CLK_BUS_SS>, <&ccu CLK_SS>;
+                       clock-names = "bus", "mod";
+               };
+
                mmc0: mmc@1c0f000 {
                        compatible = "allwinner,sun9i-a80-mmc";
                        reg = <0x01c0f000 0x1000>;
                        compatible = "allwinner,sun6i-a31-wdt";
                        reg = <0x06000ca0 0x20>;
                        interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&osc24M>;
                };
 
                pio: pinctrl@6000800 {
                        compatible = "allwinner,sun6i-a31-wdt";
                        reg = <0x08001000 0x20>;
                        interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&osc24M>;
                };
 
                prcm@8001400 {
index 107eeaf..0afea59 100644 (file)
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
+               dma-ranges;
                ranges;
 
                display_clocks: clock@1000000 {
                                function = "uart2";
                        };
 
+                       uart2_rts_cts_pins: uart2-rts-cts-pins {
+                               pins = "PA2", "PA3";
+                               function = "uart2";
+                       };
+
                        uart3_pins: uart3-pins {
                                pins = "PA13", "PA14";
                                function = "uart3";
                        };
                };
 
+               mbus: dram-controller@1c62000 {
+                       compatible = "allwinner,sun8i-h3-mbus";
+                       reg = <0x01c62000 0x1000>;
+                       clocks = <&ccu 113>;
+                       dma-ranges = <0x00000000 0x40000000 0xc0000000>;
+                       #interconnect-cells = <1>;
+               };
+
                spi0: spi@1c68000 {
                        compatible = "allwinner,sun8i-h3-spi";
                        reg = <0x01c68000 0x1000>;
index 9af21fe..fb6b3e1 100644 (file)
@@ -1,5 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 / {
+       apbmisc@70000800 {
+               nvidia,long-ram-code;
+       };
+
        clock@60006000 {
                emc-timings-1 {
                        nvidia,ram-code = <1>;
                                clocks = <&tegra_car TEGRA124_CLK_PLL_M>;
                                clock-names = "emc-parent";
                        };
-                       /* TODO: Add 528MHz frequency */
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+                               nvidia,parent-clock-frequency = <528000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M_UD>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-600000000 {
+                               clock-frequency = <600000000>;
+                               nvidia,parent-clock-frequency = <600000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_C_UD>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-792000000 {
+                               clock-frequency = <792000000>;
+                               nvidia,parent-clock-frequency = <792000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M_UD>;
+                               clock-names = "emc-parent";
+                       };
+               };
+
+               emc-timings-4 {
+                       nvidia,ram-code = <4>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-40800000 {
+                               clock-frequency = <40800000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-68000000 {
+                               clock-frequency = <68000000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+                               nvidia,parent-clock-frequency = <600000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_C>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+                               nvidia,parent-clock-frequency = <792000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+                               nvidia,parent-clock-frequency = <528000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M_UD>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-600000000 {
+                               clock-frequency = <600000000>;
+                               nvidia,parent-clock-frequency = <600000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_C_UD>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-792000000 {
+                               clock-frequency = <792000000>;
+                               nvidia,parent-clock-frequency = <792000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M_UD>;
+                               clock-names = "emc-parent";
+                       };
+               };
+
+               emc-timings-6 {
+                       nvidia,ram-code = <6>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-40800000 {
+                               clock-frequency = <40800000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-68000000 {
+                               clock-frequency = <68000000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+                               nvidia,parent-clock-frequency = <600000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_C>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+                               nvidia,parent-clock-frequency = <792000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+                               nvidia,parent-clock-frequency = <528000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_M_UD>;
+                               clock-names = "emc-parent";
+                       };
                        timing-600000000 {
                                clock-frequency = <600000000>;
                                nvidia,parent-clock-frequency = <600000000>;
                                nvidia,emc-zcal-interval = <0x00000000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000a
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000000
-                                       0x00000000
-                                       0x00000003
-                                       0x00000003
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x00000006
-                                       0x00000002
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00010000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000c
-                                       0x0000000d
-                                       0x0000000f
-                                       0x00000060
-                                       0x00000000
-                                       0x00000018
-                                       0x00000002
-                                       0x00000002
-                                       0x00000001
-                                       0x00000000
-                                       0x00000007
-                                       0x0000000f
-                                       0x00000005
-                                       0x00000005
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000000
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000064
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x106aa298
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000303
-                                       0x81f1f108
-                                       0x07070004
-                                       0x0000003f
-                                       0x016eeeee
-                                       0x51451400
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x00000007
-                                       0x00000000
-                                       0x00000042
-                                       0x000c000c
-                                       0x00000000
-                                       0x00000003
-                                       0x0000f2f3
-                                       0x800001c5
-                                       0x0000000a
+                                       0x00000000 /* EMC_RC */
+                                       0x00000003 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000000 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000060 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000018 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000007 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000005 /* EMC_TXSR */
+                                       0x00000005 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000064 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000007 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x800001c5 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00000000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000000
-                                       0x00000005
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000a
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000000
-                                       0x00000000
-                                       0x00000003
-                                       0x00000003
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x00000006
-                                       0x00000002
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00010000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000c
-                                       0x0000000d
-                                       0x0000000f
-                                       0x0000009a
-                                       0x00000000
-                                       0x00000026
-                                       0x00000002
-                                       0x00000002
-                                       0x00000001
-                                       0x00000000
-                                       0x00000007
-                                       0x0000000f
-                                       0x00000006
-                                       0x00000006
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000000
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x000000a0
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x106aa298
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000303
-                                       0x81f1f108
-                                       0x07070004
-                                       0x0000003f
-                                       0x016eeeee
-                                       0x51451400
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x0000000b
-                                       0x00000000
-                                       0x00000042
-                                       0x000c000c
-                                       0x00000000
-                                       0x00000003
-                                       0x0000f2f3
-                                       0x8000023a
-                                       0x0000000a
+                                       0x00000000 /* EMC_RC */
+                                       0x00000005 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000000 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x0000009a /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000026 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000007 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000006 /* EMC_TXSR */
+                                       0x00000006 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x000000a0 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x0000000b /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x8000023a /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00000000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000001
-                                       0x0000000a
-                                       0x00000000
-                                       0x00000001
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000a
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000000
-                                       0x00000000
-                                       0x00000003
-                                       0x00000003
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x00000006
-                                       0x00000002
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00010000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000c
-                                       0x0000000d
-                                       0x0000000f
-                                       0x00000134
-                                       0x00000000
-                                       0x0000004d
-                                       0x00000002
-                                       0x00000002
-                                       0x00000001
-                                       0x00000000
-                                       0x00000008
-                                       0x0000000f
-                                       0x0000000c
-                                       0x0000000c
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000000
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x0000013f
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x106aa298
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000303
-                                       0x81f1f108
-                                       0x07070004
-                                       0x0000003f
-                                       0x016eeeee
-                                       0x51451400
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x00000015
-                                       0x00000000
-                                       0x00000042
-                                       0x000c000c
-                                       0x00000000
-                                       0x00000003
-                                       0x0000f2f3
-                                       0x80000370
-                                       0x0000000a
+                                       0x00000001 /* EMC_RC */
+                                       0x0000000a /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000001 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000134 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x0000004d /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000008 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000000c /* EMC_TXSR */
+                                       0x0000000c /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x0000013f /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000015 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x80000370 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00000000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000003
-                                       0x00000011
-                                       0x00000000
-                                       0x00000002
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000a
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000000
-                                       0x00000000
-                                       0x00000003
-                                       0x00000003
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x00000006
-                                       0x00000002
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00010000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000c
-                                       0x0000000d
-                                       0x0000000f
-                                       0x00000202
-                                       0x00000000
-                                       0x00000080
-                                       0x00000002
-                                       0x00000002
-                                       0x00000001
-                                       0x00000000
-                                       0x0000000f
-                                       0x0000000f
-                                       0x00000013
-                                       0x00000013
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000001
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000213
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x106aa298
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000303
-                                       0x81f1f108
-                                       0x07070004
-                                       0x0000003f
-                                       0x016eeeee
-                                       0x51451400
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x00000022
-                                       0x00000000
-                                       0x00000042
-                                       0x000c000c
-                                       0x00000000
-                                       0x00000003
-                                       0x0000f2f3
-                                       0x8000050e
-                                       0x0000000a
+                                       0x00000003 /* EMC_RC */
+                                       0x00000011 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000002 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000202 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000080 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x0000000f /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000013 /* EMC_TXSR */
+                                       0x00000013 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000001 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000213 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000022 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x8000050e /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00000000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000004
-                                       0x0000001a
-                                       0x00000000
-                                       0x00000003
-                                       0x00000001
-                                       0x00000004
-                                       0x0000000a
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000001
-                                       0x00000001
-                                       0x00000003
-                                       0x00000003
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x00000006
-                                       0x00000002
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00010000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x0000000c
-                                       0x0000000d
-                                       0x0000000f
-                                       0x00000304
-                                       0x00000000
-                                       0x000000c1
-                                       0x00000002
-                                       0x00000002
-                                       0x00000001
-                                       0x00000000
-                                       0x00000018
-                                       0x0000000f
-                                       0x0000001c
-                                       0x0000001c
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000003
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x0000031c
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x106aa298
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x000fc000
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x0000fc00
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000303
-                                       0x81f1f108
-                                       0x07070004
-                                       0x0000003f
-                                       0x016eeeee
-                                       0x51451400
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x00000033
-                                       0x00000000
-                                       0x00000042
-                                       0x000c000c
-                                       0x00000000
-                                       0x00000003
-                                       0x0000f2f3
-                                       0x80000713
-                                       0x0000000a
+                                       0x00000004 /* EMC_RC */
+                                       0x0000001a /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000003 /* EMC_RAS */
+                                       0x00000001 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000001 /* EMC_RD_RCD */
+                                       0x00000001 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000304 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000000c1 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000018 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000001c /* EMC_TXSR */
+                                       0x0000001c /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000003 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x0000031c /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000033 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x80000713 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00020000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000009
-                                       0x00000035
-                                       0x00000000
-                                       0x00000007
-                                       0x00000002
-                                       0x00000005
-                                       0x0000000a
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000002
-                                       0x00000002
-                                       0x00000003
-                                       0x00000003
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000006
-                                       0x00000002
-                                       0x00000000
-                                       0x00000004
-                                       0x00000006
-                                       0x00010000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000003
-                                       0x0000000d
-                                       0x0000000f
-                                       0x00000011
-                                       0x00000607
-                                       0x00000000
-                                       0x00000181
-                                       0x00000002
-                                       0x00000002
-                                       0x00000001
-                                       0x00000000
-                                       0x00000032
-                                       0x0000000f
-                                       0x00000038
-                                       0x00000038
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000007
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000638
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x106aa298
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00064000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00004000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00090000
-                                       0x00090000
-                                       0x00094000
-                                       0x00094000
-                                       0x00009400
-                                       0x00009000
-                                       0x00009000
-                                       0x00009000
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000303
-                                       0x81f1f108
-                                       0x07070004
-                                       0x0000003f
-                                       0x016eeeee
-                                       0x51451400
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x00000066
-                                       0x00000000
-                                       0x00000100
-                                       0x000c000c
-                                       0x00000000
-                                       0x00000003
-                                       0x0000d2b3
-                                       0x80000d22
-                                       0x0000000a
+                                       0x00000009 /* EMC_RC */
+                                       0x00000035 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000007 /* EMC_RAS */
+                                       0x00000002 /* EMC_RP */
+                                       0x00000005 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000002 /* EMC_RD_RCD */
+                                       0x00000002 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000005 /* EMC_WDV */
+                                       0x00000005 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000004 /* EMC_EINPUT */
+                                       0x00000006 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000003 /* EMC_QRST */
+                                       0x0000000d /* EMC_QSAFE */
+                                       0x0000000f /* EMC_RDV */
+                                       0x00000011 /* EMC_RDV_MASK */
+                                       0x00000607 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000181 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000032 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000038 /* EMC_TXSR */
+                                       0x00000038 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000007 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000638 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00090000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00090000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00094000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00094000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00009400 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000066 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000d2b3 /* EMC_CFG_PIPE */
+                                       0x80000d22 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00020000>;
 
                                nvidia,emc-configuration = <
-                                       0x0000000d
-                                       0x0000004c
-                                       0x00000000
-                                       0x00000009
-                                       0x00000003
-                                       0x00000004
-                                       0x00000008
-                                       0x00000002
-                                       0x00000009
-                                       0x00000003
-                                       0x00000003
-                                       0x00000002
-                                       0x00000002
-                                       0x00000000
-                                       0x00000003
-                                       0x00000003
-                                       0x00000005
-                                       0x00000002
-                                       0x00000000
-                                       0x00000002
-                                       0x00000007
-                                       0x00020000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000001
-                                       0x0000000e
-                                       0x00000010
-                                       0x00000012
-                                       0x000008e4
-                                       0x00000000
-                                       0x00000239
-                                       0x00000001
-                                       0x00000008
-                                       0x00000001
-                                       0x00000000
-                                       0x0000004a
-                                       0x0000000e
-                                       0x00000051
-                                       0x00000200
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000009
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000924
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x104ab098
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00098000
-                                       0x00098000
-                                       0x00000000
-                                       0x00098000
-                                       0x00098000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00060000
-                                       0x00060000
-                                       0x00060000
-                                       0x00060000
-                                       0x00006000
-                                       0x00006000
-                                       0x00006000
-                                       0x00006000
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000101
-                                       0x81f1f108
-                                       0x07070004
-                                       0x00000000
-                                       0x016eeeee
-                                       0x51451420
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x00000096
-                                       0x00000000
-                                       0x00000100
-                                       0x0174000c
-                                       0x00000000
-                                       0x00000003
-                                       0x000052a3
-                                       0x800012d7
-                                       0x00000009
+                                       0x0000000d /* EMC_RC */
+                                       0x0000004c /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000009 /* EMC_RAS */
+                                       0x00000003 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x00000008 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x00000009 /* EMC_W2P */
+                                       0x00000003 /* EMC_RD_RCD */
+                                       0x00000003 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000005 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x00000007 /* EMC_EINPUT_DURATION */
+                                       0x00020000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x0000000e /* EMC_QSAFE */
+                                       0x00000010 /* EMC_RDV */
+                                       0x00000012 /* EMC_RDV_MASK */
+                                       0x000008e4 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000239 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000001 /* EMC_PDEX2WR */
+                                       0x00000008 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x0000004a /* EMC_AR2PDEN */
+                                       0x0000000e /* EMC_RW2PDEN */
+                                       0x00000051 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000009 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000924 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000096 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x0174000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000052a3 /* EMC_CFG_PIPE */
+                                       0x800012d7 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x00000009 /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00020000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000012
-                                       0x00000065
-                                       0x00000000
-                                       0x0000000c
-                                       0x00000004
-                                       0x00000005
-                                       0x00000008
-                                       0x00000002
-                                       0x0000000a
-                                       0x00000004
-                                       0x00000004
-                                       0x00000002
-                                       0x00000002
-                                       0x00000000
-                                       0x00000003
-                                       0x00000003
-                                       0x00000005
-                                       0x00000002
-                                       0x00000000
-                                       0x00000001
-                                       0x00000008
-                                       0x00020000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x0000000f
-                                       0x00000010
-                                       0x00000012
-                                       0x00000bd1
-                                       0x00000000
-                                       0x000002f4
-                                       0x00000001
-                                       0x00000008
-                                       0x00000001
-                                       0x00000000
-                                       0x00000063
-                                       0x0000000f
-                                       0x0000006b
-                                       0x00000200
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x0000000d
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000c11
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x104ab098
-                                       0x002c00a0
-                                       0x00008000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00030000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00070000
-                                       0x00070000
-                                       0x00000000
-                                       0x00070000
-                                       0x00070000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00048000
-                                       0x00048000
-                                       0x00048000
-                                       0x00048000
-                                       0x00004800
-                                       0x00004800
-                                       0x00004800
-                                       0x00004800
-                                       0x10000280
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc081
-                                       0x00000101
-                                       0x81f1f108
-                                       0x07070004
-                                       0x00000000
-                                       0x016eeeee
-                                       0x51451420
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0000003f
-                                       0x000000c6
-                                       0x00000000
-                                       0x00000100
-                                       0x015b000c
-                                       0x00000000
-                                       0x00000003
-                                       0x000052a3
-                                       0x8000188b
-                                       0x00000009
+                                       0x00000012 /* EMC_RC */
+                                       0x00000065 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x0000000c /* EMC_RAS */
+                                       0x00000004 /* EMC_RP */
+                                       0x00000005 /* EMC_R2W */
+                                       0x00000008 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x0000000a /* EMC_W2P */
+                                       0x00000004 /* EMC_RD_RCD */
+                                       0x00000004 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000005 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000001 /* EMC_EINPUT */
+                                       0x00000008 /* EMC_EINPUT_DURATION */
+                                       0x00020000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000000 /* EMC_QRST */
+                                       0x0000000f /* EMC_QSAFE */
+                                       0x00000010 /* EMC_RDV */
+                                       0x00000012 /* EMC_RDV_MASK */
+                                       0x00000bd1 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000002f4 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000001 /* EMC_PDEX2WR */
+                                       0x00000008 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000063 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000006b /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x0000000d /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000c11 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x000000c6 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x015b000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000052a3 /* EMC_CFG_PIPE */
+                                       0x8000188b /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x00000009 /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0000089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100002>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80000941>;
+                               nvidia,emc-mrs-wait-cnt = <0x013a000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0123133d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000018 /* EMC_RC */
+                                       0x00000088 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000011 /* EMC_RAS */
+                                       0x00000006 /* EMC_RP */
+                                       0x00000006 /* EMC_R2W */
+                                       0x00000009 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x0000000d /* EMC_W2P */
+                                       0x00000006 /* EMC_RD_RCD */
+                                       0x00000006 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000007 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x00000009 /* EMC_EINPUT_DURATION */
+                                       0x00040000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x00000010 /* EMC_QSAFE */
+                                       0x00000013 /* EMC_RDV */
+                                       0x00000015 /* EMC_RDV_MASK */
+                                       0x00000fd6 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000003f5 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x0000000b /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000084 /* EMC_AR2PDEN */
+                                       0x00000012 /* EMC_RW2PDEN */
+                                       0x0000008f /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000013 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000006 /* EMC_TCLKSTABLE */
+                                       0x00000006 /* EMC_TCLKSTOP */
+                                       0x00001017 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0xe01200b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS8 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS9 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS10 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS11 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS12 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS13 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS14 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000001 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000001 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x013a000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000042a0 /* EMC_CFG_PIPE */
+                                       0x80002062 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000b /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00020000>;
 
                                nvidia,emc-configuration = <
-                                       0x0000001c
-                                       0x0000009a
-                                       0x00000000
-                                       0x00000013
-                                       0x00000007
-                                       0x00000007
-                                       0x0000000b
-                                       0x00000003
-                                       0x00000010
-                                       0x00000007
-                                       0x00000007
-                                       0x00000002
-                                       0x00000002
-                                       0x00000000
-                                       0x00000005
-                                       0x00000005
-                                       0x0000000a
-                                       0x00000002
-                                       0x00000000
-                                       0x00000003
-                                       0x0000000b
-                                       0x00070000
-                                       0x00000003
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000002
-                                       0x00000012
-                                       0x00000016
-                                       0x00000018
-                                       0x00001208
-                                       0x00000000
-                                       0x00000482
-                                       0x00000002
-                                       0x0000000d
-                                       0x00000001
-                                       0x00000000
-                                       0x00000096
-                                       0x00000015
-                                       0x000000a2
-                                       0x00000200
-                                       0x00000004
-                                       0x00000005
-                                       0x00000004
-                                       0x00000015
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x00001249
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x104ab098
-                                       0xe00e00b1
-                                       0x00008000
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00048000
-                                       0x00048000
-                                       0x00000000
-                                       0x00048000
-                                       0x00048000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000004
-                                       0x00000004
-                                       0x00000002
-                                       0x00000005
-                                       0x00000006
-                                       0x00000003
-                                       0x00000006
-                                       0x00000005
-                                       0x00000004
-                                       0x00000004
-                                       0x00000002
-                                       0x00000005
-                                       0x00000006
-                                       0x00000003
-                                       0x00000006
-                                       0x00000005
-                                       0x0000000e
-                                       0x0000000e
-                                       0x0000000e
-                                       0x0000000e
-                                       0x0000000e
-                                       0x0000000e
-                                       0x0000000e
-                                       0x0000000e
-                                       0x100002a0
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc085
-                                       0x00000101
-                                       0x81f1f108
-                                       0x07070004
-                                       0x00000000
-                                       0x016eeeee
-                                       0x51451420
-                                       0x00514514
-                                       0x00514514
-                                       0x51451400
-                                       0x0606003f
-                                       0x00000000
-                                       0x00000000
-                                       0x00000100
-                                       0x0128000c
-                                       0x00000000
-                                       0x00000003
-                                       0x000040a0
-                                       0x800024aa
-                                       0x0000000e
+                                       0x0000001c /* EMC_RC */
+                                       0x0000009a /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000013 /* EMC_RAS */
+                                       0x00000007 /* EMC_RP */
+                                       0x00000007 /* EMC_R2W */
+                                       0x0000000b /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x00000010 /* EMC_W2P */
+                                       0x00000007 /* EMC_RD_RCD */
+                                       0x00000007 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000005 /* EMC_WDV */
+                                       0x00000005 /* EMC_WDV_MASK */
+                                       0x0000000a /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000003 /* EMC_EINPUT */
+                                       0x0000000b /* EMC_EINPUT_DURATION */
+                                       0x00070000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000002 /* EMC_QRST */
+                                       0x00000012 /* EMC_QSAFE */
+                                       0x00000016 /* EMC_RDV */
+                                       0x00000018 /* EMC_RDV_MASK */
+                                       0x00001208 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000482 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x0000000d /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000096 /* EMC_AR2PDEN */
+                                       0x00000015 /* EMC_RW2PDEN */
+                                       0x000000a2 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000015 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000006 /* EMC_TCLKSTABLE */
+                                       0x00000006 /* EMC_TCLKSTOP */
+                                       0x00001249 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0xe00e00b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS8 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS9 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS10 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS11 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS12 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS13 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS14 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x0128000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000040a0 /* EMC_CFG_PIPE */
+                                       0x800024aa /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000e /* EMC_QPOP */
                                >;
                        };
 
                                nvidia,emc-zcal-interval = <0x00020000>;
 
                                nvidia,emc-configuration = <
-                                       0x00000025
-                                       0x000000cc
-                                       0x00000000
-                                       0x0000001a
-                                       0x00000009
-                                       0x00000008
-                                       0x0000000d
-                                       0x00000004
-                                       0x00000013
-                                       0x00000009
-                                       0x00000009
-                                       0x00000003
-                                       0x00000002
-                                       0x00000000
-                                       0x00000006
-                                       0x00000006
-                                       0x0000000b
-                                       0x00000002
-                                       0x00000000
-                                       0x00000002
-                                       0x0000000d
-                                       0x00080000
-                                       0x00000004
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000001
-                                       0x00000014
-                                       0x00000018
-                                       0x0000001a
-                                       0x000017e2
-                                       0x00000000
-                                       0x000005f8
-                                       0x00000003
-                                       0x00000011
-                                       0x00000001
-                                       0x00000000
-                                       0x000000c6
-                                       0x00000018
-                                       0x000000d6
-                                       0x00000200
-                                       0x00000005
-                                       0x00000006
-                                       0x00000005
-                                       0x0000001d
-                                       0x00000000
-                                       0x00000008
-                                       0x00000008
-                                       0x00001822
-                                       0x00000000
-                                       0x80000005
-                                       0x00000000
-                                       0x104ab198
-                                       0xe00700b1
-                                       0x00008000
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000005
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00034000
-                                       0x00034000
-                                       0x00000000
-                                       0x00034000
-                                       0x00034000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000000
-                                       0x00000008
-                                       0x00000008
-                                       0x00000005
-                                       0x00000009
-                                       0x00000009
-                                       0x00000007
-                                       0x00000009
-                                       0x00000008
-                                       0x00000008
-                                       0x00000008
-                                       0x00000005
-                                       0x00000009
-                                       0x00000009
-                                       0x00000007
-                                       0x00000009
-                                       0x00000008
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x0000000a
-                                       0x100002a0
-                                       0x00000000
-                                       0x00111111
-                                       0x00000000
-                                       0x00000000
-                                       0x77ffc085
-                                       0x00000101
-                                       0x81f1f108
-                                       0x07070004
-                                       0x00000000
-                                       0x016eeeee
-                                       0x61861820
-                                       0x00514514
-                                       0x00514514
-                                       0x61861800
-                                       0x0606003f
-                                       0x00000000
-                                       0x00000000
-                                       0x00000100
-                                       0x00f8000c
-                                       0x00000007
-                                       0x00000004
-                                       0x00004080
-                                       0x80003012
-                                       0x0000000f
+                                       0x00000025 /* EMC_RC */
+                                       0x000000cc /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x0000001a /* EMC_RAS */
+                                       0x00000009 /* EMC_RP */
+                                       0x00000008 /* EMC_R2W */
+                                       0x0000000d /* EMC_W2R */
+                                       0x00000004 /* EMC_R2P */
+                                       0x00000013 /* EMC_W2P */
+                                       0x00000009 /* EMC_RD_RCD */
+                                       0x00000009 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x0000000b /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x0000000d /* EMC_EINPUT_DURATION */
+                                       0x00080000 /* EMC_PUTERM_EXTRA */
+                                       0x00000004 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x00000014 /* EMC_QSAFE */
+                                       0x00000018 /* EMC_RDV */
+                                       0x0000001a /* EMC_RDV_MASK */
+                                       0x000017e2 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000005f8 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000003 /* EMC_PDEX2WR */
+                                       0x00000011 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x000000c6 /* EMC_AR2PDEN */
+                                       0x00000018 /* EMC_RW2PDEN */
+                                       0x000000d6 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000005 /* EMC_TCKE */
+                                       0x00000006 /* EMC_TCKESR */
+                                       0x00000005 /* EMC_TPD */
+                                       0x0000001d /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000008 /* EMC_TCLKSTABLE */
+                                       0x00000008 /* EMC_TCLKSTOP */
+                                       0x00001822 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x80000005 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab198 /* EMC_FBIO_CFG5 */
+                                       0xe00700b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00000005 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000007 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000007 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x61861820 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x61861800 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x00f8000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000007 /* EMC_CTT */
+                                       0x00000004 /* EMC_CTT_DURATION */
+                                       0x00004080 /* EMC_CFG_PIPE */
+                                       0x80003012 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000f /* EMC_QPOP */
                                >;
                        };
-
                };
-       };
-
-       memory-controller@70019000 {
-               emc-timings-1 {
-                       nvidia,ram-code = <1>;
 
+               emc-timings-4 {
+                       nvidia,ram-code = <4>;
 
                        timing-12750000 {
                                clock-frequency = <12750000>;
 
-                               nvidia,emem-configuration = <
-                                       0x40040001
-                                       0x8000000a
-                                       0x00000001
-                                       0x00000001
-                                       0x00000002
-                                       0x00000000
-                                       0x00000002
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000003
-                                       0x00000002
-                                       0x00000003
-                                       0x00000006
-                                       0x06030203
-                                       0x000a0402
-                                       0x77e30303
-                                       0x70000f03
-                                       0x001f0000
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100003>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000e000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000000 /* EMC_RC */
+                                       0x00000004 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000000 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000005 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000060 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000018 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000007 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000005 /* EMC_TXSR */
+                                       0x00000005 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000064 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000007 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000e000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x800001c5 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                        timing-20400000 {
                                clock-frequency = <20400000>;
 
-                               nvidia,emem-configuration = <
-                                       0x40020001
-                                       0x80000012
-                                       0x00000001
-                                       0x00000001
-                                       0x00000002
-                                       0x00000000
-                                       0x00000002
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000003
-                                       0x00000002
-                                       0x00000003
-                                       0x00000006
-                                       0x06030203
-                                       0x000a0402
-                                       0x76230303
-                                       0x70000f03
-                                       0x001f0000
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100003>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000e000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000000 /* EMC_RC */
+                                       0x00000007 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000000 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000005 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x0000009a /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000026 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000007 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000008 /* EMC_TXSR */
+                                       0x00000008 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x000000a0 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x0000000b /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000e000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x8000023a /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                        timing-40800000 {
                                clock-frequency = <40800000>;
 
-                               nvidia,emem-configuration = <
-                                       0xa0000001
-                                       0x80000017
-                                       0x00000001
-                                       0x00000001
-                                       0x00000002
-                                       0x00000000
-                                       0x00000002
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000003
-                                       0x00000002
-                                       0x00000003
-                                       0x00000006
-                                       0x06030203
-                                       0x000a0402
-                                       0x74a30303
-                                       0x70000f03
-                                       0x001f0000
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100003>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000e000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000001 /* EMC_RC */
+                                       0x0000000e /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000001 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000005 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000134 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x0000004d /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x0000000c /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000000f /* EMC_TXSR */
+                                       0x0000000f /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x0000013f /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000015 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000e000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x80000370 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                        timing-68000000 {
                                clock-frequency = <68000000>;
 
-                               nvidia,emem-configuration = <
-                                       0x00000001
-                                       0x8000001e
-                                       0x00000001
-                                       0x00000001
-                                       0x00000002
-                                       0x00000000
-                                       0x00000002
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000003
-                                       0x00000002
-                                       0x00000003
-                                       0x00000006
-                                       0x06030203
-                                       0x000a0402
-                                       0x74230403
-                                       0x70000f03
-                                       0x001f0000
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100003>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000e000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000003 /* EMC_RC */
+                                       0x00000017 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000002 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000005 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000202 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000080 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000015 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000019 /* EMC_TXSR */
+                                       0x00000019 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000001 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000213 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000022 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000e000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x8000050e /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                        timing-102000000 {
                                clock-frequency = <102000000>;
 
-                               nvidia,emem-configuration = <
-                                       0x08000001
-                                       0x80000026
-                                       0x00000001
-                                       0x00000001
-                                       0x00000003
-                                       0x00000000
-                                       0x00000002
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000003
-                                       0x00000002
-                                       0x00000003
-                                       0x00000006
-                                       0x06030203
-                                       0x000a0403
-                                       0x73c30504
-                                       0x70000f03
-                                       0x001f0000
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100003>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000e000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000004 /* EMC_RC */
+                                       0x00000023 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000003 /* EMC_RAS */
+                                       0x00000001 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000005 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000001 /* EMC_RD_RCD */
+                                       0x00000001 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000304 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000000c1 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000021 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000025 /* EMC_TXSR */
+                                       0x00000025 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000003 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x0000031c /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00080000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00008000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000033 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000e000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x80000713 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
                                >;
                        };
 
                        timing-204000000 {
                                clock-frequency = <204000000>;
 
-                               nvidia,emem-configuration = <
-                                       0x01000003
-                                       0x80000040
-                                       0x00000001
-                                       0x00000001
-                                       0x00000005
-                                       0x00000002
-                                       0x00000004
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000003
-                                       0x00000002
-                                       0x00000004
-                                       0x00000006
-                                       0x06040203
-                                       0x000a0405
-                                       0x73840a06
-                                       0x70000f03
-                                       0x001f0000
-                               >;
-                       };
-
-                       timing-300000000 {
-                               clock-frequency = <300000000>;
-
-                               nvidia,emem-configuration = <
-                                       0x08000004
-                                       0x80000040
-                                       0x00000001
-                                       0x00000002
-                                       0x00000007
-                                       0x00000004
-                                       0x00000005
-                                       0x00000001
-                                       0x00000002
-                                       0x00000007
-                                       0x00000002
-                                       0x00000002
-                                       0x00000004
-                                       0x00000006
-                                       0x06040202
-                                       0x000b0607
-                                       0x77450e08
-                                       0x70000f03
-                                       0x001f0000
-                               >;
-                       };
-
-                       timing-396000000 {
-                               clock-frequency = <396000000>;
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x0000088d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100003>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000e000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000009 /* EMC_RC */
+                                       0x00000047 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000006 /* EMC_RAS */
+                                       0x00000002 /* EMC_RP */
+                                       0x00000005 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000005 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000002 /* EMC_RD_RCD */
+                                       0x00000002 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000005 /* EMC_WDV */
+                                       0x00000005 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000004 /* EMC_EINPUT */
+                                       0x00000006 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000003 /* EMC_QRST */
+                                       0x0000000d /* EMC_QSAFE */
+                                       0x0000000f /* EMC_RDV */
+                                       0x00000011 /* EMC_RDV_MASK */
+                                       0x00000607 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000181 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000044 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000004a /* EMC_TXSR */
+                                       0x0000004a /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000007 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000638 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00090000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00090000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00094000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00094000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00009400 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000066 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000e000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000d2b3 /* EMC_CFG_PIPE */
+                                       0x80000d22 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73340000>;
+                               nvidia,emc-cfg-2 = <0x000008d5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100002>;
+                               nvidia,emc-mode-2 = <0x00200000>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00000321>;
+                               nvidia,emc-mrs-wait-cnt = <0x0117000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x01231339>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x0000000d /* EMC_RC */
+                                       0x00000067 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000009 /* EMC_RAS */
+                                       0x00000003 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x00000008 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x00000009 /* EMC_W2P */
+                                       0x00000003 /* EMC_RD_RCD */
+                                       0x00000003 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000005 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x00000007 /* EMC_EINPUT_DURATION */
+                                       0x00020000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x0000000e /* EMC_QSAFE */
+                                       0x00000010 /* EMC_RDV */
+                                       0x00000012 /* EMC_RDV_MASK */
+                                       0x000008e4 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000239 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000001 /* EMC_PDEX2WR */
+                                       0x00000008 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000065 /* EMC_AR2PDEN */
+                                       0x0000000e /* EMC_RW2PDEN */
+                                       0x0000006c /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000009 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000924 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000096 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x0117000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000052a3 /* EMC_CFG_PIPE */
+                                       0x800012d7 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x00000009 /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73340000>;
+                               nvidia,emc-cfg-2 = <0x00000895>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100002>;
+                               nvidia,emc-mode-2 = <0x00200000>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00000521>;
+                               nvidia,emc-mrs-wait-cnt = <0x00f5000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x01231339>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000011 /* EMC_RC */
+                                       0x00000089 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x0000000c /* EMC_RAS */
+                                       0x00000004 /* EMC_RP */
+                                       0x00000005 /* EMC_R2W */
+                                       0x00000008 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x0000000a /* EMC_W2P */
+                                       0x00000004 /* EMC_RD_RCD */
+                                       0x00000004 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000005 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000001 /* EMC_EINPUT */
+                                       0x00000008 /* EMC_EINPUT_DURATION */
+                                       0x00020000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000000 /* EMC_QRST */
+                                       0x0000000f /* EMC_QSAFE */
+                                       0x00000010 /* EMC_RDV */
+                                       0x00000012 /* EMC_RDV_MASK */
+                                       0x00000bd1 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000002f4 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000001 /* EMC_PDEX2WR */
+                                       0x00000008 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000087 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000008f /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x0000000d /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000c11 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x000000c6 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x00f5000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000052a3 /* EMC_CFG_PIPE */
+                                       0x8000188b /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x00000009 /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0000089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100002>;
+                               nvidia,emc-mode-2 = <0x00200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00000941>;
+                               nvidia,emc-mrs-wait-cnt = <0x00c8000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0123133d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000018 /* EMC_RC */
+                                       0x000000b7 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000010 /* EMC_RAS */
+                                       0x00000006 /* EMC_RP */
+                                       0x00000006 /* EMC_R2W */
+                                       0x00000009 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x0000000d /* EMC_W2P */
+                                       0x00000006 /* EMC_RD_RCD */
+                                       0x00000006 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000007 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x00000009 /* EMC_EINPUT_DURATION */
+                                       0x00040000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x00000010 /* EMC_QSAFE */
+                                       0x00000013 /* EMC_RDV */
+                                       0x00000015 /* EMC_RDV_MASK */
+                                       0x00000fd6 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000003f5 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x0000000b /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x000000b4 /* EMC_AR2PDEN */
+                                       0x00000012 /* EMC_RW2PDEN */
+                                       0x000000bf /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000013 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000006 /* EMC_TCLKSTABLE */
+                                       0x00000006 /* EMC_TCLKSTOP */
+                                       0x00001017 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0xe01200b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS8 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS9 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS10 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS11 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS12 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS13 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS14 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000001 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000001 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x00c8000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000042a0 /* EMC_CFG_PIPE */
+                                       0x80002062 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000b /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-600000000 {
+                               clock-frequency = <600000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0000089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100002>;
+                               nvidia,emc-mode-2 = <0x00200010>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00000b61>;
+                               nvidia,emc-mrs-wait-cnt = <0x00b0000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0121113d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x0000001b /* EMC_RC */
+                                       0x000000d0 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000013 /* EMC_RAS */
+                                       0x00000007 /* EMC_RP */
+                                       0x00000007 /* EMC_R2W */
+                                       0x0000000b /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x00000010 /* EMC_W2P */
+                                       0x00000007 /* EMC_RD_RCD */
+                                       0x00000007 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000005 /* EMC_WDV */
+                                       0x00000005 /* EMC_WDV_MASK */
+                                       0x0000000a /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000003 /* EMC_EINPUT */
+                                       0x0000000b /* EMC_EINPUT_DURATION */
+                                       0x00070000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000002 /* EMC_QRST */
+                                       0x00000012 /* EMC_QSAFE */
+                                       0x00000016 /* EMC_RDV */
+                                       0x00000018 /* EMC_RDV_MASK */
+                                       0x00001208 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000482 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x0000000d /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x000000cc /* EMC_AR2PDEN */
+                                       0x00000015 /* EMC_RW2PDEN */
+                                       0x000000d8 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000015 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000006 /* EMC_TCLKSTABLE */
+                                       0x00000006 /* EMC_TCLKSTOP */
+                                       0x00001249 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0xe00e00b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS8 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS9 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS10 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS11 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS12 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS13 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS14 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x00b0000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000040a0 /* EMC_CFG_PIPE */
+                                       0x800024aa /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000e /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-792000000 {
+                               clock-frequency = <792000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0080089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x00100002>;
+                               nvidia,emc-mode-2 = <0x00200418>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x00000d71>;
+                               nvidia,emc-mrs-wait-cnt = <0x006f000e>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040000>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0120113d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000024 /* EMC_RC */
+                                       0x00000114 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000019 /* EMC_RAS */
+                                       0x0000000a /* EMC_RP */
+                                       0x00000008 /* EMC_R2W */
+                                       0x0000000d /* EMC_W2R */
+                                       0x00000004 /* EMC_R2P */
+                                       0x00000013 /* EMC_W2P */
+                                       0x0000000a /* EMC_RD_RCD */
+                                       0x0000000a /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x0000000b /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x0000000d /* EMC_EINPUT_DURATION */
+                                       0x00080000 /* EMC_PUTERM_EXTRA */
+                                       0x00000004 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x00000014 /* EMC_QSAFE */
+                                       0x00000018 /* EMC_RDV */
+                                       0x0000001a /* EMC_RDV_MASK */
+                                       0x000017e2 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000005f8 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000003 /* EMC_PDEX2WR */
+                                       0x00000011 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x0000010d /* EMC_AR2PDEN */
+                                       0x00000018 /* EMC_RW2PDEN */
+                                       0x0000011e /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000005 /* EMC_TCKE */
+                                       0x00000006 /* EMC_TCKESR */
+                                       0x00000005 /* EMC_TPD */
+                                       0x0000001d /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000008 /* EMC_TCLKSTABLE */
+                                       0x00000008 /* EMC_TCLKSTOP */
+                                       0x00001822 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x80000005 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab198 /* EMC_FBIO_CFG5 */
+                                       0xe00700b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x007fc007 /* EMC_DLL_XFORM_DQS0 */
+                                       0x007fc008 /* EMC_DLL_XFORM_DQS1 */
+                                       0x007f400c /* EMC_DLL_XFORM_DQS2 */
+                                       0x007fc007 /* EMC_DLL_XFORM_DQS3 */
+                                       0x007f4006 /* EMC_DLL_XFORM_DQS4 */
+                                       0x007f8004 /* EMC_DLL_XFORM_DQS5 */
+                                       0x007f8005 /* EMC_DLL_XFORM_DQS6 */
+                                       0x007f8004 /* EMC_DLL_XFORM_DQS7 */
+                                       0x007fc007 /* EMC_DLL_XFORM_DQS8 */
+                                       0x007fc008 /* EMC_DLL_XFORM_DQS9 */
+                                       0x007f400c /* EMC_DLL_XFORM_DQS10 */
+                                       0x007fc007 /* EMC_DLL_XFORM_DQS11 */
+                                       0x007f4006 /* EMC_DLL_XFORM_DQS12 */
+                                       0x007f8004 /* EMC_DLL_XFORM_DQS13 */
+                                       0x007f8005 /* EMC_DLL_XFORM_DQS14 */
+                                       0x007f8004 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00034000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000007 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000007 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x61861820 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00492492 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00492492 /* EMC_XM2DQSPADCTRL5 */
+                                       0x61861800 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x006f000e /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000007 /* EMC_CTT */
+                                       0x00000004 /* EMC_CTT_DURATION */
+                                       0x00004080 /* EMC_CFG_PIPE */
+                                       0x80003012 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000f /* EMC_QPOP */
+                               >;
+                       };
+               };
+
+               emc-timings-6 {
+                       nvidia,ram-code = <6>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100003>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000c000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000000 /* EMC_RC */
+                                       0x00000003 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000000 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000060 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000018 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000007 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000005 /* EMC_TXSR */
+                                       0x00000005 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000064 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000007 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x800001c5 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100003>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000c000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000000 /* EMC_RC */
+                                       0x00000005 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000000 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x0000009a /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000026 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000007 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000006 /* EMC_TXSR */
+                                       0x00000006 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x000000a0 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x0000000b /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x8000023a /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-40800000 {
+                               clock-frequency = <40800000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100003>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000c000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000001 /* EMC_RC */
+                                       0x0000000a /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000001 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000134 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x0000004d /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000008 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000000c /* EMC_TXSR */
+                                       0x0000000c /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000000 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x0000013f /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000015 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x80000370 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-68000000 {
+                               clock-frequency = <68000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100003>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000c000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000003 /* EMC_RC */
+                                       0x00000011 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000002 /* EMC_RAS */
+                                       0x00000000 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000000 /* EMC_RD_RCD */
+                                       0x00000000 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000202 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000080 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x0000000f /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000013 /* EMC_TXSR */
+                                       0x00000013 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000001 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000213 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000022 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x8000050e /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x000008c5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100003>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000c000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00000000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000004 /* EMC_RC */
+                                       0x0000001a /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000003 /* EMC_RAS */
+                                       0x00000001 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000001 /* EMC_RD_RCD */
+                                       0x00000001 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000005 /* EMC_EINPUT */
+                                       0x00000005 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000004 /* EMC_QRST */
+                                       0x0000000c /* EMC_QSAFE */
+                                       0x0000000d /* EMC_RDV */
+                                       0x0000000f /* EMC_RDV_MASK */
+                                       0x00000304 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000000c1 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000018 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000001c /* EMC_TXSR */
+                                       0x0000001c /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000003 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x0000031c /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000033 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000042 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000f2f3 /* EMC_CFG_PIPE */
+                                       0x80000713 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000008>;
+                               nvidia,emc-cfg = <0x73240000>;
+                               nvidia,emc-cfg-2 = <0x0000088d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100003>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80001221>;
+                               nvidia,emc-mrs-wait-cnt = <0x000c000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0130b118>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000009 /* EMC_RC */
+                                       0x00000035 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000007 /* EMC_RAS */
+                                       0x00000002 /* EMC_RP */
+                                       0x00000005 /* EMC_R2W */
+                                       0x0000000a /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x0000000b /* EMC_W2P */
+                                       0x00000002 /* EMC_RD_RCD */
+                                       0x00000002 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000003 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000005 /* EMC_WDV */
+                                       0x00000005 /* EMC_WDV_MASK */
+                                       0x00000006 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000004 /* EMC_EINPUT */
+                                       0x00000006 /* EMC_EINPUT_DURATION */
+                                       0x00010000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000003 /* EMC_QRST */
+                                       0x0000000d /* EMC_QSAFE */
+                                       0x0000000f /* EMC_RDV */
+                                       0x00000011 /* EMC_RDV_MASK */
+                                       0x00000607 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000181 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x00000002 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000032 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x00000038 /* EMC_TXSR */
+                                       0x00000038 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000007 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000638 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x106aa298 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00064000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00004000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00090000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00090000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00094000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00094000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00009400 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00009000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000303 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000066 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x000c000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x0000d2b3 /* EMC_CFG_PIPE */
+                                       0x80000d22 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000a /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73340000>;
+                               nvidia,emc-cfg-2 = <0x000008d5>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100002>;
+                               nvidia,emc-mode-2 = <0x80200000>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80000321>;
+                               nvidia,emc-mrs-wait-cnt = <0x0174000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x01231339>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x0000000d /* EMC_RC */
+                                       0x0000004c /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000009 /* EMC_RAS */
+                                       0x00000003 /* EMC_RP */
+                                       0x00000004 /* EMC_R2W */
+                                       0x00000008 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x00000009 /* EMC_W2P */
+                                       0x00000003 /* EMC_RD_RCD */
+                                       0x00000003 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000005 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x00000007 /* EMC_EINPUT_DURATION */
+                                       0x00020000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x0000000e /* EMC_QSAFE */
+                                       0x00000010 /* EMC_RDV */
+                                       0x00000012 /* EMC_RDV_MASK */
+                                       0x000008e4 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000239 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000001 /* EMC_PDEX2WR */
+                                       0x00000008 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x0000004a /* EMC_AR2PDEN */
+                                       0x0000000e /* EMC_RW2PDEN */
+                                       0x00000051 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000009 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000924 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00098000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00060000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00006000 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000096 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x0174000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000052a3 /* EMC_CFG_PIPE */
+                                       0x800012d7 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x00000009 /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73340000>;
+                               nvidia,emc-cfg-2 = <0x00000895>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100002>;
+                               nvidia,emc-mode-2 = <0x80200000>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80000521>;
+                               nvidia,emc-mrs-wait-cnt = <0x015b000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x01231339>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000012 /* EMC_RC */
+                                       0x00000065 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x0000000c /* EMC_RAS */
+                                       0x00000004 /* EMC_RP */
+                                       0x00000005 /* EMC_R2W */
+                                       0x00000008 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x0000000a /* EMC_W2P */
+                                       0x00000004 /* EMC_RD_RCD */
+                                       0x00000004 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000005 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000001 /* EMC_EINPUT */
+                                       0x00000008 /* EMC_EINPUT_DURATION */
+                                       0x00020000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000000 /* EMC_QRST */
+                                       0x0000000f /* EMC_QSAFE */
+                                       0x00000010 /* EMC_RDV */
+                                       0x00000012 /* EMC_RDV_MASK */
+                                       0x00000bd1 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000002f4 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000001 /* EMC_PDEX2WR */
+                                       0x00000008 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000063 /* EMC_AR2PDEN */
+                                       0x0000000f /* EMC_RW2PDEN */
+                                       0x0000006b /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x0000000d /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000005 /* EMC_TCLKSTABLE */
+                                       0x00000005 /* EMC_TCLKSTOP */
+                                       0x00000c11 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0x002c00a0 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS5 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00030000 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00070000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ0 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ1 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ2 */
+                                       0x00048000 /* EMC_DLL_XFORM_DQ3 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ4 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ5 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ6 */
+                                       0x00004800 /* EMC_DLL_XFORM_DQ7 */
+                                       0x10000280 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc081 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0000003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x000000c6 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x015b000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000052a3 /* EMC_CFG_PIPE */
+                                       0x8000188b /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x00000009 /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0000089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100002>;
+                               nvidia,emc-mode-2 = <0x80200008>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80000941>;
+                               nvidia,emc-mrs-wait-cnt = <0x013a000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0123133d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000018 /* EMC_RC */
+                                       0x00000088 /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000011 /* EMC_RAS */
+                                       0x00000006 /* EMC_RP */
+                                       0x00000006 /* EMC_R2W */
+                                       0x00000009 /* EMC_W2R */
+                                       0x00000002 /* EMC_R2P */
+                                       0x0000000d /* EMC_W2P */
+                                       0x00000006 /* EMC_RD_RCD */
+                                       0x00000006 /* EMC_WR_RCD */
+                                       0x00000002 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000003 /* EMC_WDV */
+                                       0x00000003 /* EMC_WDV_MASK */
+                                       0x00000007 /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x00000009 /* EMC_EINPUT_DURATION */
+                                       0x00040000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x00000010 /* EMC_QSAFE */
+                                       0x00000013 /* EMC_RDV */
+                                       0x00000015 /* EMC_RDV_MASK */
+                                       0x00000fd6 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000003f5 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x0000000b /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000084 /* EMC_AR2PDEN */
+                                       0x00000012 /* EMC_RW2PDEN */
+                                       0x0000008f /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000013 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000006 /* EMC_TCLKSTABLE */
+                                       0x00000006 /* EMC_TCLKSTOP */
+                                       0x00001017 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0xe01200b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS8 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS9 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS10 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS11 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS12 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS13 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS14 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00050000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000001 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000001 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x013a000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000042a0 /* EMC_CFG_PIPE */
+                                       0x80002062 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000b /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-600000000 {
+                               clock-frequency = <600000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0000089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100002>;
+                               nvidia,emc-mode-2 = <0x80200010>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80000b61>;
+                               nvidia,emc-mrs-wait-cnt = <0x0128000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040008>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0121113d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x0000001c /* EMC_RC */
+                                       0x0000009a /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x00000013 /* EMC_RAS */
+                                       0x00000007 /* EMC_RP */
+                                       0x00000007 /* EMC_R2W */
+                                       0x0000000b /* EMC_W2R */
+                                       0x00000003 /* EMC_R2P */
+                                       0x00000010 /* EMC_W2P */
+                                       0x00000007 /* EMC_RD_RCD */
+                                       0x00000007 /* EMC_WR_RCD */
+                                       0x00000003 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000005 /* EMC_WDV */
+                                       0x00000005 /* EMC_WDV_MASK */
+                                       0x0000000a /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000003 /* EMC_EINPUT */
+                                       0x0000000b /* EMC_EINPUT_DURATION */
+                                       0x00070000 /* EMC_PUTERM_EXTRA */
+                                       0x00000003 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000002 /* EMC_QRST */
+                                       0x00000012 /* EMC_QSAFE */
+                                       0x00000016 /* EMC_RDV */
+                                       0x00000018 /* EMC_RDV_MASK */
+                                       0x00001208 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x00000482 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000002 /* EMC_PDEX2WR */
+                                       0x0000000d /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x00000096 /* EMC_AR2PDEN */
+                                       0x00000015 /* EMC_RW2PDEN */
+                                       0x000000a2 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000004 /* EMC_TCKE */
+                                       0x00000005 /* EMC_TCKESR */
+                                       0x00000004 /* EMC_TPD */
+                                       0x00000015 /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000006 /* EMC_TCLKSTABLE */
+                                       0x00000006 /* EMC_TCLKSTOP */
+                                       0x00001249 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x00000000 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab098 /* EMC_FBIO_CFG5 */
+                                       0xe00e00b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS0 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS1 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS2 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS3 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS4 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS5 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS6 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS7 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS8 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS9 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS10 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS11 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS12 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS13 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS14 */
+                                       0x0000000a /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00048000 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000004 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000002 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000003 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000006 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x51451420 /* EMC_XM2DQSPADCTRL3 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL4 */
+                                       0x00514514 /* EMC_XM2DQSPADCTRL5 */
+                                       0x51451400 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x0128000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000000 /* EMC_CTT */
+                                       0x00000003 /* EMC_CTT_DURATION */
+                                       0x000040a0 /* EMC_CFG_PIPE */
+                                       0x800024aa /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000e /* EMC_QPOP */
+                               >;
+                       };
+
+                       timing-792000000 {
+                               clock-frequency = <792000000>;
+
+                               nvidia,emc-auto-cal-config = <0xa1430000>;
+                               nvidia,emc-auto-cal-config2 = <0x00000000>;
+                               nvidia,emc-auto-cal-config3 = <0x00000000>;
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-bgbias-ctl0 = <0x00000000>;
+                               nvidia,emc-cfg = <0x73300000>;
+                               nvidia,emc-cfg-2 = <0x0080089d>;
+                               nvidia,emc-ctt-term-ctrl = <0x00000802>;
+                               nvidia,emc-mode-1 = <0x80100002>;
+                               nvidia,emc-mode-2 = <0x80200418>;
+                               nvidia,emc-mode-4 = <0x00000000>;
+                               nvidia,emc-mode-reset = <0x80000d71>;
+                               nvidia,emc-mrs-wait-cnt = <0x00f8000c>;
+                               nvidia,emc-sel-dpd-ctrl = <0x00040000>;
+                               nvidia,emc-xm2dqspadctrl2 = <0x0120113d>;
+                               nvidia,emc-zcal-cnt-long = <0x00000042>;
+                               nvidia,emc-zcal-interval = <0x00020000>;
+
+                               nvidia,emc-configuration = <
+                                       0x00000025 /* EMC_RC */
+                                       0x000000cc /* EMC_RFC */
+                                       0x00000000 /* EMC_RFC_SLR */
+                                       0x0000001a /* EMC_RAS */
+                                       0x00000009 /* EMC_RP */
+                                       0x00000008 /* EMC_R2W */
+                                       0x0000000d /* EMC_W2R */
+                                       0x00000004 /* EMC_R2P */
+                                       0x00000013 /* EMC_W2P */
+                                       0x00000009 /* EMC_RD_RCD */
+                                       0x00000009 /* EMC_WR_RCD */
+                                       0x00000004 /* EMC_RRD */
+                                       0x00000002 /* EMC_REXT */
+                                       0x00000000 /* EMC_WEXT */
+                                       0x00000006 /* EMC_WDV */
+                                       0x00000006 /* EMC_WDV_MASK */
+                                       0x0000000b /* EMC_QUSE */
+                                       0x00000002 /* EMC_QUSE_WIDTH */
+                                       0x00000000 /* EMC_IBDLY */
+                                       0x00000002 /* EMC_EINPUT */
+                                       0x0000000d /* EMC_EINPUT_DURATION */
+                                       0x00080000 /* EMC_PUTERM_EXTRA */
+                                       0x00000004 /* EMC_PUTERM_WIDTH */
+                                       0x00000000 /* EMC_PUTERM_ADJ */
+                                       0x00000000 /* EMC_CDB_CNTL_1 */
+                                       0x00000000 /* EMC_CDB_CNTL_2 */
+                                       0x00000000 /* EMC_CDB_CNTL_3 */
+                                       0x00000001 /* EMC_QRST */
+                                       0x00000014 /* EMC_QSAFE */
+                                       0x00000018 /* EMC_RDV */
+                                       0x0000001a /* EMC_RDV_MASK */
+                                       0x000017e2 /* EMC_REFRESH */
+                                       0x00000000 /* EMC_BURST_REFRESH_NUM */
+                                       0x000005f8 /* EMC_PRE_REFRESH_REQ_CNT */
+                                       0x00000003 /* EMC_PDEX2WR */
+                                       0x00000011 /* EMC_PDEX2RD */
+                                       0x00000001 /* EMC_PCHG2PDEN */
+                                       0x00000000 /* EMC_ACT2PDEN */
+                                       0x000000c6 /* EMC_AR2PDEN */
+                                       0x00000018 /* EMC_RW2PDEN */
+                                       0x000000d6 /* EMC_TXSR */
+                                       0x00000200 /* EMC_TXSRDLL */
+                                       0x00000005 /* EMC_TCKE */
+                                       0x00000006 /* EMC_TCKESR */
+                                       0x00000005 /* EMC_TPD */
+                                       0x0000001d /* EMC_TFAW */
+                                       0x00000000 /* EMC_TRPAB */
+                                       0x00000008 /* EMC_TCLKSTABLE */
+                                       0x00000008 /* EMC_TCLKSTOP */
+                                       0x00001822 /* EMC_TREFBW */
+                                       0x00000000 /* EMC_FBIO_CFG6 */
+                                       0x80000005 /* EMC_ODT_WRITE */
+                                       0x00000000 /* EMC_ODT_READ */
+                                       0x104ab198 /* EMC_FBIO_CFG5 */
+                                       0xe00700b1 /* EMC_CFG_DIG_DLL */
+                                       0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS0 */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS1 */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS2 */
+                                       0x00000007 /* EMC_DLL_XFORM_DQS3 */
+                                       0x00000006 /* EMC_DLL_XFORM_DQS4 */
+                                       0x00000006 /* EMC_DLL_XFORM_DQS5 */
+                                       0x007fc009 /* EMC_DLL_XFORM_DQS6 */
+                                       0x00000006 /* EMC_DLL_XFORM_DQS7 */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS8 */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS9 */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS10 */
+                                       0x00000007 /* EMC_DLL_XFORM_DQS11 */
+                                       0x00000006 /* EMC_DLL_XFORM_DQS12 */
+                                       0x00000007 /* EMC_DLL_XFORM_DQS13 */
+                                       0x00000009 /* EMC_DLL_XFORM_DQS14 */
+                                       0x00000007 /* EMC_DLL_XFORM_DQS15 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+                                       0x00034002 /* EMC_DLL_XFORM_ADDR0 */
+                                       0x00034002 /* EMC_DLL_XFORM_ADDR1 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+                                       0x00034002 /* EMC_DLL_XFORM_ADDR3 */
+                                       0x00034002 /* EMC_DLL_XFORM_ADDR4 */
+                                       0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+                                       0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS0 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS1 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS2 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS3 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS4 */
+                                       0x00000007 /* EMC_DLI_TRIM_TXDQS5 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS6 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS7 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS8 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS9 */
+                                       0x00000005 /* EMC_DLI_TRIM_TXDQS10 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS11 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS12 */
+                                       0x00000007 /* EMC_DLI_TRIM_TXDQS13 */
+                                       0x00000009 /* EMC_DLI_TRIM_TXDQS14 */
+                                       0x00000008 /* EMC_DLI_TRIM_TXDQS15 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ0 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ1 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ2 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ3 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ4 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ5 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ6 */
+                                       0x0000000e /* EMC_DLL_XFORM_DQ7 */
+                                       0x100002a0 /* EMC_XM2CMDPADCTRL */
+                                       0x00000000 /* EMC_XM2CMDPADCTRL4 */
+                                       0x00111111 /* EMC_XM2CMDPADCTRL5 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL2 */
+                                       0x00000000 /* EMC_XM2DQPADCTRL3 */
+                                       0x77ffc085 /* EMC_XM2CLKPADCTRL */
+                                       0x00000101 /* EMC_XM2CLKPADCTRL2 */
+                                       0x81f1f108 /* EMC_XM2COMPPADCTRL */
+                                       0x07070004 /* EMC_XM2VTTGENPADCTRL */
+                                       0x00000000 /* EMC_XM2VTTGENPADCTRL2 */
+                                       0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+                                       0x61861820 /* EMC_XM2DQSPADCTRL3 */
+                                       0x004d34d3 /* EMC_XM2DQSPADCTRL4 */
+                                       0x004d34d3 /* EMC_XM2DQSPADCTRL5 */
+                                       0x61861800 /* EMC_XM2DQSPADCTRL6 */
+                                       0x0606003f /* EMC_DSR_VTTGEN_DRV */
+                                       0x00000000 /* EMC_TXDSRVTTGEN */
+                                       0x00000000 /* EMC_FBIO_SPARE */
+                                       0x00000100 /* EMC_ZCAL_WAIT_CNT */
+                                       0x00f8000c /* EMC_MRS_WAIT_CNT2 */
+                                       0x00000007 /* EMC_CTT */
+                                       0x00000004 /* EMC_CTT_DURATION */
+                                       0x00004080 /* EMC_CFG_PIPE */
+                                       0x80003012 /* EMC_DYN_SELF_REF_CONTROL */
+                                       0x0000000f /* EMC_QPOP */
+                               >;
+                       };
+               };
+       };
+
+       memory-controller@70019000 {
+               emc-timings-1 {
+                       nvidia,ram-code = <1>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emem-configuration = <
+                                       0x40040001 /* MC_EMEM_ARB_CFG */
+                                       0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77e30303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+
+                               nvidia,emem-configuration = <
+                                       0x40020001 /* MC_EMEM_ARB_CFG */
+                                       0x80000012 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x76230303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-40800000 {
+                               clock-frequency = <40800000>;
+
+                               nvidia,emem-configuration = <
+                                       0xa0000001 /* MC_EMEM_ARB_CFG */
+                                       0x80000017 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74a30303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-68000000 {
+                               clock-frequency = <68000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x00000001 /* MC_EMEM_ARB_CFG */
+                                       0x8000001e /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74230403 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x08000001 /* MC_EMEM_ARB_CFG */
+                                       0x80000026 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0403 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x73c30504 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x01000003 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0405 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x73840a06 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x08000004 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000b0607 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77450e08 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0f000005 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000d0709 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x7586120a /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0f000007 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x0000000d /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000a /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06050202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x0010090d /* MC_EMEM_ARB_DA_COVERS */
+                                       0x7428180e /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-600000000 {
+                               clock-frequency = <600000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x00000009 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x0000000e /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000b /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x0000000b /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x07050202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x00130b0e /* MC_EMEM_ARB_DA_COVERS */
+                                       0x73a91b0f /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-792000000 {
+                               clock-frequency = <792000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0e00000b /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000013 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000f /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x08060202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x00160d13 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x734c2414 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f02 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+               };
+
+               emc-timings-4 {
+                       nvidia,ram-code = <4>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emem-configuration = <
+                                       0x40040001 /* MC_EMEM_ARB_CFG */
+                                       0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0502 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77e30303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+
+                               nvidia,emem-configuration = <
+                                       0x40020001 /* MC_EMEM_ARB_CFG */
+                                       0x80000012 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0502 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77430303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-40800000 {
+                               clock-frequency = <40800000>;
+
+                               nvidia,emem-configuration = <
+                                       0xa0000001 /* MC_EMEM_ARB_CFG */
+                                       0x80000017 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0502 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x75e30303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-68000000 {
+                               clock-frequency = <68000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x00000001 /* MC_EMEM_ARB_CFG */
+                                       0x8000001e /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0502 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x75430403 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x08000001 /* MC_EMEM_ARB_CFG */
+                                       0x80000026 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0503 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74e30504 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x01000003 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0504 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74a40a05 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x08000004 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000b0607 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77450e08 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0f000005 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000d0709 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x7586120a /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0f000007 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000a /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06050202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x0010090c /* MC_EMEM_ARB_DA_COVERS */
+                                       0x7488180d /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-600000000 {
+                               clock-frequency = <600000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x00000009 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x0000000e /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000b /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x0000000b /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x07050202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x00130b0e /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74691b0f /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-792000000 {
+                               clock-frequency = <792000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0e00000b /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000013 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000f /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x08060202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x00170e13 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x746c2414 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f02 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+               };
+
+               emc-timings-6 {
+                       nvidia,ram-code = <6>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emem-configuration = <
+                                       0x40040001 /* MC_EMEM_ARB_CFG */
+                                       0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77e30303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+
+                               nvidia,emem-configuration = <
+                                       0x40020001 /* MC_EMEM_ARB_CFG */
+                                       0x80000012 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x76230303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-40800000 {
+                               clock-frequency = <40800000>;
+
+                               nvidia,emem-configuration = <
+                                       0xa0000001 /* MC_EMEM_ARB_CFG */
+                                       0x80000017 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74a30303 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-68000000 {
+                               clock-frequency = <68000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x00000001 /* MC_EMEM_ARB_CFG */
+                                       0x8000001e /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x74230403 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x08000001 /* MC_EMEM_ARB_CFG */
+                                       0x80000026 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0403 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x73c30504 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x01000003 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040203 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000a0405 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x73840a06 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-300000000 {
+                               clock-frequency = <300000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x08000004 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000b0607 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x77450e08 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-396000000 {
+                               clock-frequency = <396000000>;
+
+                               nvidia,emem-configuration = <
+                                       0x0f000005 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06040202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x000d0709 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x7586120a /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+                               >;
+                       };
+
+                       timing-528000000 {
+                               clock-frequency = <528000000>;
 
                                nvidia,emem-configuration = <
-                                       0x0f000005
-                                       0x80000040
-                                       0x00000001
-                                       0x00000002
-                                       0x00000009
-                                       0x00000005
-                                       0x00000007
-                                       0x00000001
-                                       0x00000002
-                                       0x00000008
-                                       0x00000002
-                                       0x00000002
-                                       0x00000004
-                                       0x00000006
-                                       0x06040202
-                                       0x000d0709
-                                       0x7586120a
-                                       0x70000f03
-                                       0x001f0000
+                                       0x0f000007 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x0000000d /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000a /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x06050202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x0010090d /* MC_EMEM_ARB_DA_COVERS */
+                                       0x7428180e /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
                                >;
                        };
 
                                clock-frequency = <600000000>;
 
                                nvidia,emem-configuration = <
-                                       0x00000009
-                                       0x80000040
-                                       0x00000003
-                                       0x00000004
-                                       0x0000000e
-                                       0x00000009
-                                       0x0000000b
-                                       0x00000001
-                                       0x00000003
-                                       0x0000000b
-                                       0x00000002
-                                       0x00000002
-                                       0x00000005
-                                       0x00000007
-                                       0x07050202
-                                       0x00130b0e
-                                       0x73a91b0f
-                                       0x70000f03
-                                       0x001f0000
+                                       0x00000009 /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x0000000e /* MC_EMEM_ARB_TIMING_RC */
+                                       0x00000009 /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000b /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x0000000b /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000007 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x07050202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x00130b0e /* MC_EMEM_ARB_DA_COVERS */
+                                       0x73a91b0f /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f03 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
                                >;
                        };
 
                                clock-frequency = <792000000>;
 
                                nvidia,emem-configuration = <
-                                       0x0e00000b
-                                       0x80000040
-                                       0x00000004
-                                       0x00000005
-                                       0x00000013
-                                       0x0000000c
-                                       0x0000000f
-                                       0x00000002
-                                       0x00000003
-                                       0x0000000c
-                                       0x00000002
-                                       0x00000002
-                                       0x00000006
-                                       0x00000008
-                                       0x08060202
-                                       0x00160d13
-                                       0x734c2414
-                                       0x70000f02
-                                       0x001f0000
+                                       0x0e00000b /* MC_EMEM_ARB_CFG */
+                                       0x80000040 /* MC_EMEM_ARB_OUTSTANDING_REQ */
+                                       0x00000004 /* MC_EMEM_ARB_TIMING_RCD */
+                                       0x00000005 /* MC_EMEM_ARB_TIMING_RP */
+                                       0x00000013 /* MC_EMEM_ARB_TIMING_RC */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_RAS */
+                                       0x0000000f /* MC_EMEM_ARB_TIMING_FAW */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_RRD */
+                                       0x00000003 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+                                       0x0000000c /* MC_EMEM_ARB_TIMING_WAP2PRE */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_R2R */
+                                       0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+                                       0x00000006 /* MC_EMEM_ARB_TIMING_R2W */
+                                       0x00000008 /* MC_EMEM_ARB_TIMING_W2R */
+                                       0x08060202 /* MC_EMEM_ARB_DA_TURNS */
+                                       0x00160d13 /* MC_EMEM_ARB_DA_COVERS */
+                                       0x734c2414 /* MC_EMEM_ARB_MISC0 */
+                                       0x70000f02 /* MC_EMEM_ARB_MISC1 */
+                                       0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
                                >;
                        };
                };
index 5d5e6e1..7309393 100644 (file)
@@ -38,6 +38,9 @@
                sor@54540000 {
                        status = "okay";
 
+                       avdd-io-hdmi-dp-supply = <&vdd_1v05_run>;
+                       vdd-hdmi-dp-pll-supply = <&vdd_3v3_run>;
+
                        nvidia,dpaux = <&dpaux>;
                        nvidia,panel = <&panel>;
                };
index b113e47..413bfb9 100644 (file)
                        reg = <0x0 0x54540000 0x0 0x00040000>;
                        interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&tegra_car TEGRA124_CLK_SOR0>,
+                                <&tegra_car TEGRA124_CLK_SOR0_OUT>,
                                 <&tegra_car TEGRA124_CLK_PLL_D_OUT0>,
                                 <&tegra_car TEGRA124_CLK_PLL_DP>,
                                 <&tegra_car TEGRA124_CLK_CLK_M>;
-                       clock-names = "sor", "parent", "dp", "safe";
+                       clock-names = "sor", "out", "parent", "dp", "safe";
                        resets = <&tegra_car 182>;
                        reset-names = "sor";
                        status = "disabled";
diff --git a/arch/arm/boot/dts/tegra20-cpu-opp-microvolt.dtsi b/arch/arm/boot/dts/tegra20-cpu-opp-microvolt.dtsi
new file mode 100644 (file)
index 0000000..e85ffdb
--- /dev/null
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       cpu0_opp_table: cpu_opp_table0 {
+               opp@216000000_750 {
+                       opp-microvolt = <750000 750000 1125000>;
+               };
+
+               opp@216000000_800 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@312000000_750 {
+                       opp-microvolt = <750000 750000 1125000>;
+               };
+
+               opp@312000000_800 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@456000000_750 {
+                       opp-microvolt = <750000 750000 1125000>;
+               };
+
+               opp@456000000_800 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@456000000_800_2_2 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@456000000_800_3_2 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@456000000_825 {
+                       opp-microvolt = <825000 825000 1125000>;
+               };
+
+               opp@608000000_750 {
+                       opp-microvolt = <750000 750000 1125000>;
+               };
+
+               opp@608000000_800 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@608000000_800_3_2 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@608000000_825 {
+                       opp-microvolt = <825000 825000 1125000>;
+               };
+
+               opp@608000000_850 {
+                       opp-microvolt = <850000 850000 1125000>;
+               };
+
+               opp@608000000_900 {
+                       opp-microvolt = <900000 900000 1125000>;
+               };
+
+               opp@760000000_775 {
+                       opp-microvolt = <775000 775000 1125000>;
+               };
+
+               opp@760000000_800 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@760000000_850 {
+                       opp-microvolt = <850000 850000 1125000>;
+               };
+
+               opp@760000000_875 {
+                       opp-microvolt = <875000 875000 1125000>;
+               };
+
+               opp@760000000_875_1_1 {
+                       opp-microvolt = <875000 875000 1125000>;
+               };
+
+               opp@760000000_875_0_2 {
+                       opp-microvolt = <875000 875000 1125000>;
+               };
+
+               opp@760000000_875_1_2 {
+                       opp-microvolt = <875000 875000 1125000>;
+               };
+
+               opp@760000000_900 {
+                       opp-microvolt = <900000 900000 1125000>;
+               };
+
+               opp@760000000_975 {
+                       opp-microvolt = <975000 975000 1125000>;
+               };
+
+               opp@816000000_800 {
+                       opp-microvolt = <800000 800000 1125000>;
+               };
+
+               opp@816000000_850 {
+                       opp-microvolt = <850000 850000 1125000>;
+               };
+
+               opp@816000000_875 {
+                       opp-microvolt = <875000 875000 1125000>;
+               };
+
+               opp@816000000_950 {
+                       opp-microvolt = <950000 950000 1125000>;
+               };
+
+               opp@816000000_1000 {
+                       opp-microvolt = <1000000 1000000 1125000>;
+               };
+
+               opp@912000000_850 {
+                       opp-microvolt = <850000 850000 1125000>;
+               };
+
+               opp@912000000_900 {
+                       opp-microvolt = <900000 900000 1125000>;
+               };
+
+               opp@912000000_925 {
+                       opp-microvolt = <925000 925000 1125000>;
+               };
+
+               opp@912000000_950 {
+                       opp-microvolt = <950000 950000 1125000>;
+               };
+
+               opp@912000000_950_0_2 {
+                       opp-microvolt = <950000 950000 1125000>;
+               };
+
+               opp@912000000_950_2_2 {
+                       opp-microvolt = <950000 950000 1125000>;
+               };
+
+               opp@912000000_1000 {
+                       opp-microvolt = <1000000 1000000 1125000>;
+               };
+
+               opp@912000000_1050 {
+                       opp-microvolt = <1050000 1050000 1125000>;
+               };
+
+               opp@1000000000_875 {
+                       opp-microvolt = <875000 875000 1125000>;
+               };
+
+               opp@1000000000_900 {
+                       opp-microvolt = <900000 900000 1125000>;
+               };
+
+               opp@1000000000_950 {
+                       opp-microvolt = <950000 950000 1125000>;
+               };
+
+               opp@1000000000_975 {
+                       opp-microvolt = <975000 975000 1125000>;
+               };
+
+               opp@1000000000_1000 {
+                       opp-microvolt = <1000000 1000000 1125000>;
+               };
+
+               opp@1000000000_1000_0_2 {
+                       opp-microvolt = <1000000 1000000 1125000>;
+               };
+
+               opp@1000000000_1025 {
+                       opp-microvolt = <1025000 1025000 1125000>;
+               };
+
+               opp@1000000000_1100 {
+                       opp-microvolt = <1100000 1100000 1125000>;
+               };
+
+               opp@1200000000_1000 {
+                       opp-microvolt = <1000000 1000000 1125000>;
+               };
+
+               opp@1200000000_1050 {
+                       opp-microvolt = <1050000 1050000 1125000>;
+               };
+
+               opp@1200000000_1100 {
+                       opp-microvolt = <1100000 1100000 1125000>;
+               };
+
+               opp@1200000000_1125 {
+                       opp-microvolt = <1125000 1125000 1125000>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/tegra20-cpu-opp.dtsi b/arch/arm/boot/dts/tegra20-cpu-opp.dtsi
new file mode 100644 (file)
index 0000000..c878f42
--- /dev/null
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       cpu0_opp_table: cpu_opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@216000000_750 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x0F 0x0003>;
+                       opp-hz = /bits/ 64 <216000000>;
+               };
+
+               opp@216000000_800 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x0F 0x0004>;
+                       opp-hz = /bits/ 64 <216000000>;
+               };
+
+               opp@312000000_750 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x0F 0x0003>;
+                       opp-hz = /bits/ 64 <312000000>;
+               };
+
+               opp@312000000_800 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x0F 0x0004>;
+                       opp-hz = /bits/ 64 <312000000>;
+               };
+
+               opp@456000000_750 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x0C 0x0003>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@456000000_800 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0006>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@456000000_800_2_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@456000000_800_3_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@456000000_825 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@608000000_750 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0003>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@608000000_800 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0006>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@608000000_800_3_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@608000000_825 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0001>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@608000000_850 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0006>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@608000000_900 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@760000000_775 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0003>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_800 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0006>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_875 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0001>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_875_1_1 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x02 0x0002>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_875_0_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0004>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_875_1_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x02 0x0004>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0002>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_975 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@816000000_800 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0007>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@816000000_850 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@816000000_875 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0005>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@816000000_950 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0006>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@816000000_1000 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@912000000_850 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0007>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_900 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_925 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0001>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_950 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x02 0x0006>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_950_0_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0004>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_950_2_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_1000 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0002>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@912000000_1050 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <912000000>;
+               };
+
+               opp@1000000000_875 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0007>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_900 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_950 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0001>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_1000 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x02 0x0006>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_1000_0_2 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0004>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_1025 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0002>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_1100 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1200000000_1000 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1050 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1100 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x02 0x0004>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1125 {
+                       clock-latency-ns = <400000>;
+                       opp-supported-hw = <0x01 0x0004>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+       };
+};
index 8861e09..85fce5b 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <dt-bindings/input/input.h>
 #include "tegra20.dtsi"
+#include "tegra20-cpu-opp.dtsi"
+#include "tegra20-cpu-opp-microvolt.dtsi"
 
 / {
        model = "Toshiba AC100 / Dynabook AZ";
                                        regulator-always-on;
                                };
 
-                               sm0 {
+                               core_vdd_reg: sm0 {
                                        regulator-name = "+1.2vs_sm0,vdd_core";
                                        regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1225000>;
+                                       regulator-coupled-with = <&rtc_vdd_reg &cpu_vdd_reg>;
+                                       regulator-coupled-max-spread = <170000 450000>;
                                        regulator-always-on;
+
+                                       nvidia,tegra-core-regulator;
                                };
 
-                               sm1 {
+                               cpu_vdd_reg: sm1 {
                                        regulator-name = "+1.0vs_sm1,vdd_cpu";
-                                       regulator-min-microvolt = <1000000>;
-                                       regulator-max-microvolt = <1000000>;
+                                       regulator-min-microvolt = <750000>;
+                                       regulator-max-microvolt = <1100000>;
+                                       regulator-coupled-with = <&core_vdd_reg &rtc_vdd_reg>;
+                                       regulator-coupled-max-spread = <450000 450000>;
                                        regulator-always-on;
+
+                                       nvidia,tegra-cpu-regulator;
                                };
 
                                sm2_reg: sm2 {
                                        regulator-always-on;
                                };
 
-                               ldo2 {
+                               rtc_vdd_reg: ldo2 {
                                        regulator-name = "+1.2vs_ldo2,vdd_rtc";
                                        regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1225000>;
+                                       regulator-coupled-with = <&core_vdd_reg &cpu_vdd_reg>;
+                                       regulator-coupled-max-spread = <170000 450000>;
+                                       regulator-always-on;
+
+                                       nvidia,tegra-rtc-regulator;
                                };
 
                                ldo3 {
                         <&tegra_car TEGRA20_CLK_CDEV1>;
                clock-names = "pll_a", "pll_a_out0", "mclk";
        };
+
+       cpus {
+               cpu0: cpu@0 {
+                       cpu-supply = <&cpu_vdd_reg>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+
+               cpu@1 {
+                       cpu-supply = <&cpu_vdd_reg>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+       };
 };
index 3e5ac09..8debd3d 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <dt-bindings/input/input.h>
 #include "tegra20.dtsi"
+#include "tegra20-cpu-opp.dtsi"
 
 / {
        model = "Compulab TrimSlice board";
                         <&tegra_car TEGRA20_CLK_CDEV1>;
                clock-names = "pll_a", "pll_a_out0", "mclk";
        };
+
+       cpus {
+               cpu0: cpu@0 {
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+
+               cpu@1 {
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+       };
 };
index 8c942e6..9c58e7f 100644 (file)
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0>;
+                       clocks = <&tegra_car TEGRA20_CLK_CCLK>;
                };
 
                cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <1>;
+                       clocks = <&tegra_car TEGRA20_CLK_CCLK>;
                };
        };
 
index 02f8126..8b7a827 100644 (file)
                        id = <0>;
                        blocks = <0x5>;
                        irq-trigger = <0x1>;
+                       /* 3.25 MHz ADC clock speed */
+                       st,adc-freq = <1>;
+                       /* 12-bit ADC */
+                       st,mod-12b = <1>;
+                       /* internal ADC reference */
+                       st,ref-sel = <0>;
+                       /* ADC converstion time: 80 clocks */
+                       st,sample-time = <4>;
 
                        stmpe_touchscreen {
                                compatible = "st,stmpe-ts";
-                               /* 3.25 MHz ADC clock speed */
-                               st,adc-freq = <1>;
                                /* 8 sample average control */
                                st,ave-ctrl = <3>;
                                /* 7 length fractional part in z */
                                 * current limit value
                                 */
                                st,i-drive = <1>;
-                               /* 12-bit ADC */
-                               st,mod-12b = <1>;
-                               /* internal ADC reference */
-                               st,ref-sel = <0>;
-                               /* ADC converstion time: 80 clocks */
-                               st,sample-time = <4>;
                                /* 1 ms panel driver settling time */
                                st,settling = <3>;
                                /* 5 ms touch detect interrupt delay */
                                st,touch-det-delay = <5>;
                        };
+
+                       stmpe_adc {
+                               compatible = "st,stmpe-adc";
+                               /* forbid to use ADC channels 3-0 (touch) */
+                               st,norequest-mask = <0x0F>;
+                       };
                };
 
                /*
index 7f112f1..c18f6f6 100644 (file)
                        id = <0>;
                        blocks = <0x5>;
                        irq-trigger = <0x1>;
+                       /* 3.25 MHz ADC clock speed */
+                       st,adc-freq = <1>;
+                       /* 12-bit ADC */
+                       st,mod-12b = <1>;
+                       /* internal ADC reference */
+                       st,ref-sel = <0>;
+                       /* ADC converstion time: 80 clocks */
+                       st,sample-time = <4>;
 
                        stmpe_touchscreen {
                                compatible = "st,stmpe-ts";
-                               /* 3.25 MHz ADC clock speed */
-                               st,adc-freq = <1>;
                                /* 8 sample average control */
                                st,ave-ctrl = <3>;
                                /* 7 length fractional part in z */
                                 * current limit value
                                 */
                                st,i-drive = <1>;
-                               /* 12-bit ADC */
-                               st,mod-12b = <1>;
-                               /* internal ADC reference */
-                               st,ref-sel = <0>;
-                               /* ADC converstion time: 80 clocks */
-                               st,sample-time = <4>;
                                /* 1 ms panel driver settling time */
                                st,settling = <3>;
                                /* 5 ms touch detect interrupt delay */
                                st,touch-det-delay = <5>;
                        };
+
+                       stmpe_adc {
+                               compatible = "st,stmpe-adc";
+                               /* forbid to use ADC channels 3-0 (touch) */
+                               st,norequest-mask = <0x0F>;
+                       };
                };
 
                /*
index 4dbd4af..9234988 100644 (file)
@@ -2,6 +2,8 @@
 /dts-v1/;
 
 #include "tegra30-cardhu.dtsi"
+#include "tegra30-cpu-opp.dtsi"
+#include "tegra30-cpu-opp-microvolt.dtsi"
 
 /* This dts file support the cardhu A04 and later versions of board */
 
                        gpio = <&gpio TEGRA_GPIO(DD, 0) GPIO_ACTIVE_HIGH>;
                };
        };
+
+       i2c@7000d000 {
+               pmic: tps65911@2d {
+                       regulators {
+                               vddctrl_reg: vddctrl {
+                                       regulator-min-microvolt = <800000>;
+                                       regulator-max-microvolt = <1125000>;
+                                       regulator-coupled-with = <&vddcore_reg>;
+                                       regulator-coupled-max-spread = <300000>;
+                                       regulator-max-step-microvolt = <100000>;
+
+                                       nvidia,tegra-cpu-regulator;
+                               };
+                       };
+               };
+
+               vddcore_reg: tps62361@60 {
+                       regulator-coupled-with = <&vddctrl_reg>;
+                       regulator-coupled-max-spread = <300000>;
+                       regulator-max-step-microvolt = <100000>;
+
+                       nvidia,tegra-core-regulator;
+               };
+       };
+
+       cpus {
+               cpu0: cpu@0 {
+                       cpu-supply = <&vddctrl_reg>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+
+               cpu@1 {
+                       cpu-supply = <&vddctrl_reg>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+
+               cpu@2 {
+                       cpu-supply = <&vddctrl_reg>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+
+               cpu@3 {
+                       cpu-supply = <&vddctrl_reg>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+       };
 };
index 35af03c..1f9198b 100644 (file)
                        id = <0>;
                        blocks = <0x5>;
                        irq-trigger = <0x1>;
+                       /* 3.25 MHz ADC clock speed */
+                       st,adc-freq = <1>;
+                       /* 12-bit ADC */
+                       st,mod-12b = <1>;
+                       /* internal ADC reference */
+                       st,ref-sel = <0>;
+                       /* ADC converstion time: 80 clocks */
+                       st,sample-time = <4>;
+                       /* forbid to use ADC channels 3-0 (touch) */
 
                        stmpe_touchscreen {
                                compatible = "st,stmpe-ts";
-                               /* 3.25 MHz ADC clock speed */
-                               st,adc-freq = <1>;
                                /* 8 sample average control */
                                st,ave-ctrl = <3>;
                                /* 7 length fractional part in z */
                                 * current limit value
                                 */
                                st,i-drive = <1>;
-                               /* 12-bit ADC */
-                               st,mod-12b = <1>;
-                               /* internal ADC reference */
-                               st,ref-sel = <0>;
-                               /* ADC converstion time: 80 clocks */
-                               st,sample-time = <4>;
                                /* 1 ms panel driver settling time */
                                st,settling = <3>;
                                /* 5 ms touch detect interrupt delay */
                                st,touch-det-delay = <5>;
                        };
+
+                       stmpe_adc {
+                               compatible = "st,stmpe-adc";
+                               st,norequest-mask = <0x0F>;
+                       };
                };
 
                /*
diff --git a/arch/arm/boot/dts/tegra30-cpu-opp-microvolt.dtsi b/arch/arm/boot/dts/tegra30-cpu-opp-microvolt.dtsi
new file mode 100644 (file)
index 0000000..5c40ef4
--- /dev/null
@@ -0,0 +1,801 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       cpu0_opp_table: cpu_opp_table0 {
+               opp@51000000_800 {
+                       opp-microvolt = <800000 800000 1250000>;
+               };
+
+               opp@51000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@51000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@102000000_800 {
+                       opp-microvolt = <800000 800000 1250000>;
+               };
+
+               opp@102000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@102000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@204000000_800 {
+                       opp-microvolt = <800000 800000 1250000>;
+               };
+
+               opp@204000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@204000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@312000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@312000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@340000000_800 {
+                       opp-microvolt = <800000 800000 1250000>;
+               };
+
+               opp@340000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@370000000_800 {
+                       opp-microvolt = <800000 800000 1250000>;
+               };
+
+               opp@456000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@456000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@475000000_800 {
+                       opp-microvolt = <800000 800000 1250000>;
+               };
+
+               opp@475000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@475000000_850_0_1 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@475000000_850_0_4 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@475000000_850_0_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@475000000_850_0_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@608000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@608000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@620000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_1_1 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_2_1 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_3_1 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_1_4 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_2_4 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_3_4 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_1_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_2_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_3_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_4_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_1_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_2_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_3_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_850_4_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@640000000_900 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_3_1 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_3_2 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_3_3 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_3_4 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_3_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_4_7 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_3_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_4_8 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_850_0_10 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@760000000_900 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_1_1 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_2_1 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_1_2 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_2_2 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_1_3 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_2_3 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_1_4 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_2_4 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_1_7 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_2_7 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_1_8 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_900_2_8 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@760000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@760000000_975 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@816000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@816000000_912 {
+                       opp-microvolt = <912000 912000 1250000>;
+               };
+
+               opp@860000000_850 {
+                       opp-microvolt = <850000 850000 1250000>;
+               };
+
+               opp@860000000_900 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_2_1 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_3_1 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_2_2 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_3_2 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_2_3 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_3_3 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_2_4 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_3_4 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_2_7 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_3_7 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_4_7 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_2_8 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_3_8 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_900_4_8 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@860000000_975 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_975_1_1 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_975_1_2 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_975_1_3 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_975_1_4 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_975_1_7 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_975_1_8 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@860000000_1000 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@910000000_900 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@1000000000_900 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@1000000000_975 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_2_1 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_3_1 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_2_2 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_3_2 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_2_3 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_3_3 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_2_4 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_3_4 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_2_7 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_3_7 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_4_7 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_2_8 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_3_8 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_975_4_8 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1000000000_1000 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1000000000_1025 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1100000000_900 {
+                       opp-microvolt = <900000 900000 1250000>;
+               };
+
+               opp@1100000000_975 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_3_1 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_3_2 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_3_3 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_3_4 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_3_7 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_4_7 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_3_8 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_975_4_8 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1100000000_1000 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1000_2_1 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1000_2_2 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1000_2_3 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1000_2_4 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1000_2_7 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1000_2_8 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1100000000_1025 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1100000000_1075 {
+                       opp-microvolt = <1075000 1075000 1250000>;
+               };
+
+               opp@1150000000_975 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1200000000_975 {
+                       opp-microvolt = <975000 975000 1250000>;
+               };
+
+               opp@1200000000_1000 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_3_1 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_3_2 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_3_3 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_3_4 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_3_7 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_4_7 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_3_8 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1000_4_8 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1200000000_1025 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1025_2_1 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1025_2_2 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1025_2_3 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1025_2_4 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1025_2_7 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1025_2_8 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1200000000_1050 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1200000000_1075 {
+                       opp-microvolt = <1075000 1075000 1250000>;
+               };
+
+               opp@1200000000_1100 {
+                       opp-microvolt = <1100000 1100000 1250000>;
+               };
+
+               opp@1300000000_1000 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1300000000_1000_4_7 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1300000000_1000_4_8 {
+                       opp-microvolt = <1000000 1000000 1250000>;
+               };
+
+               opp@1300000000_1025 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1300000000_1025_3_1 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1300000000_1025_3_7 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1300000000_1025_3_8 {
+                       opp-microvolt = <1025000 1025000 1250000>;
+               };
+
+               opp@1300000000_1050 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_2_1 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_2 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_3 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_4 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_5 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_6 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_2_7 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_2_8 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_12 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1050_3_13 {
+                       opp-microvolt = <1050000 1050000 1250000>;
+               };
+
+               opp@1300000000_1075 {
+                       opp-microvolt = <1075000 1075000 1250000>;
+               };
+
+               opp@1300000000_1075_2_2 {
+                       opp-microvolt = <1075000 1075000 1250000>;
+               };
+
+               opp@1300000000_1075_2_3 {
+                       opp-microvolt = <1075000 1075000 1250000>;
+               };
+
+               opp@1300000000_1075_2_4 {
+                       opp-microvolt = <1075000 1075000 1250000>;
+               };
+
+               opp@1300000000_1100 {
+                       opp-microvolt = <1100000 1100000 1250000>;
+               };
+
+               opp@1300000000_1125 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1300000000_1150 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1300000000_1175 {
+                       opp-microvolt = <1175000 1175000 1250000>;
+               };
+
+               opp@1400000000_1100 {
+                       opp-microvolt = <1100000 1100000 1250000>;
+               };
+
+               opp@1400000000_1125 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1400000000_1150 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1400000000_1150_2_4 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1400000000_1175 {
+                       opp-microvolt = <1175000 1175000 1250000>;
+               };
+
+               opp@1400000000_1237 {
+                       opp-microvolt = <1237000 1237000 1250000>;
+               };
+
+               opp@1500000000_1125 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1500000000_1125_4_5 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1500000000_1125_4_6 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1500000000_1125_4_12 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1500000000_1125_4_13 {
+                       opp-microvolt = <1125000 1125000 1250000>;
+               };
+
+               opp@1500000000_1150 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1500000000_1150_3_5 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1500000000_1150_3_6 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1500000000_1150_3_12 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1500000000_1150_3_13 {
+                       opp-microvolt = <1150000 1150000 1250000>;
+               };
+
+               opp@1500000000_1200 {
+                       opp-microvolt = <1200000 1200000 1250000>;
+               };
+
+               opp@1500000000_1237 {
+                       opp-microvolt = <1237000 1237000 1250000>;
+               };
+
+               opp@1600000000_1212 {
+                       opp-microvolt = <1212000 1212000 1250000>;
+               };
+
+               opp@1600000000_1237 {
+                       opp-microvolt = <1237000 1237000 1250000>;
+               };
+
+               opp@1700000000_1212 {
+                       opp-microvolt = <1212000 1212000 1250000>;
+               };
+
+               opp@1700000000_1237 {
+                       opp-microvolt = <1237000 1237000 1250000>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/tegra30-cpu-opp.dtsi b/arch/arm/boot/dts/tegra30-cpu-opp.dtsi
new file mode 100644 (file)
index 0000000..d64fc26
--- /dev/null
@@ -0,0 +1,1202 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       cpu0_opp_table: cpu_opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@51000000_800 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x31FE>;
+                       opp-hz = /bits/ 64 <51000000>;
+               };
+
+               opp@51000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0C01>;
+                       opp-hz = /bits/ 64 <51000000>;
+               };
+
+               opp@51000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <51000000>;
+               };
+
+               opp@102000000_800 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x31FE>;
+                       opp-hz = /bits/ 64 <102000000>;
+               };
+
+               opp@102000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0C01>;
+                       opp-hz = /bits/ 64 <102000000>;
+               };
+
+               opp@102000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <102000000>;
+               };
+
+               opp@204000000_800 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x31FE>;
+                       opp-hz = /bits/ 64 <204000000>;
+               };
+
+               opp@204000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0C01>;
+                       opp-hz = /bits/ 64 <204000000>;
+               };
+
+               opp@204000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <204000000>;
+               };
+
+               opp@312000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0C00>;
+                       opp-hz = /bits/ 64 <312000000>;
+               };
+
+               opp@312000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <312000000>;
+               };
+
+               opp@340000000_800 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0192>;
+                       opp-hz = /bits/ 64 <340000000>;
+               };
+
+               opp@340000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x0F 0x0001>;
+                       opp-hz = /bits/ 64 <340000000>;
+               };
+
+               opp@370000000_800 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1E 0x306C>;
+                       opp-hz = /bits/ 64 <370000000>;
+               };
+
+               opp@456000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0C00>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@456000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <456000000>;
+               };
+
+               opp@475000000_800 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1E 0x31FE>;
+                       opp-hz = /bits/ 64 <475000000>;
+               };
+
+               opp@475000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x0F 0x0001>;
+                       opp-hz = /bits/ 64 <475000000>;
+               };
+
+               opp@475000000_850_0_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0002>;
+                       opp-hz = /bits/ 64 <475000000>;
+               };
+
+               opp@475000000_850_0_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0010>;
+                       opp-hz = /bits/ 64 <475000000>;
+               };
+
+               opp@475000000_850_0_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0080>;
+                       opp-hz = /bits/ 64 <475000000>;
+               };
+
+               opp@475000000_850_0_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0100>;
+                       opp-hz = /bits/ 64 <475000000>;
+               };
+
+               opp@608000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0400>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@608000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <608000000>;
+               };
+
+               opp@620000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1E 0x306C>;
+                       opp-hz = /bits/ 64 <620000000>;
+               };
+
+               opp@640000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x0F 0x0001>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_1_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0002>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_1_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0010>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_1_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0080>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_1_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0100>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_850_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@640000000_900 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0192>;
+                       opp-hz = /bits/ 64 <640000000>;
+               };
+
+               opp@760000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1E 0x3461>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_3_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_3_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0008>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_850_0_10 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0400>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0001>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_1_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0002>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_1_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0004>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_2_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_1_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0008>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_2_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0008>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_1_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0010>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_1_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0080>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_1_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0100>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_900_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@760000000_975 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0192>;
+                       opp-hz = /bits/ 64 <760000000>;
+               };
+
+               opp@816000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0400>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@816000000_912 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x1F 0x0200>;
+                       opp-hz = /bits/ 64 <816000000>;
+               };
+
+               opp@860000000_850 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x0C 0x0001>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0001>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_2_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_3_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_2_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0008>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_3_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0008>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_900_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0001>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975_1_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0002>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975_1_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0004>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975_1_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0008>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975_1_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0010>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975_1_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0080>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_975_1_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0100>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@860000000_1000 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0192>;
+                       opp-hz = /bits/ 64 <860000000>;
+               };
+
+               opp@910000000_900 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x18 0x3060>;
+                       opp-hz = /bits/ 64 <910000000>;
+               };
+
+               opp@1000000000_900 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x0C 0x0001>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x03 0x0001>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_2_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_3_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_2_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0008>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_3_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0008>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_975_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_1000 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x019E>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1000000000_1025 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0192>;
+                       opp-hz = /bits/ 64 <1000000000>;
+               };
+
+               opp@1100000000_900 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0001>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x06 0x0001>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_3_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_3_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0008>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_975_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0001>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000_2_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000_2_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0008>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1000_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1025 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x019E>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1100000000_1075 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0192>;
+                       opp-hz = /bits/ 64 <1100000000>;
+               };
+
+               opp@1150000000_975 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x18 0x3060>;
+                       opp-hz = /bits/ 64 <1150000000>;
+               };
+
+               opp@1200000000_975 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0001>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0001>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_3_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_3_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0008>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1000_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0001>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025_2_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025_2_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0008>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1025_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1050 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x019E>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1075 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0001>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1200000000_1100 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0192>;
+                       opp-hz = /bits/ 64 <1200000000>;
+               };
+
+               opp@1300000000_1000 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0001>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1000_4_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0080>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1000_4_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0100>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1025 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0001>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1025_3_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0002>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1025_3_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0080>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1025_3_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0100>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x12 0x3061>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_2_1 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0002>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0004>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0008>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_5 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0020>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_6 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0040>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_2_7 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0080>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_2_8 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0100>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_12 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x1000>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1050_3_13 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x2000>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1075 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0182>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1075_2_2 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0004>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1075_2_3 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0008>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1075_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1100 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x001C>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1125 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0001>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1150 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0182>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1300000000_1175 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0010>;
+                       opp-hz = /bits/ 64 <1300000000>;
+               };
+
+               opp@1400000000_1100 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x18 0x307C>;
+                       opp-hz = /bits/ 64 <1400000000>;
+               };
+
+               opp@1400000000_1125 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x000C>;
+                       opp-hz = /bits/ 64 <1400000000>;
+               };
+
+               opp@1400000000_1150 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x000C>;
+                       opp-hz = /bits/ 64 <1400000000>;
+               };
+
+               opp@1400000000_1150_2_4 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <1400000000>;
+               };
+
+               opp@1400000000_1175 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0010>;
+                       opp-hz = /bits/ 64 <1400000000>;
+               };
+
+               opp@1400000000_1237 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0010>;
+                       opp-hz = /bits/ 64 <1400000000>;
+               };
+
+               opp@1500000000_1125 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0010>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1125_4_5 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0020>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1125_4_6 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x0040>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1125_4_12 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x1000>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1125_4_13 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x2000>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1150 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x04 0x0010>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1150_3_5 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0020>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1150_3_6 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x0040>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1150_3_12 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x1000>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1150_3_13 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x2000>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1200 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x02 0x0010>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1500000000_1237 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x01 0x0010>;
+                       opp-hz = /bits/ 64 <1500000000>;
+               };
+
+               opp@1600000000_1212 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x3060>;
+                       opp-hz = /bits/ 64 <1600000000>;
+               };
+
+               opp@1600000000_1237 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x3060>;
+                       opp-hz = /bits/ 64 <1600000000>;
+               };
+
+               opp@1700000000_1212 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x10 0x3060>;
+                       opp-hz = /bits/ 64 <1700000000>;
+               };
+
+               opp@1700000000_1237 {
+                       clock-latency-ns = <100000>;
+                       opp-supported-hw = <0x08 0x3060>;
+                       opp-hz = /bits/ 64 <1700000000>;
+               };
+       };
+};
index e074258..55ae050 100644 (file)
                clocks = <&tegra_car TEGRA30_CLK_VDE>;
                reset-names = "vde", "mc";
                resets = <&tegra_car 61>, <&mc TEGRA30_MC_RESET_VDE>;
+               iommus = <&mc TEGRA_SWGROUP_VDE>;
        };
 
        apbmisc@70000800 {
                #reset-cells = <1>;
        };
 
+       memory-controller@7000f400 {
+               compatible = "nvidia,tegra30-emc";
+               reg = <0x7000f400 0x400>;
+               interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&tegra_car TEGRA30_CLK_EMC>;
+
+               nvidia,memory-controller = <&mc>;
+       };
+
        fuse@7000f800 {
                compatible = "nvidia,tegra30-efuse";
                reg = <0x7000f800 0x400>;
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0>;
+                       clocks = <&tegra_car TEGRA30_CLK_CCLK_G>;
                };
 
                cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <1>;
+                       clocks = <&tegra_car TEGRA30_CLK_CCLK_G>;
                };
 
                cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <2>;
+                       clocks = <&tegra_car TEGRA30_CLK_CCLK_G>;
                };
 
                cpu@3 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <3>;
+                       clocks = <&tegra_car TEGRA30_CLK_CCLK_G>;
                };
        };
 
index b6a1eee..fba37b8 100644 (file)
 
 &i2c0 {
        clock-frequency = <400000>;
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c0>;
+       pinctrl-1 = <&pinctrl_i2c0_gpio>;
+       scl-gpios = <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio1 5 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 };
 
 &nfc {
                        >;
                };
 
+               pinctrl_i2c0_gpio: i2c0gpiogrp {
+                       fsl,pins = <
+                               VF610_PAD_PTB14__GPIO_36                0x37ff
+                               VF610_PAD_PTB15__GPIO_37                0x37ff
+                       >;
+               };
+
                pinctrl_nfc: nfcgrp {
                        fsl,pins = <
                                VF610_PAD_PTD23__NF_IO7         0x28df
index 237b024..92255f8 100644 (file)
@@ -44,7 +44,7 @@
 
 / {
        model = "Toradex Colibri VF50 COM";
-       compatible = "toradex,vf610-colibri_vf50", "fsl,vf500";
+       compatible = "toradex,vf500-colibri_vf50", "fsl,vf500";
 
        memory@80000000 {
                device_type = "memory";
index 0f3870d..830c854 100644 (file)
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart0>;
+       /delete-property/dma-names;
        status = "okay";
 };
 
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
+       /delete-property/dma-names;
        status = "okay";
 };
 
 &uart2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2>;
+       /delete-property/dma-names;
        status = "okay";
 };
 
 &uart3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart3>;
+       /delete-property/dma-names;
        status = "okay";
 };
 
index c8ebb23..d7caf61 100644 (file)
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       port@1 {
-                                               reg = <1>;
-                                               label = "internal_j9";
-                                       };
-
                                        port@2 {
                                                reg = <2>;
                                                label = "eth_fc_1000_2";
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       port@1 {
-                                               reg = <1>;
-                                               label = "internal_j8";
-                                       };
-
                                        port@2 {
                                                reg = <2>;
                                                label = "eth_fc_1000_8";
        linux,rs485-enabled-at-boot-time;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
-       rs485-rts-delay = <0 200>;
        status = "okay";
 };
 
        linux,rs485-enabled-at-boot-time;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2>;
-       rs485-rts-delay = <0 200>;
        status = "okay";
 };
 
index 1857df9..303f75a 100644 (file)
@@ -132,10 +132,12 @@ CONFIG_ASPEED_BT_IPMI_BMC=y
 CONFIG_HW_RANDOM_TIMERIOMEM=y
 # CONFIG_I2C_COMPAT is not set
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
 CONFIG_I2C_MUX_PCA9541=y
 CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_ASPEED=y
 CONFIG_I2C_FSI=y
+CONFIG_SPI=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_ASPEED=y
@@ -185,6 +187,12 @@ CONFIG_USB_CONFIGFS_F_LB_SS=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_MMC=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_ASPEED=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_CLASS_FLASH=y
@@ -216,7 +224,6 @@ CONFIG_FSI_MASTER_GPIO=y
 CONFIG_FSI_MASTER_HUB=y
 CONFIG_FSI_MASTER_AST_CF=y
 CONFIG_FSI_SCOM=y
-CONFIG_FSI_SBEFIFO=y
 CONFIG_FANOTIFY=y
 CONFIG_OVERLAY_FS=y
 CONFIG_TMPFS=y
@@ -231,7 +238,6 @@ CONFIG_SQUASHFS_ZSTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_HARDENED_USERCOPY=y
 CONFIG_FORTIFY_SOURCE=y
-# CONFIG_CRYPTO_ECHAINIV is not set
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_USER_API_HASH=y
@@ -247,14 +253,14 @@ CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_GDB_SCRIPTS=y
 CONFIG_STRIP_ASM_SYMS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PANIC_TIMEOUT=-1
 CONFIG_SOFTLOCKUP_DETECTOR=y
 # CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_WQ_WATCHDOG=y
-CONFIG_PANIC_ON_OOPS=y
-CONFIG_PANIC_TIMEOUT=-1
 # CONFIG_SCHED_DEBUG is not set
-CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_FUNCTION_TRACER=y
-# CONFIG_RUNTIME_TESTING_MENU is not set
 CONFIG_DEBUG_WX=y
 CONFIG_DEBUG_USER=y
+# CONFIG_RUNTIME_TESTING_MENU is not set
index 597536c..b0d056d 100644 (file)
@@ -139,6 +139,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=6
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_ASPEED_VUART=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DW=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_ASPEED_KCS_IPMI_BMC=y
 CONFIG_ASPEED_BT_IPMI_BMC=y
@@ -154,6 +155,7 @@ CONFIG_SPI=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_ASPEED=y
+CONFIG_GPIO_ASPEED_SGPIO=y
 CONFIG_W1=y
 CONFIG_W1_MASTER_GPIO=y
 CONFIG_W1_SLAVE_THERM=y
@@ -236,8 +238,10 @@ CONFIG_FSI=y
 CONFIG_FSI_MASTER_GPIO=y
 CONFIG_FSI_MASTER_HUB=y
 CONFIG_FSI_MASTER_AST_CF=y
+CONFIG_FSI_MASTER_ASPEED=y
 CONFIG_FSI_SCOM=y
 CONFIG_FSI_SBEFIFO=y
+CONFIG_FSI_OCC=y
 CONFIG_FANOTIFY=y
 CONFIG_OVERLAY_FS=y
 CONFIG_TMPFS=y
index 309c55a..3729a6e 100644 (file)
@@ -18,6 +18,7 @@ CONFIG_ARCH_MULTI_V5=y
 CONFIG_ARCH_AT91=y
 CONFIG_SOC_AT91RM9200=y
 CONFIG_SOC_AT91SAM9=y
+# CONFIG_ATMEL_CLOCKSOURCE_PIT is not set
 CONFIG_AEABI=y
 CONFIG_UACCESS_WITH_MEMCPY=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
index 08db1c8..e7e4bb5 100644 (file)
@@ -230,6 +230,7 @@ CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=y
 CONFIG_SND_SOC_SMDK_WM8994_PCM=y
 CONFIG_SND_SOC_SNOW=y
 CONFIG_SND_SOC_ODROID=y
+CONFIG_SND_SOC_ARNDALE=y
 CONFIG_SND_SIMPLE_CARD=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -294,6 +295,7 @@ CONFIG_DEVFREQ_GOV_PERFORMANCE=y
 CONFIG_DEVFREQ_GOV_POWERSAVE=y
 CONFIG_DEVFREQ_GOV_USERSPACE=y
 CONFIG_ARM_EXYNOS_BUS_DEVFREQ=y
+CONFIG_EXYNOS5422_DMC=y
 CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=y
 CONFIG_EXTCON=y
 CONFIG_EXTCON_MAX14577=y
index 0f7381e..26d6dee 100644 (file)
@@ -179,6 +179,7 @@ CONFIG_MOUSE_PS2=m
 CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_TOUCHSCREEN_DA9052=y
 CONFIG_TOUCHSCREEN_EGALAX=y
 CONFIG_TOUCHSCREEN_GOODIX=y
 CONFIG_TOUCHSCREEN_MAX11801=y
@@ -236,6 +237,7 @@ CONFIG_DA9062_WATCHDOG=y
 CONFIG_DA9063_WATCHDOG=m
 CONFIG_RN5T618_WATCHDOG=y
 CONFIG_IMX2_WDT=y
+CONFIG_IMX7ULP_WDT=y
 CONFIG_MFD_DA9052_I2C=y
 CONFIG_MFD_DA9062=y
 CONFIG_MFD_DA9063=y
@@ -335,7 +337,7 @@ CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_MXS_PHY=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_FSL_USB2=y
-CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS=y
 CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_ACM=y
 CONFIG_USB_CONFIGFS_OBEX=y
index f33f5d7..11e2211 100644 (file)
@@ -134,6 +134,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_NETDEVICES=y
 CONFIG_TI_KEYSTONE_NETCP=y
 CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
+CONFIG_TI_CPTS=y
 CONFIG_MARVELL_PHY=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
index bd01887..56315e1 100644 (file)
@@ -165,6 +165,7 @@ CONFIG_SPI_ATMEL=y
 CONFIG_SPI_IMX=y
 CONFIG_SPI_ORION=y
 CONFIG_GPIO_ASPEED=m
+CONFIG_GPIO_ASPEED_SGPIO=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_QNAP=y
@@ -241,6 +242,9 @@ CONFIG_USB_ASPEED_VHUB=m
 CONFIG_USB_CONFIGFS=m
 CONFIG_MMC=y
 CONFIG_SDIO_UART=y
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+CONFIG_MMC_SDHCI_OF_ASPEED=m
 CONFIG_MMC_ATMELMCI=y
 CONFIG_MMC_MVSDIO=y
 CONFIG_NEW_LEDS=y
index e4c8def..24962d0 100644 (file)
@@ -53,6 +53,9 @@ CONFIG_ARCH_MEDIATEK=y
 CONFIG_ARCH_MESON=y
 CONFIG_ARCH_MILBEAUT=y
 CONFIG_ARCH_MILBEAUT_M10V=y
+CONFIG_ARCH_MMP=y
+CONFIG_MACH_MMP2_DT=y
+CONFIG_MACH_MMP3_DT=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_MACH_ARMADA_370=y
 CONFIG_MACH_ARMADA_375=y
@@ -168,6 +171,14 @@ CONFIG_MAC80211=m
 CONFIG_RFKILL=y
 CONFIG_RFKILL_INPUT=y
 CONFIG_RFKILL_GPIO=y
+CONFIG_NFC=m
+CONFIG_NFC_DIGITAL=m
+CONFIG_NFC_NCI=m
+CONFIG_NFC_NCI_SPI=m
+CONFIG_NFC_NCI_UART=m
+CONFIG_NFC_HCI=m
+CONFIG_NFC_SHDLC=y
+CONFIG_NFC_S3FWRN5_I2C=m
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCI_MVEBU=y
 CONFIG_PCI_TEGRA=y
@@ -244,6 +255,7 @@ CONFIG_BGMAC_BCMA=y
 CONFIG_SYSTEMPORT=m
 CONFIG_MACB=y
 CONFIG_NET_CALXEDA_XGMAC=y
+CONFIG_FTGMAC100=m
 CONFIG_GIANFAR=y
 CONFIG_HIX5HD2_GMAC=y
 CONFIG_E1000E=y
@@ -283,6 +295,7 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_QT1070=m
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_TEGRA=y
+CONFIG_KEYBOARD_PXA27x=m
 CONFIG_KEYBOARD_SAMSUNG=m
 CONFIG_KEYBOARD_ST_KEYSCAN=y
 CONFIG_KEYBOARD_SPEAR=y
@@ -437,6 +450,7 @@ CONFIG_PINCTRL_MSM8X74=y
 CONFIG_PINCTRL_MSM8916=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_QCOM_SSBI_PMIC=y
+CONFIG_GPIO_ASPEED_SGPIO=y
 CONFIG_GPIO_DAVINCI=y
 CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_EM=y
@@ -491,12 +505,12 @@ CONFIG_BCM2835_THERMAL=m
 CONFIG_BRCMSTB_THERMAL=m
 CONFIG_ST_THERMAL_MEMMAP=y
 CONFIG_UNIPHIER_THERMAL=y
-CONFIG_WATCHDOG=y
 CONFIG_DA9063_WATCHDOG=m
 CONFIG_XILINX_WATCHDOG=y
 CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_SAMA5D4_WATCHDOG=y
+CONFIG_S3C2410_WATCHDOG=m
 CONFIG_DW_WATCHDOG=y
 CONFIG_DAVINCI_WATCHDOG=m
 CONFIG_ORION_WATCHDOG=y
@@ -581,6 +595,7 @@ CONFIG_REGULATOR_QCOM_RPM=y
 CONFIG_REGULATOR_QCOM_SMD_RPM=m
 CONFIG_REGULATOR_RK808=y
 CONFIG_REGULATOR_RN5T618=y
+CONFIG_REGULATOR_S2MPA01=m
 CONFIG_REGULATOR_S2MPS11=y
 CONFIG_REGULATOR_S5M8767=y
 CONFIG_REGULATOR_STM32_BOOSTER=m
@@ -605,6 +620,7 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_MMP_CAMERA=m
 CONFIG_VIDEO_ASPEED=m
 CONFIG_VIDEO_STM32_DCMI=m
 CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS=m
@@ -702,6 +718,9 @@ CONFIG_SND_ATMEL_SOC_PDMIC=m
 CONFIG_SND_ATMEL_SOC_I2S=m
 CONFIG_SND_BCM2835_SOC_I2S=m
 CONFIG_SND_SOC_FSL_SAI=m
+CONFIG_SND_MMP_SOC=y
+CONFIG_SND_PXA_SOC_SSP=m
+CONFIG_SND_PXA910_SOC=m
 CONFIG_SND_SOC_ROCKCHIP=m
 CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
 CONFIG_SND_SOC_ROCKCHIP_MAX98090=m
@@ -711,9 +730,12 @@ CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=m
 CONFIG_SND_SOC_SMDK_WM8994_PCM=m
 CONFIG_SND_SOC_SNOW=m
 CONFIG_SND_SOC_ODROID=m
+CONFIG_SND_SOC_ARNDALE=m
 CONFIG_SND_SOC_SH4_FSI=m
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_STI=m
+CONFIG_SND_SOC_STM32_SAI=m
+CONFIG_SND_SOC_STM32_I2S=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
@@ -727,10 +749,12 @@ CONFIG_SND_SOC_TEGRA_ALC5632=m
 CONFIG_SND_SOC_TEGRA_MAX98090=m
 CONFIG_SND_SOC_AK4642=m
 CONFIG_SND_SOC_CPCAP=m
+CONFIG_SND_SOC_CS42L51_I2C=m
 CONFIG_SND_SOC_SGTL5000=m
 CONFIG_SND_SOC_SPDIF=m
 CONFIG_SND_SOC_STI_SAS=m
 CONFIG_SND_SOC_WM8978=m
+CONFIG_SND_AUDIO_GRAPH_CARD=m
 CONFIG_USB=y
 CONFIG_USB_OTG=y
 CONFIG_USB_XHCI_HCD=y
@@ -740,6 +764,7 @@ CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_HCD_STI=y
 CONFIG_USB_EHCI_TEGRA=y
 CONFIG_USB_EHCI_EXYNOS=y
+CONFIG_USB_EHCI_MV=m
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_STI=y
 CONFIG_USB_OHCI_EXYNOS=m
@@ -810,6 +835,7 @@ CONFIG_MMC_SDHCI_DOVE=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_S3C=y
 CONFIG_MMC_SDHCI_PXAV3=y
+CONFIG_MMC_SDHCI_PXAV2=m
 CONFIG_MMC_SDHCI_SPEAR=y
 CONFIG_MMC_SDHCI_S3C_DMA=y
 CONFIG_MMC_SDHCI_BCM_KONA=y
@@ -875,6 +901,7 @@ CONFIG_RTC_DRV_DA9063=m
 CONFIG_RTC_DRV_EFI=m
 CONFIG_RTC_DRV_DIGICOLOR=m
 CONFIG_RTC_DRV_S3C=m
+CONFIG_RTC_DRV_SA1100=m
 CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_AT91RM9200=m
 CONFIG_RTC_DRV_AT91SAM9=m
@@ -933,6 +960,7 @@ CONFIG_BCM2835_MBOX=y
 CONFIG_ROCKCHIP_IOMMU=y
 CONFIG_TEGRA_IOMMU_GART=y
 CONFIG_TEGRA_IOMMU_SMMU=y
+CONFIG_EXYNOS_IOMMU=y
 CONFIG_REMOTEPROC=y
 CONFIG_ST_REMOTEPROC=m
 CONFIG_RPMSG_VIRTIO=m
@@ -967,8 +995,14 @@ CONFIG_ARCH_TEGRA_2x_SOC=y
 CONFIG_ARCH_TEGRA_3x_SOC=y
 CONFIG_ARCH_TEGRA_114_SOC=y
 CONFIG_ARCH_TEGRA_124_SOC=y
+CONFIG_ARM_EXYNOS_BUS_DEVFREQ=m
 CONFIG_ARM_TEGRA_DEVFREQ=m
+CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=m
+CONFIG_EXTCON_MAX14577=m
+CONFIG_EXTCON_MAX77693=m
+CONFIG_EXTCON_MAX8997=m
 CONFIG_TI_AEMIF=y
+CONFIG_EXYNOS5422_DMC=m
 CONFIG_IIO=y
 CONFIG_IIO_SW_TRIGGER=y
 CONFIG_ASPEED_ADC=m
@@ -1020,12 +1054,14 @@ CONFIG_PHY_SUN9I_USB=y
 CONFIG_PHY_HIX5HD2_SATA=y
 CONFIG_PHY_BERLIN_SATA=y
 CONFIG_PHY_BERLIN_USB=y
+CONFIG_PHY_MMP3_USB=m
 CONFIG_PHY_CPCAP_USB=m
 CONFIG_PHY_QCOM_APQ8064_SATA=m
 CONFIG_PHY_RCAR_GEN2=m
 CONFIG_PHY_ROCKCHIP_DP=m
 CONFIG_PHY_ROCKCHIP_USB=y
 CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_PHY_EXYNOS5250_SATA=m
 CONFIG_PHY_UNIPHIER_USB2=y
 CONFIG_PHY_UNIPHIER_USB3=y
 CONFIG_PHY_MIPHY28LP=y
@@ -1041,6 +1077,13 @@ CONFIG_ROCKCHIP_EFUSE=m
 CONFIG_NVMEM_IMX_OCOTP=y
 CONFIG_NVMEM_SUNXI_SID=y
 CONFIG_NVMEM_VF610_OCOTP=y
+CONFIG_FSI=m
+CONFIG_FSI_MASTER_GPIO=m
+CONFIG_FSI_MASTER_HUB=m
+CONFIG_FSI_MASTER_ASPEED=m
+CONFIG_FSI_SCOM=m
+CONFIG_FSI_SBEFIFO=m
+CONFIG_FSI_OCC=m
 CONFIG_EXT4_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_MSDOS_FS=y
index 89cce8d..8c37cc8 100644 (file)
@@ -128,7 +128,6 @@ CONFIG_PCI_ENDPOINT_CONFIGFS=y
 CONFIG_PCI_EPF_TEST=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
 CONFIG_OMAP_OCP2SCP=y
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
@@ -343,18 +342,16 @@ CONFIG_VIDEO_OMAP3=m
 CONFIG_CEC_PLATFORM_DRIVERS=y
 # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
 CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_MT9P031=m
 CONFIG_DRM=m
 CONFIG_DRM_OMAP=m
 CONFIG_OMAP5_DSS_HDMI=y
 CONFIG_OMAP2_DSS_SDI=y
 CONFIG_OMAP2_DSS_DSI=y
 CONFIG_DRM_OMAP_ENCODER_OPA362=m
-CONFIG_DRM_OMAP_ENCODER_TFP410=m
 CONFIG_DRM_OMAP_ENCODER_TPD12S015=m
-CONFIG_DRM_OMAP_CONNECTOR_DVI=m
 CONFIG_DRM_OMAP_CONNECTOR_HDMI=m
 CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV=m
-CONFIG_DRM_OMAP_PANEL_DPI=m
 CONFIG_DRM_OMAP_PANEL_DSI_CM=m
 CONFIG_DRM_TILCDC=m
 CONFIG_DRM_PANEL_SIMPLE=m
@@ -539,11 +536,16 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_DEV_OMAP=m
+CONFIG_CRYPTO_DEV_OMAP_SHAM=m
+CONFIG_CRYPTO_DEV_OMAP_AES=m
+CONFIG_CRYPTO_DEV_OMAP_DES=m
 CONFIG_CRC_CCITT=y
 CONFIG_CRC_T10DIF=y
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
 CONFIG_LIBCRC32C=y
+CONFIG_DMA_CMA=y
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
index 67c306f..4dd1d8c 100644 (file)
@@ -225,6 +225,7 @@ CONFIG_QCOM_WCNSS_PIL=y
 CONFIG_RPMSG_CHAR=y
 CONFIG_RPMSG_QCOM_SMD=y
 CONFIG_QCOM_GSBI=y
+CONFIG_QCOM_OCMEM=y
 CONFIG_QCOM_PM=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD_RPM=y
index ef78534..27f6135 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_ARCH_AT91=y
 CONFIG_SOC_SAMA5D2=y
 CONFIG_SOC_SAMA5D3=y
 CONFIG_SOC_SAMA5D4=y
+# CONFIG_ATMEL_CLOCKSOURCE_PIT is not set
 CONFIG_AEABI=y
 CONFIG_UACCESS_WITH_MEMCPY=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
index c6c7035..bda57ca 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_PERF_EVENTS=y
 CONFIG_SLAB=y
 CONFIG_ARCH_RENESAS=y
 CONFIG_PL310_ERRATA_588369=y
-CONFIG_ARM_ERRATA_754322=y
 CONFIG_SMP=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
@@ -50,7 +49,6 @@ 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
 CONFIG_BLK_DEV_SD=y
@@ -130,7 +128,6 @@ CONFIG_DRM_SII902X=y
 CONFIG_DRM_I2C_ADV7511=y
 CONFIG_DRM_I2C_ADV7511_AUDIO=y
 CONFIG_FB_SH_MOBILE_LCDC=y
-# CONFIG_LCD_CLASS_DEVICE is not set
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_BACKLIGHT_AS3711=y
index df433ab..3f5d727 100644 (file)
@@ -56,6 +56,7 @@ CONFIG_SUN4I_EMAC=y
 CONFIG_STMMAC_ETH=y
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_MICREL_PHY=y
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_SUN4I_LRADC=y
@@ -150,4 +151,6 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
+CONFIG_CRYPTO_DEV_ALLWINNER=y
+CONFIG_CRYPTO_DEV_SUN8I_CE=y
 CONFIG_CRYPTO_DEV_SUN4I_SS=y
index 8f5c6a5..a27592d 100644 (file)
@@ -250,6 +250,8 @@ CONFIG_KEYBOARD_NVEC=y
 CONFIG_SERIO_NVEC_PS2=y
 CONFIG_NVEC_POWER=y
 CONFIG_NVEC_PAZ00=y
+CONFIG_STAGING_MEDIA=y
+CONFIG_TEGRA_VDE=y
 CONFIG_TEGRA_IOMMU_GART=y
 CONFIG_TEGRA_IOMMU_SMMU=y
 CONFIG_ARCH_TEGRA_2x_SOC=y
index 3f0c057..6ebbb2b 100644 (file)
@@ -286,11 +286,13 @@ static struct skcipher_alg neon_algs[] = {
 
 static int __init chacha_simd_mod_init(void)
 {
-       int err;
+       int err = 0;
 
-       err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
-       if (err)
-               return err;
+       if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) {
+               err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
+               if (err)
+                       return err;
+       }
 
        if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) {
                int i;
@@ -310,18 +312,22 @@ static int __init chacha_simd_mod_init(void)
                        static_branch_enable(&use_neon);
                }
 
-               err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
-               if (err)
-                       crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
+               if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) {
+                       err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
+                       if (err)
+                               crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
+               }
        }
        return err;
 }
 
 static void __exit chacha_simd_mod_fini(void)
 {
-       crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
-       if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON))
-               crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
+       if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) {
+               crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
+               if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON))
+                       crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
+       }
 }
 
 module_init(chacha_simd_mod_init);
index 2e9e12d..f3f42cf 100644 (file)
@@ -108,14 +108,15 @@ static int __init mod_init(void)
 {
        if (elf_hwcap & HWCAP_NEON) {
                static_branch_enable(&have_neon);
-               return crypto_register_kpp(&curve25519_alg);
+               return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
+                       crypto_register_kpp(&curve25519_alg) : 0;
        }
        return 0;
 }
 
 static void __exit mod_exit(void)
 {
-       if (elf_hwcap & HWCAP_NEON)
+       if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && elf_hwcap & HWCAP_NEON)
                crypto_unregister_kpp(&curve25519_alg);
 }
 
index 74a725a..abe3f2d 100644 (file)
@@ -249,16 +249,19 @@ static int __init arm_poly1305_mod_init(void)
        if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
            (elf_hwcap & HWCAP_NEON))
                static_branch_enable(&have_neon);
-       else
+       else if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
                /* register only the first entry */
                return crypto_register_shash(&arm_poly1305_algs[0]);
 
-       return crypto_register_shashes(arm_poly1305_algs,
-                                      ARRAY_SIZE(arm_poly1305_algs));
+       return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
+               crypto_register_shashes(arm_poly1305_algs,
+                                       ARRAY_SIZE(arm_poly1305_algs)) : 0;
 }
 
 static void __exit arm_poly1305_mod_exit(void)
 {
+       if (!IS_REACHABLE(CONFIG_CRYPTO_HASH))
+               return;
        if (!static_branch_likely(&have_neon)) {
                crypto_unregister_shash(&arm_poly1305_algs[0]);
                return;
index 68ca86f..fa579b2 100644 (file)
@@ -12,7 +12,6 @@ generic-y += local.h
 generic-y += local64.h
 generic-y += mm-arch-hooks.h
 generic-y += mmiowb.h
-generic-y += msi.h
 generic-y += parport.h
 generic-y += preempt.h
 generic-y += seccomp.h
index 0555f14..fa50bb0 100644 (file)
@@ -333,7 +333,7 @@ static inline u64 __gic_readq_nonatomic(const volatile void __iomem *addr)
  * GITS_VPENDBASER - the Valid bit must be cleared before changing
  * anything else.
  */
-static inline void gits_write_vpendbaser(u64 val, void * __iomem addr)
+static inline void gits_write_vpendbaser(u64 val, void __iomem *addr)
 {
        u32 tmp;
 
index 32edfad..a6d4ee8 100644 (file)
 #define L310_AUX_CTRL_STORE_LIMITATION         BIT(11) /* R2P0+ */
 #define L310_AUX_CTRL_EXCLUSIVE_CACHE          BIT(12)
 #define L310_AUX_CTRL_ASSOCIATIVITY_16         BIT(16)
+#define L310_AUX_CTRL_FWA_SHIFT                        23
+#define L310_AUX_CTRL_FWA_MASK                 (3 << 23)
 #define L310_AUX_CTRL_CACHE_REPLACE_RR         BIT(25) /* R2P0+ */
 #define L310_AUX_CTRL_NS_LOCKDOWN              BIT(26)
 #define L310_AUX_CTRL_NS_INT_CTRL              BIT(27)
index 3ae120c..eabcb48 100644 (file)
@@ -12,7 +12,7 @@
 
 #ifndef CONFIG_MMU
 
-#include <asm-generic/4level-fixup.h>
+#include <asm-generic/pgtable-nopud.h>
 #include <asm/pgtable-nommu.h>
 
 #else
index 5e5f1fa..e4e25f2 100644 (file)
@@ -161,6 +161,8 @@ config ARCH_BCM2835
        select GPIOLIB
        select ARM_AMBA
        select ARM_ERRATA_411920 if ARCH_MULTI_V6
+       select ARM_GIC if ARCH_MULTI_V7
+       select ZONE_DMA if ARCH_MULTI_V7
        select ARM_TIMER_SP804
        select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
        select TIMER_OF
@@ -169,7 +171,7 @@ config ARCH_BCM2835
        select PINCTRL_BCM2835
        select MFD_CORE
        help
-         This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
+         This enables support for the Broadcom BCM2711 and BCM283x SoCs.
          This SoC is used in the Raspberry Pi and Roku 2 devices.
 
 config ARCH_BCM_53573
index b59c813..7baa8c9 100644 (file)
@@ -42,8 +42,9 @@ obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
 obj-$(CONFIG_ARCH_BCM_MOBILE_SMC) += bcm_kona_smc.o
 
 # BCM2835
-obj-$(CONFIG_ARCH_BCM2835)     += board_bcm2835.o
 ifeq ($(CONFIG_ARCH_BCM2835),y)
+obj-y                          += board_bcm2835.o
+obj-y                          += bcm2711.o
 ifeq ($(CONFIG_ARM),y)
 obj-$(CONFIG_SMP)              += platsmp.o
 endif
diff --git a/arch/arm/mach-bcm/bcm2711.c b/arch/arm/mach-bcm/bcm2711.c
new file mode 100644 (file)
index 0000000..dbe2967
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Stefan Wahren
+ */
+
+#include <linux/of_address.h>
+
+#include <asm/mach/arch.h>
+
+#include "platsmp.h"
+
+static const char * const bcm2711_compat[] = {
+#ifdef CONFIG_ARCH_MULTI_V7
+       "brcm,bcm2711",
+#endif
+};
+
+DT_MACHINE_START(BCM2711, "BCM2711")
+#ifdef CONFIG_ZONE_DMA
+       .dma_zone_size  = SZ_1G,
+#endif
+       .dt_compat = bcm2711_compat,
+       .smp = smp_ops(bcm2836_smp_ops),
+MACHINE_END
index 541e850..43a16f9 100644 (file)
@@ -140,7 +140,7 @@ static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys)
 static void __bcm_kona_smc(void *info)
 {
        struct bcm_kona_smc_data *data = info;
-       u32 *args = bcm_smc_buffer;
+       u32 __iomem *args = bcm_smc_buffer;
 
        BUG_ON(smp_processor_id() != 0);
        BUG_ON(!args);
index 47f8053..21400b3 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
 
+#include "platsmp.h"
+
 /* Size of mapped Cortex A9 SCU address space */
 #define CORTEX_A9_SCU_SIZE     0x58
 
index 9dab1f5..4ef5657 100644 (file)
@@ -13,6 +13,7 @@ menuconfig ARCH_EXYNOS
        select ARM_AMBA
        select ARM_GIC
        select COMMON_CLK_SAMSUNG
+       select EXYNOS_ASV
        select EXYNOS_CHIPID
        select EXYNOS_THERMAL
        select EXYNOS_PMU
index 98338a4..3b010fe 100644 (file)
@@ -15,7 +15,6 @@ menu "Hisilicon platform type"
 
 config ARCH_HI3xxx
        bool "Hisilicon Hi36xx family"
-       depends on ARCH_MULTI_V7
        select CACHE_L2X0
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
@@ -25,17 +24,15 @@ config ARCH_HI3xxx
          Support for Hisilicon Hi36xx SoC family
 
 config ARCH_HIP01
-       bool "Hisilicon HIP01 family"
-       depends on ARCH_MULTI_V7
-       select HAVE_ARM_SCU if SMP
-       select HAVE_ARM_TWD if SMP
-       select ARM_GLOBAL_TIMER
-       help
-         Support for Hisilicon HIP01 SoC family
+       bool "Hisilicon HIP01 family"
+       select HAVE_ARM_SCU if SMP
+       select HAVE_ARM_TWD if SMP
+       select ARM_GLOBAL_TIMER
+       help
+         Support for Hisilicon HIP01 SoC family
 
 config ARCH_HIP04
        bool "Hisilicon HiP04 Cortex A15 family"
-       depends on ARCH_MULTI_V7
        select ARM_ERRATA_798181 if SMP
        select HAVE_ARM_ARCH_TIMER
        select MCPM if SMP
@@ -46,7 +43,6 @@ config ARCH_HIP04
 
 config ARCH_HIX5HD2
        bool "Hisilicon X5HD2 family"
-       depends on ARCH_MULTI_V7
        select CACHE_L2X0
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
index 777d8c2..8fb68c0 100644 (file)
@@ -19,8 +19,6 @@
 #define ANADIG_REG_2P5         0x130
 #define ANADIG_REG_CORE                0x140
 #define ANADIG_ANA_MISC0       0x150
-#define ANADIG_USB1_CHRG_DETECT        0x1b0
-#define ANADIG_USB2_CHRG_DETECT        0x210
 #define ANADIG_DIGPROG         0x260
 #define ANADIG_DIGPROG_IMX6SL  0x280
 #define ANADIG_DIGPROG_IMX7D   0x800
@@ -33,8 +31,6 @@
 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG   0x1000
 /* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
 #define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS   0x2000
-#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B   0x80000
-#define BM_ANADIG_USB_CHRG_DETECT_EN_B         0x100000
 
 static struct regmap *anatop;
 
@@ -96,16 +92,6 @@ void imx_anatop_post_resume(void)
 
 }
 
-static void imx_anatop_usb_chrg_detect_disable(void)
-{
-       regmap_write(anatop, ANADIG_USB1_CHRG_DETECT,
-               BM_ANADIG_USB_CHRG_DETECT_EN_B
-               | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
-       regmap_write(anatop, ANADIG_USB2_CHRG_DETECT,
-               BM_ANADIG_USB_CHRG_DETECT_EN_B |
-               BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
-}
-
 void __init imx_init_revision_from_anatop(void)
 {
        struct device_node *np;
@@ -171,10 +157,6 @@ void __init imx_init_revision_from_anatop(void)
 void __init imx_anatop_init(void)
 {
        anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
-       if (IS_ERR(anatop)) {
+       if (IS_ERR(anatop))
                pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__);
-               return;
-       }
-
-       imx_anatop_usb_chrg_detect_disable();
 }
index 0b137ee..d811803 100644 (file)
@@ -1,15 +1,20 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/err.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 
 #include "hardware.h"
 #include "common.h"
 
+#define OCOTP_UID_H    0x420
+#define OCOTP_UID_L    0x410
+
 unsigned int __mxc_cpu_type;
 static unsigned int imx_soc_revision;
 
@@ -76,9 +81,13 @@ void __init imx_aips_allow_unprivileged_access(
 struct device * __init imx_soc_device_init(void)
 {
        struct soc_device_attribute *soc_dev_attr;
+       const char *ocotp_compat = NULL;
        struct soc_device *soc_dev;
        struct device_node *root;
+       struct regmap *ocotp;
        const char *soc_id;
+       u64 soc_uid = 0;
+       u32 val;
        int ret;
 
        soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
@@ -119,30 +128,39 @@ struct device * __init imx_soc_device_init(void)
                soc_id = "i.MX53";
                break;
        case MXC_CPU_IMX6SL:
+               ocotp_compat = "fsl,imx6sl-ocotp";
                soc_id = "i.MX6SL";
                break;
        case MXC_CPU_IMX6DL:
+               ocotp_compat = "fsl,imx6q-ocotp";
                soc_id = "i.MX6DL";
                break;
        case MXC_CPU_IMX6SX:
+               ocotp_compat = "fsl,imx6sx-ocotp";
                soc_id = "i.MX6SX";
                break;
        case MXC_CPU_IMX6Q:
+               ocotp_compat = "fsl,imx6q-ocotp";
                soc_id = "i.MX6Q";
                break;
        case MXC_CPU_IMX6UL:
+               ocotp_compat = "fsl,imx6ul-ocotp";
                soc_id = "i.MX6UL";
                break;
        case MXC_CPU_IMX6ULL:
+               ocotp_compat = "fsl,imx6ul-ocotp";
                soc_id = "i.MX6ULL";
                break;
        case MXC_CPU_IMX6ULZ:
+               ocotp_compat = "fsl,imx6ul-ocotp";
                soc_id = "i.MX6ULZ";
                break;
        case MXC_CPU_IMX6SLL:
+               ocotp_compat = "fsl,imx6sll-ocotp";
                soc_id = "i.MX6SLL";
                break;
        case MXC_CPU_IMX7D:
+               ocotp_compat = "fsl,imx7d-ocotp";
                soc_id = "i.MX7D";
                break;
        case MXC_CPU_IMX7ULP:
@@ -153,18 +171,36 @@ struct device * __init imx_soc_device_init(void)
        }
        soc_dev_attr->soc_id = soc_id;
 
+       if (ocotp_compat) {
+               ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat);
+               if (IS_ERR(ocotp))
+                       pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat);
+
+               regmap_read(ocotp, OCOTP_UID_H, &val);
+               soc_uid = val;
+               regmap_read(ocotp, OCOTP_UID_L, &val);
+               soc_uid <<= 32;
+               soc_uid |= val;
+       }
+
        soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
                                           (imx_soc_revision >> 4) & 0xf,
                                           imx_soc_revision & 0xf);
        if (!soc_dev_attr->revision)
                goto free_soc;
 
+       soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);
+       if (!soc_dev_attr->serial_number)
+               goto free_rev;
+
        soc_dev = soc_device_register(soc_dev_attr);
        if (IS_ERR(soc_dev))
-               goto free_rev;
+               goto free_serial_number;
 
        return soc_device_to_device(soc_dev);
 
+free_serial_number:
+       kfree(soc_dev_attr->serial_number);
 free_rev:
        kfree(soc_dev_attr->revision);
 free_soc:
index 089d11f..82e2239 100644 (file)
@@ -6,32 +6,12 @@
 
 #include <linux/errno.h>
 #include <linux/jiffies.h>
+#include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/proc-fns.h>
 
 #include "common.h"
 
-static inline void cpu_enter_lowpower(void)
-{
-       unsigned int v;
-
-       asm volatile(
-               "mcr    p15, 0, %1, c7, c5, 0\n"
-       "       mcr     p15, 0, %1, c7, c10, 4\n"
-       /*
-        * Turn off coherency
-        */
-       "       mrc     p15, 0, %0, c1, c0, 1\n"
-       "       bic     %0, %0, %3\n"
-       "       mcr     p15, 0, %0, c1, c0, 1\n"
-       "       mrc     p15, 0, %0, c1, c0, 0\n"
-       "       bic     %0, %0, %2\n"
-       "       mcr     p15, 0, %0, c1, c0, 0\n"
-         : "=&r" (v)
-         : "r" (0), "Ir" (CR_C), "Ir" (0x40)
-         : "cc");
-}
-
 /*
  * platform-specific code to shutdown a CPU
  *
@@ -39,7 +19,7 @@ static inline void cpu_enter_lowpower(void)
  */
 void imx_cpu_die(unsigned int cpu)
 {
-       cpu_enter_lowpower();
+       v7_exit_coherency_flush(louis);
        /*
         * We use the cpu jumping argument register to sync with
         * imx_cpu_kill() which is running on cpu0 and waiting for
index 0440109..b58a03b 100644 (file)
@@ -1,13 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig ARCH_MMP
-       bool "Marvell PXA168/910/MMP2"
+       bool "Marvell PXA168/910/MMP2/MMP3"
        depends on ARCH_MULTI_V5 || ARCH_MULTI_V7
        select GPIO_PXA
        select GPIOLIB
        select PINCTRL
        select PLAT_PXA
        help
-         Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
+         Support for Marvell's PXA168/PXA910(MMP), MMP2, and MMP3 processor lines.
 
 if ARCH_MMP
 
@@ -129,6 +129,24 @@ config MACH_MMP2_DT
          Include support for Marvell MMP2 based platforms using
          the device tree.
 
+config MACH_MMP3_DT
+       bool "Support MMP3 (ARMv7) platforms"
+       depends on ARCH_MULTI_V7
+       select ARM_GIC
+       select HAVE_ARM_SCU if SMP
+       select HAVE_ARM_TWD if SMP
+       select CACHE_L2X0
+       select PINCTRL
+       select PINCTRL_SINGLE
+       select ARCH_HAS_RESET_CONTROLLER
+       select CPU_PJ4B
+       select PM_GENERIC_DOMAINS if PM
+       select PM_GENERIC_DOMAINS_OF if PM && OF
+       help
+         Say 'Y' here if you want to include support for platforms
+         with Marvell MMP3 processor, also known as PXA2128 or
+         Armada 620.
+
 endmenu
 
 config CPU_PXA168
index 8f267c7..7b3a7f9 100644 (file)
@@ -22,6 +22,9 @@ ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_CPU_PXA910)       += pm-pxa910.o
 obj-$(CONFIG_CPU_MMP2)         += pm-mmp2.o
 endif
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_MACH_MMP3_DT)     += platsmp.o
+endif
 
 # board support
 obj-$(CONFIG_MACH_ASPENITE)    += aspenite.o
@@ -34,5 +37,6 @@ obj-$(CONFIG_MACH_FLINT)      += flint.o
 obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
 obj-$(CONFIG_MACH_MMP_DT)      += mmp-dt.o
 obj-$(CONFIG_MACH_MMP2_DT)     += mmp2-dt.o
+obj-$(CONFIG_MACH_MMP3_DT)     += mmp3.o
 obj-$(CONFIG_MACH_TETON_BGA)   += teton_bga.o
 obj-$(CONFIG_MACH_GPLUGD)      += gplugd.o
index 25edf6a..3dc2f0b 100644 (file)
 #define AXI_VIRT_BASE          IOMEM(0xfe200000)
 #define AXI_PHYS_SIZE          0x00200000
 
+#define PGU_PHYS_BASE          0xe0000000
+#define PGU_VIRT_BASE          IOMEM(0xfe400000)
+#define PGU_PHYS_SIZE          0x00100000
+
 /* Static Memory Controller - Chip Select 0 and 1 */
 #define SMC_CS0_PHYS_BASE      0x80000000
 #define SMC_CS0_PHYS_SIZE      0x10000000
@@ -38,4 +42,7 @@
 #define CIU_VIRT_BASE          (AXI_VIRT_BASE + 0x82c00)
 #define CIU_REG(x)             (CIU_VIRT_BASE + (x))
 
+#define SCU_VIRT_BASE          (PGU_VIRT_BASE)
+#define SCU_REG(x)             (SCU_VIRT_BASE + (x))
+
 #endif /* __ASM_MACH_ADDR_MAP_H */
index 6684abc..e94349d 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include "addr-map.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 
 #include "common.h"
 
-#define MMP_CHIPID     (AXI_VIRT_BASE + 0x82c00)
+#define MMP_CHIPID     CIU_REG(0x00)
 
 unsigned int mmp_chip_id;
 EXPORT_SYMBOL(mmp_chip_id);
@@ -36,6 +36,15 @@ static struct map_desc standard_io_desc[] __initdata = {
        },
 };
 
+static struct map_desc mmp2_io_desc[] __initdata = {
+       {
+               .pfn            = __phys_to_pfn(PGU_PHYS_BASE),
+               .virtual        = (unsigned long)PGU_VIRT_BASE,
+               .length         = PGU_PHYS_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+
 void __init mmp_map_io(void)
 {
        iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
@@ -44,6 +53,12 @@ void __init mmp_map_io(void)
        mmp_chip_id = __raw_readl(MMP_CHIPID);
 }
 
+void __init mmp2_map_io(void)
+{
+       mmp_map_io();
+       iotable_init(mmp2_io_desc, ARRAY_SIZE(mmp2_io_desc));
+}
+
 void mmp_restart(enum reboot_mode mode, const char *cmd)
 {
        soft_restart(0);
index 483b8b6..ed56b3f 100644 (file)
@@ -5,4 +5,5 @@
 extern void mmp_timer_init(int irq, unsigned long rate);
 
 extern void __init mmp_map_io(void);
+extern void __init mmp2_map_io(void);
 extern void mmp_restart(enum reboot_mode, const char *);
diff --git a/arch/arm/mach-mmp/cputype.h b/arch/arm/mach-mmp/cputype.h
deleted file mode 100644 (file)
index a96abcf..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __ASM_MACH_CPUTYPE_H
-#define __ASM_MACH_CPUTYPE_H
-
-#include <asm/cputype.h>
-
-/*
- *  CPU   Stepping   CPU_ID      CHIP_ID
- *
- * PXA168    S0    0x56158400   0x0000C910
- * PXA168    A0    0x56158400   0x00A0A168
- * PXA910    Y1    0x56158400   0x00F2C920
- * PXA910    A0    0x56158400   0x00F2C910
- * PXA910    A1    0x56158400   0x00A0C910
- * PXA920    Y0    0x56158400   0x00F2C920
- * PXA920    A0    0x56158400   0x00A0C920
- * PXA920    A1    0x56158400   0x00A1C920
- * MMP2             Z0    0x560f5811   0x00F00410
- * MMP2      Z1    0x560f5811   0x00E00410
- * MMP2      A0    0x560f5811   0x00A0A610
- */
-
-extern unsigned int mmp_chip_id;
-
-#ifdef CONFIG_CPU_PXA168
-static inline int cpu_is_pxa168(void)
-{
-       return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
-               ((mmp_chip_id & 0xfff) == 0x168);
-}
-#else
-#define cpu_is_pxa168()        (0)
-#endif
-
-/* cpu_is_pxa910() is shared on both pxa910 and pxa920 */
-#ifdef CONFIG_CPU_PXA910
-static inline int cpu_is_pxa910(void)
-{
-       return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
-               (((mmp_chip_id & 0xfff) == 0x910) ||
-                ((mmp_chip_id & 0xfff) == 0x920));
-}
-#else
-#define cpu_is_pxa910()        (0)
-#endif
-
-#if defined(CONFIG_CPU_MMP2) || defined(CONFIG_MACH_MMP2_DT)
-static inline int cpu_is_mmp2(void)
-{
-       return (((read_cpuid_id() >> 8) & 0xff) == 0x58) &&
-               (((mmp_chip_id & 0xfff) == 0x410) ||
-                ((mmp_chip_id & 0xfff) == 0x610));
-}
-#else
-#define cpu_is_mmp2()  (0)
-#endif
-
-#endif /* __ASM_MACH_CPUTYPE_H */
index 130c1a6..18bee66 100644 (file)
@@ -11,7 +11,7 @@
 #include <asm/irq.h>
 #include "irqs.h"
 #include "devices.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "regs-usb.h"
 
 int __init pxa_register_device(struct pxa_device_desc *desc,
index 3555979..9121499 100644 (file)
@@ -9,14 +9,13 @@
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <linux/clk-provider.h>
+#include <linux/clocksource.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/cache-tauros2.h>
 
 #include "common.h"
 
-extern void __init mmp_dt_init_timer(void);
-
 static const char *const pxa168_dt_board_compat[] __initconst = {
        "mrvl,pxa168-aspenite",
        NULL,
@@ -32,8 +31,8 @@ static void __init mmp_init_time(void)
 #ifdef CONFIG_CACHE_TAUROS2
        tauros2_init(0);
 #endif
-       mmp_dt_init_timer();
        of_clk_init(NULL);
+       timer_probe();
 }
 
 DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
index 305a9da..510c762 100644 (file)
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <linux/clk-provider.h>
+#include <linux/clocksource.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/cache-tauros2.h>
 
 #include "common.h"
 
-extern void __init mmp_dt_init_timer(void);
-
 static void __init mmp_init_time(void)
 {
 #ifdef CONFIG_CACHE_TAUROS2
        tauros2_init(0);
 #endif
        of_clk_init(NULL);
-       mmp_dt_init_timer();
+       timer_probe();
 }
 
 static const char *const mmp2_dt_board_compat[] __initconst = {
@@ -33,7 +32,7 @@ static const char *const mmp2_dt_board_compat[] __initconst = {
 };
 
 DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
-       .map_io         = mmp_map_io,
+       .map_io         = mmp2_map_io,
        .init_time      = mmp_init_time,
        .dt_compat      = mmp2_dt_board_compat,
 MACHINE_END
index 18ea3e1..bbc4c22 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/mach/time.h>
 #include "addr-map.h"
 #include "regs-apbc.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "irqs.h"
 #include "mfp.h"
 #include "devices.h"
diff --git a/arch/arm/mach-mmp/mmp3.c b/arch/arm/mach-mmp/mmp3.c
new file mode 100644 (file)
index 0000000..b0e8696
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  Marvell MMP3 aka PXA2128 aka 88AP2128 support
+ *
+ *  Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/of_platform.h>
+#include <linux/clk-provider.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "common.h"
+
+static const char *const mmp3_dt_board_compat[] __initconst = {
+       "marvell,mmp3",
+       NULL,
+};
+
+DT_MACHINE_START(MMP2_DT, "Marvell MMP3")
+       .map_io         = mmp2_map_io,
+       .dt_compat      = mmp3_dt_board_compat,
+       .l2c_aux_val    = 1 << L310_AUX_CTRL_FWA_SHIFT |
+                         L310_AUX_CTRL_DATA_PREFETCH |
+                         L310_AUX_CTRL_INSTR_PREFETCH,
+       .l2c_aux_mask   = 0xc20fffff,
+MACHINE_END
diff --git a/arch/arm/mach-mmp/platsmp.c b/arch/arm/mach-mmp/platsmp.c
new file mode 100644 (file)
index 0000000..c994054
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+#include <linux/io.h>
+#include <asm/smp_scu.h>
+#include <asm/smp.h>
+#include "addr-map.h"
+
+#define SW_BRANCH_VIRT_ADDR    CIU_REG(0x24)
+
+static int mmp3_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       /*
+        * Apparently, the boot ROM on the second core spins on this
+        * register becoming non-zero and then jumps to the address written
+        * there. No IPIs involved.
+        */
+       __raw_writel(__pa_symbol(secondary_startup), SW_BRANCH_VIRT_ADDR);
+       return 0;
+}
+
+static void mmp3_smp_prepare_cpus(unsigned int max_cpus)
+{
+       scu_enable(SCU_VIRT_BASE);
+}
+
+static const struct smp_operations mmp3_smp_ops __initconst = {
+       .smp_prepare_cpus       = mmp3_smp_prepare_cpus,
+       .smp_boot_secondary     = mmp3_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(mmp3_smp, "marvell,mmp3-smp", &mmp3_smp_ops);
index 2923dd5..2d86381 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/interrupt.h>
 #include <asm/mach-types.h>
 
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "addr-map.h"
 #include "pm-mmp2.h"
 #include "regs-icu.h"
index 58535ce..69ebe18 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/mach-types.h>
 #include <asm/outercache.h>
 
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "addr-map.h"
 #include "pm-pxa910.h"
 #include "regs-icu.h"
index 6e02774..b642e90 100644 (file)
@@ -21,7 +21,7 @@
 #include "addr-map.h"
 #include "clock.h"
 #include "common.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "devices.h"
 #include "irqs.h"
 #include "mfp.h"
index cba31c7..b19a069 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/mach/time.h>
 #include "addr-map.h"
 #include "regs-apbc.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "irqs.h"
 #include "mfp.h"
 #include "devices.h"
index d9f08c1..ed0d1aa 100644 (file)
 
 #define UTMI_OTG_ADDON_OTG_ON                  (1 << 0)
 
-/* For MMP3 USB Phy */
-#define USB2_PLL_REG0          0x4
-#define USB2_PLL_REG1          0x8
-#define USB2_TX_REG0           0x10
-#define USB2_TX_REG1           0x14
-#define USB2_TX_REG2           0x18
-#define USB2_RX_REG0           0x20
-#define USB2_RX_REG1           0x24
-#define USB2_RX_REG2           0x28
-#define USB2_ANA_REG0          0x30
-#define USB2_ANA_REG1          0x34
-#define USB2_ANA_REG2          0x38
-#define USB2_DIG_REG0          0x3C
-#define USB2_DIG_REG1          0x40
-#define USB2_DIG_REG2          0x44
-#define USB2_DIG_REG3          0x48
-#define USB2_TEST_REG0         0x4C
-#define USB2_TEST_REG1         0x50
-#define USB2_TEST_REG2         0x54
-#define USB2_CHARGER_REG0      0x58
-#define USB2_OTG_REG0          0x5C
-#define USB2_PHY_MON0          0x60
-#define USB2_RESETVE_REG0      0x64
-#define USB2_ICID_REG0         0x78
-#define USB2_ICID_REG1         0x7C
-
-/* USB2_PLL_REG0 */
-/* This is for Ax stepping */
-#define USB2_PLL_FBDIV_SHIFT_MMP3              0
-#define USB2_PLL_FBDIV_MASK_MMP3               (0xFF << 0)
-
-#define USB2_PLL_REFDIV_SHIFT_MMP3             8
-#define USB2_PLL_REFDIV_MASK_MMP3              (0xF << 8)
-
-#define USB2_PLL_VDD12_SHIFT_MMP3              12
-#define USB2_PLL_VDD18_SHIFT_MMP3              14
-
-/* This is for B0 stepping */
-#define USB2_PLL_FBDIV_SHIFT_MMP3_B0           0
-#define USB2_PLL_REFDIV_SHIFT_MMP3_B0          9
-#define USB2_PLL_VDD18_SHIFT_MMP3_B0           14
-#define USB2_PLL_FBDIV_MASK_MMP3_B0            0x01FF
-#define USB2_PLL_REFDIV_MASK_MMP3_B0           0x3E00
-
-#define USB2_PLL_CAL12_SHIFT_MMP3              0
-#define USB2_PLL_CALI12_MASK_MMP3              (0x3 << 0)
-
-#define USB2_PLL_VCOCAL_START_SHIFT_MMP3       2
-
-#define USB2_PLL_KVCO_SHIFT_MMP3               4
-#define USB2_PLL_KVCO_MASK_MMP3                        (0x7<<4)
-
-#define USB2_PLL_ICP_SHIFT_MMP3                        8
-#define USB2_PLL_ICP_MASK_MMP3                 (0x7<<8)
-
-#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3                12
-
-#define USB2_PLL_PU_PLL_SHIFT_MMP3             13
-#define USB2_PLL_PU_PLL_MASK                   (0x1 << 13)
-
-#define USB2_PLL_READY_MASK_MMP3               (0x1 << 15)
-
-/* USB2_TX_REG0 */
-#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3          8
-#define USB2_TX_IMPCAL_VTH_MASK_MMP3           (0x7 << 8)
-
-#define USB2_TX_RCAL_START_SHIFT_MMP3          13
-
-/* USB2_TX_REG1 */
-#define USB2_TX_CK60_PHSEL_SHIFT_MMP3          0
-#define USB2_TX_CK60_PHSEL_MASK_MMP3           (0xf << 0)
-
-#define USB2_TX_AMP_SHIFT_MMP3                 4
-#define USB2_TX_AMP_MASK_MMP3                  (0x7 << 4)
-
-#define USB2_TX_VDD12_SHIFT_MMP3               8
-#define USB2_TX_VDD12_MASK_MMP3                        (0x3 << 8)
-
-/* USB2_TX_REG2 */
-#define USB2_TX_DRV_SLEWRATE_SHIFT             10
-
-/* USB2_RX_REG0 */
-#define USB2_RX_SQ_THRESH_SHIFT_MMP3           4
-#define USB2_RX_SQ_THRESH_MASK_MMP3            (0xf << 4)
-
-#define USB2_RX_SQ_LENGTH_SHIFT_MMP3           10
-#define USB2_RX_SQ_LENGTH_MASK_MMP3            (0x3 << 10)
-
-/* USB2_ANA_REG1*/
-#define USB2_ANA_PU_ANA_SHIFT_MMP3             14
-
-/* USB2_OTG_REG0 */
-#define USB2_OTG_PU_OTG_SHIFT_MMP3             3
-
 /* fsic registers */
 #define FSIC_MISC                      0x4
 #define FSIC_INT                       0x28
index 483df32..110dcb3 100644 (file)
@@ -33,7 +33,7 @@
 #include "regs-timers.h"
 #include "regs-apbc.h"
 #include "irqs.h"
-#include "cputype.h"
+#include <linux/soc/mmp/cputype.h>
 #include "clock.h"
 
 #define TIMERS_VIRT_BASE       TIMERS1_VIRT_BASE
@@ -155,7 +155,8 @@ static void __init timer_config(void)
 
        __raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
 
-       ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
+       ccr &= (cpu_is_mmp2() || cpu_is_mmp3()) ?
+               (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
                (TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
        __raw_writel(ccr, mmp_timer_base + TMR_CCR);
 
@@ -195,30 +196,17 @@ void __init mmp_timer_init(int irq, unsigned long rate)
        clockevents_config_and_register(&ckevt, rate, MIN_DELTA, MAX_DELTA);
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id mmp_timer_dt_ids[] = {
-       { .compatible = "mrvl,mmp-timer", },
-       {}
-};
-
-void __init mmp_dt_init_timer(void)
+static int __init mmp_dt_init_timer(struct device_node *np)
 {
-       struct device_node *np;
        struct clk *clk;
        int irq, ret;
        unsigned long rate;
 
-       np = of_find_matching_node(NULL, mmp_timer_dt_ids);
-       if (!np) {
-               ret = -ENODEV;
-               goto out;
-       }
-
        clk = of_clk_get(np, 0);
        if (!IS_ERR(clk)) {
                ret = clk_prepare_enable(clk);
                if (ret)
-                       goto out;
+                       return ret;
                rate = clk_get_rate(clk) / 2;
        } else if (cpu_is_pj4()) {
                rate = 6500000;
@@ -227,18 +215,15 @@ void __init mmp_dt_init_timer(void)
        }
 
        irq = irq_of_parse_and_map(np, 0);
-       if (!irq) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (!irq)
+               return -EINVAL;
+
        mmp_timer_base = of_iomap(np, 0);
-       if (!mmp_timer_base) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!mmp_timer_base)
+               return -ENOMEM;
+
        mmp_timer_init(irq, rate);
-       return;
-out:
-       pr_err("Failed to get timer from device tree with error:%d\n", ret);
+       return 0;
 }
-#endif
+
+TIMER_OF_DECLARE(mmp_timer, "mrvl,mmp-timer", mmp_dt_init_timer);
index 2a17dc1..948da55 100644 (file)
@@ -4,30 +4,25 @@ if ARCH_OMAP1
 menu "TI OMAP1 specific features"
 
 comment "OMAP Core Type"
-       depends on ARCH_OMAP1
 
 config ARCH_OMAP730
-       depends on ARCH_OMAP1
        bool "OMAP730 Based System"
        select ARCH_OMAP_OTG
        select CPU_ARM926T
        select OMAP_MPU_TIMER
 
 config ARCH_OMAP850
-       depends on ARCH_OMAP1
        bool "OMAP850 Based System"
        select ARCH_OMAP_OTG
        select CPU_ARM926T
 
 config ARCH_OMAP15XX
-       depends on ARCH_OMAP1
        default y
        bool "OMAP15xx Based System"
        select CPU_ARM925T
        select OMAP_MPU_TIMER
 
 config ARCH_OMAP16XX
-       depends on ARCH_OMAP1
        bool "OMAP16xx Based System"
        select ARCH_OMAP_OTG
        select CPU_ARM926T
@@ -35,7 +30,6 @@ config ARCH_OMAP16XX
 
 config OMAP_MUX
        bool "OMAP multiplexing support"
-       depends on ARCH_OMAP
        default y
        help
          Pin multiplexing support for OMAP boards. If your bootloader
@@ -60,25 +54,24 @@ config OMAP_MUX_WARNINGS
          printed, it's safe to deselect OMAP_MUX for your product.
 
 comment "OMAP Board Type"
-       depends on ARCH_OMAP1
 
 config MACH_OMAP_INNOVATOR
        bool "TI Innovator"
-       depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
+       depends on ARCH_OMAP15XX || ARCH_OMAP16XX
        help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
 
 config MACH_OMAP_H2
        bool "TI H2 Support"
-       depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       depends on ARCH_OMAP16XX
        help
          TI OMAP 1610/1611B H2 board support. Say Y here if you have such
          a board.
 
 config MACH_OMAP_H3
        bool "TI H3 Support"
-       depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       depends on ARCH_OMAP16XX
        help
          TI OMAP 1710 H3 board support. Say Y here if you have such
          a board.
@@ -91,7 +84,7 @@ config MACH_HERALD
 
 config MACH_OMAP_OSK
        bool "TI OSK Support"
-       depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       depends on ARCH_OMAP16XX
        help
          TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
@@ -106,21 +99,21 @@ config OMAP_OSK_MISTRAL
 
 config MACH_OMAP_PERSEUS2
        bool "TI Perseus2"
-       depends on ARCH_OMAP1 && ARCH_OMAP730
+       depends on ARCH_OMAP730
        help
          Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
          a board.
 
 config MACH_OMAP_FSAMPLE
        bool "TI F-Sample"
-       depends on ARCH_OMAP1 && ARCH_OMAP730
+       depends on ARCH_OMAP730
        help
          Support for TI OMAP 850 F-Sample board. Say Y here if you have such
          a board.
 
 config MACH_OMAP_PALMTE
        bool "Palm Tungsten E"
-       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       depends on ARCH_OMAP15XX
        help
          Support for the Palm Tungsten E PDA.  To boot the kernel, you'll
          need a PalmOS compatible bootloader; check out
@@ -129,7 +122,7 @@ config MACH_OMAP_PALMTE
 
 config MACH_OMAP_PALMZ71
        bool "Palm Zire71"
-       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       depends on ARCH_OMAP15XX
        help
         Support for the Palm Zire71 PDA. To boot the kernel,
         you'll need a PalmOS compatible bootloader; check out
@@ -138,7 +131,7 @@ config MACH_OMAP_PALMZ71
 
 config MACH_OMAP_PALMTT
        bool "Palm Tungsten|T"
-       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       depends on ARCH_OMAP15XX
        help
          Support for the Palm Tungsten|T PDA. To boot the kernel, you'll
          need a PalmOS compatible bootloader (Garux); check out
@@ -147,7 +140,7 @@ config MACH_OMAP_PALMTT
 
 config MACH_SX1
        bool "Siemens SX1"
-       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       depends on ARCH_OMAP15XX
        select I2C
        help
          Support for the Siemens SX1 phone. To boot the kernel,
@@ -159,14 +152,14 @@ config MACH_SX1
 
 config MACH_NOKIA770
        bool "Nokia 770"
-       depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       depends on ARCH_OMAP16XX
        help
          Support for the Nokia 770 Internet Tablet. Say Y here if you
          have such a device.
 
 config MACH_AMS_DELTA
        bool "Amstrad E3 (Delta)"
-       depends on ARCH_OMAP1 && ARCH_OMAP15XX
+       depends on ARCH_OMAP15XX
        select FIQ
        select GPIO_GENERIC_PLATFORM
        select LEDS_GPIO_REGISTER
@@ -178,7 +171,7 @@ config MACH_AMS_DELTA
 
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
-       depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
+       depends on ARCH_OMAP15XX || ARCH_OMAP16XX
        help
           Support for generic OMAP-1510, 1610 or 1710 board with
           no FPGA. Can be used as template for porting Linux to
index 0254eb9..4eea3e3 100644 (file)
@@ -110,7 +110,7 @@ void __init ams_delta_init_fiq(struct gpio_chip *chip,
 
                /*
                 * FIQ handler takes full control over serio data and clk GPIO
-                * pins.  Initiaize them and keep requested so nobody can
+                * pins.  Initialize them and keep requested so nobody can
                 * interfere.  Fail if any of those two couldn't be requested.
                 */
                switch (i) {
index fdb6743..ad08d47 100644 (file)
@@ -109,6 +109,7 @@ config ARCH_OMAP2PLUS
        select TI_SYSC
        select OMAP_IRQCHIP
        select CLKSRC_TI_32K
+       select ARCH_HAS_RESET_CONTROLLER
        help
          Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
 
index 1e1e86d..f07cfda 100644 (file)
@@ -29,6 +29,11 @@ obj-y += mcbsp.o
 endif
 
 obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
+
+ifneq ($(CONFIG_MFD_CPCAP),)
+obj-y                                  += pmic-cpcap.o
+endif
+
 obj-$(CONFIG_SOC_HAS_OMAP2_SDRC)       += sdrc.o
 
 # SMP support ONLY available for OMAP4
index f98c8ec..dedd47e 100644 (file)
@@ -1147,7 +1147,21 @@ void clkdm_del_autodeps(struct clockdomain *clkdm)
 
 /* Clockdomain-to-clock/hwmod framework interface code */
 
-static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
+/**
+ * clkdm_clk_enable - add an enabled downstream clock to this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the enabled downstream clock
+ *
+ * Increment the usecount of the clockdomain @clkdm and ensure that it
+ * is awake before @clk is enabled.  Intended to be called by
+ * clk_enable() code.  If the clockdomain is in software-supervised
+ * idle mode, force the clockdomain to wake.  If the clockdomain is in
+ * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
+ * ensure that devices in the clockdomain can be read from/written to
+ * by on-chip processors.  Returns -EINVAL if passed null pointers;
+ * returns 0 upon success or if the clockdomain is in hwsup idle mode.
+ */
+int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *unused)
 {
        if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
                return -EINVAL;
@@ -1174,33 +1188,6 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
        return 0;
 }
 
-/**
- * clkdm_clk_enable - add an enabled downstream clock to this clkdm
- * @clkdm: struct clockdomain *
- * @clk: struct clk * of the enabled downstream clock
- *
- * Increment the usecount of the clockdomain @clkdm and ensure that it
- * is awake before @clk is enabled.  Intended to be called by
- * clk_enable() code.  If the clockdomain is in software-supervised
- * idle mode, force the clockdomain to wake.  If the clockdomain is in
- * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
- * ensure that devices in the clockdomain can be read from/written to
- * by on-chip processors.  Returns -EINVAL if passed null pointers;
- * returns 0 upon success or if the clockdomain is in hwsup idle mode.
- */
-int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
-{
-       /*
-        * XXX Rewrite this code to maintain a list of enabled
-        * downstream clocks for debugging purposes?
-        */
-
-       if (!clk)
-               return -EINVAL;
-
-       return _clkdm_clk_hwmod_enable(clkdm);
-}
-
 /**
  * clkdm_clk_disable - remove an enabled downstream clock from this clkdm
  * @clkdm: struct clockdomain *
@@ -1216,13 +1203,13 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
  */
 int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
 {
-       if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
+       if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
                return -EINVAL;
 
        pwrdm_lock(clkdm->pwrdm.ptr);
 
        /* corner case: disabling unused clocks */
-       if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)
+       if (clk && (__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)
                goto ccd_exit;
 
        if (clkdm->usecount == 0) {
@@ -1277,7 +1264,7 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
        if (!oh)
                return -EINVAL;
 
-       return _clkdm_clk_hwmod_enable(clkdm);
+       return clkdm_clk_enable(clkdm, NULL);
 }
 
 /**
@@ -1300,35 +1287,10 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
        if (cpu_is_omap24xx() || cpu_is_omap34xx())
                return 0;
 
-       /*
-        * XXX Rewrite this code to maintain a list of enabled
-        * downstream hwmods for debugging purposes?
-        */
-
-       if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
+       if (!oh)
                return -EINVAL;
 
-       pwrdm_lock(clkdm->pwrdm.ptr);
-
-       if (clkdm->usecount == 0) {
-               pwrdm_unlock(clkdm->pwrdm.ptr);
-               WARN_ON(1); /* underflow */
-               return -ERANGE;
-       }
-
-       clkdm->usecount--;
-       if (clkdm->usecount > 0) {
-               pwrdm_unlock(clkdm->pwrdm.ptr);
-               return 0;
-       }
-
-       arch_clkdm->clkdm_clk_disable(clkdm);
-       pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
-       pwrdm_unlock(clkdm->pwrdm.ptr);
-
-       pr_debug("clockdomain: %s: disabled\n", clkdm->name);
-
-       return 0;
+       return clkdm_clk_disable(clkdm, NULL);
 }
 
 /**
index c84b5e2..73338cf 100644 (file)
@@ -684,7 +684,7 @@ static u32 am33xx_control_vals[ARRAY_SIZE(am43xx_control_reg_offsets)];
  *
  * Save the wkup domain registers
  */
-void am43xx_control_save_context(void)
+static void am43xx_control_save_context(void)
 {
        int i;
 
@@ -698,7 +698,7 @@ void am43xx_control_save_context(void)
  *
  * Restore the wkup domain registers
  */
-void am43xx_control_restore_context(void)
+static void am43xx_control_restore_context(void)
 {
        int i;
 
index 393b421..eceb4b0 100644 (file)
 #define OMAP44XX_CONTROL_FUSE_MPU_OPP100       0x243
 #define OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO     0x246
 #define OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO     0x249
+#define OMAP44XX_CONTROL_FUSE_MPU_OPPNITROSB   0x24C
 #define OMAP44XX_CONTROL_FUSE_CORE_OPP50       0x254
 #define OMAP44XX_CONTROL_FUSE_CORE_OPP100      0x257
 #define OMAP44XX_CONTROL_FUSE_CORE_OPP100OV    0x25A
index 439e143..46012ca 100644 (file)
@@ -265,6 +265,7 @@ static int __init omapdss_init_of(void)
        r = of_platform_populate(node, NULL, NULL, &pdev->dev);
        if (r) {
                pr_err("Unable to populate DSS submodule devices\n");
+               put_device(&pdev->dev);
                return r;
        }
 
index 2d8f905..67fa285 100644 (file)
@@ -227,7 +227,6 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 {
        struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
        unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
-       unsigned int wakeup_cpu;
 
        if (omap_rev() == OMAP4430_REV_ES1_0)
                return -ENXIO;
@@ -292,7 +291,6 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
         * secure devices, CPUx does WFI which can result in
         * domain transition
         */
-       wakeup_cpu = smp_processor_id();
        pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
 
        pwrdm_post_transition(NULL);
index 3acb419..1d55602 100644 (file)
@@ -119,11 +119,7 @@ static void _add_hwmod_clocks_clkdev(struct omap_device *od,
 
 /**
  * omap_device_build_from_dt - build an omap_device with multiple hwmods
- * @pdev_name: name of the platform_device driver to use
- * @pdev_id: this platform_device's connection ID
- * @oh: ptr to the single omap_hwmod that backs this omap_device
- * @pdata: platform_data ptr to associate with the platform_device
- * @pdata_len: amount of memory pointed to by @pdata
+ * @pdev: The platform device to update.
  *
  * Function for building an omap_device already registered from device-tree
  *
@@ -292,7 +288,7 @@ static int _omap_device_idle_hwmods(struct omap_device *od)
 
 /**
  * omap_device_get_context_loss_count - get lost context count
- * @od: struct omap_device *
+ * @pdev: The platform device to update.
  *
  * Using the primary hwmod, query the context loss count for this
  * device.
@@ -321,9 +317,8 @@ int omap_device_get_context_loss_count(struct platform_device *pdev)
 /**
  * omap_device_alloc - allocate an omap_device
  * @pdev: platform_device that will be included in this omap_device
- * @oh: ptr to the single omap_hwmod that backs this omap_device
- * @pdata: platform_data ptr to associate with the platform_device
- * @pdata_len: amount of memory pointed to by @pdata
+ * @ohs: ptr to the omap_hwmod for this omap_device
+ * @oh_cnt: the size of the ohs list
  *
  * Convenience function for allocating an omap_device structure and filling
  * hwmods, and resources.
@@ -649,7 +644,7 @@ struct dev_pm_domain omap_device_pm_domain = {
 
 /**
  * omap_device_register - register an omap_device with one omap_hwmod
- * @od: struct omap_device * to register
+ * @pdev: the platform device (omap_device) to register.
  *
  * Register the omap_device structure.  This currently just calls
  * platform_device_register() on the underlying platform_device.
@@ -668,7 +663,7 @@ int omap_device_register(struct platform_device *pdev)
 
 /**
  * omap_device_enable - fully activate an omap_device
- * @od: struct omap_device * to activate
+ * @pdev: the platform device to activate
  *
  * Do whatever is necessary for the hwmods underlying omap_device @od
  * to be accessible and ready to operate.  This generally involves
@@ -702,7 +697,7 @@ int omap_device_enable(struct platform_device *pdev)
 
 /**
  * omap_device_idle - idle an omap_device
- * @od: struct omap_device * to idle
+ * @pdev: The platform_device (omap_device) to idle
  *
  * Idle omap_device @od.  Device drivers call this function indirectly
  * via pm_runtime_put*().  Returns -EINVAL if the omap_device is not
index 203664c..a136788 100644 (file)
@@ -623,39 +623,6 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
        return 0;
 }
 
-/**
- * _disable_wakeup: clear OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
- * @oh: struct omap_hwmod *
- *
- * Prevent the hardware module @oh to send wakeups.  Returns -EINVAL
- * upon error or 0 upon success.
- */
-static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
-{
-       if (!oh->class->sysc ||
-           !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
-             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
-             (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
-               return -EINVAL;
-
-       if (!oh->class->sysc->sysc_fields) {
-               WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
-               return -EINVAL;
-       }
-
-       if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
-               *v &= ~(0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
-
-       if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
-               _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v);
-       if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
-               _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART, v);
-
-       /* XXX test pwrdm_get_wken for this hwmod's subsystem */
-
-       return 0;
-}
-
 static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
 {
        struct clk_hw_omap *clk;
@@ -3867,70 +3834,6 @@ void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh)
  * for context save/restore operations?
  */
 
-/**
- * omap_hwmod_enable_wakeup - allow device to wake up the system
- * @oh: struct omap_hwmod *
- *
- * Sets the module OCP socket ENAWAKEUP bit to allow the module to
- * send wakeups to the PRCM, and enable I/O ring wakeup events for
- * this IP block if it has dynamic mux entries.  Eventually this
- * should set PRCM wakeup registers to cause the PRCM to receive
- * wakeup events from the module.  Does not set any wakeup routing
- * registers beyond this point - if the module is to wake up any other
- * module or subsystem, that must be set separately.  Called by
- * omap_device code.  Returns -EINVAL on error or 0 upon success.
- */
-int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
-{
-       unsigned long flags;
-       u32 v;
-
-       spin_lock_irqsave(&oh->_lock, flags);
-
-       if (oh->class->sysc &&
-           (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) {
-               v = oh->_sysc_cache;
-               _enable_wakeup(oh, &v);
-               _write_sysconfig(v, oh);
-       }
-
-       spin_unlock_irqrestore(&oh->_lock, flags);
-
-       return 0;
-}
-
-/**
- * omap_hwmod_disable_wakeup - prevent device from waking the system
- * @oh: struct omap_hwmod *
- *
- * Clears the module OCP socket ENAWAKEUP bit to prevent the module
- * from sending wakeups to the PRCM, and disable I/O ring wakeup
- * events for this IP block if it has dynamic mux entries.  Eventually
- * this should clear PRCM wakeup registers to cause the PRCM to ignore
- * wakeup events from the module.  Does not set any wakeup routing
- * registers beyond this point - if the module is to wake up any other
- * module or subsystem, that must be set separately.  Called by
- * omap_device code.  Returns -EINVAL on error or 0 upon success.
- */
-int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
-{
-       unsigned long flags;
-       u32 v;
-
-       spin_lock_irqsave(&oh->_lock, flags);
-
-       if (oh->class->sysc &&
-           (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) {
-               v = oh->_sysc_cache;
-               _disable_wakeup(oh, &v);
-               _write_sysconfig(v, oh);
-       }
-
-       spin_unlock_irqrestore(&oh->_lock, flags);
-
-       return 0;
-}
-
 /**
  * omap_hwmod_assert_hardreset - assert the HW reset line of submodules
  * contained in the hwmod module.
index ef1bb08..2d0fd99 100644 (file)
@@ -646,9 +646,6 @@ int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
 struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh);
 void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh);
 
-int omap_hwmod_enable_wakeup(struct omap_hwmod *oh);
-int omap_hwmod_disable_wakeup(struct omap_hwmod *oh);
-
 int omap_hwmod_for_each_by_class(const char *classname,
                                 int (*fn)(struct omap_hwmod *oh,
                                           void *user),
index 3de3d7a..26e13d4 100644 (file)
@@ -35,10 +35,7 @@ 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__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__mcspi0;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi1;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__timer2;
@@ -54,7 +51,6 @@ extern struct omap_hwmod_ocp_if am33xx_l3_main__tptc2;
 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;
-extern struct omap_hwmod_ocp_if am33xx_l4_per__rng;
 
 extern struct omap_hwmod am33xx_l3_main_hwmod;
 extern struct omap_hwmod am33xx_l3_s_hwmod;
@@ -67,7 +63,6 @@ extern struct omap_hwmod am33xx_gfx_hwmod;
 extern struct omap_hwmod am33xx_prcm_hwmod;
 extern struct omap_hwmod am33xx_aes0_hwmod;
 extern struct omap_hwmod am33xx_sha0_hwmod;
-extern struct omap_hwmod am33xx_rng_hwmod;
 extern struct omap_hwmod am33xx_ocmcram_hwmod;
 extern struct omap_hwmod am33xx_smartreflex0_hwmod;
 extern struct omap_hwmod am33xx_smartreflex1_hwmod;
@@ -78,9 +73,6 @@ 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_gpmc_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_rtc_hwmod;
 extern struct omap_hwmod am33xx_spi0_hwmod;
 extern struct omap_hwmod am33xx_spi1_hwmod;
@@ -96,7 +88,6 @@ 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_wd_timer1_hwmod;
 
 extern struct omap_hwmod_class am33xx_emif_hwmod_class;
 extern struct omap_hwmod_class am33xx_l4_hwmod_class;
index 63698ff..7123c45 100644 (file)
@@ -158,14 +158,6 @@ struct omap_hwmod_ocp_if am33xx_l3_s__gpmc = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4 ls -> mailbox */
-struct omap_hwmod_ocp_if am33xx_l4_per__mailbox = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_mailbox_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
 /* l4 ls -> spinlock */
 struct omap_hwmod_ocp_if am33xx_l4_ls__spinlock = {
        .master         = &am33xx_l4_ls_hwmod,
@@ -174,22 +166,6 @@ struct omap_hwmod_ocp_if am33xx_l4_ls__spinlock = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4 ls -> mcasp0 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp0 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_mcasp0_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4 ls -> mcasp1 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp1 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_mcasp1_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
 /* l4 ls -> mcspi0 */
 struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi0 = {
        .master         = &am33xx_l4_ls_hwmod,
@@ -308,11 +284,3 @@ struct omap_hwmod_ocp_if am33xx_l3_main__aes0 = {
        .clk            = "aes0_fck",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
-
-/* l4 per -> rng */
-struct omap_hwmod_ocp_if am33xx_l4_per__rng = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_rng_hwmod,
-       .clk            = "rng_fck",
-       .user           = OCP_USER_MPU,
-};
index 29fd136..2df8659 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 
 #include "omap_hwmod.h"
-#include "wd_timer.h"
 #include "cm33xx.h"
 #include "prm33xx.h"
 #include "omap_hwmod_33xx_43xx_common_data.h"
@@ -266,33 +265,6 @@ struct omap_hwmod am33xx_sha0_hwmod = {
        },
 };
 
-/* rng */
-static struct omap_hwmod_class_sysconfig am33xx_rng_sysc = {
-       .rev_offs       = 0x1fe0,
-       .sysc_offs      = 0x1fe4,
-       .sysc_flags     = SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE,
-       .idlemodes      = SIDLE_FORCE | SIDLE_NO,
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class am33xx_rng_hwmod_class = {
-       .name           = "rng",
-       .sysc           = &am33xx_rng_sysc,
-};
-
-struct omap_hwmod am33xx_rng_hwmod = {
-       .name           = "rng",
-       .class          = &am33xx_rng_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE,
-       .main_clk       = "rng_fck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /* ocmcram */
 static struct omap_hwmod_class am33xx_ocmcram_hwmod_class = {
        .name = "ocmcram",
@@ -466,86 +438,6 @@ struct omap_hwmod am33xx_epwmss2_hwmod = {
        },
 };
 
-/*
- * 'gpio' class: for gpio 0,1,2,3
- */
-static struct omap_hwmod_class_sysconfig am33xx_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 am33xx_gpio_hwmod_class = {
-       .name           = "gpio",
-       .sysc           = &am33xx_gpio_sysc,
-};
-
-/* gpio1 */
-static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio1_dbclk" },
-};
-
-static struct omap_hwmod am33xx_gpio1_hwmod = {
-       .name           = "gpio2",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4ls_gclk",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .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 am33xx_gpio2_hwmod = {
-       .name           = "gpio3",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4ls_gclk",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .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 am33xx_gpio3_hwmod = {
-       .name           = "gpio4",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4ls_gclk",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = gpio3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio3_opt_clks),
-};
-
 /* gpmc */
 static struct omap_hwmod_class_sysconfig gpmc_sysc = {
        .rev_offs       = 0x0,
@@ -576,78 +468,6 @@ struct omap_hwmod am33xx_gpmc_hwmod = {
        },
 };
 
-/*
- * 'mailbox' class
- * mailbox module allowing communication between the on-chip processors using a
- * queued mailbox-interrupt mechanism.
- */
-static struct omap_hwmod_class_sysconfig am33xx_mailbox_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                         SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class am33xx_mailbox_hwmod_class = {
-       .name   = "mailbox",
-       .sysc   = &am33xx_mailbox_sysc,
-};
-
-struct omap_hwmod am33xx_mailbox_hwmod = {
-       .name           = "mailbox",
-       .class          = &am33xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .main_clk       = "l4ls_gclk",
-       .prcm = {
-               .omap4 = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'mcasp' class
- */
-static struct omap_hwmod_class_sysconfig am33xx_mcasp_sysc = {
-       .rev_offs       = 0x0,
-       .sysc_offs      = 0x4,
-       .sysc_flags     = SYSC_HAS_SIDLEMODE,
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type3,
-};
-
-static struct omap_hwmod_class am33xx_mcasp_hwmod_class = {
-       .name           = "mcasp",
-       .sysc           = &am33xx_mcasp_sysc,
-};
-
-/* mcasp0 */
-struct omap_hwmod am33xx_mcasp0_hwmod = {
-       .name           = "mcasp0",
-       .class          = &am33xx_mcasp_hwmod_class,
-       .clkdm_name     = "l3s_clkdm",
-       .main_clk       = "mcasp0_fck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcasp1 */
-struct omap_hwmod am33xx_mcasp1_hwmod = {
-       .name           = "mcasp1",
-       .class          = &am33xx_mcasp_hwmod_class,
-       .clkdm_name     = "l3s_clkdm",
-       .main_clk       = "mcasp1_fck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
 
 /*
  * 'rtc' class
@@ -950,41 +770,6 @@ struct omap_hwmod am33xx_tptc2_hwmod = {
        },
 };
 
-/* 'wd_timer' class */
-static struct omap_hwmod_class_sysconfig wdt_sysc = {
-       .rev_offs       = 0x0,
-       .sysc_offs      = 0x10,
-       .syss_offs      = 0x14,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | 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 am33xx_wd_timer_hwmod_class = {
-       .name           = "wd_timer",
-       .sysc           = &wdt_sysc,
-       .pre_shutdown   = &omap2_wd_timer_disable,
-};
-
-/*
- * XXX: device.c file uses hardcoded name for watchdog timer
- * driver "wd_timer2, so we are also using same name as of now...
- */
-struct omap_hwmod am33xx_wd_timer1_hwmod = {
-       .name           = "wd_timer2",
-       .class          = &am33xx_wd_timer_hwmod_class,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE,
-       .main_clk       = "wdt1_fck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 static void omap_hwmod_am33xx_clkctrl(void)
 {
        CLKCTRL(am33xx_dcan0_hwmod, AM33XX_CM_PER_DCAN0_CLKCTRL_OFFSET);
@@ -993,12 +778,6 @@ static void omap_hwmod_am33xx_clkctrl(void)
        CLKCTRL(am33xx_epwmss0_hwmod, AM33XX_CM_PER_EPWMSS0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_epwmss1_hwmod, AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_epwmss2_hwmod, AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET);
-       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_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_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);
@@ -1013,7 +792,6 @@ static void omap_hwmod_am33xx_clkctrl(void)
        CLKCTRL(am33xx_smartreflex1_hwmod,
                AM33XX_CM_WKUP_SMARTREFLEX1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_timer1_hwmod, AM33XX_CM_WKUP_TIMER1_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_gpmc_hwmod, AM33XX_CM_PER_GPMC_CLKCTRL_OFFSET);
@@ -1031,7 +809,6 @@ static void omap_hwmod_am33xx_clkctrl(void)
        CLKCTRL(am33xx_ocmcram_hwmod , AM33XX_CM_PER_OCMCRAM_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_sha0_hwmod , AM33XX_CM_PER_SHA0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_aes0_hwmod , AM33XX_CM_PER_AES0_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_rng_hwmod, AM33XX_CM_PER_RNG_CLKCTRL_OFFSET);
 }
 
 static void omap_hwmod_am33xx_rst(void)
@@ -1055,12 +832,6 @@ static void omap_hwmod_am43xx_clkctrl(void)
        CLKCTRL(am33xx_epwmss0_hwmod, AM43XX_CM_PER_EPWMSS0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_epwmss1_hwmod, AM43XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_epwmss2_hwmod, AM43XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET);
-       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_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_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);
@@ -1075,7 +846,6 @@ static void omap_hwmod_am43xx_clkctrl(void)
        CLKCTRL(am33xx_smartreflex1_hwmod,
                AM43XX_CM_WKUP_SMARTREFLEX1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_timer1_hwmod, AM43XX_CM_WKUP_TIMER1_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_gpmc_hwmod, AM43XX_CM_PER_GPMC_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_l4_ls_hwmod, AM43XX_CM_PER_L4LS_CLKCTRL_OFFSET);
@@ -1092,7 +862,6 @@ static void omap_hwmod_am43xx_clkctrl(void)
        CLKCTRL(am33xx_ocmcram_hwmod , AM43XX_CM_PER_OCMCRAM_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_sha0_hwmod , AM43XX_CM_PER_SHA0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_aes0_hwmod , AM43XX_CM_PER_AES0_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_rng_hwmod, AM43XX_CM_PER_RNG_CLKCTRL_OFFSET);
 }
 
 static void omap_hwmod_am43xx_rst(void)
index 5452477..c63f664 100644 (file)
@@ -21,7 +21,6 @@
 #include "cm33xx.h"
 #include "prm33xx.h"
 #include "prm-regbits-33xx.h"
-#include "wd_timer.h"
 #include "omap_hwmod_33xx_43xx_common_data.h"
 
 /*
@@ -256,39 +255,6 @@ static struct omap_hwmod am33xx_lcdc_hwmod = {
        },
 };
 
-/*
- * 'usb_otg' class
- * high-speed on-the-go universal serial bus (usb_otg) controller
- */
-static struct omap_hwmod_class_sysconfig am33xx_usbhsotg_sysc = {
-       .rev_offs       = 0x0,
-       .sysc_offs      = 0x10,
-       .sysc_flags     = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                         MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class am33xx_usbotg_class = {
-       .name           = "usbotg",
-       .sysc           = &am33xx_usbhsotg_sysc,
-};
-
-static struct omap_hwmod am33xx_usbss_hwmod = {
-       .name           = "usb_otg_hs",
-       .class          = &am33xx_usbotg_class,
-       .clkdm_name     = "l3s_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
-       .main_clk       = "usbotg_fck",
-       .prcm           = {
-               .omap4  = {
-                       .clkctrl_offs   = AM33XX_CM_PER_USB0_CLKCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-
 /*
  * Interfaces
  */
@@ -388,24 +354,6 @@ static struct omap_hwmod_ocp_if am33xx_l4_wkup__timer1 = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4 wkup -> wd_timer1 */
-static struct omap_hwmod_ocp_if am33xx_l4_wkup__wd_timer1 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am33xx_wd_timer1_hwmod,
-       .clk            = "dpll_core_m4_div2_ck",
-       .user           = OCP_USER_MPU,
-};
-
-/* usbss */
-/* l3 s -> USBSS interface */
-static struct omap_hwmod_ocp_if am33xx_l3_s__usbss = {
-       .master         = &am33xx_l3_s_hwmod,
-       .slave          = &am33xx_usbss_hwmod,
-       .clk            = "l3s_gclk",
-       .user           = OCP_USER_MPU,
-       .flags          = OCPIF_SWSUP_IDLE,
-};
-
 static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l3_main__emif,
        &am33xx_mpu__l3_main,
@@ -428,13 +376,9 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l4_wkup__timer1,
        &am33xx_l4_wkup__rtc,
        &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__mailbox,
-       &am33xx_l4_ls__mcasp0,
-       &am33xx_l4_ls__mcasp1,
        &am33xx_l4_ls__timer2,
        &am33xx_l4_ls__timer3,
        &am33xx_l4_ls__timer4,
@@ -455,10 +399,8 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l3_main__tptc1,
        &am33xx_l3_main__tptc2,
        &am33xx_l3_main__ocmc,
-       &am33xx_l3_s__usbss,
        &am33xx_l3_main__sha0,
        &am33xx_l3_main__aes0,
-       &am33xx_l4_per__rng,
        NULL,
 };
 
index 5c3db6b..b81f834 100644 (file)
@@ -18,8 +18,6 @@
 #include "omap_hwmod_33xx_43xx_common_data.h"
 #include "prcm43xx.h"
 #include "omap_hwmod_common_data.h"
-#include "hdq1w.h"
-
 
 /* IP blocks */
 static struct omap_hwmod am43xx_emif_hwmod = {
@@ -468,32 +466,6 @@ static struct omap_hwmod am43xx_dss_rfbi_hwmod = {
        .parent_hwmod   = &am43xx_dss_core_hwmod,
 };
 
-/* HDQ1W */
-static struct omap_hwmod_class_sysconfig am43xx_hdq1w_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0014,
-       .syss_offs      = 0x0018,
-       .sysc_flags     = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class am43xx_hdq1w_hwmod_class = {
-       .name   = "hdq1w",
-       .sysc   = &am43xx_hdq1w_sysc,
-       .reset  = &omap_hdq1w_reset,
-};
-
-static struct omap_hwmod am43xx_hdq1w_hwmod = {
-       .name           = "hdq1w",
-       .class          = &am43xx_hdq1w_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
 
 static struct omap_hwmod_class_sysconfig am43xx_vpfe_sysc = {
        .rev_offs       = 0x0,
@@ -604,13 +576,6 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__timer1 = {
        .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,
-       .clk            = "sys_clkin_ck",
-       .user           = OCP_USER_MPU,
-};
-
 static struct omap_hwmod_ocp_if am33xx_l4_wkup__synctimer = {
        .master         = &am33xx_l4_wkup_hwmod,
        .slave          = &am43xx_synctimer_hwmod,
@@ -751,13 +716,6 @@ static struct omap_hwmod_ocp_if am43xx_l4_ls__dss_rfbi = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-static struct omap_hwmod_ocp_if am43xx_l4_ls__hdq1w = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am43xx_hdq1w_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 static struct omap_hwmod_ocp_if am43xx_l3__vpfe0 = {
        .master         = &am43xx_vpfe0_hwmod,
        .slave          = &am33xx_l3_main_hwmod,
@@ -824,15 +782,10 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am43xx_l4_wkup__smartreflex0,
        &am43xx_l4_wkup__smartreflex1,
        &am43xx_l4_wkup__timer1,
-       &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__mailbox,
-       &am33xx_l4_per__rng,
-       &am33xx_l4_ls__mcasp0,
-       &am33xx_l4_ls__mcasp1,
        &am33xx_l4_ls__timer2,
        &am33xx_l4_ls__timer3,
        &am33xx_l4_ls__timer4,
@@ -863,7 +816,6 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am43xx_l4_ls__dss,
        &am43xx_l4_ls__dss_dispc,
        &am43xx_l4_ls__dss_rfbi,
-       &am43xx_l4_ls__hdq1w,
        &am43xx_l3__vpfe0,
        &am43xx_l3__vpfe1,
        &am43xx_l4_ls__vpfe0,
index 28ea296..292f544 100644 (file)
@@ -790,7 +790,7 @@ static struct omap_hwmod_class omap44xx_sha0_hwmod_class = {
        .sysc           = &omap44xx_sha0_sysc,
 };
 
-struct omap_hwmod omap44xx_sha0_hwmod = {
+static struct omap_hwmod omap44xx_sha0_hwmod = {
        .name           = "sham",
        .class          = &omap44xx_sha0_hwmod_class,
        .clkdm_name     = "l4_secure_clkdm",
@@ -974,7 +974,7 @@ static struct omap_hwmod omap44xx_des_hwmod = {
        },
 };
 
-struct omap_hwmod_ocp_if omap44xx_l3_main_2__des = {
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__des = {
        .master         = &omap44xx_l3_main_2_hwmod,
        .slave          = &omap44xx_des_hwmod,
        .clk            = "l3_div_ck",
@@ -1061,40 +1061,6 @@ static struct omap_hwmod omap44xx_gpmc_hwmod = {
        },
 };
 
-/*
- * 'hdq1w' class
- * hdq / 1-wire serial interface controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_hdq1w_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0014,
-       .syss_offs      = 0x0018,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_hdq1w_hwmod_class = {
-       .name   = "hdq1w",
-       .sysc   = &omap44xx_hdq1w_sysc,
-};
-
-/* hdq1w */
-static struct omap_hwmod omap44xx_hdq1w_hwmod = {
-       .name           = "hdq1w",
-       .class          = &omap44xx_hdq1w_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_INIT_NO_RESET, /* XXX temporary */
-       .main_clk       = "func_12m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_HDQ1W_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
 
 /*
  * 'hsi' class
@@ -1288,180 +1254,6 @@ static struct omap_hwmod omap44xx_kbd_hwmod = {
        },
 };
 
-/*
- * 'mailbox' class
- * mailbox module allowing communication between the on-chip processors using a
- * queued mailbox-interrupt mechanism.
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mailbox_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mailbox_hwmod_class = {
-       .name   = "mailbox",
-       .sysc   = &omap44xx_mailbox_sysc,
-};
-
-/* mailbox */
-static struct omap_hwmod omap44xx_mailbox_hwmod = {
-       .name           = "mailbox",
-       .class          = &omap44xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4_cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/*
- * 'mcasp' class
- * multi-channel audio serial port controller
- */
-
-/* The IP is not compliant to type1 / type2 scheme */
-static struct omap_hwmod_class_sysconfig omap44xx_mcasp_sysc = {
-       .rev_offs       = 0,
-       .sysc_offs      = 0x0004,
-       .sysc_flags     = SYSC_HAS_SIDLEMODE,
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type_mcasp,
-};
-
-static struct omap_hwmod_class omap44xx_mcasp_hwmod_class = {
-       .name   = "mcasp",
-       .sysc   = &omap44xx_mcasp_sysc,
-};
-
-/* mcasp */
-static struct omap_hwmod omap44xx_mcasp_hwmod = {
-       .name           = "mcasp",
-       .class          = &omap44xx_mcasp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "func_mcasp_abe_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_ABE_MCASP_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'mcbsp' class
- * multi channel buffered serial port controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mcbsp_sysc = {
-       .rev_offs       = -ENODEV,
-       .sysc_offs      = 0x008c,
-       .sysc_flags     = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = {
-       .name   = "mcbsp",
-       .sysc   = &omap44xx_mcbsp_sysc,
-};
-
-/* mcbsp1 */
-static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp1_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
-       .name           = "mcbsp1",
-       .class          = &omap44xx_mcbsp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "func_mcbsp1_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_ABE_MCBSP1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp1_opt_clks),
-};
-
-/* mcbsp2 */
-static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp2_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
-       .name           = "mcbsp2",
-       .class          = &omap44xx_mcbsp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "func_mcbsp2_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_ABE_MCBSP2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp2_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp2_opt_clks),
-};
-
-/* mcbsp3 */
-static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp3_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
-       .name           = "mcbsp3",
-       .class          = &omap44xx_mcbsp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "func_mcbsp3_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_ABE_MCBSP3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp3_opt_clks),
-};
-
-/* mcbsp4 */
-static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp4_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
-       .name           = "mcbsp4",
-       .class          = &omap44xx_mcbsp_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "per_mcbsp4_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MCBSP4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp4_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp4_opt_clks),
-};
 
 /*
  * 'mcpdm' class
@@ -2294,51 +2086,6 @@ static struct omap_hwmod omap44xx_usb_host_hs_hwmod = {
        .flags          = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
 };
 
-/*
- * 'usb_otg_hs' class
- * high-speed on-the-go universal serial bus (usb_otg_hs) controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_usb_otg_hs_sysc = {
-       .rev_offs       = 0x0400,
-       .sysc_offs      = 0x0404,
-       .syss_offs      = 0x0408,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-                          MSTANDBY_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_usb_otg_hs_hwmod_class = {
-       .name   = "usb_otg_hs",
-       .sysc   = &omap44xx_usb_otg_hs_sysc,
-};
-
-/* usb_otg_hs */
-static struct omap_hwmod_opt_clk usb_otg_hs_opt_clks[] = {
-       { .role = "xclk", .clk = "usb_otg_hs_xclk" },
-};
-
-static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = {
-       .name           = "usb_otg_hs",
-       .class          = &omap44xx_usb_otg_hs_hwmod_class,
-       .clkdm_name     = "l3_init_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
-       .main_clk       = "usb_otg_hs_ick",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L3INIT_USB_OTG_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = usb_otg_hs_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(usb_otg_hs_opt_clks),
-};
-
 /*
  * 'usb_tll_hs' class
  * usb_tll_hs module is the adapter on the usb_host_hs ports
@@ -2546,14 +2293,6 @@ static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* usb_otg_hs -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_usb_otg_hs__l3_main_2 = {
-       .master         = &omap44xx_usb_otg_hs_hwmod,
-       .slave          = &omap44xx_l3_main_2_hwmod,
-       .clk            = "l3_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l3_main_1 -> l3_main_3 */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
        .master         = &omap44xx_l3_main_1_hwmod,
@@ -2898,14 +2637,6 @@ static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpmc = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per -> hdq1w */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__hdq1w = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_hdq1w_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> hsi */
 static struct omap_hwmod_ocp_if omap44xx_l4_cfg__hsi = {
        .master         = &omap44xx_l4_cfg_hwmod,
@@ -2954,62 +2685,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_wkup__kbd = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> mailbox */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__mailbox = {
-       .master         = &omap44xx_l4_cfg_hwmod,
-       .slave          = &omap44xx_mailbox_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_abe -> mcasp */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp = {
-       .master         = &omap44xx_l4_abe_hwmod,
-       .slave          = &omap44xx_mcasp_hwmod,
-       .clk            = "ocp_abe_iclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4_abe -> mcasp (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp_dma = {
-       .master         = &omap44xx_l4_abe_hwmod,
-       .slave          = &omap44xx_mcasp_hwmod,
-       .clk            = "ocp_abe_iclk",
-       .user           = OCP_USER_SDMA,
-};
-
-/* l4_abe -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1 = {
-       .master         = &omap44xx_l4_abe_hwmod,
-       .slave          = &omap44xx_mcbsp1_hwmod,
-       .clk            = "ocp_abe_iclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_abe -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2 = {
-       .master         = &omap44xx_l4_abe_hwmod,
-       .slave          = &omap44xx_mcbsp2_hwmod,
-       .clk            = "ocp_abe_iclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_abe -> mcbsp3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3 = {
-       .master         = &omap44xx_l4_abe_hwmod,
-       .slave          = &omap44xx_mcbsp3_hwmod,
-       .clk            = "ocp_abe_iclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcbsp4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcbsp4 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mcbsp4_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_abe -> mcpdm */
 static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
        .master         = &omap44xx_l4_abe_hwmod,
@@ -3242,14 +2917,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> usb_otg_hs */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_otg_hs = {
-       .master         = &omap44xx_l4_cfg_hwmod,
-       .slave          = &omap44xx_usb_otg_hs_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> usb_tll_hs */
 static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = {
        .master         = &omap44xx_l4_cfg_hwmod,
@@ -3296,7 +2963,6 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_cfg__l3_main_2,
        /* &omap44xx_usb_host_fs__l3_main_2, */
        &omap44xx_usb_host_hs__l3_main_2,
-       &omap44xx_usb_otg_hs__l3_main_2,
        &omap44xx_l3_main_1__l3_main_3,
        &omap44xx_l3_main_2__l3_main_3,
        &omap44xx_l4_cfg__l3_main_3,
@@ -3339,20 +3005,12 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_per__elm,
        &omap44xx_l4_cfg__fdif,
        &omap44xx_l3_main_2__gpmc,
-       &omap44xx_l4_per__hdq1w,
        &omap44xx_l4_cfg__hsi,
        &omap44xx_l3_main_2__ipu,
        &omap44xx_l3_main_2__iss,
        /* &omap44xx_iva__sl2if, */
        &omap44xx_l3_main_2__iva,
        &omap44xx_l4_wkup__kbd,
-       &omap44xx_l4_cfg__mailbox,
-       &omap44xx_l4_abe__mcasp,
-       &omap44xx_l4_abe__mcasp_dma,
-       &omap44xx_l4_abe__mcbsp1,
-       &omap44xx_l4_abe__mcbsp2,
-       &omap44xx_l4_abe__mcbsp3,
-       &omap44xx_l4_per__mcbsp4,
        &omap44xx_l4_abe__mcpdm,
        &omap44xx_l3_main_2__mmu_ipu,
        &omap44xx_l4_cfg__mmu_dsp,
@@ -3384,7 +3042,6 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_per__timer11,
        /* &omap44xx_l4_cfg__usb_host_fs, */
        &omap44xx_l4_cfg__usb_host_hs,
-       &omap44xx_l4_cfg__usb_otg_hs,
        &omap44xx_l4_cfg__usb_tll_hs,
        &omap44xx_mpu__emif1,
        &omap44xx_mpu__emif2,
index 8006b43..cc5ad6a 100644 (file)
@@ -24,7 +24,6 @@
 #include "cm1_54xx.h"
 #include "cm2_54xx.h"
 #include "prm54xx.h"
-#include "wd_timer.h"
 
 /* Base offset for all OMAP5 interrupts external to MPUSS */
 #define OMAP54XX_IRQ_GIC_START 32
@@ -628,124 +627,6 @@ static struct omap_hwmod omap54xx_kbd_hwmod = {
        },
 };
 
-/*
- * 'mailbox' class
- * mailbox module allowing communication between the on-chip processors using a
- * queued mailbox-interrupt mechanism.
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_mailbox_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap54xx_mailbox_hwmod_class = {
-       .name   = "mailbox",
-       .sysc   = &omap54xx_mailbox_sysc,
-};
-
-/* mailbox */
-static struct omap_hwmod omap54xx_mailbox_hwmod = {
-       .name           = "mailbox",
-       .class          = &omap54xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/*
- * 'mcbsp' class
- * multi channel buffered serial port controller
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_mcbsp_sysc = {
-       .rev_offs       = -ENODEV,
-       .sysc_offs      = 0x008c,
-       .sysc_flags     = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap54xx_mcbsp_hwmod_class = {
-       .name   = "mcbsp",
-       .sysc   = &omap54xx_mcbsp_sysc,
-};
-
-/* mcbsp1 */
-static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp1_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap54xx_mcbsp1_hwmod = {
-       .name           = "mcbsp1",
-       .class          = &omap54xx_mcbsp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "mcbsp1_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_ABE_MCBSP1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_ABE_MCBSP1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp1_opt_clks),
-};
-
-/* mcbsp2 */
-static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp2_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap54xx_mcbsp2_hwmod = {
-       .name           = "mcbsp2",
-       .class          = &omap54xx_mcbsp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "mcbsp2_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_ABE_MCBSP2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_ABE_MCBSP2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp2_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp2_opt_clks),
-};
-
-/* mcbsp3 */
-static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
-       { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_fck", .clk = "mcbsp3_sync_mux_ck" },
-};
-
-static struct omap_hwmod omap54xx_mcbsp3_hwmod = {
-       .name           = "mcbsp3",
-       .class          = &omap54xx_mcbsp_hwmod_class,
-       .clkdm_name     = "abe_clkdm",
-       .main_clk       = "mcbsp3_gfclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_ABE_MCBSP3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_ABE_MCBSP3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mcbsp3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mcbsp3_opt_clks),
-};
-
 /*
  * 'mcpdm' class
  * multi channel pdm controller (proprietary interface with phoenix power
@@ -795,86 +676,6 @@ static struct omap_hwmod omap54xx_mcpdm_hwmod = {
        },
 };
 
-/*
- * 'mcspi' class
- * multichannel serial port interface (mcspi) / master/slave synchronous serial
- * bus
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_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 omap54xx_mcspi_hwmod_class = {
-       .name   = "mcspi",
-       .sysc   = &omap54xx_mcspi_sysc,
-};
-
-/* mcspi1 */
-static struct omap_hwmod omap54xx_mcspi1_hwmod = {
-       .name           = "mcspi1",
-       .class          = &omap54xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MCSPI1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcspi2 */
-static struct omap_hwmod omap54xx_mcspi2_hwmod = {
-       .name           = "mcspi2",
-       .class          = &omap54xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MCSPI2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcspi3 */
-static struct omap_hwmod omap54xx_mcspi3_hwmod = {
-       .name           = "mcspi3",
-       .class          = &omap54xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MCSPI3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcspi4 */
-static struct omap_hwmod omap54xx_mcspi4_hwmod = {
-       .name           = "mcspi4",
-       .class          = &omap54xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MCSPI4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
 
 /*
  * 'mmu' class
@@ -1392,43 +1193,6 @@ static struct omap_hwmod omap54xx_usb_otg_ss_hwmod = {
        .opt_clks_cnt   = ARRAY_SIZE(usb_otg_ss_opt_clks),
 };
 
-/*
- * 'wd_timer' class
- * 32-bit watchdog upward counter that generates a pulse on the reset pin on
- * overflow condition
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_wd_timer_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0014,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | 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_wd_timer_hwmod_class = {
-       .name           = "wd_timer",
-       .sysc           = &omap54xx_wd_timer_sysc,
-       .pre_shutdown   = &omap2_wd_timer_disable,
-};
-
-/* wd_timer2 */
-static struct omap_hwmod omap54xx_wd_timer2_hwmod = {
-       .name           = "wd_timer2",
-       .class          = &omap54xx_wd_timer_hwmod_class,
-       .clkdm_name     = "wkupaon_clkdm",
-       .main_clk       = "sys_32k_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_WKUPAON_WD_TIMER2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_WKUPAON_WD_TIMER2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
 
 /*
  * 'ocp2scp' class
@@ -1747,38 +1511,6 @@ static struct omap_hwmod_ocp_if omap54xx_l4_wkup__kbd = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> mailbox */
-static struct omap_hwmod_ocp_if omap54xx_l4_cfg__mailbox = {
-       .master         = &omap54xx_l4_cfg_hwmod,
-       .slave          = &omap54xx_mailbox_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_abe -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap54xx_l4_abe__mcbsp1 = {
-       .master         = &omap54xx_l4_abe_hwmod,
-       .slave          = &omap54xx_mcbsp1_hwmod,
-       .clk            = "abe_iclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4_abe -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_abe__mcbsp2 = {
-       .master         = &omap54xx_l4_abe_hwmod,
-       .slave          = &omap54xx_mcbsp2_hwmod,
-       .clk            = "abe_iclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4_abe -> mcbsp3 */
-static struct omap_hwmod_ocp_if omap54xx_l4_abe__mcbsp3 = {
-       .master         = &omap54xx_l4_abe_hwmod,
-       .slave          = &omap54xx_mcbsp3_hwmod,
-       .clk            = "abe_iclk",
-       .user           = OCP_USER_MPU,
-};
-
 /* l4_abe -> mcpdm */
 static struct omap_hwmod_ocp_if omap54xx_l4_abe__mcpdm = {
        .master         = &omap54xx_l4_abe_hwmod,
@@ -1787,38 +1519,6 @@ static struct omap_hwmod_ocp_if omap54xx_l4_abe__mcpdm = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4_per -> mcspi1 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mcspi1 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mcspi1_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcspi2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mcspi2 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mcspi2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcspi3 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mcspi3 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mcspi3_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcspi4 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mcspi4 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mcspi4_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,
@@ -1955,14 +1655,6 @@ static struct omap_hwmod_ocp_if omap54xx_l4_cfg__usb_otg_ss = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_wkup__wd_timer2 = {
-       .master         = &omap54xx_l4_wkup_hwmod,
-       .slave          = &omap54xx_wd_timer2_hwmod,
-       .clk            = "wkupaon_iclk_mux",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_l3_main_1__dmm,
        &omap54xx_l3_main_3__l3_instr,
@@ -1994,15 +1686,7 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_mpu__emif2,
        &omap54xx_l3_main_2__mmu_ipu,
        &omap54xx_l4_wkup__kbd,
-       &omap54xx_l4_cfg__mailbox,
-       &omap54xx_l4_abe__mcbsp1,
-       &omap54xx_l4_abe__mcbsp2,
-       &omap54xx_l4_abe__mcbsp3,
        &omap54xx_l4_abe__mcpdm,
-       &omap54xx_l4_per__mcspi1,
-       &omap54xx_l4_per__mcspi2,
-       &omap54xx_l4_per__mcspi3,
-       &omap54xx_l4_per__mcspi4,
        &omap54xx_l4_cfg__mpu,
        &omap54xx_l4_cfg__spinlock,
        &omap54xx_l4_cfg__ocp2scp1,
@@ -2020,7 +1704,6 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_l4_cfg__usb_host_hs,
        &omap54xx_l4_cfg__usb_tll_hs,
        &omap54xx_l4_cfg__usb_otg_ss,
-       &omap54xx_l4_wkup__wd_timer2,
        &omap54xx_l4_cfg__ocp2scp3,
        &omap54xx_l4_cfg__sata,
        NULL,
index e5bd549..f8715bd 100644 (file)
@@ -24,7 +24,6 @@
 #include "cm1_7xx.h"
 #include "cm2_7xx.h"
 #include "prm7xx.h"
-#include "wd_timer.h"
 #include "soc.h"
 
 /* Base offset for all DRA7XX interrupts external to MPUSS */
@@ -683,7 +682,7 @@ static struct omap_hwmod_class dra7xx_sha0_hwmod_class = {
        .sysc           = &dra7xx_sha0_sysc,
 };
 
-struct omap_hwmod dra7xx_sha0_hwmod = {
+static struct omap_hwmod dra7xx_sha0_hwmod = {
        .name           = "sham",
        .class          = &dra7xx_sha0_hwmod_class,
        .clkdm_name     = "l4sec_clkdm",
@@ -772,229 +771,7 @@ static struct omap_hwmod dra7xx_gpmc_hwmod = {
        },
 };
 
-/*
- * 'hdq1w' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_hdq1w_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0014,
-       .syss_offs      = 0x0018,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
 
-static struct omap_hwmod_class dra7xx_hdq1w_hwmod_class = {
-       .name   = "hdq1w",
-       .sysc   = &dra7xx_hdq1w_sysc,
-};
-
-/* hdq1w */
-
-static struct omap_hwmod dra7xx_hdq1w_hwmod = {
-       .name           = "hdq1w",
-       .class          = &dra7xx_hdq1w_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_INIT_NO_RESET,
-       .main_clk       = "func_12m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_HDQ1W_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_HDQ1W_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'mailbox' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_mailbox_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class dra7xx_mailbox_hwmod_class = {
-       .name   = "mailbox",
-       .sysc   = &dra7xx_mailbox_sysc,
-};
-
-/* mailbox1 */
-static struct omap_hwmod dra7xx_mailbox1_hwmod = {
-       .name           = "mailbox1",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX1_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX1_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox2 */
-static struct omap_hwmod dra7xx_mailbox2_hwmod = {
-       .name           = "mailbox2",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX2_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX2_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox3 */
-static struct omap_hwmod dra7xx_mailbox3_hwmod = {
-       .name           = "mailbox3",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX3_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX3_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox4 */
-static struct omap_hwmod dra7xx_mailbox4_hwmod = {
-       .name           = "mailbox4",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX4_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX4_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox5 */
-static struct omap_hwmod dra7xx_mailbox5_hwmod = {
-       .name           = "mailbox5",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX5_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX5_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox6 */
-static struct omap_hwmod dra7xx_mailbox6_hwmod = {
-       .name           = "mailbox6",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX6_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX6_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox7 */
-static struct omap_hwmod dra7xx_mailbox7_hwmod = {
-       .name           = "mailbox7",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX7_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX7_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox8 */
-static struct omap_hwmod dra7xx_mailbox8_hwmod = {
-       .name           = "mailbox8",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX8_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX8_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox9 */
-static struct omap_hwmod dra7xx_mailbox9_hwmod = {
-       .name           = "mailbox9",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX9_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX9_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox10 */
-static struct omap_hwmod dra7xx_mailbox10_hwmod = {
-       .name           = "mailbox10",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX10_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX10_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox11 */
-static struct omap_hwmod dra7xx_mailbox11_hwmod = {
-       .name           = "mailbox11",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX11_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX11_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox12 */
-static struct omap_hwmod dra7xx_mailbox12_hwmod = {
-       .name           = "mailbox12",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX12_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX12_CONTEXT_OFFSET,
-               },
-       },
-};
-
-/* mailbox13 */
-static struct omap_hwmod dra7xx_mailbox13_hwmod = {
-       .name           = "mailbox13",
-       .class          = &dra7xx_mailbox_hwmod_class,
-       .clkdm_name     = "l4cfg_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4CFG_MAILBOX13_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4CFG_MAILBOX13_CONTEXT_OFFSET,
-               },
-       },
-};
 
 /*
  * 'mpu' class
@@ -1655,34 +1432,6 @@ static struct omap_hwmod dra7xx_des_hwmod = {
        },
 };
 
-/* rng */
-static struct omap_hwmod_class_sysconfig dra7xx_rng_sysc = {
-       .rev_offs       = 0x1fe0,
-       .sysc_offs      = 0x1fe4,
-       .sysc_flags     = SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE,
-       .idlemodes      = SIDLE_FORCE | SIDLE_NO,
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class dra7xx_rng_hwmod_class = {
-       .name           = "rng",
-       .sysc           = &dra7xx_rng_sysc,
-};
-
-static struct omap_hwmod dra7xx_rng_hwmod = {
-       .name           = "rng",
-       .class          = &dra7xx_rng_hwmod_class,
-       .flags          = HWMOD_SWSUP_SIDLE,
-       .clkdm_name     = "l4sec_clkdm",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4SEC_RNG_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4SEC_RNG_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-};
-
 /*
  * 'usb_otg_ss' class
  *
@@ -1815,43 +1564,6 @@ static struct omap_hwmod dra7xx_vcp2_hwmod = {
        },
 };
 
-/*
- * 'wd_timer' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_wd_timer_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0014,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | 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_wd_timer_hwmod_class = {
-       .name           = "wd_timer",
-       .sysc           = &dra7xx_wd_timer_sysc,
-       .pre_shutdown   = &omap2_wd_timer_disable,
-       .reset          = &omap2_wd_timer_reset,
-};
-
-/* wd_timer2 */
-static struct omap_hwmod dra7xx_wd_timer2_hwmod = {
-       .name           = "wd_timer2",
-       .class          = &dra7xx_wd_timer_hwmod_class,
-       .clkdm_name     = "wkupaon_clkdm",
-       .main_clk       = "sys_32k_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_WKUPAON_WD_TIMER2_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_WKUPAON_WD_TIMER2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
 
 
 /*
@@ -2090,118 +1802,6 @@ static struct omap_hwmod_ocp_if dra7xx_l3_main_1__gpmc = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per1 -> hdq1w */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__hdq1w = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_hdq1w_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,
-       .slave          = &dra7xx_mailbox1_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox2 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox2_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox3 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox3 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox3_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox4 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox4 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox4_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox5 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox5 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox5_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox6 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox6 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox6_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox7 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox7 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox7_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox8 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox8 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox8_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox9 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox9 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox9_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox10 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox10 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox10_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox11 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox11 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox11_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox12 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox12 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox12_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per3 -> mailbox13 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per3__mailbox13 = {
-       .master         = &dra7xx_l4_per3_hwmod,
-       .slave          = &dra7xx_mailbox13_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,
@@ -2442,13 +2042,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__des = {
        .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,
-       .slave          = &dra7xx_rng_hwmod,
-       .user           = OCP_USER_MPU,
-};
-
 /* l4_per3 -> usb_otg_ss1 */
 static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = {
        .master         = &dra7xx_l4_per3_hwmod,
@@ -2513,14 +2106,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per2__vcp2 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_wkup__wd_timer2 = {
-       .master         = &dra7xx_l4_wkup_hwmod,
-       .slave          = &dra7xx_wd_timer2_hwmod,
-       .clk            = "wkupaon_iclk_mux",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_per2 -> epwmss0 */
 static struct omap_hwmod_ocp_if dra7xx_l4_per2__epwmss0 = {
        .master         = &dra7xx_l4_per2_hwmod,
@@ -2575,20 +2160,6 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l3_main_1__sha0,
        &dra7xx_l4_per1__elm,
        &dra7xx_l3_main_1__gpmc,
-       &dra7xx_l4_per1__hdq1w,
-       &dra7xx_l4_cfg__mailbox1,
-       &dra7xx_l4_per3__mailbox2,
-       &dra7xx_l4_per3__mailbox3,
-       &dra7xx_l4_per3__mailbox4,
-       &dra7xx_l4_per3__mailbox5,
-       &dra7xx_l4_per3__mailbox6,
-       &dra7xx_l4_per3__mailbox7,
-       &dra7xx_l4_per3__mailbox8,
-       &dra7xx_l4_per3__mailbox9,
-       &dra7xx_l4_per3__mailbox10,
-       &dra7xx_l4_per3__mailbox11,
-       &dra7xx_l4_per3__mailbox12,
-       &dra7xx_l4_per3__mailbox13,
        &dra7xx_l4_cfg__mpu,
        &dra7xx_l4_cfg__ocp2scp1,
        &dra7xx_l4_cfg__ocp2scp3,
@@ -2624,7 +2195,6 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_per2__vcp1,
        &dra7xx_l3_main_1__vcp2,
        &dra7xx_l4_per2__vcp2,
-       &dra7xx_l4_wkup__wd_timer2,
        &dra7xx_l4_per2__epwmss0,
        &dra7xx_l4_per2__epwmss1,
        &dra7xx_l4_per2__epwmss2,
@@ -2634,7 +2204,6 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
 /* GP-only hwmod links */
 static struct omap_hwmod_ocp_if *dra7xx_gp_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_wkup__timer12,
-       &dra7xx_l4_per1__rng,
        NULL,
 };
 
index 6787f1e..a642d3b 100644 (file)
 #define OMAP4_VDD_CORE_SR_VOLT_REG     0x61
 #define OMAP4_VDD_CORE_SR_CMD_REG      0x62
 
-#define OMAP4_VP_CONFIG_ERROROFFSET    0x00
-#define OMAP4_VP_VSTEPMIN_VSTEPMIN     0x01
-#define OMAP4_VP_VSTEPMAX_VSTEPMAX     0x04
-#define OMAP4_VP_VLIMITTO_TIMEOUT_US   200
-
 static bool is_offset_valid;
 static u8 smps_offset;
 
@@ -219,7 +214,8 @@ int __init omap4_twl_init(void)
 {
        struct voltagedomain *voltdm;
 
-       if (!cpu_is_omap44xx())
+       if (!cpu_is_omap44xx() ||
+           of_find_compatible_node(NULL, NULL, "motorola,cpcap"))
                return -ENODEV;
 
        voltdm = voltdm_lookup("mpu");
index adea43e..985aeab 100644 (file)
 
 #define OMAP4430_VDD_MPU_OPP50_UV              1025000
 #define OMAP4430_VDD_MPU_OPP100_UV             1200000
-#define OMAP4430_VDD_MPU_OPPTURBO_UV           1313000
-#define OMAP4430_VDD_MPU_OPPNITRO_UV           1375000
+#define OMAP4430_VDD_MPU_OPPTURBO_UV           1325000
+#define OMAP4430_VDD_MPU_OPPNITRO_UV           1388000
+#define OMAP4430_VDD_MPU_OPPNITROSB_UV         1398000
 
 struct omap_volt_data omap443x_vdd_mpu_volt_data[] = {
        VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP50_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c),
        VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP100_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16),
        VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23),
        VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPNITRO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27),
+       VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPNITROSB_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPNITROSB, 0xfa, 0x27),
        VOLT_DATA_DEFINE(0, 0, 0, 0),
 };
 
-#define OMAP4430_VDD_IVA_OPP50_UV              1013000
-#define OMAP4430_VDD_IVA_OPP100_UV             1188000
-#define OMAP4430_VDD_IVA_OPPTURBO_UV           1300000
+#define OMAP4430_VDD_IVA_OPP50_UV               950000
+#define OMAP4430_VDD_IVA_OPP100_UV             1114000
+#define OMAP4430_VDD_IVA_OPPTURBO_UV           1291000
 
 struct omap_volt_data omap443x_vdd_iva_volt_data[] = {
        VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP50_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c),
@@ -54,8 +56,8 @@ struct omap_volt_data omap443x_vdd_iva_volt_data[] = {
        VOLT_DATA_DEFINE(0, 0, 0, 0),
 };
 
-#define OMAP4430_VDD_CORE_OPP50_UV             1025000
-#define OMAP4430_VDD_CORE_OPP100_UV            1200000
+#define OMAP4430_VDD_CORE_OPP50_UV              962000
+#define OMAP4430_VDD_CORE_OPP100_UV            1127000
 
 struct omap_volt_data omap443x_vdd_core_volt_data[] = {
        VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP50_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c),
index c47a2af..ca52271 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/of_platform.h>
-#include <linux/ti_wilink_st.h>
 #include <linux/wl12xx.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -144,53 +143,6 @@ static void __init omap3_sbc_t3530_legacy_init(void)
        omap3_sbc_t3x_usb_hub_init(167, "sb-t35 usb hub");
 }
 
-static struct ti_st_plat_data wilink_pdata = {
-       .nshutdown_gpio = 137,
-       .dev_name = "/dev/ttyO1",
-       .flow_cntrl = 1,
-       .baud_rate = 300000,
-};
-
-static struct platform_device wl18xx_device = {
-       .name   = "kim",
-       .id     = -1,
-       .dev    = {
-               .platform_data = &wilink_pdata,
-       }
-};
-
-static struct ti_st_plat_data wilink7_pdata = {
-       .nshutdown_gpio = 162,
-       .dev_name = "/dev/ttyO1",
-       .flow_cntrl = 1,
-       .baud_rate = 3000000,
-};
-
-static struct platform_device wl128x_device = {
-       .name   = "kim",
-       .id     = -1,
-       .dev    = {
-               .platform_data = &wilink7_pdata,
-       }
-};
-
-static struct platform_device btwilink_device = {
-       .name   = "btwilink",
-       .id     = -1,
-};
-
-static void __init omap3_igep0020_rev_f_legacy_init(void)
-{
-       platform_device_register(&wl18xx_device);
-       platform_device_register(&btwilink_device);
-}
-
-static void __init omap3_igep0030_rev_g_legacy_init(void)
-{
-       platform_device_register(&wl18xx_device);
-       platform_device_register(&btwilink_device);
-}
-
 static void __init omap3_evm_legacy_init(void)
 {
        hsmmc2_internal_input_clk();
@@ -293,8 +245,6 @@ static void __init omap3_tao3530_legacy_init(void)
 static void __init omap3_logicpd_torpedo_init(void)
 {
        omap3_gpio126_127_129();
-       platform_device_register(&wl128x_device);
-       platform_device_register(&btwilink_device);
 }
 
 /* omap3pandora legacy devices */
@@ -575,8 +525,6 @@ static struct pdata_init pdata_quirks[] __initdata = {
        { "nokia,omap3-n900", nokia_n900_legacy_init, },
        { "nokia,omap3-n9", hsmmc2_internal_input_clk, },
        { "nokia,omap3-n950", hsmmc2_internal_input_clk, },
-       { "isee,omap3-igep0020-rev-f", omap3_igep0020_rev_f_legacy_init, },
-       { "isee,omap3-igep0030-rev-g", omap3_igep0030_rev_g_legacy_init, },
        { "logicpd,dm3730-torpedo-devkit", omap3_logicpd_torpedo_init, },
        { "ti,omap3-evm-37xx", omap3_evm_legacy_init, },
        { "ti,am3517-evm", am3517_evm_legacy_init, },
index 7ac9af5..01ec1ba 100644 (file)
@@ -148,6 +148,7 @@ int __init omap2_common_pm_late_init(void)
        /* Init the voltage layer */
        omap3_twl_init();
        omap4_twl_init();
+       omap4_cpcap_init();
        omap_voltage_late_init();
 
        /* Smartreflex device init */
index 8a55b69..2a883a0 100644 (file)
@@ -107,6 +107,11 @@ extern u16 pm44xx_errata;
 #define IS_PM44XX_ERRATUM(id)          0
 #endif
 
+#define OMAP4_VP_CONFIG_ERROROFFSET    0x00
+#define OMAP4_VP_VSTEPMIN_VSTEPMIN     0x01
+#define OMAP4_VP_VSTEPMAX_VSTEPMAX     0x04
+#define OMAP4_VP_VLIMITTO_TIMEOUT_US   200
+
 #ifdef CONFIG_POWER_AVS_OMAP
 extern int omap_devinit_smartreflex(void);
 extern void omap_enable_smartreflex_on_init(void);
@@ -134,6 +139,15 @@ static inline int omap4_twl_init(void)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_MFD_CPCAP)
+extern int omap4_cpcap_init(void);
+#else
+static inline int omap4_cpcap_init(void)
+{
+       return -EINVAL;
+}
+#endif
+
 #ifdef CONFIG_PM
 extern void omap_pm_setup_oscillator(u32 tstart, u32 tshut);
 extern void omap_pm_get_oscillator(u32 *tstart, u32 *tshut);
index 485550a..5a7a949 100644 (file)
@@ -128,18 +128,9 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
                return 0;
        }
 
-       /*
-        * Bootloader or kexec boot may have LOGICRETSTATE cleared
-        * for some domains. This is the case when kexec booting from
-        * Android kernels that support off mode for example.
-        * Make sure it's set at least for core and per, otherwise
-        * we currently will see lost GPIO interrupts for wlcore and
-        * smsc911x at least if per hits retention during idle.
-        */
        if (!strncmp(pwrdm->name, "core", 4) ||
-           !strncmp(pwrdm->name, "l4per", 5) ||
-           !strncmp(pwrdm->name, "wkup", 4))
-               pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_RET);
+           !strncmp(pwrdm->name, "l4per", 5))
+               pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_OFF);
 
        pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
        if (!pwrst)
diff --git a/arch/arm/mach-omap2/pmic-cpcap.c b/arch/arm/mach-omap2/pmic-cpcap.c
new file mode 100644 (file)
index 0000000..eab281a
--- /dev/null
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * pmic-cpcap.c - CPCAP-specific functions for the OPP code
+ *
+ * Adapted from Motorola Mapphone Android Linux kernel
+ * Copyright (C) 2011 Motorola, Inc.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include "soc.h"
+#include "pm.h"
+#include "voltage.h"
+
+#include <linux/init.h>
+#include "vc.h"
+
+/**
+ * omap_cpcap_vsel_to_vdc - convert CPCAP VSEL value to microvolts DC
+ * @vsel: CPCAP VSEL value to convert
+ *
+ * Returns the microvolts DC that the CPCAP PMIC should generate when
+ * programmed with @vsel.
+ */
+static unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel)
+{
+       if (vsel > 0x44)
+               vsel = 0x44;
+       return (((vsel * 125) + 6000)) * 100;
+}
+
+/**
+ * omap_cpcap_uv_to_vsel - convert microvolts DC to CPCAP VSEL value
+ * @uv: microvolts DC to convert
+ *
+ * Returns the VSEL value necessary for the CPCAP PMIC to
+ * generate an output voltage equal to or greater than @uv microvolts DC.
+ */
+static unsigned char omap_cpcap_uv_to_vsel(unsigned long uv)
+{
+       if (uv < 600000)
+               uv = 600000;
+       else if (uv > 1450000)
+               uv = 1450000;
+       return DIV_ROUND_UP(uv - 600000, 12500);
+}
+
+static struct omap_voltdm_pmic omap_cpcap_core = {
+       .slew_rate = 4000,
+       .step_size = 12500,
+       .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
+       .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
+       .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
+       .vddmin = 900000,
+       .vddmax = 1350000,
+       .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
+       .i2c_slave_addr = 0x02,
+       .volt_reg_addr = 0x00,
+       .cmd_reg_addr = 0x01,
+       .i2c_high_speed = false,
+       .vsel_to_uv = omap_cpcap_vsel_to_uv,
+       .uv_to_vsel = omap_cpcap_uv_to_vsel,
+};
+
+static struct omap_voltdm_pmic omap_cpcap_iva = {
+       .slew_rate = 4000,
+       .step_size = 12500,
+       .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
+       .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
+       .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
+       .vddmin = 900000,
+       .vddmax = 1350000,
+       .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
+       .i2c_slave_addr = 0x44,
+       .volt_reg_addr = 0x0,
+       .cmd_reg_addr = 0x01,
+       .i2c_high_speed = false,
+       .vsel_to_uv = omap_cpcap_vsel_to_uv,
+       .uv_to_vsel = omap_cpcap_uv_to_vsel,
+};
+
+/**
+ * omap_max8952_vsel_to_vdc - convert MAX8952 VSEL value to microvolts DC
+ * @vsel: MAX8952 VSEL value to convert
+ *
+ * Returns the microvolts DC that the MAX8952 Regulator should generate when
+ * programmed with @vsel.
+ */
+static unsigned long omap_max8952_vsel_to_uv(unsigned char vsel)
+{
+       if (vsel > 0x3F)
+               vsel = 0x3F;
+       return (((vsel * 100) + 7700)) * 100;
+}
+
+/**
+ * omap_max8952_uv_to_vsel - convert microvolts DC to MAX8952 VSEL value
+ * @uv: microvolts DC to convert
+ *
+ * Returns the VSEL value necessary for the MAX8952 Regulator to
+ * generate an output voltage equal to or greater than @uv microvolts DC.
+ */
+static unsigned char omap_max8952_uv_to_vsel(unsigned long uv)
+{
+       if (uv < 770000)
+               uv = 770000;
+       else if (uv > 1400000)
+               uv = 1400000;
+       return DIV_ROUND_UP(uv - 770000, 10000);
+}
+
+static struct omap_voltdm_pmic omap443x_max8952_mpu = {
+       .slew_rate = 16000,
+       .step_size = 10000,
+       .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
+       .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
+       .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
+       .vddmin = 900000,
+       .vddmax = 1400000,
+       .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
+       .i2c_slave_addr = 0x60,
+       .volt_reg_addr = 0x03,
+       .cmd_reg_addr = 0x03,
+       .i2c_high_speed = false,
+       .vsel_to_uv = omap_max8952_vsel_to_uv,
+       .uv_to_vsel = omap_max8952_uv_to_vsel,
+};
+
+/**
+ * omap_fan5355_vsel_to_vdc - convert FAN535503 VSEL value to microvolts DC
+ * @vsel: FAN535503 VSEL value to convert
+ *
+ * Returns the microvolts DC that the FAN535503 Regulator should generate when
+ * programmed with @vsel.
+ */
+static unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel)
+{
+       /* Extract bits[5:0] */
+       vsel &= 0x3F;
+
+       return (((vsel * 125) + 7500)) * 100;
+}
+
+/**
+ * omap_fan535508_vsel_to_vdc - convert FAN535508 VSEL value to microvolts DC
+ * @vsel: FAN535508 VSEL value to convert
+ *
+ * Returns the microvolts DC that the FAN535508 Regulator should generate when
+ * programmed with @vsel.
+ */
+static unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel)
+{
+       /* Extract bits[5:0] */
+       vsel &= 0x3F;
+
+       if (vsel > 0x37)
+               vsel = 0x37;
+       return (((vsel * 125) + 7500)) * 100;
+}
+
+
+/**
+ * omap_fan535503_uv_to_vsel - convert microvolts DC to FAN535503 VSEL value
+ * @uv: microvolts DC to convert
+ *
+ * Returns the VSEL value necessary for the MAX8952 Regulator to
+ * generate an output voltage equal to or greater than @uv microvolts DC.
+ */
+static unsigned char omap_fan535503_uv_to_vsel(unsigned long uv)
+{
+       unsigned char vsel;
+       if (uv < 750000)
+               uv = 750000;
+       else if (uv > 1537500)
+               uv = 1537500;
+
+       vsel = DIV_ROUND_UP(uv - 750000, 12500);
+       return vsel | 0xC0;
+}
+
+/**
+ * omap_fan535508_uv_to_vsel - convert microvolts DC to FAN535508 VSEL value
+ * @uv: microvolts DC to convert
+ *
+ * Returns the VSEL value necessary for the MAX8952 Regulator to
+ * generate an output voltage equal to or greater than @uv microvolts DC.
+ */
+static unsigned char omap_fan535508_uv_to_vsel(unsigned long uv)
+{
+       unsigned char vsel;
+       if (uv < 750000)
+               uv = 750000;
+       else if (uv > 1437500)
+               uv = 1437500;
+
+       vsel = DIV_ROUND_UP(uv - 750000, 12500);
+       return vsel | 0xC0;
+}
+
+/* fan5335-core */
+static struct omap_voltdm_pmic omap4_fan_core = {
+       .slew_rate = 4000,
+       .step_size = 12500,
+       .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
+       .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
+       .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
+       .vddmin = 850000,
+       .vddmax = 1375000,
+       .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
+       .i2c_slave_addr = 0x4A,
+       .i2c_high_speed = false,
+       .volt_reg_addr = 0x01,
+       .cmd_reg_addr = 0x01,
+       .vsel_to_uv = omap_fan535508_vsel_to_uv,
+       .uv_to_vsel = omap_fan535508_uv_to_vsel,
+};
+
+/* fan5335 iva */
+static struct omap_voltdm_pmic omap4_fan_iva = {
+       .slew_rate = 4000,
+       .step_size = 12500,
+       .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
+       .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
+       .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
+       .vddmin = 850000,
+       .vddmax = 1375000,
+       .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
+       .i2c_slave_addr = 0x48,
+       .volt_reg_addr = 0x01,
+       .cmd_reg_addr = 0x01,
+       .i2c_high_speed = false,
+       .vsel_to_uv = omap_fan535503_vsel_to_uv,
+       .uv_to_vsel = omap_fan535503_uv_to_vsel,
+};
+
+int __init omap4_cpcap_init(void)
+{
+       struct voltagedomain *voltdm;
+
+       if (!of_find_compatible_node(NULL, NULL, "motorola,cpcap"))
+               return -ENODEV;
+
+       voltdm = voltdm_lookup("mpu");
+       omap_voltage_register_pmic(voltdm, &omap443x_max8952_mpu);
+
+       if (of_machine_is_compatible("motorola,droid-bionic")) {
+               voltdm = voltdm_lookup("mpu");
+               omap_voltage_register_pmic(voltdm, &omap_cpcap_core);
+
+               voltdm = voltdm_lookup("mpu");
+               omap_voltage_register_pmic(voltdm, &omap_cpcap_iva);
+       } else {
+               voltdm = voltdm_lookup("core");
+               omap_voltage_register_pmic(voltdm, &omap4_fan_core);
+
+               voltdm = voltdm_lookup("iva");
+               omap_voltage_register_pmic(voltdm, &omap4_fan_iva);
+       }
+
+       return 0;
+}
+
+static int __init cpcap_late_init(void)
+{
+       omap4_vc_set_pmic_signaling(PWRDM_POWER_RET);
+
+       return 0;
+}
+omap_late_initcall(cpcap_late_init);
index 1d9346f..25093c1 100644 (file)
@@ -745,7 +745,7 @@ struct pwrdm_ops omap4_pwrdm_operations = {
 
 static int omap44xx_prm_late_init(void);
 
-void prm_save_context(void)
+static void prm_save_context(void)
 {
        omap_prm_context.irq_enable =
                        omap4_prm_read_inst_reg(AM43XX_PRM_OCP_SOCKET_INST,
@@ -756,7 +756,7 @@ void prm_save_context(void)
                                                omap4_prcm_irq_setup.pm_ctrl);
 }
 
-void prm_restore_context(void)
+static void prm_restore_context(void)
 {
        omap4_prm_write_inst_reg(omap_prm_context.irq_enable,
                                 OMAP4430_PRM_OCP_SOCKET_INST,
index d76b1e5..86f1ac4 100644 (file)
 #include "scrm44xx.h"
 #include "control.h"
 
+#define OMAP4430_VDD_IVA_I2C_DISABLE           BIT(14)
+#define OMAP4430_VDD_MPU_I2C_DISABLE           BIT(13)
+#define OMAP4430_VDD_CORE_I2C_DISABLE          BIT(12)
+#define OMAP4430_VDD_IVA_PRESENCE              BIT(9)
+#define OMAP4430_VDD_MPU_PRESENCE              BIT(8)
+#define OMAP4430_AUTO_CTRL_VDD_IVA(x)          ((x) << 4)
+#define OMAP4430_AUTO_CTRL_VDD_MPU(x)          ((x) << 2)
+#define OMAP4430_AUTO_CTRL_VDD_CORE(x)         ((x) << 0)
+#define OMAP4430_AUTO_CTRL_VDD_RET             2
+
+#define OMAP4430_VDD_I2C_DISABLE_MASK  \
+       (OMAP4430_VDD_IVA_I2C_DISABLE | \
+        OMAP4430_VDD_MPU_I2C_DISABLE | \
+        OMAP4430_VDD_CORE_I2C_DISABLE)
+
+#define OMAP4_VDD_DEFAULT_VAL  \
+       (OMAP4430_VDD_I2C_DISABLE_MASK | \
+        OMAP4430_VDD_IVA_PRESENCE | OMAP4430_VDD_MPU_PRESENCE | \
+        OMAP4430_AUTO_CTRL_VDD_IVA(OMAP4430_AUTO_CTRL_VDD_RET) | \
+        OMAP4430_AUTO_CTRL_VDD_MPU(OMAP4430_AUTO_CTRL_VDD_RET) | \
+        OMAP4430_AUTO_CTRL_VDD_CORE(OMAP4430_AUTO_CTRL_VDD_RET))
+
+#define OMAP4_VDD_RET_VAL      \
+       (OMAP4_VDD_DEFAULT_VAL & ~OMAP4430_VDD_I2C_DISABLE_MASK)
+
 /**
  * struct omap_vc_channel_cfg - describe the cfg_channel bitfield
  * @sa: bit for slave address
@@ -280,6 +305,26 @@ void omap3_vc_set_pmic_signaling(int core_next_state)
        }
 }
 
+void omap4_vc_set_pmic_signaling(int core_next_state)
+{
+       struct voltagedomain *vd = vc.vd;
+       u32 val;
+
+       if (!vd)
+               return;
+
+       switch (core_next_state) {
+       case PWRDM_POWER_RET:
+               val = OMAP4_VDD_RET_VAL;
+               break;
+       default:
+               val = OMAP4_VDD_DEFAULT_VAL;
+               break;
+       }
+
+       vd->write(val, OMAP4_PRM_VOLTCTRL_OFFSET);
+}
+
 /*
  * Configure signal polarity for sys_clkreq and sys_off_mode pins
  * as the default values are wrong and can cause the system to hang
@@ -542,9 +587,19 @@ static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode)
        writel_relaxed(val, OMAP4_SCRM_CLKSETUPTIME);
 }
 
+static void __init omap4_vc_init_pmic_signaling(struct voltagedomain *voltdm)
+{
+       if (vc.vd)
+               return;
+
+       vc.vd = voltdm;
+       voltdm->write(OMAP4_VDD_DEFAULT_VAL, OMAP4_PRM_VOLTCTRL_OFFSET);
+}
+
 /* OMAP4 specific voltage init functions */
 static void __init omap4_vc_init_channel(struct voltagedomain *voltdm)
 {
+       omap4_vc_init_pmic_signaling(voltdm);
        omap4_set_timings(voltdm, true);
        omap4_set_timings(voltdm, false);
 }
@@ -615,7 +670,7 @@ static void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm)
        const struct i2c_init_data *i2c_data;
 
        if (!voltdm->pmic->i2c_high_speed) {
-               pr_warn("%s: only high speed supported!\n", __func__);
+               pr_info("%s: using bootloader low-speed timings\n", __func__);
                return;
        }
 
index 5bf0886..9e861db 100644 (file)
@@ -117,7 +117,7 @@ extern struct omap_vc_param omap4_iva_vc_data;
 extern struct omap_vc_param omap4_core_vc_data;
 
 void omap3_vc_set_pmic_signaling(int core_next_state);
-
+void omap4_vc_set_pmic_signaling(int core_next_state);
 
 void omap_vc_init_channel(struct voltagedomain *voltdm);
 int omap_vc_pre_scale(struct voltagedomain *voltdm,
index 1cdb7bd..9514196 100644 (file)
@@ -113,7 +113,7 @@ void __init s3c2416_map_io(void)
        /* initialize device information early */
        s3c2416_default_sdhci0();
        s3c2416_default_sdhci1();
-       s3c64xx_spi_setname("s3c2443-spi");
+       s3c24xx_spi_setname("s3c2443-spi");
 
        iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
 }
index 313e369..4cbeb74 100644 (file)
@@ -91,7 +91,7 @@ void __init s3c2443_map_io(void)
        s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull;
 
        /* initialize device information early */
-       s3c64xx_spi_setname("s3c2443-spi");
+       s3c24xx_spi_setname("s3c2443-spi");
 
        iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
 }
index bb555cc..1048fac 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 /* re-define device name depending on support. */
-static inline void s3c64xx_spi_setname(char *name)
+static inline void s3c24xx_spi_setname(char *name)
 {
 #ifdef CONFIG_S3C64XX_DEV_SPI0
        s3c64xx_device_spi0.name = name;
index 6aaaa1d..d6b0e3b 100644 (file)
@@ -73,7 +73,7 @@ static int s3c_usb_otgphy_exit(struct platform_device *pdev)
        return 0;
 }
 
-int s5p_usb_phy_init(struct platform_device *pdev, int type)
+int s3c_usb_phy_init(struct platform_device *pdev, int type)
 {
        if (type == USB_PHY_TYPE_DEVICE)
                return s3c_usb_otgphy_init(pdev);
@@ -81,7 +81,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
        return -EINVAL;
 }
 
-int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+int s3c_usb_phy_exit(struct platform_device *pdev, int type)
 {
        if (type == USB_PHY_TYPE_DEVICE)
                return s3c_usb_otgphy_exit(pdev);
index 9e4bc18..2fd3aa6 100644 (file)
@@ -24,7 +24,6 @@
 #include "rcar-gen2.h"
 
 static const struct of_device_id cpg_matches[] __initconst = {
-       { .compatible = "renesas,rcar-gen2-cpg-clocks", },
        { .compatible = "renesas,r8a7743-cpg-mssr", .data = "extal" },
        { .compatible = "renesas,r8a7744-cpg-mssr", .data = "extal" },
        { .compatible = "renesas,r8a7790-cpg-mssr", .data = "extal" },
index 67b763f..e3f3481 100644 (file)
@@ -44,16 +44,16 @@ ENTRY(tegra_resume)
        cmp     r6, #TEGRA20
        beq     1f                              @ Yes
        /* Clear the flow controller flags for this CPU. */
-       cpu_to_csr_reg r1, r0
+       cpu_to_csr_reg r3, r0
        mov32   r2, TEGRA_FLOW_CTRL_BASE
-       ldr     r1, [r2, r1]
+       ldr     r1, [r2, r3]
        /* Clear event & intr flag */
        orr     r1, r1, \
                #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
        movw    r0, #0x3FFD     @ enable, cluster_switch, immed, bitmaps
                                @ & ext flags for CPU power mgnt
        bic     r1, r1, r0
-       str     r1, [r2]
+       str     r1, [r2, r3]
 1:
 
        mov32   r9, 0xc09
index b408fa5..3341a12 100644 (file)
@@ -682,10 +682,12 @@ tegra30_enter_sleep:
        dsb
        ldr     r0, [r6, r2] /* memory barrier */
 
+       cmp     r10, #TEGRA30
 halted:
        isb
        dsb
-       wfi     /* CPU should be power gated here */
+       wfine   /* CPU should be power gated here */
+       wfeeq
 
        /* !!!FIXME!!! Implement halt failure handler */
        b       halted
index f112dde..65e4482 100644 (file)
@@ -1044,7 +1044,7 @@ endif
 
 config CACHE_TAUROS2
        bool "Enable the Tauros2 L2 cache controller"
-       depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4)
+       depends on (CPU_MOHAWK || CPU_PJ4)
        default y
        select OUTER_CACHE
        help
index 1df6eb4..e822af0 100644 (file)
@@ -529,7 +529,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
 
 static bool __in_atomic_pool(void *start, size_t size)
 {
-       return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
+       return gen_pool_has_addr(atomic_pool, (unsigned long)start, size);
 }
 
 static int __free_from_pool(void *start, size_t size)
index 1d1fa06..1602f6d 100644 (file)
@@ -1010,9 +1010,9 @@ void __init dwc2_hsotg_set_platdata(struct dwc2_hsotg_plat *pd)
        npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_usb_hsotg);
 
        if (!npd->phy_init)
-               npd->phy_init = s5p_usb_phy_init;
+               npd->phy_init = s3c_usb_phy_init;
        if (!npd->phy_exit)
-               npd->phy_exit = s5p_usb_phy_exit;
+               npd->phy_exit = s3c_usb_phy_exit;
 }
 #endif /* CONFIG_S3C_DEV_USB_HSOTG */
 
index 94da89e..759d66a 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef __PLAT_SAMSUNG_USB_PHY_H
 #define __PLAT_SAMSUNG_USB_PHY_H __FILE__
 
-extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
-extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);
+extern int s3c_usb_phy_init(struct platform_device *pdev, int type);
+extern int s3c_usb_phy_exit(struct platform_device *pdev, int type);
 
 #endif /* __PLAT_SAMSUNG_USB_PHY_H */
index 16d7614..b2b504e 100644 (file)
@@ -37,11 +37,12 @@ config ARCH_BCM2835
        select PINCTRL
        select PINCTRL_BCM2835
        select ARM_AMBA
+       select ARM_GIC
        select ARM_TIMER_SP804
        select HAVE_ARM_ARCH_TIMER
        help
-         This enables support for the Broadcom BCM2837 SoC.
-         This SoC is used in the Raspberry Pi 3 device.
+         This enables support for the Broadcom BCM2837 and BCM2711 SoC.
+         These SoCs are used in the Raspberry Pi 3 and 4 devices.
 
 config ARCH_BCM_IPROC
        bool "Broadcom iProc SoC Family"
@@ -188,6 +189,7 @@ config ARCH_QCOM
 
 config ARCH_REALTEK
        bool "Realtek Platforms"
+       select RESET_CONTROLLER
        help
          This enables support for the ARMv8 based Realtek chipsets,
          like the RTD1295.
@@ -212,6 +214,11 @@ config ARCH_ROCKCHIP
          This enables support for the ARMv8 based Rockchip chipsets,
          like the RK3368.
 
+config ARCH_S32
+       bool "NXP S32 SoC Family"
+       help
+         This enables support for the NXP S32 family of processors.
+
 config ARCH_SEATTLE
        bool "AMD Seattle SoC Family"
        help
index 732daaa..59291e0 100644 (file)
@@ -12,6 +12,9 @@
        model = "Bubblegum-96";
 
        aliases {
+               mmc0 = &mmc0;
+               mmc1 = &mmc1;
+               mmc2 = &mmc2;
                serial5 = &uart5;
        };
 
                device_type = "memory";
                reg = <0x0 0x0 0x0 0x80000000>;
        };
+
+       /* Fixed regulator used in the absence of PMIC */
+       vcc_3v1: vcc-3v1 {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-3.1V";
+               regulator-min-microvolt = <3100000>;
+               regulator-max-microvolt = <3100000>;
+               regulator-always-on;
+       };
+
+       /* Fixed regulator used in the absence of PMIC */
+       sd_vcc: sd-vcc {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-3.1V";
+               regulator-min-microvolt = <3100000>;
+               regulator-max-microvolt = <3100000>;
+               regulator-always-on;
+       };
 };
 
 &i2c0 {
                        bias-pull-up;
                };
        };
+
+       mmc0_default: mmc0_default {
+               pinmux {
+                       groups = "sd0_d0_mfp", "sd0_d1_mfp", "sd0_d2_d3_mfp",
+                                "sd0_cmd_mfp", "sd0_clk_mfp";
+                       function = "sd0";
+               };
+       };
+
+       mmc2_default: mmc2_default {
+               pinmux {
+                       groups = "nand0_d0_ceb3_mfp";
+                       function = "sd2";
+               };
+       };
+};
+
+/* uSD */
+&mmc0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc0_default>;
+       no-sdio;
+       no-mmc;
+       no-1-8-v;
+       cd-gpios = <&pinctrl 120 GPIO_ACTIVE_LOW>;
+       bus-width = <4>;
+       vmmc-supply = <&sd_vcc>;
+       vqmmc-supply = <&sd_vcc>;
+};
+
+/* eMMC */
+&mmc2 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc2_default>;
+       no-sdio;
+       no-sd;
+       non-removable;
+       bus-width = <8>;
+       vmmc-supply = <&vcc_3v1>;
 };
 
 &timer {
index df3a68a..eb35cf7 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/actions,s900-cmu.h>
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/reset/actions,s900-reset.h>
 
                        dma-requests = <46>;
                        clocks = <&cmu CLK_DMAC>;
                };
+
+               mmc0: mmc@e0330000 {
+                       compatible = "actions,owl-mmc";
+                       reg = <0x0 0xe0330000 0x0 0x4000>;
+                       interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu CLK_SD0>;
+                       resets = <&cmu RESET_SD0>;
+                       dmas = <&dma 2>;
+                       dma-names = "mmc";
+                       status = "disabled";
+               };
+
+               mmc1: mmc@e0334000 {
+                       compatible = "actions,owl-mmc";
+                       reg = <0x0 0xe0334000 0x0 0x4000>;
+                       interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu CLK_SD1>;
+                       resets = <&cmu RESET_SD1>;
+                       dmas = <&dma 3>;
+                       dma-names = "mmc";
+                       status = "disabled";
+               };
+
+               mmc2: mmc@e0338000 {
+                       compatible = "actions,owl-mmc";
+                       reg = <0x0 0xe0338000 0x0 0x4000>;
+                       interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu CLK_SD2>;
+                       resets = <&cmu RESET_SD2>;
+                       dmas = <&dma 4>;
+                       dma-names = "mmc";
+                       status = "disabled";
+               };
+
+               mmc3: mmc@e033c000 {
+                       compatible = "actions,owl-mmc";
+                       reg = <0x0 0xe033c000 0x0 0x4000>;
+                       interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu CLK_SD3>;
+                       resets = <&cmu RESET_SD3>;
+                       dmas = <&dma 46>;
+                       dma-names = "mmc";
+                       status = "disabled";
+               };
        };
 };
index 04446e4..f54a415 100644 (file)
        };
 };
 
+&codec {
+       status = "okay";
+};
+
+&codec_analog {
+       cpvdd-supply = <&reg_eldo1>;
+       status = "okay";
+};
+
+&dai {
+       status = "okay";
+};
+
 &de {
        status = "okay";
 };
        vcc-hdmi-supply = <&reg_dldo1>;
 };
 
+&sound {
+       status = "okay";
+       simple-audio-card,widgets = "Headphone", "Headphone Jack",
+                                   "Microphone", "Microphone Jack",
+                                   "Microphone", "Onboard Microphone";
+       simple-audio-card,routing =
+                       "Left DAC", "AIF1 Slot 0 Left",
+                       "Right DAC", "AIF1 Slot 0 Right",
+                       "AIF1 Slot 0 Left ADC", "Left ADC",
+                       "AIF1 Slot 0 Right ADC", "Right ADC",
+                       "Headphone Jack", "HP",
+                       "MIC2", "Microphone Jack",
+                       "Onboard Microphone", "MBIAS",
+                       "MIC1", "Onboard Microphone";
+};
+
 &spi0 {
        status = "okay";
 
index 2509920..920103e 100644 (file)
        aliases {
                ethernet0 = &emac;
                serial0 = &uart0;
+               serial1 = &uart1;
+               serial2 = &uart2;
+               serial3 = &uart3;
+               serial4 = &uart4;
        };
 
        chosen {
        status = "okay";
 };
 
+/* On Pi-2 connector */
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pins>;
+       status = "disabled";
+};
+
+/* On Euler connector */
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart3_pins>;
+       status = "disabled";
+};
+
+/* On Euler connector, RTS/CTS optional */
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart4_pins>;
+       status = "disabled";
+};
+
 &usb_otg {
        dr_mode = "host";
        status = "okay";
index 1069e70..9704151 100644 (file)
        status = "okay";
 };
 
+&de {
+       status = "okay";
+};
+
 &ehci1 {
        status = "okay";
 };
 
 
-/* The ANX6345 eDP-bridge is on i2c0. There is no linux (mainline)
- * driver for this chip at the moment, the bootloader initializes it.
- * However it can be accessed with the i2c-dev driver from user space.
- */
 &i2c0 {
        clock-frequency = <100000>;
        status = "okay";
+
+       anx6345: anx6345@38 {
+               compatible = "analogix,anx6345";
+               reg = <0x38>;
+               reset-gpios = <&pio 3 24 GPIO_ACTIVE_LOW>; /* PD24 */
+               dvdd25-supply = <&reg_dldo2>;
+               dvdd12-supply = <&reg_dldo3>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               anx6345_in: endpoint {
+                                       remote-endpoint = <&tcon0_out_anx6345>;
+                               };
+                       };
+               };
+       };
+};
+
+&mixer0 {
+       status = "okay";
 };
 
 &mmc0 {
        status = "okay";
 };
 
+&tcon0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&lcd_rgb666_pins>;
+
+       status = "okay";
+};
+
+&tcon0_out {
+       tcon0_out_anx6345: endpoint@0 {
+               reg = <0>;
+               remote-endpoint = <&anx6345_in>;
+       };
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pb_pins>;
index 70f4cce..27e4823 100644 (file)
                clock-output-names = "ext-osc32k";
        };
 
+       pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
                        reg = <0x1c14000 0x400>;
                };
 
+               crypto: crypto@1c15000 {
+                       compatible = "allwinner,sun50i-a64-crypto";
+                       reg = <0x01c15000 0x1000>;
+                       interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+                       clock-names = "bus", "mod";
+                       resets = <&ccu RST_BUS_CE>;
+               };
+
                usb_otg: usb@1c19000 {
                        compatible = "allwinner,sun8i-a33-musb";
                        reg = <0x01c19000 0x0400>;
index 82f4b44..5bec574 100644 (file)
@@ -23,6 +23,8 @@
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&pio 2 7 GPIO_ACTIVE_LOW>; /* PC7 */
                post-power-on-delay-ms = <200>;
+               clocks = <&rtc 1>;
+               clock-names = "ext_clock";
        };
 };
 
 &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>;
+               shutdown-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */
+               device-wakeup-gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
+       };
 };
index f002a49..e92c4de 100644 (file)
                        allwinner,sram = <&ve_sram 1>;
                };
 
+               crypto: crypto@1c15000 {
+                       compatible = "allwinner,sun50i-h5-crypto";
+                       reg = <0x01c15000 0x1000>;
+                       interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+                       clock-names = "bus", "mod";
+                       resets = <&ccu RST_BUS_CE>;
+               };
+
                mali: gpu@1e80000 {
                        compatible = "allwinner,sun50i-h5-mali", "arm,mali-450";
                        reg = <0x01e80000 0x30000>;
index ce4b067..f335f74 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&reg_dcdcc>;
+       status = "okay";
+};
+
 &hdmi {
        status = "okay";
 };
                        };
 
                        reg_dcdcc: dcdcc {
+                               regulator-enable-ramp-delay = <32000>;
                                regulator-min-microvolt = <810000>;
                                regulator-max-microvolt = <1080000>;
                                regulator-name = "vdd-gpu";
index eb379cd..4ed3fc2 100644 (file)
@@ -15,6 +15,7 @@
 
        aliases {
                serial0 = &uart0;
+               serial1 = &uart1;
        };
 
        chosen {
        status = "okay";
 };
 
+&dwc3 {
+       status = "okay";
+};
+
 &ehci0 {
        status = "okay";
 };
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&reg_dcdcc>;
+       status = "okay";
+};
+
 &hdmi {
        status = "okay";
 };
                        };
 
                        reg_dcdcc: dcdcc {
+                               regulator-enable-ramp-delay = <32000>;
                                regulator-min-microvolt = <810000>;
                                regulator-max-microvolt = <1080000>;
                                regulator-name = "vdd-gpu";
        status = "okay";
 };
 
+/* There's the BT part of the AP6256 connected to that UART */
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm4345c5";
+               clocks = <&rtc 1>;
+               clock-names = "lpo";
+               device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
+               host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
+               shutdown-gpios = <&r_pio 1 4 GPIO_ACTIVE_HIGH>; /* PM4 */
+               max-speed = <1500000>;
+       };
+};
+
 &usb2otg {
        /*
         * This board doesn't have a controllable VBUS even though it
        usb3_vbus-supply = <&reg_vcc5v>;
        status = "okay";
 };
+
+&usb3phy {
+       status = "okay";
+};
index ec9b6a5..df4cbd7 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&reg_dcdcc>;
+       status = "okay";
+};
+
 &mmc0 {
        vmmc-supply = <&reg_cldo1>;
        cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
                        };
 
                        reg_dcdcc: dcdcc {
+                               regulator-enable-ramp-delay = <32000>;
                                regulator-min-microvolt = <810000>;
                                regulator-max-microvolt = <1080000>;
                                regulator-name = "vdd-gpu";
index 30102da..74899ed 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&reg_dcdcc>;
+       status = "okay";
+};
+
 &hdmi {
        status = "okay";
 };
                        };
 
                        reg_dcdcc: dcdcc {
+                               regulator-enable-ramp-delay = <32000>;
                                regulator-min-microvolt = <810000>;
                                regulator-max-microvolt = <1080000>;
                                regulator-name = "vdd-gpu";
index 7e7cb10..bccfe1e 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       status = "okay";
+};
+
 &hdmi {
        status = "okay";
 };
index 0d5ea19..2982408 100644 (file)
                        allwinner,sram = <&ve_sram 1>;
                };
 
+               gpu: gpu@1800000 {
+                       compatible = "allwinner,sun50i-h6-mali",
+                                    "arm,mali-t720";
+                       reg = <0x01800000 0x4000>;
+                       interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "job", "mmu", "gpu";
+                       clocks = <&ccu CLK_GPU>, <&ccu CLK_BUS_GPU>;
+                       clock-names = "core", "bus";
+                       resets = <&ccu RST_BUS_GPU>;
+                       status = "disabled";
+               };
+
+               crypto: crypto@1904000 {
+                       compatible = "allwinner,sun50i-h6-crypto";
+                       reg = <0x01904000 0x1000>;
+                       interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>, <&ccu CLK_MBUS_CE>;
+                       clock-names = "bus", "mod", "ram";
+                       resets = <&ccu RST_BUS_CE>;
+               };
+
                syscon: syscon@3000000 {
                        compatible = "allwinner,sun50i-h6-system-control",
                                     "allwinner,sun50i-a64-system-control";
                                pins = "PH0", "PH1";
                                function = "uart0";
                        };
+
+                       uart1_pins: uart1-pins {
+                               pins = "PG6", "PG7";
+                               function = "uart1";
+                       };
+
+                       uart1_rts_cts_pins: uart1-rts-cts-pins {
+                               pins = "PG8", "PG9";
+                               function = "uart1";
+                       };
                };
 
                gic: interrupt-controller@3021000 {
                        status = "disabled";
                };
 
+               dwc3: dwc3@5200000 {
+                       compatible = "snps,dwc3";
+                       reg = <0x05200000 0x10000>;
+                       interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_XHCI>,
+                                <&ccu CLK_BUS_XHCI>,
+                                <&rtc 0>;
+                       clock-names = "ref", "bus_early", "suspend";
+                       resets = <&ccu RST_BUS_XHCI>;
+                       /*
+                        * The datasheet of the chip doesn't declare the
+                        * peripheral function, and there's no boards known
+                        * to have a USB Type-B port routed to the port.
+                        * In addition, no one has tested the peripheral
+                        * function yet.
+                        * So set the dr_mode to "host" in the DTSI file.
+                        */
+                       dr_mode = "host";
+                       phys = <&usb3phy>;
+                       phy-names = "usb3-phy";
+                       status = "disabled";
+               };
+
+               usb3phy: phy@5210000 {
+                       compatible = "allwinner,sun50i-h6-usb3-phy";
+                       reg = <0x5210000 0x10000>;
+                       clocks = <&ccu CLK_USB_PHY1>;
+                       resets = <&ccu RST_USB_PHY1>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
                ehci3: usb@5311000 {
                        compatible = "allwinner,sun50i-h6-ehci", "generic-ehci";
                        reg = <0x05311000 0x100>;
                                      "tcon-tv0";
                        clock-output-names = "tcon-top-tv0";
                        resets = <&ccu RST_BUS_TCON_TOP>;
-                       reset-names = "rst";
                        #clock-cells = <1>;
 
                        ports {
index 66e4ffb..fb11ef0 100644 (file)
 
                        qspi_boot: partition@0 {
                                label = "Boot and fpga data";
-                               reg = <0x0 0x4000000>;
+                               reg = <0x0 0x034B0000>;
                        };
 
                        qspi_rootfs: partition@4000000 {
                                label = "Root Filesystem - JFFS2";
-                               reg = <0x4000000 0x4000000>;
+                               reg = <0x034B0000 0x0EB50000>;
                        };
                };
        };
index 84afecb..6340053 100644 (file)
@@ -6,6 +6,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12b-s922x-khadas-vim3.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-g12b-ugoos-am6.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-odroidc2.dtb
@@ -36,3 +37,4 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxm-rbox-pro.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxm-vega-s96.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-sm1-sei610.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-a1-ad401.dtb
diff --git a/arch/arm64/boot/dts/amlogic/meson-a1-ad401.dts b/arch/arm64/boot/dts/amlogic/meson-a1-ad401.dts
new file mode 100644 (file)
index 0000000..69c25c6
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "meson-a1.dtsi"
+
+/ {
+       compatible = "amlogic,ad401", "amlogic,a1";
+       model = "Amlogic Meson A1 AD401 Development Board";
+
+       aliases {
+               serial0 = &uart_AO_B;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x8000000>;
+       };
+};
+
+&uart_AO_B {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
new file mode 100644 (file)
index 0000000..7210ad0
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "amlogic,a1";
+
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35";
+                       reg = <0x0 0x0>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35";
+                       reg = <0x0 0x1>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               l2: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0x0 0x800000>;
+                       alignment = <0x0 0x400000>;
+                       linux,cma-default;
+               };
+       };
+
+       sm: secure-monitor {
+               compatible = "amlogic,meson-gxbb-sm";
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               apb: bus@fe000000 {
+                       compatible = "simple-bus";
+                       reg = <0x0 0xfe000000 0x0 0x1000000>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x1000000>;
+
+                       uart_AO: serial@1c00 {
+                               compatible = "amlogic,meson-gx-uart",
+                                            "amlogic,meson-ao-uart";
+                               reg = <0x0 0x1c00 0x0 0x18>;
+                               interrupts = <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&xtal>, <&xtal>, <&xtal>;
+                               clock-names = "xtal", "pclk", "baud";
+                               status = "disabled";
+                       };
+
+                       uart_AO_B: serial@2000 {
+                               compatible = "amlogic,meson-gx-uart",
+                                            "amlogic,meson-ao-uart";
+                               reg = <0x0 0x2000 0x0 0x18>;
+                               interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&xtal>, <&xtal>, <&xtal>;
+                               clock-names = "xtal", "pclk", "baud";
+                               status = "disabled";
+                       };
+               };
+
+               gic: interrupt-controller@ff901000 {
+                       compatible = "arm,gic-400";
+                       reg = <0x0 0xff901000 0x0 0x1000>,
+                             <0x0 0xff902000 0x0 0x2000>,
+                             <0x0 0xff904000 0x0 0x2000>,
+                             <0x0 0xff906000 0x0 0x2000>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9
+                               (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13
+                       (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14
+                       (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11
+                       (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10
+                       (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       xtal: xtal-clk {
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+               clock-output-names = "xtal";
+               #clock-cells = <0>;
+       };
+};
index 82919b1..04803c3 100644 (file)
                #address-cells = <1>;
                #size-cells = <1>;
                read-only;
+               secure-monitor = <&sm>;
        };
 
        psci {
 
                        toddr_a: audio-controller@100 {
                                compatible = "amlogic,axg-toddr";
-                               reg = <0x0 0x100 0x0 0x1c>;
+                               reg = <0x0 0x100 0x0 0x2c>;
                                #sound-dai-cells = <0>;
                                sound-name-prefix = "TODDR_A";
                                interrupts = <GIC_SPI 84 IRQ_TYPE_EDGE_RISING>;
 
                        toddr_b: audio-controller@140 {
                                compatible = "amlogic,axg-toddr";
-                               reg = <0x0 0x140 0x0 0x1c>;
+                               reg = <0x0 0x140 0x0 0x2c>;
                                #sound-dai-cells = <0>;
                                sound-name-prefix = "TODDR_B";
                                interrupts = <GIC_SPI 85 IRQ_TYPE_EDGE_RISING>;
 
                        toddr_c: audio-controller@180 {
                                compatible = "amlogic,axg-toddr";
-                               reg = <0x0 0x180 0x0 0x1c>;
+                               reg = <0x0 0x180 0x0 0x2c>;
                                #sound-dai-cells = <0>;
                                sound-name-prefix = "TODDR_C";
                                interrupts = <GIC_SPI 86 IRQ_TYPE_EDGE_RISING>;
 
                        frddr_a: audio-controller@1c0 {
                                compatible = "amlogic,axg-frddr";
-                               reg = <0x0 0x1c0 0x0 0x1c>;
+                               reg = <0x0 0x1c0 0x0 0x2c>;
                                #sound-dai-cells = <0>;
                                sound-name-prefix = "FRDDR_A";
                                interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
 
                        frddr_b: audio-controller@200 {
                                compatible = "amlogic,axg-frddr";
-                               reg = <0x0 0x200 0x0 0x1c>;
+                               reg = <0x0 0x200 0x0 0x2c>;
                                #sound-dai-cells = <0>;
                                sound-name-prefix = "FRDDR_B";
                                interrupts = <GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
 
                        frddr_c: audio-controller@240 {
                                compatible = "amlogic,axg-frddr";
-                               reg = <0x0 0x240 0x0 0x1c>;
+                               reg = <0x0 0x240 0x0 0x2c>;
                                #sound-dai-cells = <0>;
                                sound-name-prefix = "FRDDR_C";
                                interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
index 3f39e02..7fabc8d 100644 (file)
@@ -5,51 +5,42 @@
 
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/clock/axg-audio-clkc.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-axg-audio-arb.h>
-#include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
 #include <dt-bindings/reset/amlogic,meson-g12a-reset.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
        interrupt-parent = <&gic>;
        #address-cells = <2>;
        #size-cells = <2>;
 
-       tdmif_a: audio-controller-0 {
-               compatible = "amlogic,axg-tdm-iface";
-               #sound-dai-cells = <0>;
-               sound-name-prefix = "TDM_A";
-               clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>,
-                        <&clkc_audio AUD_CLKID_MST_A_SCLK>,
-                        <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
-               clock-names = "mclk", "sclk", "lrclk";
-               status = "disabled";
-       };
+       chosen {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
 
-       tdmif_b: audio-controller-1 {
-               compatible = "amlogic,axg-tdm-iface";
-               #sound-dai-cells = <0>;
-               sound-name-prefix = "TDM_B";
-               clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>,
-                        <&clkc_audio AUD_CLKID_MST_B_SCLK>,
-                        <&clkc_audio AUD_CLKID_MST_B_LRCLK>;
-               clock-names = "mclk", "sclk", "lrclk";
-               status = "disabled";
-       };
+               simplefb_cvbs: framebuffer-cvbs {
+                       compatible = "amlogic,simple-framebuffer",
+                                    "simple-framebuffer";
+                       amlogic,pipeline = "vpu-cvbs";
+                       clocks = <&clkc CLKID_HDMI>,
+                                <&clkc CLKID_HTX_PCLK>,
+                                <&clkc CLKID_VPU_INTR>;
+                       status = "disabled";
+               };
 
-       tdmif_c: audio-controller-2 {
-               compatible = "amlogic,axg-tdm-iface";
-               #sound-dai-cells = <0>;
-               sound-name-prefix = "TDM_C";
-               clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>,
-                        <&clkc_audio AUD_CLKID_MST_C_SCLK>,
-                        <&clkc_audio AUD_CLKID_MST_C_LRCLK>;
-               clock-names = "mclk", "sclk", "lrclk";
-               status = "disabled";
+               simplefb_hdmi: framebuffer-hdmi {
+                       compatible = "amlogic,simple-framebuffer",
+                                   "simple-framebuffer";
+                       amlogic,pipeline = "vpu-hdmi";
+                       clocks = <&clkc CLKID_HDMI>,
+                                <&clkc CLKID_HTX_PCLK>,
+                                <&clkc CLKID_VPU_INTR>;
+                       status = "disabled";
+               };
        };
 
        efuse: efuse {
@@ -58,6 +49,7 @@
                #address-cells = <1>;
                #size-cells = <1>;
                read-only;
+               secure-monitor = <&sm>;
        };
 
        psci {
                #size-cells = <2>;
                ranges;
 
+               pcie: pcie@fc000000 {
+                       compatible = "amlogic,g12a-pcie", "snps,dw-pcie";
+                       reg = <0x0 0xfc000000 0x0 0x400000
+                              0x0 0xff648000 0x0 0x2000
+                              0x0 0xfc400000 0x0 0x200000>;
+                       reg-names = "elbi", "cfg", "config";
+                       interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
+                       bus-range = <0x0 0xff>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       ranges = <0x81000000 0 0 0x0 0xfc600000 0 0x00100000
+                                 0x82000000 0 0xfc700000 0x0 0xfc700000 0 0x1900000>;
+
+                       clocks = <&clkc CLKID_PCIE_PHY
+                                 &clkc CLKID_PCIE_COMB
+                                 &clkc CLKID_PCIE_PLL>;
+                       clock-names = "general",
+                                     "pclk",
+                                     "port";
+                       resets = <&reset RESET_PCIE_CTRL_A>,
+                                <&reset RESET_PCIE_APB>;
+                       reset-names = "port",
+                                     "apb";
+                       num-lanes = <1>;
+                       phys = <&usb3_pcie_phy PHY_TYPE_PCIE>;
+                       phy-names = "pcie";
+                       status = "disabled";
+               };
+
+               thermal-zones {
+                       cpu_thermal: cpu-thermal {
+                               polling-delay = <1000>;
+                               polling-delay-passive = <100>;
+                               thermal-sensors = <&cpu_temp>;
+
+                               trips {
+                                       cpu_passive: cpu-passive {
+                                               temperature = <85000>; /* millicelsius */
+                                               hysteresis = <2000>; /* millicelsius */
+                                               type = "passive";
+                                       };
+
+                                       cpu_hot: cpu-hot {
+                                               temperature = <95000>; /* millicelsius */
+                                               hysteresis = <2000>; /* millicelsius */
+                                               type = "hot";
+                                       };
+
+                                       cpu_critical: cpu-critical {
+                                               temperature = <110000>; /* millicelsius */
+                                               hysteresis = <2000>; /* millicelsius */
+                                               type = "critical";
+                                       };
+                               };
+                       };
+
+                       ddr_thermal: ddr-thermal {
+                               polling-delay = <1000>;
+                               polling-delay-passive = <100>;
+                               thermal-sensors = <&ddr_temp>;
+
+                               trips {
+                                       ddr_passive: ddr-passive {
+                                               temperature = <85000>; /* millicelsius */
+                                               hysteresis = <2000>; /* millicelsius */
+                                               type = "passive";
+                                       };
+
+                                       ddr_critical: ddr-critical {
+                                               temperature = <110000>; /* millicelsius */
+                                               hysteresis = <2000>; /* millicelsius */
+                                               type = "critical";
+                                       };
+                               };
+
+                               cooling-maps {
+                                       map {
+                                               trip = <&ddr_passive>;
+                                               cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                                       };
+                               };
+                       };
+               };
+
                ethmac: ethernet@ff3f0000 {
                        compatible = "amlogic,meson-axg-dwmac",
                                     "snps,dwmac-3.70a",
                                };
                        };
 
+                       cpu_temp: temperature-sensor@34800 {
+                               compatible = "amlogic,g12a-cpu-thermal",
+                                            "amlogic,g12a-thermal";
+                               reg = <0x0 0x34800 0x0 0x50>;
+                               interrupts = <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&clkc CLKID_TS>;
+                               #thermal-sensor-cells = <0>;
+                               amlogic,ao-secure = <&sec_AO>;
+                       };
+
+                       ddr_temp: temperature-sensor@34c00 {
+                               compatible = "amlogic,g12a-ddr-thermal",
+                                            "amlogic,g12a-thermal";
+                               reg = <0x0 0x34c00 0x0 0x50>;
+                               interrupts = <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&clkc CLKID_TS>;
+                               #thermal-sensor-cells = <0>;
+                               amlogic,ao-secure = <&sec_AO>;
+                       };
+
                        usb2_phy0: phy@36000 {
                                compatible = "amlogic,g12a-usb2-phy";
                                reg = <0x0 0x36000 0x0 0x2000>;
                                };
                        };
 
-                       pdm: audio-controller@40000 {
-                               compatible = "amlogic,g12a-pdm",
-                                            "amlogic,axg-pdm";
-                               reg = <0x0 0x40000 0x0 0x34>;
-                               #sound-dai-cells = <0>;
-                               sound-name-prefix = "PDM";
-                               clocks = <&clkc_audio AUD_CLKID_PDM>,
-                                        <&clkc_audio AUD_CLKID_PDM_DCLK>,
-                                        <&clkc_audio AUD_CLKID_PDM_SYSCLK>;
-                               clock-names = "pclk", "dclk", "sysclk";
-                               status = "disabled";
-                       };
-
-                       audio: bus@42000 {
-                               compatible = "simple-bus";
-                               reg = <0x0 0x42000 0x0 0x2000>;
-                               #address-cells = <2>;
-                               #size-cells = <2>;
-                               ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>;
-
-                               clkc_audio: clock-controller@0 {
-                                       status = "disabled";
-                                       compatible = "amlogic,g12a-audio-clkc";
-                                       reg = <0x0 0x0 0x0 0xb4>;
-                                       #clock-cells = <1>;
-                                       #reset-cells = <1>;
-
-                                       clocks = <&clkc CLKID_AUDIO>,
-                                                <&clkc CLKID_MPLL0>,
-                                                <&clkc CLKID_MPLL1>,
-                                                <&clkc CLKID_MPLL2>,
-                                                <&clkc CLKID_MPLL3>,
-                                                <&clkc CLKID_HIFI_PLL>,
-                                                <&clkc CLKID_FCLK_DIV3>,
-                                                <&clkc CLKID_FCLK_DIV4>,
-                                                <&clkc CLKID_GP0_PLL>;
-                                       clock-names = "pclk",
-                                                     "mst_in0",
-                                                     "mst_in1",
-                                                     "mst_in2",
-                                                     "mst_in3",
-                                                     "mst_in4",
-                                                     "mst_in5",
-                                                     "mst_in6",
-                                                     "mst_in7";
-
-                                       resets = <&reset RESET_AUDIO>;
-                               };
-
-                               toddr_a: audio-controller@100 {
-                                       compatible = "amlogic,g12a-toddr",
-                                                    "amlogic,axg-toddr";
-                                       reg = <0x0 0x100 0x0 0x1c>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "TODDR_A";
-                                       interrupts = <GIC_SPI 148 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_TODDR_A>;
-                                       resets = <&arb AXG_ARB_TODDR_A>;
-                                       status = "disabled";
-                               };
-
-                               toddr_b: audio-controller@140 {
-                                       compatible = "amlogic,g12a-toddr",
-                                                    "amlogic,axg-toddr";
-                                       reg = <0x0 0x140 0x0 0x1c>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "TODDR_B";
-                                       interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_TODDR_B>;
-                                       resets = <&arb AXG_ARB_TODDR_B>;
-                                       status = "disabled";
-                               };
-
-                               toddr_c: audio-controller@180 {
-                                       compatible = "amlogic,g12a-toddr",
-                                                    "amlogic,axg-toddr";
-                                       reg = <0x0 0x180 0x0 0x1c>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "TODDR_C";
-                                       interrupts = <GIC_SPI 150 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_TODDR_C>;
-                                       resets = <&arb AXG_ARB_TODDR_C>;
-                                       status = "disabled";
-                               };
-
-                               frddr_a: audio-controller@1c0 {
-                                       compatible = "amlogic,g12a-frddr",
-                                                    "amlogic,axg-frddr";
-                                       reg = <0x0 0x1c0 0x0 0x1c>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "FRDDR_A";
-                                       interrupts = <GIC_SPI 152 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
-                                       resets = <&arb AXG_ARB_FRDDR_A>;
-                                       status = "disabled";
-                               };
-
-                               frddr_b: audio-controller@200 {
-                                       compatible = "amlogic,g12a-frddr",
-                                                    "amlogic,axg-frddr";
-                                       reg = <0x0 0x200 0x0 0x1c>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "FRDDR_B";
-                                       interrupts = <GIC_SPI 153 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_FRDDR_B>;
-                                       resets = <&arb AXG_ARB_FRDDR_B>;
-                                       status = "disabled";
-                               };
-
-                               frddr_c: audio-controller@240 {
-                                       compatible = "amlogic,g12a-frddr",
-                                                    "amlogic,axg-frddr";
-                                       reg = <0x0 0x240 0x0 0x1c>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "FRDDR_C";
-                                       interrupts = <GIC_SPI 154 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_FRDDR_C>;
-                                       resets = <&arb AXG_ARB_FRDDR_C>;
-                                       status = "disabled";
-                               };
-
-                               arb: reset-controller@280 {
-                                       status = "disabled";
-                                       compatible = "amlogic,meson-axg-audio-arb";
-                                       reg = <0x0 0x280 0x0 0x4>;
-                                       #reset-cells = <1>;
-                                       clocks = <&clkc_audio AUD_CLKID_DDR_ARB>;
-                               };
-
-                               tdmin_a: audio-controller@300 {
-                                       compatible = "amlogic,g12a-tdmin",
-                                                    "amlogic,axg-tdmin";
-                                       reg = <0x0 0x300 0x0 0x40>;
-                                       sound-name-prefix = "TDMIN_A";
-                                       resets = <&clkc_audio AUD_RESET_TDMIN_A>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_A>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               tdmin_b: audio-controller@340 {
-                                       compatible = "amlogic,g12a-tdmin",
-                                                    "amlogic,axg-tdmin";
-                                       reg = <0x0 0x340 0x0 0x40>;
-                                       sound-name-prefix = "TDMIN_B";
-                                       resets = <&clkc_audio AUD_RESET_TDMIN_B>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_B>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               tdmin_c: audio-controller@380 {
-                                       compatible = "amlogic,g12a-tdmin",
-                                                    "amlogic,axg-tdmin";
-                                       reg = <0x0 0x380 0x0 0x40>;
-                                       sound-name-prefix = "TDMIN_C";
-                                       resets = <&clkc_audio AUD_RESET_TDMIN_C>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_C>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               tdmin_lb: audio-controller@3c0 {
-                                       compatible = "amlogic,g12a-tdmin",
-                                                    "amlogic,axg-tdmin";
-                                       reg = <0x0 0x3c0 0x0 0x40>;
-                                       sound-name-prefix = "TDMIN_LB";
-                                       resets = <&clkc_audio AUD_RESET_TDMIN_LB>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               spdifin: audio-controller@400 {
-                                       compatible = "amlogic,g12a-spdifin",
-                                                    "amlogic,axg-spdifin";
-                                       reg = <0x0 0x400 0x0 0x30>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "SPDIFIN";
-                                       interrupts = <GIC_SPI 151 IRQ_TYPE_EDGE_RISING>;
-                                       clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
-                                                <&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
-                                       clock-names = "pclk", "refclk";
-                                       status = "disabled";
-                               };
-
-                               spdifout: audio-controller@480 {
-                                       compatible = "amlogic,g12a-spdifout",
-                                                    "amlogic,axg-spdifout";
-                                       reg = <0x0 0x480 0x0 0x50>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "SPDIFOUT";
-                                       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>,
-                                                <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>;
-                                       clock-names = "pclk", "mclk";
-                                       status = "disabled";
-                               };
-
-                               tdmout_a: audio-controller@500 {
-                                       compatible = "amlogic,g12a-tdmout";
-                                       reg = <0x0 0x500 0x0 0x40>;
-                                       sound-name-prefix = "TDMOUT_A";
-                                       resets = <&clkc_audio AUD_RESET_TDMOUT_A>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               tdmout_b: audio-controller@540 {
-                                       compatible = "amlogic,g12a-tdmout";
-                                       reg = <0x0 0x540 0x0 0x40>;
-                                       sound-name-prefix = "TDMOUT_B";
-                                       resets = <&clkc_audio AUD_RESET_TDMOUT_B>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               tdmout_c: audio-controller@580 {
-                                       compatible = "amlogic,g12a-tdmout";
-                                       reg = <0x0 0x580 0x0 0x40>;
-                                       sound-name-prefix = "TDMOUT_C";
-                                       resets = <&clkc_audio AUD_RESET_TDMOUT_C>;
-                                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>,
-                                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>;
-                                       clock-names = "pclk", "sclk", "sclk_sel",
-                                                     "lrclk", "lrclk_sel";
-                                       status = "disabled";
-                               };
-
-                               spdifout_b: audio-controller@680 {
-                                       compatible = "amlogic,g12a-spdifout",
-                                                    "amlogic,axg-spdifout";
-                                       reg = <0x0 0x680 0x0 0x50>;
-                                       #sound-dai-cells = <0>;
-                                       sound-name-prefix = "SPDIFOUT_B";
-                                       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>,
-                                                <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>;
-                                       clock-names = "pclk", "mclk";
-                                       status = "disabled";
-                               };
-
-                               tohdmitx: audio-controller@744 {
-                                       compatible = "amlogic,g12a-tohdmitx";
-                                       reg = <0x0 0x744 0x0 0x4>;
-                                       #sound-dai-cells = <1>;
-                                       sound-name-prefix = "TOHDMITX";
-                                       status = "disabled";
-                               };
-                       };
-
                        usb3_pcie_phy: phy@46000 {
                                compatible = "amlogic,g12a-usb3-pcie-phy";
                                reg = <0x0 0x46000 0x0 0x2000>;
                        compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost";
                        reg = <0x0 0xffe40000 0x0 0x40000>;
                        interrupt-parent = <&gic>;
-                       interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "gpu", "mmu", "job";
+                                    <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "job", "mmu", "gpu";
                        clocks = <&clkc CLKID_MALI>;
                        resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>;
 
                        assigned-clock-rates = <0>, /* Do Nothing */
                                               <800000000>,
                                               <0>; /* Do Nothing */
+                       #cooling-cells = <2>;
                };
        };
 
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
new file mode 100644 (file)
index 0000000..b3ba2fd
--- /dev/null
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include "meson-g12-common.dtsi"
+#include <dt-bindings/clock/axg-audio-clkc.h>
+#include <dt-bindings/power/meson-g12a-power.h>
+#include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h>
+#include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
+
+/ {
+       tdmif_a: audio-controller-0 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_A";
+               clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_A_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
+       tdmif_b: audio-controller-1 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_B";
+               clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_B_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_B_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
+       tdmif_c: audio-controller-2 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_C";
+               clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_C_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_C_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+};
+
+&apb {
+       pdm: audio-controller@40000 {
+               compatible = "amlogic,g12a-pdm",
+                            "amlogic,axg-pdm";
+               reg = <0x0 0x40000 0x0 0x34>;
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "PDM";
+               clocks = <&clkc_audio AUD_CLKID_PDM>,
+                        <&clkc_audio AUD_CLKID_PDM_DCLK>,
+                        <&clkc_audio AUD_CLKID_PDM_SYSCLK>;
+               clock-names = "pclk", "dclk", "sysclk";
+               status = "disabled";
+       };
+
+       audio: bus@42000 {
+               compatible = "simple-bus";
+               reg = <0x0 0x42000 0x0 0x2000>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>;
+
+               clkc_audio: clock-controller@0 {
+                       status = "disabled";
+                       compatible = "amlogic,g12a-audio-clkc";
+                       reg = <0x0 0x0 0x0 0xb4>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+
+                       clocks = <&clkc CLKID_AUDIO>,
+                                <&clkc CLKID_MPLL0>,
+                                <&clkc CLKID_MPLL1>,
+                                <&clkc CLKID_MPLL2>,
+                                <&clkc CLKID_MPLL3>,
+                                <&clkc CLKID_HIFI_PLL>,
+                                <&clkc CLKID_FCLK_DIV3>,
+                                <&clkc CLKID_FCLK_DIV4>,
+                                <&clkc CLKID_GP0_PLL>;
+                       clock-names = "pclk",
+                                     "mst_in0",
+                                     "mst_in1",
+                                     "mst_in2",
+                                     "mst_in3",
+                                     "mst_in4",
+                                     "mst_in5",
+                                     "mst_in6",
+                                     "mst_in7";
+
+                       resets = <&reset RESET_AUDIO>;
+               };
+
+               toddr_a: audio-controller@100 {
+                       compatible = "amlogic,g12a-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x100 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_A";
+                       interrupts = <GIC_SPI 148 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_A>;
+                       resets = <&arb AXG_ARB_TODDR_A>,
+                                <&clkc_audio AUD_RESET_TODDR_A>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               toddr_b: audio-controller@140 {
+                       compatible = "amlogic,g12a-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x140 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_B";
+                       interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_B>;
+                       resets = <&arb AXG_ARB_TODDR_B>,
+                                <&clkc_audio AUD_RESET_TODDR_B>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               toddr_c: audio-controller@180 {
+                       compatible = "amlogic,g12a-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x180 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_C";
+                       interrupts = <GIC_SPI 150 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_C>;
+                       resets = <&arb AXG_ARB_TODDR_C>,
+                                <&clkc_audio AUD_RESET_TODDR_C>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_a: audio-controller@1c0 {
+                       compatible = "amlogic,g12a-frddr",
+                                    "amlogic,axg-frddr";
+                       reg = <0x0 0x1c0 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_A";
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
+                       resets = <&arb AXG_ARB_FRDDR_A>,
+                                <&clkc_audio AUD_RESET_FRDDR_A>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_b: audio-controller@200 {
+                       compatible = "amlogic,g12a-frddr",
+                                    "amlogic,axg-frddr";
+                       reg = <0x0 0x200 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_B";
+                       interrupts = <GIC_SPI 153 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_B>;
+                       resets = <&arb AXG_ARB_FRDDR_B>,
+                                <&clkc_audio AUD_RESET_FRDDR_B>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_c: audio-controller@240 {
+                       compatible = "amlogic,g12a-frddr",
+                                    "amlogic,axg-frddr";
+                       reg = <0x0 0x240 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_C";
+                       interrupts = <GIC_SPI 154 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_C>;
+                       resets = <&arb AXG_ARB_FRDDR_C>,
+                                <&clkc_audio AUD_RESET_FRDDR_C>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               arb: reset-controller@280 {
+                       status = "disabled";
+                       compatible = "amlogic,meson-axg-audio-arb";
+                       reg = <0x0 0x280 0x0 0x4>;
+                       #reset-cells = <1>;
+                       clocks = <&clkc_audio AUD_CLKID_DDR_ARB>;
+               };
+
+               tdmin_a: audio-controller@300 {
+                       compatible = "amlogic,g12a-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x300 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_A";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_A>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_A>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmin_b: audio-controller@340 {
+                       compatible = "amlogic,g12a-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x340 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_B";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_B>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_B>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmin_c: audio-controller@380 {
+                       compatible = "amlogic,g12a-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x380 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_C";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_C>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_C>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmin_lb: audio-controller@3c0 {
+                       compatible = "amlogic,g12a-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x3c0 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_LB";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_LB>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               spdifin: audio-controller@400 {
+                       compatible = "amlogic,g12a-spdifin",
+                                    "amlogic,axg-spdifin";
+                       reg = <0x0 0x400 0x0 0x30>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "SPDIFIN";
+                       interrupts = <GIC_SPI 151 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
+                                <&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
+                       clock-names = "pclk", "refclk";
+                       resets = <&clkc_audio AUD_RESET_SPDIFIN>;
+                       status = "disabled";
+               };
+
+               spdifout: audio-controller@480 {
+                       compatible = "amlogic,g12a-spdifout",
+                                    "amlogic,axg-spdifout";
+                       reg = <0x0 0x480 0x0 0x50>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "SPDIFOUT";
+                       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>,
+                                <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>;
+                       clock-names = "pclk", "mclk";
+                       resets = <&clkc_audio AUD_RESET_SPDIFOUT>;
+                       status = "disabled";
+               };
+
+               tdmout_a: audio-controller@500 {
+                       compatible = "amlogic,g12a-tdmout";
+                       reg = <0x0 0x500 0x0 0x40>;
+                       sound-name-prefix = "TDMOUT_A";
+                       resets = <&clkc_audio AUD_RESET_TDMOUT_A>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmout_b: audio-controller@540 {
+                       compatible = "amlogic,g12a-tdmout";
+                       reg = <0x0 0x540 0x0 0x40>;
+                       sound-name-prefix = "TDMOUT_B";
+                       resets = <&clkc_audio AUD_RESET_TDMOUT_B>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmout_c: audio-controller@580 {
+                       compatible = "amlogic,g12a-tdmout";
+                       reg = <0x0 0x580 0x0 0x40>;
+                       sound-name-prefix = "TDMOUT_C";
+                       resets = <&clkc_audio AUD_RESET_TDMOUT_C>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               spdifout_b: audio-controller@680 {
+                       compatible = "amlogic,g12a-spdifout",
+                                    "amlogic,axg-spdifout";
+                       reg = <0x0 0x680 0x0 0x50>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "SPDIFOUT_B";
+                       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>,
+                                <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>;
+                       clock-names = "pclk", "mclk";
+                       resets = <&clkc_audio AUD_RESET_SPDIFOUT_B>;
+                       status = "disabled";
+               };
+
+               tohdmitx: audio-controller@744 {
+                       compatible = "amlogic,g12a-tohdmitx";
+                       reg = <0x0 0x744 0x0 0x4>;
+                       #sound-dai-cells = <1>;
+                       sound-name-prefix = "TOHDMITX";
+                       resets = <&clkc_audio AUD_RESET_TOHDMITX>;
+                       status = "disabled";
+               };
+       };
+};
+
+&cpu_thermal {
+       cooling-maps {
+               map0 {
+                       trip = <&cpu_passive>;
+                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu102 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu103 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+               };
+               map1 {
+                       trip = <&cpu_hot>;
+                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu102 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                        <&cpu103 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+               };
+       };
+};
+
+&ethmac {
+       power-domains = <&pwrc PWRC_G12A_ETH_ID>;
+};
+
+&vpu {
+       power-domains = <&pwrc PWRC_G12A_VPU_ID>;
+};
+
+&sd_emmc_a {
+       amlogic,dram-access-quirk;
+};
+
+&simplefb_cvbs {
+       power-domains = <&pwrc PWRC_G12A_VPU_ID>;
+};
+
+&simplefb_hdmi {
+       power-domains = <&pwrc PWRC_G12A_VPU_ID>;
+};
+
index c9fa23a..2ac9e3a 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 17155fb..4f2596d 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index eb5d177..fb0ab27 100644 (file)
@@ -3,8 +3,7 @@
  * Copyright (c) 2018 Amlogic, Inc. All rights reserved.
  */
 
-#include "meson-g12-common.dtsi"
-#include <dt-bindings/power/meson-g12a-power.h>
+#include "meson-g12.dtsi"
 
 / {
        compatible = "amlogic,g12a";
@@ -19,6 +18,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "psci";
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu1: cpu@1 {
@@ -27,6 +27,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "psci";
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu2: cpu@2 {
@@ -35,6 +36,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "psci";
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu3: cpu@3 {
@@ -43,6 +45,7 @@
                        reg = <0x0 0x3>;
                        enable-method = "psci";
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                l2: l2-cache0 {
        };
 };
 
-&ethmac {
-       power-domains = <&pwrc PWRC_G12A_ETH_ID>;
-};
-
-&vpu {
-       power-domains = <&pwrc PWRC_G12A_VPU_ID>;
-};
+&cpu_thermal {
+       cooling-maps {
+               map0 {
+                       trip = <&cpu_passive>;
+                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+               };
 
-&sd_emmc_a {
-       amlogic,dram-access-quirk;
+               map1 {
+                       trip = <&cpu_hot>;
+                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+               };
+       };
 };
index 3a6a1e0..124a809 100644 (file)
 / {
        compatible = "khadas,vim3", "amlogic,a311d", "amlogic,g12b";
 };
+
+/*
+ * The VIM3 on-board  MCU can mux the PCIe/USB3.0 shared differential
+ * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between
+ * an USB3.0 Type A connector and a M.2 Key M slot.
+ * The PHY driving these differential lines is shared between
+ * the USB3.0 controller and the PCIe Controller, thus only
+ * a single controller can use it.
+ * If the MCU is configured to mux the PCIe/USB3.0 differential lines
+ * to the M.2 Key M slot, uncomment the following block to disable
+ * USB3.0 from the USB Complex and enable the PCIe controller.
+ * The End User is not expected to uncomment the following except for
+ * testing purposes, but instead rely on the firmware/bootloader to
+ * update these nodes accordingly if PCIe mode is selected by the MCU.
+ */
+/*
+&pcie {
+       status = "okay";
+};
+
+&usb {
+       phys = <&usb2_phy0>, <&usb2_phy1>;
+       phy-names = "usb2-phy0", "usb2-phy1";
+};
+ */
index 42f1540..0e54c1d 100644 (file)
@@ -12,7 +12,7 @@
 #include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
-       compatible = "hardkernel,odroid-n2", "amlogic,g12b";
+       compatible = "hardkernel,odroid-n2", "amlogic,s922x", "amlogic,g12b";
        model = "Hardkernel ODROID-N2";
 
        aliases {
index b73deb2..bba98f9 100644 (file)
 / {
        compatible = "khadas,vim3", "amlogic,s922x", "amlogic,g12b";
 };
+
+/*
+ * The VIM3 on-board  MCU can mux the PCIe/USB3.0 shared differential
+ * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between
+ * an USB3.0 Type A connector and a M.2 Key M slot.
+ * The PHY driving these differential lines is shared between
+ * the USB3.0 controller and the PCIe Controller, thus only
+ * a single controller can use it.
+ * If the MCU is configured to mux the PCIe/USB3.0 differential lines
+ * to the M.2 Key M slot, uncomment the following block to disable
+ * USB3.0 from the USB Complex and enable the PCIe controller.
+ * The End User is not expected to uncomment the following except for
+ * testing purposes, but instead rely on the firmware/bootloader to
+ * update these nodes accordingly if PCIe mode is selected by the MCU.
+ */
+/*
+&pcie {
+       status = "okay";
+};
+
+&usb {
+       phys = <&usb2_phy0>, <&usb2_phy1>;
+       phy-names = "usb2-phy0", "usb2-phy1";
+};
+ */
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts
new file mode 100644 (file)
index 0000000..ccd0bce
--- /dev/null
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (c) 2019 Christian Hewitt <christianshewitt@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "meson-g12b.dtsi"
+#include "meson-g12b-s922x.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
+
+/ {
+       compatible = "ugoos,am6", "amlogic,g12b";
+       model = "Ugoos AM6";
+
+       aliases {
+               serial0 = &uart_AO;
+               ethernet0 = &ethmac;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x40000000>;
+       };
+
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+               clocks = <&wifi32k>;
+               clock-names = "ext_clock";
+       };
+
+       spdif_dit: audio-codec-1 {
+               #sound-dai-cells = <0>;
+               compatible = "linux,spdif-dit";
+               status = "okay";
+               sound-name-prefix = "DIT";
+       };
+
+       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;
+       };
+
+       main_12v: regulator-main_12v {
+               compatible = "regulator-fixed";
+               regulator-name = "12V";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               regulator-always-on;
+       };
+
+       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;
+       };
+
+       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 */
+       };
+
+       vddcpu_a: regulator-vddcpu-a {
+               /*
+                * MP1653 Regulator.
+                */
+               compatible = "pwm-regulator";
+
+               regulator-name = "VDDCPU_A";
+               regulator-min-microvolt = <721000>;
+               regulator-max-microvolt = <1022000>;
+
+               vin-supply = <&main_12v>;
+
+               pwms = <&pwm_ab 0 1250 0>;
+               pwm-dutycycle-range = <100 0>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       vddcpu_b: regulator-vddcpu-b {
+               /*
+                * MP1652 Regulator.
+                */
+               compatible = "pwm-regulator";
+
+               regulator-name = "VDDCPU_B";
+               regulator-min-microvolt = <721000>;
+               regulator-max-microvolt = <1022000>;
+
+               vin-supply = <&main_12v>;
+
+               pwms = <&pwm_AO_cd 1 1250 0>;
+               pwm-dutycycle-range = <100 0>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       usb1_pow: regulator-usb1-pow {
+               compatible = "regulator-fixed";
+               regulator-name = "USB1_POW";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc_5v>;
+
+               /* connected to SY6280A Power Switch */
+               gpio = <&gpio GPIOA_8 GPIO_ACTIVE_HIGH>;
+               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>;
+
+               /* Connected to USB3 Type-A Port power enable */
+               gpio = <&gpio GPIOAO_7 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;
+       };
+
+       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>;
+                       };
+               };
+       };
+
+       sound {
+               compatible = "amlogic,axg-sound-card";
+               model = "G12B-UGOOS-AM6";
+               audio-aux-devs = <&tdmout_b>;
+               audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+                               "TDMOUT_B IN 1", "FRDDR_B OUT 1",
+                               "TDMOUT_B IN 2", "FRDDR_C OUT 1",
+                               "TDM_B Playback", "TDMOUT_B OUT",
+                               "SPDIFOUT IN 0", "FRDDR_A OUT 3",
+                               "SPDIFOUT IN 1", "FRDDR_B OUT 3",
+                               "SPDIFOUT IN 2", "FRDDR_C OUT 3";
+
+               assigned-clocks = <&clkc CLKID_MPLL2>,
+                                 <&clkc CLKID_MPLL0>,
+                                 <&clkc CLKID_MPLL1>;
+               assigned-clock-parents = <0>, <0>, <0>;
+               assigned-clock-rates = <294912000>,
+                                      <270950400>,
+                                      <393216000>;
+               status = "okay";
+
+               dai-link-0 {
+                       sound-dai = <&frddr_a>;
+               };
+
+               dai-link-1 {
+                       sound-dai = <&frddr_b>;
+               };
+
+               dai-link-2 {
+                       sound-dai = <&frddr_c>;
+               };
+
+               /* 8ch hdmi interface */
+               dai-link-3 {
+                       sound-dai = <&tdmif_b>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       dai-tdm-slot-tx-mask-1 = <1 1>;
+                       dai-tdm-slot-tx-mask-2 = <1 1>;
+                       dai-tdm-slot-tx-mask-3 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
+                       };
+               };
+
+               /* spdif hdmi or toslink interface */
+               dai-link-4 {
+                       sound-dai = <&spdifout>;
+
+                       codec-0 {
+                               sound-dai = <&spdif_dit>;
+                       };
+
+                       codec-1 {
+                               sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_A>;
+                       };
+               };
+
+               /* spdif hdmi interface */
+               dai-link-5 {
+                       sound-dai = <&spdifout_b>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_B>;
+                       };
+               };
+
+               /* hdmi glue */
+               dai-link-6 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+                       codec {
+                               sound-dai = <&hdmi_tx>;
+                       };
+               };
+       };
+
+       wifi32k: wifi32k {
+               compatible = "pwm-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+       };
+};
+
+&arb {
+       status = "okay";
+};
+
+&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>;
+};
+
+&clkc_audio {
+       status = "okay";
+};
+
+&cpu0 {
+       cpu-supply = <&vddcpu_b>;
+       operating-points-v2 = <&cpu_opp_table_0>;
+       clocks = <&clkc CLKID_CPU_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu1 {
+       cpu-supply = <&vddcpu_b>;
+       operating-points-v2 = <&cpu_opp_table_0>;
+       clocks = <&clkc CLKID_CPU_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu100 {
+       cpu-supply = <&vddcpu_a>;
+       operating-points-v2 = <&cpub_opp_table_1>;
+       clocks = <&clkc CLKID_CPUB_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu101 {
+       cpu-supply = <&vddcpu_a>;
+       operating-points-v2 = <&cpub_opp_table_1>;
+       clocks = <&clkc CLKID_CPUB_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu102 {
+       cpu-supply = <&vddcpu_a>;
+       operating-points-v2 = <&cpub_opp_table_1>;
+       clocks = <&clkc CLKID_CPUB_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu103 {
+       cpu-supply = <&vddcpu_a>;
+       operating-points-v2 = <&cpub_opp_table_1>;
+       clocks = <&clkc CLKID_CPUB_CLK>;
+       clock-latency = <50000>;
+};
+
+&cvbs_vdac_port {
+       cvbs_vdac_out: endpoint {
+               remote-endpoint = <&cvbs_connector_in>;
+       };
+};
+
+&ext_mdio {
+       external_phy: ethernet-phy@0 {
+               /* Realtek RTL8211F (0x001cc916) */
+               reg = <0>;
+               max-speed = <1000>;
+
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
+
+               interrupt-parent = <&gpio_intc>;
+               /* MAC_INTR on GPIOZ_14 */
+               interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
+&ethmac {
+       pinctrl-0 = <&eth_pins>, <&eth_rgmii_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-handle = <&external_phy>;
+       amlogic,tx-delay-ns = <2>;
+};
+
+&frddr_a {
+       status = "okay";
+};
+
+&frddr_b {
+       status = "okay";
+};
+
+&frddr_c {
+       status = "okay";
+};
+
+&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>;
+       };
+};
+
+&ir {
+       status = "okay";
+       pinctrl-0 = <&remote_input_ao_pins>;
+       pinctrl-names = "default";
+       linux,rc-map-name = "rc-khadas";
+};
+
+&pwm_ab {
+       pinctrl-0 = <&pwm_a_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin0";
+       status = "okay";
+};
+
+&pwm_AO_cd {
+       pinctrl-0 = <&pwm_ao_d_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin1";
+       status = "okay";
+};
+
+&pwm_ef {
+       pinctrl-0 = <&pwm_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin0";
+       status = "okay";
+};
+
+/* SDIO */
+&sd_emmc_a {
+       status = "okay";
+       pinctrl-0 = <&sdio_pins>;
+       pinctrl-1 = <&sdio_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       sd-uhs-sdr50;
+       max-frequency = <100000000>;
+
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&sdio_pwrseq>;
+
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_1v8>;
+
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+       };
+};
+
+/* SD card */
+&sd_emmc_b {
+       status = "okay";
+       pinctrl-0 = <&sdcard_c_pins>;
+       pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <50000000>;
+       disable-wp;
+
+       cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_3v3>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+       status = "okay";
+       pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       max-frequency = <100000000>;
+       disable-wp;
+
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vcc_3v3>;
+       vqmmc-supply = <&flash_1v8>;
+};
+
+&spdifout {
+       pinctrl-0 = <&spdif_out_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&spdifout_b {
+       status = "okay";
+};
+
+&tdmif_b {
+       status = "okay";
+};
+
+&tdmout_b {
+       status = "okay";
+};
+
+&tohdmitx {
+       status = "okay";
+};
+
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+       uart-has-rtscts;
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               max-speed = <2000000>;
+               clocks = <&wifi32k>;
+       clock-names = "lpo";
+       };
+};
+
+&uart_AO {
+       status = "okay";
+       pinctrl-0 = <&uart_ao_a_pins>;
+       pinctrl-names = "default";
+};
+
+&usb {
+       status = "okay";
+       dr_mode = "host";
+       vbus-regulator = <&usb_pwr_en>;
+};
+
+&usb2_phy0 {
+       phy-supply = <&usb1_pow>;
+};
+
+&usb2_phy1 {
+       phy-supply = <&usb1_pow>;
+};
index 5628ccd..6dbc396 100644 (file)
@@ -4,8 +4,7 @@
  * Author: Neil Armstrong <narmstrong@baylibre.com>
  */
 
-#include "meson-g12-common.dtsi"
-#include <dt-bindings/power/meson-g12a-power.h>
+#include "meson-g12.dtsi"
 
 / {
        compatible = "amlogic,g12b";
@@ -49,7 +48,9 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <592>;
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu1: cpu@1 {
@@ -57,7 +58,9 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x1>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <592>;
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu100: cpu@100 {
@@ -65,7 +68,9 @@
                        compatible = "arm,cortex-a73";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu101: cpu@101 {
@@ -73,7 +78,9 @@
                        compatible = "arm,cortex-a73";
                        reg = <0x0 0x101>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu102: cpu@102 {
@@ -81,7 +88,9 @@
                        compatible = "arm,cortex-a73";
                        reg = <0x0 0x102>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                cpu103: cpu@103 {
@@ -89,7 +98,9 @@
                        compatible = "arm,cortex-a73";
                        reg = <0x0 0x103>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&l2>;
+                       #cooling-cells = <2>;
                };
 
                l2: l2-cache0 {
        compatible = "amlogic,g12b-clkc";
 };
 
-&ethmac {
-       power-domains = <&pwrc PWRC_G12A_ETH_ID>;
-};
-
-&vpu {
-       power-domains = <&pwrc PWRC_G12A_VPU_ID>;
-};
-
-&sd_emmc_a {
-       amlogic,dram-access-quirk;
-};
index a9b7785..12d5e33 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 6733050..40db06e 100644 (file)
                #address-cells = <1>;
                #size-cells = <1>;
                read-only;
+               secure-monitor = <&sm>;
 
                sn: sn@14 {
                        reg = <0x14 0x10>;
                        };
 
                        i2c_A: i2c@8500 {
-                               compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c";
+                               compatible = "amlogic,meson-gxbb-i2c";
                                reg = <0x0 0x08500 0x0 0x20>;
                                interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>;
                                #address-cells = <1>;
                        };
 
                        i2c_B: i2c@87c0 {
-                               compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c";
+                               compatible = "amlogic,meson-gxbb-i2c";
                                reg = <0x0 0x087c0 0x0 0x20>;
                                interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>;
                                #address-cells = <1>;
                        };
 
                        i2c_C: i2c@87e0 {
-                               compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c";
+                               compatible = "amlogic,meson-gxbb-i2c";
                                reg = <0x0 0x087e0 0x0 0x20>;
                                interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>;
                                #address-cells = <1>;
                                compatible = "amlogic,meson-gx-ao-cec";
                                reg = <0x0 0x00100 0x0 0x14>;
                                interrupts = <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>;
+                               status = "disabled";
                        };
 
                        sec_AO: ao-secure@140 {
                        };
 
                        i2c_AO: i2c@500 {
-                               compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c";
+                               compatible = "amlogic,meson-gxbb-i2c";
                                reg = <0x0 0x500 0x0 0x20>;
                                interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
                                #address-cells = <1>;
index 233eb1c..d6ca684 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddio_ao3v3>;
index afcf8a9..65ec7de 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 6039add..6ded279 100644 (file)
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
 
+               /*
+                * signal name from schematics: PWREN
+                */
                gpio = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>;
                enable-active-high;
+               /*
+                * signal name from schematics: USB_POWER
+                */
+               vin-supply = <&p5v0>;
        };
 
        leds {
                };
        };
 
+       p5v0: regulator-p5v0 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "P5V0";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       hdmi_p5v0: regulator-hdmi_p5v0 {
+               compatible = "regulator-fixed";
+               regulator-name = "HDMI_P5V0";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               /* AP2331SA-7 */
+               vin-supply = <&p5v0>;
+       };
+
        tflash_vdd: regulator-tflash_vdd {
-               /*
-                * signal name from schematics: TFLASH_VDD_EN
-                */
                compatible = "regulator-fixed";
 
                regulator-name = "TFLASH_VDD";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
 
+               /*
+                * signal name from schematics: TFLASH_VDD_EN
+                */
                gpio = <&gpio GPIOY_12 GPIO_ACTIVE_HIGH>;
                enable-active-high;
+               /* U16 RT9179GB */
+               vin-supply = <&vddio_ao3v3>;
        };
 
        tf_io: gpio-regulator-tf_io {
 
                states = <3300000 0>,
                         <1800000 1>;
+               /* U12/U13 RT9179GB */
+               vin-supply = <&vddio_ao3v3>;
        };
 
        vcc1v8: regulator-vcc1v8 {
                regulator-name = "VCC1V8";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               /* U18 RT9179GB */
+               vin-supply = <&vddio_ao3v3>;
        };
 
        vcc3v3: regulator-vcc3v3 {
                regulator-max-microvolt = <3300000>;
        };
 
+       vddio_ao1v8: regulator-vddio-ao1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDIO_AO1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               /* U17 RT9179GB */
+               vin-supply = <&p5v0>;
+       };
+
+       vddio_ao3v3: regulator-vddio-ao3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDIO_AO3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               /* U11 MP2161GJ-C499 */
+               vin-supply = <&p5v0>;
+       };
+
+       ddr3_1v5: regulator-ddr3_1v5 {
+               compatible = "regulator-fixed";
+               regulator-name = "DDR3_1V5";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               regulator-always-on;
+               /* U15 MP2161GJ-C499 */
+               vin-supply = <&p5v0>;
+       };
+
        emmc_pwrseq: emmc-pwrseq {
                compatible = "mmc-pwrseq-emmc";
                reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
        status = "okay";
        pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
        pinctrl-names = "default";
+       hdmi-supply = <&hdmi_p5v0>;
 };
 
 &hdmi_tx_tmds_port {
 };
 
 &usb0_phy {
-       status = "okay";
+       status = "disabled";
        phy-supply = <&usb_otg_pwr>;
 };
 
 };
 
 &usb0 {
-       status = "okay";
+       status = "disabled";
 };
 
 &usb1 {
index 89f7b41..e803a46 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 43b11e3..5eab3df 100644 (file)
        status = "okay";
        pinctrl-0 = <&remote_input_ao_pins>;
        pinctrl-names = "default";
+       linux,rc-map-name = "rc-vega-s9x";
 };
 
 &pwm_ef {
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 4c53988..dee51cf 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 82b1c48..4d59494 100644 (file)
@@ -14,7 +14,7 @@
 / {
        compatible = "libretech,aml-s805x-ac", "amlogic,s805x",
                     "amlogic,meson-gxl";
-       model = "Libre Computer Board AML-S805X-AC";
+       model = "Libre Computer AML-S805X-AC";
 
        aliases {
                serial0 = &uart_AO;
index 3a1484e..a1119cf 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 2a5cd30..440bc23 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               power-button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
        bluetooth {
                compatible = "brcm,bcm43438-bt";
                shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               max-speed = <2000000>;
+               clocks = <&wifi32k>;
+               clock-names = "lpo";
        };
 };
 
index 4b8ce73..e8348b2 100644 (file)
@@ -12,8 +12,9 @@
 #include "meson-gxl-s905x.dtsi"
 
 / {
-       compatible = "libretech,cc", "amlogic,s905x", "amlogic,meson-gxl";
-       model = "Libre Computer Board AML-S905X-CC";
+       compatible = "libretech,aml-s905x-cc", "amlogic,s905x",
+                    "amlogic,meson-gxl";
+       model = "Libre Computer AML-S905X-CC";
 
        aliases {
                serial0 = &uart_AO;
index c433a03..62dd878 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index e3c16f5..43eb7d1 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index 49ff0a7..ed33d8e 100644 (file)
                                phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>;
                        };
                };
+
+               crypto: crypto@c883e000 {
+                       compatible = "amlogic,gxl-crypto";
+                       reg = <0x0 0xc883e000 0x0 0x36>;
+                       interrupts = <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc CLKID_BLKMV>;
+                       clock-names = "blkmv";
+                       status = "okay";
+               };
        };
 };
 
index f25ddd1..f82f25c 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
        bluetooth {
                compatible = "brcm,bcm43438-bt";
                shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               max-speed = <2000000>;
+               clocks = <&wifi32k>;
+               clock-names = "lpo";
        };
 };
 
index 5cd4d35..420a88e 100644 (file)
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
index e2ea675..0bdf51d 100644 (file)
@@ -35,3 +35,7 @@
                reg = <0>;
        };
 };
+
+&ir {
+       linux,rc-map-name = "rc-vega-s9x";
+};
index a0e677d..5ff64a0 100644 (file)
                compatible = "amlogic,meson-gxm-mali", "arm,mali-t820";
                reg = <0x0 0xc0000 0x0 0x40000>;
                interrupt-parent = <&gic>;
-               interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+               interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-               interrupt-names = "gpu", "mmu", "job";
+                            <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "job", "mmu", "gpu";
                clocks = <&clkc CLKID_MALI>;
                resets = <&reset RESET_MALI_CAPB3>, <&reset RESET_MALI>;
 
index 8647da7..90815fa 100644 (file)
        linux,rc-map-name = "rc-khadas";
 };
 
+&pcie {
+       reset-gpios = <&gpio GPIOA_8 GPIO_ACTIVE_LOW>;
+};
+
 &pwm_ef {
         status = "okay";
         pinctrl-0 = <&pwm_e_pins>;
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vsys_3v3>;
index 5233bd7..dbbf29a 100644 (file)
        clock-names = "clkin1";
        status = "okay";
 };
+
+/*
+ * The VIM3 on-board  MCU can mux the PCIe/USB3.0 shared differential
+ * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between
+ * an USB3.0 Type A connector and a M.2 Key M slot.
+ * The PHY driving these differential lines is shared between
+ * the USB3.0 controller and the PCIe Controller, thus only
+ * a single controller can use it.
+ * If the MCU is configured to mux the PCIe/USB3.0 differential lines
+ * to the M.2 Key M slot, uncomment the following block to disable
+ * USB3.0 from the USB Complex and enable the PCIe controller.
+ * The End User is not expected to uncomment the following except for
+ * testing purposes, but instead rely on the firmware/bootloader to
+ * update these nodes accordingly if PCIe mode is selected by the MCU.
+ */
+/*
+&pcie {
+       status = "okay";
+};
+
+&usb {
+       phys = <&usb2_phy0>, <&usb2_phy1>;
+       phy-names = "usb2-phy0", "usb2-phy1";
+};
+ */
index 3435aaa..5bd0746 100644 (file)
@@ -9,6 +9,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
        compatible = "seirobotics,sei610", "amlogic,sm1";
                ethernet0 = &ethmac;
        };
 
+       mono_dac: audio-codec-0 {
+               compatible = "maxim,max98357a";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "U16";
+               sdmode-gpios = <&gpio GPIOX_8 GPIO_ACTIVE_HIGH>;
+       };
+
+       dmics: audio-codec-1 {
+               #sound-dai-cells = <0>;
+               compatible = "dmic-codec";
+               num-channels = <2>;
+               wakeup-delay-ms = <50>;
+               status = "okay";
+               sound-name-prefix = "MIC";
+       };
+
        chosen {
                stdout-path = "serial0:115200n8";
        };
                clock-names = "ext_clock";
        };
 
+       sound {
+               compatible = "amlogic,axg-sound-card";
+               model = "SM1-SEI610";
+               audio-aux-devs = <&tdmout_a>, <&tdmout_b>,
+                                <&tdmin_a>, <&tdmin_b>;
+               audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0",
+                               "TDMOUT_A IN 1", "FRDDR_B OUT 0",
+                               "TDMOUT_A IN 2", "FRDDR_C OUT 0",
+                               "TDM_A Playback", "TDMOUT_A OUT",
+                               "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+                               "TDMOUT_B IN 1", "FRDDR_B OUT 1",
+                               "TDMOUT_B IN 2", "FRDDR_C OUT 1",
+                               "TDM_B Playback", "TDMOUT_B OUT",
+                               "TODDR_A IN 4", "PDM Capture",
+                               "TODDR_B IN 4", "PDM Capture",
+                               "TODDR_C IN 4", "PDM Capture",
+                               "TDMIN_A IN 0", "TDM_A Capture",
+                               "TDMIN_A IN 3", "TDM_A Loopback",
+                               "TDMIN_B IN 0", "TDM_A Capture",
+                               "TDMIN_B IN 3", "TDM_A Loopback",
+                               "TDMIN_A IN 1", "TDM_B Capture",
+                               "TDMIN_A IN 4", "TDM_B Loopback",
+                               "TDMIN_B IN 1", "TDM_B Capture",
+                               "TDMIN_B IN 4", "TDM_B Loopback",
+                               "TODDR_A IN 0", "TDMIN_A OUT",
+                               "TODDR_B IN 0", "TDMIN_A OUT",
+                               "TODDR_C IN 0", "TDMIN_A OUT",
+                               "TODDR_A IN 1", "TDMIN_B OUT",
+                               "TODDR_B IN 1", "TDMIN_B OUT",
+                               "TODDR_C IN 1", "TDMIN_B OUT";
+
+               assigned-clocks = <&clkc CLKID_MPLL2>,
+                                 <&clkc CLKID_MPLL0>,
+                                 <&clkc CLKID_MPLL1>;
+               assigned-clock-parents = <0>, <0>, <0>;
+               assigned-clock-rates = <294912000>,
+                                      <270950400>,
+                                      <393216000>;
+               status = "okay";
+
+               dai-link-0 {
+                       sound-dai = <&frddr_a>;
+               };
+
+               dai-link-1 {
+                       sound-dai = <&frddr_b>;
+               };
+
+               dai-link-2 {
+                       sound-dai = <&frddr_c>;
+               };
+
+               dai-link-3 {
+                       sound-dai = <&toddr_a>;
+               };
+
+               dai-link-4 {
+                       sound-dai = <&toddr_b>;
+               };
+
+               dai-link-5 {
+                       sound-dai = <&toddr_c>;
+               };
+
+               /* internal speaker interface */
+               dai-link-6 {
+                       sound-dai = <&tdmif_a>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec-0 {
+                               sound-dai = <&mono_dac>;
+                       };
+
+                       codec-1 {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>;
+                       };
+               };
+
+               /* 8ch hdmi interface */
+               dai-link-7 {
+                       sound-dai = <&tdmif_b>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       dai-tdm-slot-tx-mask-1 = <1 1>;
+                       dai-tdm-slot-tx-mask-2 = <1 1>;
+                       dai-tdm-slot-tx-mask-3 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
+                       };
+               };
+
+               /* internal digital mics */
+               dai-link-8 {
+                       sound-dai = <&pdm>;
+
+                       codec {
+                               sound-dai = <&dmics>;
+                       };
+               };
+
+               /* hdmi glue */
+               dai-link-9 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+                       codec {
+                               sound-dai = <&hdmi_tx>;
+                       };
+               };
+       };
+
        wifi32k: wifi32k {
                compatible = "pwm-clock";
                #clock-cells = <0>;
        };
 };
 
+&arb {
+       status = "okay";
+};
+
 &cec_AO {
        pinctrl-0 = <&cec_ao_a_h_pins>;
        pinctrl-names = "default";
        hdmi-phandle = <&hdmi_tx>;
 };
 
+&clkc_audio {
+       status = "okay";
+};
+
 &cpu0 {
        cpu-supply = <&vddcpu>;
        operating-points-v2 = <&cpu_opp_table>;
        phy-mode = "rmii";
 };
 
+&frddr_a {
+       status = "okay";
+};
+
+&frddr_b {
+       status = "okay";
+};
+
+&frddr_c {
+       status = "okay";
+};
+
 &hdmi_tx {
        status = "okay";
        pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
        pinctrl-names = "default";
 };
 
+&pdm {
+       pinctrl-0 = <&pdm_din0_z_pins>, <&pdm_dclk_z_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
 &pwm_AO_ab {
        status = "okay";
        pinctrl-0 = <&pwm_ao_a_pins>;
        non-removable;
        disable-wp;
 
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
        mmc-pwrseq = <&sdio_pwrseq>;
 
        vmmc-supply = <&vddao_3v3>;
        vqmmc-supply = <&emmc_1v8>;
 };
 
+&tdmif_a {
+       pinctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD0>,
+                         <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD0>;
+       assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_A_SCLK>,
+                                <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
+       assigned-clock-rates = <0>, <0>;
+};
+
+&tdmif_b {
+       status = "okay";
+};
+
+&tdmin_a {
+       status = "okay";
+};
+
+&tdmin_b {
+       status = "okay";
+};
+
+&tdmout_a {
+       status = "okay";
+};
+
+&tdmout_b {
+       status = "okay";
+};
+
+&toddr_a {
+       status = "okay";
+};
+
+&toddr_b {
+       status = "okay";
+};
+
+&toddr_c {
+       status = "okay";
+};
+
+&tohdmitx {
+       status = "okay";
+};
+
 &uart_A {
        status = "okay";
        pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
index 521573f..7894a54 100644 (file)
@@ -5,11 +5,47 @@
  */
 
 #include "meson-g12-common.dtsi"
+#include <dt-bindings/clock/axg-audio-clkc.h>
 #include <dt-bindings/power/meson-sm1-power.h>
+#include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h>
+#include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
 
 / {
        compatible = "amlogic,sm1";
 
+       tdmif_a: audio-controller-0 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_A";
+               clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_A_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
+       tdmif_b: audio-controller-1 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_B";
+               clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_B_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_B_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
+       tdmif_c: audio-controller-2 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_C";
+               clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_C_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_C_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
        cpus {
                #address-cells = <0x2>;
                #size-cells = <0x0>;
        };
 };
 
+&apb {
+       audio: bus@60000 {
+               compatible = "simple-bus";
+               reg = <0x0 0x60000 0x0 0x1000>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges = <0x0 0x0 0x0 0x60000 0x0 0x1000>;
+
+               clkc_audio: clock-controller@0 {
+                       status = "disabled";
+                       compatible = "amlogic,sm1-audio-clkc";
+                       reg = <0x0 0x0 0x0 0xb4>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+
+                       clocks = <&clkc CLKID_AUDIO>,
+                                <&clkc CLKID_MPLL0>,
+                                <&clkc CLKID_MPLL1>,
+                                <&clkc CLKID_MPLL2>,
+                                <&clkc CLKID_MPLL3>,
+                                <&clkc CLKID_HIFI_PLL>,
+                                <&clkc CLKID_FCLK_DIV3>,
+                                <&clkc CLKID_FCLK_DIV4>,
+                                <&clkc CLKID_FCLK_DIV5>;
+                       clock-names = "pclk",
+                                     "mst_in0",
+                                     "mst_in1",
+                                     "mst_in2",
+                                     "mst_in3",
+                                     "mst_in4",
+                                     "mst_in5",
+                                     "mst_in6",
+                                     "mst_in7";
+
+                       resets = <&reset RESET_AUDIO>;
+               };
+
+               toddr_a: audio-controller@100 {
+                       compatible = "amlogic,sm1-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x100 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_A";
+                       interrupts = <GIC_SPI 148 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_A>;
+                       resets = <&arb AXG_ARB_TODDR_A>,
+                                <&clkc_audio AUD_RESET_TODDR_A>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               toddr_b: audio-controller@140 {
+                       compatible = "amlogic,sm1-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x140 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_B";
+                       interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_B>;
+                       resets = <&arb AXG_ARB_TODDR_B>,
+                                <&clkc_audio AUD_RESET_TODDR_B>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               toddr_c: audio-controller@180 {
+                       compatible = "amlogic,sm1-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x180 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_C";
+                       interrupts = <GIC_SPI 150 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_C>;
+                       resets = <&arb AXG_ARB_TODDR_C>,
+                                <&clkc_audio AUD_RESET_TODDR_C>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_a: audio-controller@1c0 {
+                       compatible = "amlogic,sm1-frddr",
+                                    "amlogic,axg-frddr";
+                       reg = <0x0 0x1c0 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_A";
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
+                       resets = <&arb AXG_ARB_FRDDR_A>,
+                                <&clkc_audio AUD_RESET_FRDDR_A>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_b: audio-controller@200 {
+                       compatible = "amlogic,sm1-frddr",
+                                    "amlogic,axg-frddr";
+                       reg = <0x0 0x200 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_B";
+                       interrupts = <GIC_SPI 153 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_B>;
+                       resets = <&arb AXG_ARB_FRDDR_B>,
+                                <&clkc_audio AUD_RESET_FRDDR_B>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_c: audio-controller@240 {
+                       compatible = "amlogic,sm1-frddr",
+                                    "amlogic,axg-frddr";
+                       reg = <0x0 0x240 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_C";
+                       interrupts = <GIC_SPI 154 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_C>;
+                       resets = <&arb AXG_ARB_FRDDR_C>,
+                                <&clkc_audio AUD_RESET_FRDDR_C>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               arb: reset-controller@280 {
+                       status = "disabled";
+                       compatible = "amlogic,meson-sm1-audio-arb";
+                       reg = <0x0 0x280 0x0 0x4>;
+                       #reset-cells = <1>;
+                       clocks = <&clkc_audio AUD_CLKID_DDR_ARB>;
+               };
+
+               tdmin_a: audio-controller@300 {
+                       compatible = "amlogic,sm1-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x300 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_A";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_A>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_A>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmin_b: audio-controller@340 {
+                       compatible = "amlogic,sm1-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x340 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_B";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_B>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_B>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmin_c: audio-controller@380 {
+                       compatible = "amlogic,sm1-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x380 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_C";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_C>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_C>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmin_lb: audio-controller@3c0 {
+                       compatible = "amlogic,sm1-tdmin",
+                                    "amlogic,axg-tdmin";
+                       reg = <0x0 0x3c0 0x0 0x40>;
+                       sound-name-prefix = "TDMIN_LB";
+                       resets = <&clkc_audio AUD_RESET_TDMIN_LB>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmout_a: audio-controller@500 {
+                       compatible = "amlogic,sm1-tdmout";
+                       reg = <0x0 0x500 0x0 0x40>;
+                       sound-name-prefix = "TDMOUT_A";
+                       resets = <&clkc_audio AUD_RESET_TDMOUT_A>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmout_b: audio-controller@540 {
+                       compatible = "amlogic,sm1-tdmout";
+                       reg = <0x0 0x540 0x0 0x40>;
+                       sound-name-prefix = "TDMOUT_B";
+                       resets = <&clkc_audio AUD_RESET_TDMOUT_B>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tdmout_c: audio-controller@580 {
+                       compatible = "amlogic,sm1-tdmout";
+                       reg = <0x0 0x580 0x0 0x40>;
+                       sound-name-prefix = "TDMOUT_C";
+                       resets = <&clkc_audio AUD_RESET_TDMOUT_C>;
+                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>,
+                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>;
+                       clock-names = "pclk", "sclk", "sclk_sel",
+                                     "lrclk", "lrclk_sel";
+                       status = "disabled";
+               };
+
+               tohdmitx: audio-controller@744 {
+                       compatible = "amlogic,sm1-tohdmitx",
+                                    "amlogic,g12a-tohdmitx";
+                       reg = <0x0 0x744 0x0 0x4>;
+                       #sound-dai-cells = <1>;
+                       sound-name-prefix = "TOHDMITX";
+                       resets = <&clkc_audio AUD_RESET_TOHDMITX>;
+                       status = "disabled";
+               };
+
+               toddr_d: audio-controller@840 {
+                       compatible = "amlogic,sm1-toddr",
+                                    "amlogic,axg-toddr";
+                       reg = <0x0 0x840 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "TODDR_D";
+                       interrupts = <GIC_SPI 49 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_TODDR_D>;
+                       resets = <&arb AXG_ARB_TODDR_D>,
+                                <&clkc_audio AUD_RESET_TODDR_D>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+
+               frddr_d: audio-controller@880 {
+                        compatible = "amlogic,sm1-frddr",
+                                     "amlogic,axg-frddr";
+                       reg = <0x0 0x880 0x0 0x2c>;
+                       #sound-dai-cells = <0>;
+                       sound-name-prefix = "FRDDR_D";
+                       interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&clkc_audio AUD_CLKID_FRDDR_D>;
+                       resets = <&arb AXG_ARB_FRDDR_D>,
+                                <&clkc_audio AUD_RESET_FRDDR_D>;
+                       reset-names = "arb", "rst";
+                       status = "disabled";
+               };
+       };
+
+       pdm: audio-controller@61000 {
+               compatible = "amlogic,sm1-pdm",
+                            "amlogic,axg-pdm";
+               reg = <0x0 0x61000 0x0 0x34>;
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "PDM";
+               clocks = <&clkc_audio AUD_CLKID_PDM>,
+                        <&clkc_audio AUD_CLKID_PDM_DCLK>,
+                        <&clkc_audio AUD_CLKID_PDM_SYSCLK>;
+               clock-names = "pclk", "dclk", "sysclk";
+               status = "disabled";
+       };
+};
+
 &cecb_AO {
        compatible = "amlogic,meson-sm1-ao-cec";
 };
        power-domains = <&pwrc PWRC_SM1_ETH_ID>;
 };
 
+&gpio_intc {
+       compatible = "amlogic,meson-sm1-gpio-intc",
+                    "amlogic,meson-gpio-intc";
+};
+
+&pcie {
+       power-domains = <&pwrc PWRC_SM1_PCIE_ID>;
+};
+
 &pwrc {
        compatible = "amlogic,meson-sm1-pwrc";
 };
 
+&simplefb_cvbs {
+       power-domains = <&pwrc PWRC_SM1_VPU_ID>;
+};
+
+&simplefb_hdmi {
+       power-domains = <&pwrc PWRC_SM1_VPU_ID>;
+};
+
 &vpu {
        power-domains = <&pwrc PWRC_SM1_VPU_ID>;
 };
index 26a039a..9e3e8ce 100644 (file)
                clock-names = "apb_pclk";
        };
 
+       smmu_gpu: iommu@2b400000 {
+               compatible = "arm,mmu-400", "arm,smmu-v1";
+               reg = <0x0 0x2b400000 0x0 0x10000>;
+               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+               #iommu-cells = <1>;
+               #global-interrupts = <1>;
+               power-domains = <&scpi_devpd 1>;
+               dma-coherent;
+               status = "disabled";
+       };
+
        smmu_pcie: iommu@2b500000 {
                compatible = "arm,mmu-401", "arm,smmu-v1";
                reg = <0x0 0x2b500000 0x0 0x10000>;
                };
        };
 
+       gpu: gpu@2d000000 {
+               compatible = "arm,juno-mali", "arm,mali-t624";
+               reg = <0 0x2d000000 0 0x10000>;
+               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "gpu", "job", "mmu";
+               clocks = <&scpi_dvfs 2>;
+               power-domains = <&scpi_devpd 1>;
+               dma-coherent;
+               /* The SMMU is only really of interest to bare-metal hypervisors */
+               /* iommus = <&smmu_gpu 0>; */
+               status = "disabled";
+       };
+
        sram: sram@2e000000 {
                compatible = "arm,juno-sram-ns", "mmio-sram";
                reg = <0x0 0x2e000000 0x0 0x8000>;
index d1d31cc..cb7de8d 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
-dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-a-plus.dtb \
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb \
+                             bcm2837-rpi-3-a-plus.dtb \
                              bcm2837-rpi-3-b.dtb \
                              bcm2837-rpi-3-b-plus.dtb \
                              bcm2837-rpi-cm3-io3.dtb
diff --git a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
new file mode 100644 (file)
index 0000000..d24c536
--- /dev/null
@@ -0,0 +1,2 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "arm/bcm2711-rpi-4-b.dts"
index a76f620..6721966 100644 (file)
@@ -18,8 +18,8 @@
 
 / {
        compatible = "samsung,exynos5433";
-       #address-cells = <1>;
-       #size-cells = <1>;
+       #address-cells = <2>;
+       #size-cells = <2>;
 
        interrupt-parent = <&gic>;
 
                };
        };
 
-       gpu: gpu@14ac0000 {
-               compatible = "samsung,exynos5433-mali", "arm,mali-t760";
-               reg = <0x14ac0000 0x5000>;
-               interrupts = <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
-               interrupt-names = "job", "mmu", "gpu";
-               clocks = <&cmu_g3d CLK_ACLK_G3D>;
-               clock-names = "core";
-               power-domains = <&pd_g3d>;
-               operating-points-v2 = <&gpu_opp_table>;
-               status = "disabled";
-
-               gpu_opp_table: opp_table {
-                       compatible = "operating-points-v2";
-
-                       opp-160000000 {
-                               opp-hz = /bits/ 64 <160000000>;
-                               opp-microvolt = <1000000>;
-                       };
-                       opp-267000000 {
-                               opp-hz = /bits/ 64 <267000000>;
-                               opp-microvolt = <1000000>;
-                       };
-                       opp-350000000 {
-                               opp-hz = /bits/ 64 <350000000>;
-                               opp-microvolt = <1025000>;
-                       };
-                       opp-420000000 {
-                               opp-hz = /bits/ 64 <420000000>;
-                               opp-microvolt = <1025000>;
-                       };
-                       opp-500000000 {
-                               opp-hz = /bits/ 64 <500000000>;
-                               opp-microvolt = <1075000>;
-                       };
-                       opp-550000000 {
-                               opp-hz = /bits/ 64 <550000000>;
-                               opp-microvolt = <1125000>;
-                       };
-                       opp-600000000 {
-                               opp-hz = /bits/ 64 <600000000>;
-                               opp-microvolt = <1150000>;
-                       };
-                       opp-700000000 {
-                               opp-hz = /bits/ 64 <700000000>;
-                               opp-microvolt = <1150000>;
-                       };
-               };
-       };
-
        psci {
                compatible = "arm,psci";
                method = "smc";
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
-               ranges;
+               ranges = <0x0 0x0 0x0 0x18000000>;
 
                chipid@10000000 {
                        compatible = "samsung,exynos4210-chipid";
                        status = "disabled";
                };
 
-               mct@101c0000 {
+               timer@101c0000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x101c0000 0x800>;
                        interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
                        power-domains = <&pd_gscl>;
                };
 
+               gpu: gpu@14ac0000 {
+                       compatible = "samsung,exynos5433-mali", "arm,mali-t760";
+                       reg = <0x14ac0000 0x5000>;
+                       interrupts = <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "job", "mmu", "gpu";
+                       clocks = <&cmu_g3d CLK_ACLK_G3D>;
+                       clock-names = "core";
+                       power-domains = <&pd_g3d>;
+                       operating-points-v2 = <&gpu_opp_table>;
+                       status = "disabled";
+
+                       gpu_opp_table: opp_table {
+                               compatible = "operating-points-v2";
+
+                               opp-160000000 {
+                                       opp-hz = /bits/ 64 <160000000>;
+                                       opp-microvolt = <1000000>;
+                               };
+                               opp-267000000 {
+                                       opp-hz = /bits/ 64 <267000000>;
+                                       opp-microvolt = <1000000>;
+                               };
+                               opp-350000000 {
+                                       opp-hz = /bits/ 64 <350000000>;
+                                       opp-microvolt = <1025000>;
+                               };
+                               opp-420000000 {
+                                       opp-hz = /bits/ 64 <420000000>;
+                                       opp-microvolt = <1025000>;
+                               };
+                               opp-500000000 {
+                                       opp-hz = /bits/ 64 <500000000>;
+                                       opp-microvolt = <1075000>;
+                               };
+                               opp-550000000 {
+                                       opp-hz = /bits/ 64 <550000000>;
+                                       opp-microvolt = <1125000>;
+                               };
+                               opp-600000000 {
+                                       opp-hz = /bits/ 64 <600000000>;
+                                       opp-microvolt = <1150000>;
+                               };
+                               opp-700000000 {
+                                       opp-hz = /bits/ 64 <700000000>;
+                                       opp-microvolt = <1150000>;
+                               };
+                       };
+               };
+
                scaler_0: scaler@15000000 {
                        compatible = "samsung,exynos5433-scaler";
                        reg = <0x15000000 0x1294>;
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x13a00000 0x1000>;
                        interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_disp CLK_PCLK_SMMU_DECON0X>,
-                               <&cmu_disp CLK_ACLK_SMMU_DECON0X>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_disp CLK_ACLK_SMMU_DECON0X>,
+                               <&cmu_disp CLK_PCLK_SMMU_DECON0X>;
                        power-domains = <&pd_disp>;
                        #iommu-cells = <0>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x13a10000 0x1000>;
                        interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_disp CLK_PCLK_SMMU_DECON1X>,
-                               <&cmu_disp CLK_ACLK_SMMU_DECON1X>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_disp CLK_ACLK_SMMU_DECON1X>,
+                               <&cmu_disp CLK_PCLK_SMMU_DECON1X>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_disp>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x13a20000 0x1000>;
                        interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_disp CLK_PCLK_SMMU_TV0X>,
-                               <&cmu_disp CLK_ACLK_SMMU_TV0X>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_disp CLK_ACLK_SMMU_TV0X>,
+                               <&cmu_disp CLK_PCLK_SMMU_TV0X>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_disp>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x13a30000 0x1000>;
                        interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_disp CLK_PCLK_SMMU_TV1X>,
-                               <&cmu_disp CLK_ACLK_SMMU_TV1X>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_disp CLK_ACLK_SMMU_TV1X>,
+                               <&cmu_disp CLK_PCLK_SMMU_TV1X>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_disp>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x15040000 0x1000>;
                        interrupts = <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_mscl CLK_PCLK_SMMU_M2MSCALER0>,
-                                <&cmu_mscl CLK_ACLK_SMMU_M2MSCALER0>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_mscl CLK_ACLK_SMMU_M2MSCALER0>,
+                               <&cmu_mscl CLK_PCLK_SMMU_M2MSCALER0>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_mscl>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x15050000 0x1000>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_mscl CLK_PCLK_SMMU_M2MSCALER1>,
-                                <&cmu_mscl CLK_ACLK_SMMU_M2MSCALER1>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_mscl CLK_ACLK_SMMU_M2MSCALER1>,
+                               <&cmu_mscl CLK_PCLK_SMMU_M2MSCALER1>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_mscl>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x15060000 0x1000>;
                        interrupts = <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_mscl CLK_PCLK_SMMU_JPEG>,
-                                <&cmu_mscl CLK_ACLK_SMMU_JPEG>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_mscl CLK_ACLK_SMMU_JPEG>,
+                               <&cmu_mscl CLK_PCLK_SMMU_JPEG>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_mscl>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x15200000 0x1000>;
                        interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_mfc CLK_PCLK_SMMU_MFC_0>,
-                                <&cmu_mfc CLK_ACLK_SMMU_MFC_0>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_mfc CLK_ACLK_SMMU_MFC_0>,
+                               <&cmu_mfc CLK_PCLK_SMMU_MFC_0>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_mfc>;
                };
                        compatible = "samsung,exynos-sysmmu";
                        reg = <0x15210000 0x1000>;
                        interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "pclk", "aclk";
-                       clocks = <&cmu_mfc CLK_PCLK_SMMU_MFC_1>,
-                                <&cmu_mfc CLK_ACLK_SMMU_MFC_1>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_mfc CLK_ACLK_SMMU_MFC_1>,
+                               <&cmu_mfc CLK_PCLK_SMMU_MFC_1>;
                        #iommu-cells = <0>;
                        power-domains = <&pd_mfc>;
                };
                i2s1: i2s@14d60000 {
                        compatible = "samsung,exynos7-i2s";
                        reg = <0x14d60000 0x100>;
-                       dmas = <&pdma0 31 &pdma0 30>;
+                       dmas = <&pdma0 31>, <&pdma0 30>;
                        dma-names = "tx", "rx";
                        interrupts = <GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cmu_peric CLK_PCLK_I2S1>,
                        i2s0: i2s@11440000 {
                                compatible = "samsung,exynos7-i2s";
                                reg = <0x11440000 0x100>;
-                               dmas = <&adma 0 &adma 2>;
+                               dmas = <&adma 0>, <&adma 2>;
                                dma-names = "tx", "rx";
                                interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
                                #address-cells = <1>;
index bcb9d8c..3a00ef0 100644 (file)
@@ -12,8 +12,8 @@
 / {
        compatible = "samsung,exynos7";
        interrupt-parent = <&gic>;
-       #address-cells = <1>;
-       #size-cells = <1>;
+       #address-cells = <2>;
+       #size-cells = <2>;
 
        aliases {
                pinctrl0 = &pinctrl_alive;
                };
        };
 
-       gpu: gpu@14ac0000 {
-               compatible = "samsung,exynos5433-mali", "arm,mali-t760";
-               reg = <0x14ac0000 0x5000>;
-               interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
-               interrupt-names = "job", "mmu", "gpu";
-               status = "disabled";
-               /* TODO: operating points for DVFS, cooling device */
-       };
-
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
@@ -98,7 +87,7 @@
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
-               ranges;
+               ranges = <0 0 0 0x18000000>;
 
                chipid@10000000 {
                        compatible = "samsung,exynos4210-chipid";
                        status = "disabled";
                };
 
+               gpu: gpu@14ac0000 {
+                       compatible = "samsung,exynos5433-mali", "arm,mali-t760";
+                       reg = <0x14ac0000 0x5000>;
+                       interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "job", "mmu", "gpu";
+                       status = "disabled";
+                       /* TODO: operating points for DVFS, cooling device */
+               };
+
                mmc_0: mmc@15740000 {
                        compatible = "samsung,exynos7-dw-mshc-smu";
                        interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
index 93fce8f..38e344a 100644 (file)
@@ -22,6 +22,7 @@ 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) += imx8mn-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-hummingboard-pulse.dtb
@@ -31,4 +32,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mq-pico-pi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-eval-v3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
+
+dtb-$(CONFIG_ARCH_S32) += s32v234-evb.dtb
index 078a501..5b9d4b3 100644 (file)
        };
 
        fpga@66 {
-               #address-cells = <1>;
-               #size-cells = <0>;
                compatible = "fsl,ls1028aqds-fpga", "fsl,fpga-qixis-i2c",
                             "simple-mfd";
                reg = <0x66>;
index 1a69221..9720a19 100644 (file)
 &sata {
        status = "okay";
 };
+
+&usb1 {
+       dr_mode = "otg";
+};
index 72b9a75..8e8a77e 100644 (file)
        dpclk: clock-controller@f1f0000 {
                compatible = "fsl,ls1028a-plldig";
                reg = <0x0 0xf1f0000 0x0 0xffff>;
-               #clock-cells = <1>;
-               clocks = <&osc_27m>;
-       };
-
-       aclk: clock-axi {
-               compatible = "fixed-clock";
                #clock-cells = <0>;
-               clock-frequency = <650000000>;
-               clock-output-names= "aclk";
-       };
-
-       pclk: clock-apb {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <650000000>;
-               clock-output-names= "pclk";
+               clocks = <&osc_27m>;
        };
 
        reboot {
                };
        };
 
+       thermal-zones {
+               core-cluster {
+                       polling-delay-passive = <1000>;
+                       polling-delay = <5000>;
+                       thermal-sensors = <&tmu 0>;
+
+                       trips {
+                               core_cluster_alert: core-cluster-alert {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               core_cluster_crit: core-cluster-crit {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&core_cluster_alert>;
+                                       cooling-device =
+                                               <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+       };
+
        soc: soc {
                compatible = "simple-bus";
                #address-cells = <2>;
                        status = "disabled";
                };
 
-               tmu: tmu@1f00000 {
+               tmu: tmu@1f80000 {
                        compatible = "fsl,qoriq-tmu";
                        reg = <0x0 0x1f80000 0x0 0x10000>;
                        interrupts = <0 23 0x4>;
                        #thermal-sensor-cells = <1>;
                };
 
-               thermal-zones {
-                       core-cluster {
-                               polling-delay-passive = <1000>;
-                               polling-delay = <5000>;
-                               thermal-sensors = <&tmu 0>;
-
-                               trips {
-                                       core_cluster_alert: core-cluster-alert {
-                                               temperature = <85000>;
-                                               hysteresis = <2000>;
-                                               type = "passive";
-                                       };
-
-                                       core_cluster_crit: core-cluster-crit {
-                                               temperature = <95000>;
-                                               hysteresis = <2000>;
-                                               type = "critical";
-                                       };
-                               };
-
-                               cooling-maps {
-                                       map0 {
-                                               trip = <&core_cluster_alert>;
-                                               cooling-device =
-                                                       <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                                       };
-                               };
-                       };
-               };
-
                pcie@1f0000000 { /* Integrated Endpoint Root Complex */
                        compatible = "pci-host-ecam-generic";
                        reg = <0x01 0xf0000000 0x0 0x100000>;
                interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
                             <0 223 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-names = "DE", "SE";
-               clocks = <&dpclk 0>, <&aclk>, <&aclk>, <&pclk>;
+               clocks = <&dpclk>, <&clockgen 2 2>, <&clockgen 2 2>,
+                        <&clockgen 2 2>;
                clock-names = "pxlclk", "mclk", "aclk", "pclk";
                arm,malidp-output-port-lines = /bits/ 8 <8 8 8>;
                arm,malidp-arqos-value = <0xd000d000>;
index 6a6514d..0c742be 100644 (file)
        };
 };
 
+&usb1 {
+       dr_mode = "otg";
+};
+
 #include "fsl-ls1046-post.dtsi"
 
 &fman0 {
index 8e925df..90b1989 100644 (file)
@@ -95,5 +95,6 @@
 };
 
 &usb1 {
+       dr_mode = "otg";
        status = "okay";
 };
index b032f38..e883fe0 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
 
 /memreserve/ 0x80000000 0x00010000;
 
@@ -20,7 +21,7 @@
                #size-cells = <0>;
 
                // 8 clusters having 2 Cortex-A72 cores each
-               cpu@0 {
+               cpu0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster0_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@1 {
+               cpu1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster0_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@100 {
+               cpu100: cpu@100 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster1_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@101 {
+               cpu101: cpu@101 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster1_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@200 {
+               cpu200: cpu@200 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster2_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@201 {
+               cpu201: cpu@201 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster2_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@300 {
+               cpu300: cpu@300 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster3_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@301 {
+               cpu301: cpu@301 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster3_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@400 {
+               cpu400: cpu@400 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster4_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@401 {
+               cpu401: cpu@401 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster4_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@500 {
+               cpu500: cpu@500 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster5_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@501 {
+               cpu501: cpu@501 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster5_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@600 {
+               cpu600: cpu@600 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster6_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@601 {
+               cpu601: cpu@601 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster6_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@700 {
+               cpu700: cpu@700 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster7_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
-               cpu@701 {
+               cpu701: cpu@701 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        enable-method = "psci";
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster7_l2>;
                        cpu-idle-states = <&cpu_pw15>;
+                       #cooling-cells = <2>;
                };
 
                cluster0_l2: l2-cache0 {
                clock-output-names = "sysclk";
        };
 
+       thermal-zones {
+               core_thermal1: core-thermal1 {
+                       polling-delay-passive = <1000>;
+                       polling-delay = <5000>;
+                       thermal-sensors = <&tmu 0>;
+
+                       trips {
+                               core_cluster_alert: core-cluster-alert {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               core_cluster_crit: core-cluster-crit {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&core_cluster_alert>;
+                                       cooling-device =
+                                               <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu200 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu201 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu300 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu301 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu400 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu401 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu500 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu501 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu600 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu601 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu700 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&cpu701 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+       };
+
        soc {
                compatible = "simple-bus";
                #address-cells = <2>;
                        little-endian;
                };
 
+               tmu: tmu@1f80000 {
+                       compatible = "fsl,qoriq-tmu";
+                       reg = <0x0 0x1f80000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                       fsl,tmu-range = <0x800000e6 0x8001017d>;
+                       fsl,tmu-calibration =
+                               /* Calibration data group 1 */
+                               <0x00000000 0x00000035
+                               /* Calibration data group 2 */
+                               0x00010001 0x00000154>;
+                       little-endian;
+                       #thermal-sensor-cells = <1>;
+               };
+
                i2c0: i2c@2000000 {
                        compatible = "fsl,vf610-i2c";
                        #address-cells = <1>;
                        reg = <0x0 0x2140000 0x0 0x10000>;
                        interrupts = <0 28 0x4>; /* Level high type */
                        clocks = <&clockgen 4 1>;
+                       dma-coherent;
                        voltage-ranges = <1800 1800 3300 3300>;
                        sdhci,auto-cmd12;
                        little-endian;
                        reg = <0x0 0x2150000 0x0 0x10000>;
                        interrupts = <0 63 0x4>; /* Level high type */
                        clocks = <&clockgen 4 1>;
+                       dma-coherent;
                        voltage-ranges = <1800 1800 3300 3300>;
                        sdhci,auto-cmd12;
                        broken-cd;
index f7a15f3..28ab17a 100644 (file)
@@ -62,6 +62,8 @@
 
                cpudai: simple-audio-card,cpu {
                        sound-dai = <&sai3>;
+                       dai-tdm-slot-num = <2>;
+                       dai-tdm-slot-width = <32>;
                };
 
                simple-audio-card,codec {
        };
 };
 
-&sai3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_sai3>;
-       assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
-       assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
-       assigned-clock-rates = <24576000>;
-       status = "okay";
-};
-
-&snvs_pwrkey {
-       status = "okay";
-};
-
-&uart2 { /* console */
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart2>;
-       status = "okay";
-};
-
-&usbotg1 {
-       dr_mode = "otg";
-       hnp-disable;
-       srp-disable;
-       adp-disable;
-       usb-role-switch;
-       status = "okay";
-
-       port {
-               usb1_drd_sw: endpoint {
-                       remote-endpoint = <&typec1_dr_sw>;
-               };
-       };
-};
-
-&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";
-};
-
 &i2c1 {
        clock-frequency = <400000>;
        pinctrl-names = "default";
        };
 };
 
+&i2c3 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       pca6416: gpio@20 {
+               compatible = "ti,tca6416";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+};
+
+&sai3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai3>;
+       assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
+       assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
+&uart2 { /* console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&usbotg1 {
+       dr_mode = "otg";
+       hnp-disable;
+       srp-disable;
+       adp-disable;
+       usb-role-switch;
+       status = "okay";
+
+       port {
+               usb1_drd_sw: endpoint {
+                       remote-endpoint = <&typec1_dr_sw>;
+               };
+       };
+};
+
+&usdhc2 {
+       assigned-clocks = <&clk IMX8MM_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
+       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 {
+       assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>;
+       assigned-clock-rates = <400000000>;
+       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_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL                  0x400001c3
+                       MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA                  0x400001c3
+               >;
+       };
+
        pinctrl_pmic: pmicirq {
                fsl,pins = <
                        MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x41
index 23c8fad..6edbdfe 100644 (file)
@@ -12,7 +12,6 @@
 #include "imx8mm-pinfunc.h"
 
 / {
-       compatible = "fsl,imx8mm";
        interrupt-parent = <&gic>;
        #address-cells = <2>;
        #size-cells = <2>;
                        };
 
                        ocotp: ocotp-ctrl@30350000 {
-                               compatible = "fsl,imx8mm-ocotp", "fsl,imx7d-ocotp", "syscon";
+                               compatible = "fsl,imx8mm-ocotp", "syscon";
                                reg = <0x30350000 0x10000>;
                                clocks = <&clk IMX8MM_CLK_OCOTP_ROOT>;
                                /* For nvmem subnodes */
                                                <&clk IMX8MM_CLK_AUDIO_AHB>,
                                                <&clk IMX8MM_CLK_IPG_AUDIO_ROOT>,
                                                <&clk IMX8MM_SYS_PLL3>,
-                                               <&clk IMX8MM_VIDEO_PLL1>;
+                                               <&clk IMX8MM_VIDEO_PLL1>,
+                                               <&clk IMX8MM_AUDIO_PLL1>,
+                                               <&clk IMX8MM_AUDIO_PLL2>;
                                assigned-clock-parents = <&clk IMX8MM_SYS_PLL3_OUT>,
                                                         <&clk IMX8MM_SYS_PLL1_800M>;
                                assigned-clock-rates = <0>,
                                                        <400000000>,
                                                        <400000000>,
                                                        <750000000>,
-                                                       <594000000>;
+                                                       <594000000>,
+                                                       <393216000>,
+                                                       <361267200>;
                        };
 
                        src: reset-controller@30390000 {
                                         <&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>;
                                         <&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>;
index 11c705d..0719494 100644 (file)
 /dts-v1/;
 
 #include "imx8mn.dtsi"
+#include "imx8mn-evk.dtsi"
 
 / {
        model = "NXP i.MX8MNano DDR4 EVK board";
        compatible = "fsl,imx8mn-ddr4-evk", "fsl,imx8mn";
-
-       chosen {
-               stdout-path = &uart2;
-       };
-
-       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;
-       };
 };
 
 &A53_0 {
        cpu-supply = <&buck2_reg>;
 };
 
-&iomuxc {
-       pinctrl-names = "default";
-
-       pinctrl_fec1: fec1grp {
-               fsl,pins = <
-                       MX8MN_IOMUXC_ENET_MDC_ENET1_MDC         0x3
-                       MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO       0x3
-                       MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3   0x1f
-                       MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2   0x1f
-                       MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1   0x1f
-                       MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0   0x1f
-                       MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3   0x91
-                       MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2   0x91
-                       MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1   0x91
-                       MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0   0x91
-                       MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC   0x1f
-                       MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC   0x91
-                       MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91
-                       MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f
-                       MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22        0x19
-               >;
-       };
-
-       pinctrl_i2c1: i2c1grp {
-               fsl,pins = <
-                       MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL          0x400001c3
-                       MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA          0x400001c3
-               >;
-       };
-
-       pinctrl_pmic: pmicirq {
-               fsl,pins = <
-                       MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3       0x41
-               >;
-       };
-
-       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
-               fsl,pins = <
-                       MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19     0x41
-               >;
-       };
-
-       pinctrl_uart2: uart2grp {
-               fsl,pins = <
-                       MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX     0x140
-                       MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX     0x140
-               >;
-       };
-
-       pinctrl_usdhc2_gpio: usdhc2grpgpio {
-               fsl,pins = <
-                       MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15      0x1c4
-               >;
-       };
-
-       pinctrl_usdhc2: usdhc2grp {
-               fsl,pins = <
-                       MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK         0x190
-                       MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d0
-                       MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d0
-                       MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d0
-                       MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d0
-                       MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d0
-                       MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
-               >;
-       };
-
-       pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
-               fsl,pins = <
-                       MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK         0x194
-                       MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d4
-                       MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d4
-                       MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d4
-                       MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d4
-                       MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d4
-                       MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
-               >;
-       };
-
-       pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
-               fsl,pins = <
-                       MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK         0x196
-                       MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d6
-                       MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d6
-                       MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d6
-                       MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d6
-                       MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d6
-                       MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
-               >;
-       };
-
-       pinctrl_usdhc3: usdhc3grp {
-               fsl,pins = <
-                       MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK               0x40000190
-                       MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d0
-                       MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d0
-                       MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d0
-                       MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d0
-                       MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d0
-                       MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d0
-                       MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d0
-                       MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d0
-                       MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d0
-                       MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x190
-               >;
-       };
-
-       pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
-               fsl,pins = <
-                       MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK               0x40000194
-                       MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d4
-                       MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d4
-                       MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d4
-                       MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d4
-                       MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d4
-                       MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d4
-                       MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d4
-                       MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d4
-                       MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d4
-                       MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x194
-               >;
-       };
-
-       pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
-               fsl,pins = <
-                       MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK               0x40000196
-                       MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d6
-                       MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d6
-                       MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d6
-                       MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d6
-                       MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d6
-                       MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d6
-                       MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d6
-                       MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d6
-                       MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d6
-                       MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x196
-               >;
-       };
-
-       pinctrl_wdog: wdoggrp {
-               fsl,pins = <
-                       MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B            0xc6
-               >;
-       };
-};
-
-&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-disabled;
-                       at803x,vddio-1p8v;
-               };
-       };
-};
-
 &i2c1 {
-       clock-frequency = <400000>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c1>;
-       status = "okay";
-
        pmic@4b {
                compatible = "rohm,bd71847";
                reg = <0x4b>;
        };
 };
 
-&snvs_pwrkey {
-       status = "okay";
-};
-
-&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_pmic: pmicirq {
+               fsl,pins = <
+                       MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3       0x41
+               >;
+       };
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dts b/arch/arm64/boot/dts/freescale/imx8mn-evk.dts
new file mode 100644 (file)
index 0000000..61f3519
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+/dts-v1/;
+
+#include "imx8mn.dtsi"
+#include "imx8mn-evk.dtsi"
+
+/ {
+       model = "NXP i.MX8MNano EVK board";
+       compatible = "fsl,imx8mn-evk", "fsl,imx8mn";
+};
+
+&A53_0 {
+       /delete-property/operating-points-v2;
+};
+
+&A53_1 {
+       /delete-property/operating-points-v2;
+};
+
+&A53_2 {
+       /delete-property/operating-points-v2;
+};
+
+&A53_3 {
+       /delete-property/operating-points-v2;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
new file mode 100644 (file)
index 0000000..2a74330
--- /dev/null
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+#include "imx8mn.dtsi"
+
+/ {
+       chosen {
+               stdout-path = &uart2;
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_led>;
+
+               status {
+                       label = "yellow: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>;
+               };
+       };
+};
+
+&i2c1 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
+&uart2 { /* console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&usdhc2 {
+       assigned-clocks = <&clk IMX8MN_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
+       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 {
+       assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
+       assigned-clock-rates = <400000000>;
+       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 = <
+                       MX8MN_IOMUXC_ENET_MDC_ENET1_MDC         0x3
+                       MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO       0x3
+                       MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3   0x1f
+                       MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2   0x1f
+                       MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1   0x1f
+                       MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0   0x1f
+                       MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3   0x91
+                       MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2   0x91
+                       MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1   0x91
+                       MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0   0x91
+                       MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC   0x1f
+                       MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC   0x91
+                       MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91
+                       MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f
+                       MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22        0x19
+               >;
+       };
+
+       pinctrl_gpio_led: gpioledgrp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_NAND_READY_B_GPIO3_IO16    0x19
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL          0x400001c3
+                       MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA          0x400001c3
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
+               fsl,pins = <
+                       MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19     0x41
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX     0x140
+                       MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX     0x140
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2grpgpio {
+               fsl,pins = <
+                       MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15      0x1c4
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK         0x190
+                       MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d0
+                       MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d0
+                       MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d0
+                       MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d0
+                       MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d0
+                       MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+               fsl,pins = <
+                       MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK         0x194
+                       MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d4
+                       MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d4
+                       MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d4
+                       MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d4
+                       MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d4
+                       MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+               fsl,pins = <
+                       MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK         0x196
+                       MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d6
+                       MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d6
+                       MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d6
+                       MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d6
+                       MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d6
+                       MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK               0x40000190
+                       MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d0
+                       MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d0
+                       MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d0
+                       MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d0
+                       MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d0
+                       MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d0
+                       MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d0
+                       MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d0
+                       MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d0
+                       MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x190
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
+               fsl,pins = <
+                       MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK               0x40000194
+                       MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d4
+                       MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d4
+                       MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d4
+                       MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d4
+                       MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d4
+                       MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d4
+                       MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d4
+                       MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d4
+                       MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d4
+                       MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x194
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
+               fsl,pins = <
+                       MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK               0x40000196
+                       MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d6
+                       MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d6
+                       MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d6
+                       MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d6
+                       MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d6
+                       MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d6
+                       MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d6
+                       MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d6
+                       MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d6
+                       MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x196
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B            0xc6
+               >;
+       };
+};
index 43c4db3..e916250 100644 (file)
@@ -11,7 +11,6 @@
 #include "imx8mn-pinfunc.h"
 
 / {
-       compatible = "fsl,imx8mn";
        interrupt-parent = <&gic>;
        #address-cells = <2>;
        #size-cells = <2>;
                #address-cells = <1>;
                #size-cells = <0>;
 
+               idle-states {
+                       entry-method = "psci";
+
+                       cpu_pd_wait: cpu-pd-wait {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010033>;
+                               local-timer-stop;
+                               entry-latency-us = <1000>;
+                               exit-latency-us = <700>;
+                               min-residency-us = <2700>;
+                       };
+               };
+
                A53_0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a53";
@@ -54,6 +66,7 @@
                        operating-points-v2 = <&a53_opp_table>;
                        nvmem-cells = <&cpu_speed_grade>;
                        nvmem-cell-names = "speed_grade";
+                       cpu-idle-states = <&cpu_pd_wait>;
                };
 
                A53_1: cpu@1 {
@@ -65,6 +78,7 @@
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
                        operating-points-v2 = <&a53_opp_table>;
+                       cpu-idle-states = <&cpu_pd_wait>;
                };
 
                A53_2: cpu@2 {
@@ -76,6 +90,7 @@
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
                        operating-points-v2 = <&a53_opp_table>;
+                       cpu-idle-states = <&cpu_pd_wait>;
                };
 
                A53_3: cpu@3 {
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
                        operating-points-v2 = <&a53_opp_table>;
+                       cpu-idle-states = <&cpu_pd_wait>;
                };
 
                A53_L2: l2-cache0 {
                        };
 
                        ocotp: ocotp-ctrl@30350000 {
-                               compatible = "fsl,imx8mn-ocotp", "fsl,imx7d-ocotp", "syscon";
+                               compatible = "fsl,imx8mn-ocotp", "fsl,imx8mm-ocotp", "syscon";
                                reg = <0x30350000 0x10000>;
                                clocks = <&clk IMX8MN_CLK_OCOTP_ROOT>;
                                #address-cells = <1>;
                        };
 
                        src: reset-controller@30390000 {
-                               compatible = "fsl,imx8mn-src", "syscon";
+                               compatible = "fsl,imx8mn-src", "fsl,imx8mq-src", "syscon";
                                reg = <0x30390000 0x10000>;
                                interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
                                #reset-cells = <1>;
                                #pwm-cells = <2>;
                                status = "disabled";
                        };
+
+                       system_counter: timer@306a0000 {
+                               compatible = "nxp,sysctr-timer";
+                               reg = <0x306a0000 0x20000>;
+                               interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&osc_24m>;
+                               clock-names = "per";
+                       };
                };
 
                aips3: bus@30800000 {
                                         <&clk IMX8MN_CLK_NAND_USDHC_BUS>,
                                         <&clk IMX8MN_CLK_USDHC1_ROOT>;
                                clock-names = "ipg", "ahb", "per";
-                               assigned-clocks = <&clk IMX8MN_CLK_USDHC1>;
-                               assigned-clock-rates = <400000000>;
                                fsl,tuning-start-tap = <20>;
                                fsl,tuning-step= <2>;
                                bus-width = <4>;
                                         <&clk IMX8MN_CLK_NAND_USDHC_BUS>,
                                         <&clk IMX8MN_CLK_USDHC3_ROOT>;
                                clock-names = "ipg", "ahb", "per";
-                               assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
-                               assigned-clock-rates = <400000000>;
                                fsl,tuning-start-tap = <20>;
                                fsl,tuning-step= <2>;
                                bus-width = <4>;
                        interrupt-controller;
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
                };
+
+               ddr-pmu@3d800000 {
+                       compatible = "fsl,imx8mn-ddr-pmu", "fsl,imx8m-ddr-pmu";
+                       reg = <0x3d800000 0x400000>;
+                       interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+               };
        };
 
        usbphynop1: usbphynop1 {
index 0595812..c366859 100644 (file)
                gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
                states = <1000000 0x0
                          900000 0x1>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       ir-receiver {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ir>;
        };
 
        wm8524: audio-codec {
        };
 };
 
-&sai2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_sai2>;
-       assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1_BYPASS>, <&clk IMX8MQ_CLK_SAI2>;
-       assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL1_OUT>;
-       assigned-clock-rates = <0>, <24576000>;
-       status = "okay";
-};
-
 &gpio5 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_wifi_reset>;
        power-supply = <&sw1a_reg>;
 };
 
+&qspi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+       status = "okay";
+
+       n25q256a: flash@0 {
+               reg = <0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "micron,n25q256a", "jedec,spi-nor";
+               spi-max-frequency = <29000000>;
+       };
+};
+
+&sai2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai2>;
+       assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1_BYPASS>, <&clk IMX8MQ_CLK_SAI2>;
+       assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <0>, <24576000>;
+       status = "okay";
+};
+
 &snvs_pwrkey {
        status = "okay";
 };
        status = "okay";
 };
 
-&qspi0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_qspi>;
-       status = "okay";
-
-       n25q256a: flash@0 {
-               reg = <0>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "micron,n25q256a", "jedec,spi-nor";
-               spi-max-frequency = <29000000>;
-       };
-};
-
 &usdhc1 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+       assigned-clock-rates = <400000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc1>;
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
 };
 
 &usdhc2 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc2>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
                >;
        };
 
+       pinctrl_ir: irgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12              0x4f
+               >;
+       };
+
        pinctrl_pcie0: pcie0grp {
                fsl,pins = <
                        MX8MQ_IOMUXC_I2C4_SCL_PCIE1_CLKREQ_B            0x76
index f52e872..b8cb20c 100644 (file)
 };
 
 &usdhc2 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
index 683a110..2a759df 100644 (file)
 };
 
 &usdhc1 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+       assigned-clock-rates = <400000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc1>;
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
 };
 
 &usdhc2 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc2>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
index c832bf0..81d2692 100644 (file)
 };
 
 &usdhc1 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+       assigned-clock-rates = <400000000>;
        bus-width = <8>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
index 8a4aee2..59da96b 100644 (file)
 };
 
 &usdhc1 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+       assigned-clock-rates = <400000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc1>;
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
 };
 
 &usdhc2 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
index d7f03c6..3dc4411 100644 (file)
 };
 
 &usdhc1 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+       assigned-clock-rates = <400000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc1>;
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
index 32ce149..6a55165 100644 (file)
        reg_3p3_main: regulator-3p3-main {
                compatible = "regulator-fixed";
                vin-supply = <&reg_12p0_main>;
-               regulator-name = "3V3V_MAIN";
+               regulator-name = "3V3_MAIN";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_gen_3p3: regulator-gen-3p3 {
+               compatible = "regulator-fixed";
+               vin-supply = <&reg_3p3_main>;
+               regulator-name = "GEN_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                regulator-always-on;
@@ -72,7 +81,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_reg_usdhc2>;
                compatible = "regulator-fixed";
-               vin-supply = <&reg_3p3_main>;
+               vin-supply = <&reg_gen_3p3>;
                regulator-name = "3V3_SD";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
 
+       accelerometer@1c {
+               compatible = "fsl,mma8451";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_accel>;
+               reg = <0x1c>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-names = "INT2";
+               vdd-supply = <&reg_gen_3p3>;
+               vddio-supply = <&reg_gen_3p3>;
+       };
+
        ucs1002: charger@32 {
                compatible = "microchip,ucs1002";
                pinctrl-names = "default";
                reg = <0x2c>;
                reset-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
        };
+
+       watchdog@38 {
+               compatible = "zii,rave-wdt";
+               reg = <0x38>;
+       };
 };
 
 &i2c4 {
 };
 
 &usdhc1 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+       assigned-clock-rates = <400000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc1>;
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
 };
 
 &usdhc2 {
+       assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc2>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
 };
 
 &iomuxc {
+       pinctrl_accel: accelgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI5_RXC_GPIO3_IO20                0x41
+               >;
+       };
+
        pinctrl_fec1: fec1grp {
                fsl,pins = <
                        MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC                 0x3
index 55a3d1c..7f93194 100644 (file)
                        thermal-sensors = <&tmu 1>;
 
                        trips {
+                               gpu_alert: gpu-alert {
+                                       temperature = <80000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
                                gpu-crit {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                };
                        };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_alert>;
+                                       cooling-device =
+                                               <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
                };
 
                vpu-thermal {
                                         <&clk IMX8MQ_CLK_NAND_USDHC_BUS>,
                                         <&clk IMX8MQ_CLK_USDHC1_ROOT>;
                                clock-names = "ipg", "ahb", "per";
-                               assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
-                               assigned-clock-rates = <400000000>;
                                fsl,tuning-start-tap = <20>;
                                fsl,tuning-step = <2>;
                                bus-width = <4>;
                                 <&clk IMX8MQ_CLK_GPU_AXI>,
                                 <&clk IMX8MQ_CLK_GPU_AHB>;
                        clock-names = "core", "shader", "bus", "reg";
+                       #cooling-cells = <2>;
                        assigned-clocks = <&clk IMX8MQ_CLK_GPU_CORE_SRC>,
                                          <&clk IMX8MQ_CLK_GPU_SHADER_SRC>,
                                          <&clk IMX8MQ_CLK_GPU_AXI>,
index 91eef97..a3f8cf1 100644 (file)
 &usdhc1 {
        #address-cells = <1>;
        #size-cells = <0>;
+       assigned-clocks = <&clk IMX_CONN_SDHC0_CLK>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
        bus-width = <4>;
 
 /* SD */
 &usdhc2 {
+       assigned-clocks = <&clk IMX_CONN_SDHC1_CLK>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dts b/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dts
new file mode 100644 (file)
index 0000000..6b21a29
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Copyright 2019 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qxp-colibri.dtsi"
+#include "imx8qxp-colibri-eval-v3.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX8QXP/DX on Colibri Evaluation Board V3";
+       compatible = "toradex,colibri-imx8x-eval-v3",
+                    "toradex,colibri-imx8x", "fsl,imx8qxp";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi
new file mode 100644 (file)
index 0000000..c7336f3
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Copyright 2019 Toradex
+ */
+
+#include "dt-bindings/input/linux-event-codes.h"
+
+/ {
+       aliases {
+               rtc0 = &rtc_i2c;
+               rtc1 = &rtc;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiokeys>;
+
+               wakeup {
+                       label = "Wake-Up";
+                       gpios = <&lsio_gpio3 10 GPIO_ACTIVE_HIGH>;
+                       linux,code = <KEY_WAKEUP>;
+                       debounce-interval = <10>;
+                       wakeup-source;
+               };
+       };
+};
+
+&adma_i2c1 {
+       status = "okay";
+
+       /* M41T0M6 real time clock on carrier board */
+       rtc_i2c: rtc@68 {
+               compatible = "st,m41t0";
+               reg = <0x68>;
+       };
+};
+
+/* Colibri UART_B */
+&adma_lpuart0 {
+       status= "okay";
+};
+
+/* Colibri UART_C */
+&adma_lpuart2 {
+       status= "okay";
+};
+
+/* Colibri UART_A */
+&adma_lpuart3 {
+       status= "okay";
+};
+
+/* Colibri FastEthernet */
+&fec1 {
+       status = "okay";
+};
+
+/* Colibri SD/MMC Card */
+&usdhc2 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-colibri.dtsi
new file mode 100644 (file)
index 0000000..75f17a2
--- /dev/null
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Copyright 2019 Toradex
+ */
+
+#include "imx8qxp.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX8QXP/DX Module";
+       compatible = "toradex,colibri-imx8x", "fsl,imx8qxp";
+
+       chosen {
+               stdout-path = &adma_lpuart3;
+       };
+
+       reg_module_3v3: regulator-module-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "+V3.3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+};
+
+/* On-module I2C */
+&adma_i2c0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c0>, <&pinctrl_sgtl5000_usb_clk>;
+       status = "okay";
+
+       /* Touch controller */
+       touchscreen@2c {
+               compatible = "adi,ad7879-1";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ad7879_int>;
+               reg = <0x2c>;
+               interrupt-parent = <&lsio_gpio3>;
+               interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+               touchscreen-max-pressure = <4096>;
+               adi,resistance-plate-x = <120>;
+               adi,first-conversion-delay = /bits/ 8 <3>;
+               adi,acquisition-time = /bits/ 8 <1>;
+               adi,median-filter-size = /bits/ 8 <2>;
+               adi,averaging = /bits/ 8 <1>;
+               adi,conversion-interval = /bits/ 8 <255>;
+       };
+};
+
+/* Colibri I2C */
+&adma_i2c1 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+};
+
+/* Colibri UART_B */
+&adma_lpuart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpuart0>;
+};
+
+/* Colibri UART_C */
+&adma_lpuart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpuart2>;
+};
+
+/* Colibri UART_A */
+&adma_lpuart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpuart3>, <&pinctrl_lpuart3_ctrl>;
+};
+
+/* Colibri FastEthernet */
+&fec1 {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&pinctrl_fec1>;
+       pinctrl-1 = <&pinctrl_fec1_sleep>;
+       phy-mode = "rmii";
+       phy-handle = <&ethphy0>;
+       fsl,magic-packet;
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy0: ethernet-phy@2 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       max-speed = <100>;
+                       reg = <2>;
+               };
+       };
+};
+
+/* On-module eMMC */
+&usdhc1 {
+       bus-width = <8>;
+       non-removable;
+       no-sd;
+       no-sdio;
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+       status = "okay";
+};
+
+/* Colibri SD/MMC Card */
+&usdhc2 {
+       bus-width = <4>;
+       cd-gpios = <&lsio_gpio3 9 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&reg_module_3v3>;
+       pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+       pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
+       disable-wp;
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ext_io0>, <&pinctrl_hog0>, <&pinctrl_hog1>;
+
+       /* On-module touch pen-down interrupt */
+       pinctrl_ad7879_int: ad7879intgrp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_CSI0_I2C0_SCL_LSIO_GPIO3_IO05      0x21
+               >;
+       };
+
+       /* Colibri Analogue Inputs */
+       pinctrl_adc0: adc0grp {
+               fsl,pins = <
+                       IMX8QXP_ADC_IN0_ADMA_ADC_IN0                    0x60            /* SODIMM   8 */
+                       IMX8QXP_ADC_IN1_ADMA_ADC_IN1                    0x60            /* SODIMM   6 */
+                       IMX8QXP_ADC_IN4_ADMA_ADC_IN4                    0x60            /* SODIMM   4 */
+                       IMX8QXP_ADC_IN5_ADMA_ADC_IN5                    0x60            /* SODIMM   2 */
+               >;
+       };
+
+       pinctrl_can_int: canintgrp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_DQS_LSIO_GPIO3_IO13              0x40            /* SODIMM  73 */
+               >;
+       };
+
+       pinctrl_csi_ctl: csictlgrp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_SS0_B_LSIO_GPIO3_IO14            0x20            /* SODIMM  77 */
+                       IMX8QXP_QSPI0A_SS1_B_LSIO_GPIO3_IO15            0x20            /* SODIMM  89 */
+               >;
+       };
+
+       pinctrl_ext_io0: extio0grp {
+               fsl,pins = <
+                       IMX8QXP_ENET0_RGMII_RXD3_LSIO_GPIO5_IO08        0x06000040      /* SODIMM 135 */
+               >;
+       };
+
+       /* Colibri Ethernet: On-module 100Mbps PHY Micrel KSZ8041 */
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <
+                       IMX8QXP_ENET0_MDC_CONN_ENET0_MDC                        0x06000020
+                       IMX8QXP_ENET0_MDIO_CONN_ENET0_MDIO                      0x06000020
+                       IMX8QXP_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL      0x61
+                       IMX8QXP_ENET0_RGMII_TXC_CONN_ENET0_RCLK50M_OUT          0x06000061
+                       IMX8QXP_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0          0x61
+                       IMX8QXP_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1          0x61
+                       IMX8QXP_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL      0x61
+                       IMX8QXP_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0          0x61
+                       IMX8QXP_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1          0x61
+                       IMX8QXP_ENET0_RGMII_RXD2_CONN_ENET0_RMII_RX_ER          0x61
+               >;
+       };
+
+       pinctrl_fec1_sleep: fec1slpgrp {
+               fsl,pins = <
+                       IMX8QXP_ENET0_MDC_LSIO_GPIO5_IO11               0x06000041
+                       IMX8QXP_ENET0_MDIO_LSIO_GPIO5_IO10              0x06000041
+                       IMX8QXP_ENET0_RGMII_TX_CTL_LSIO_GPIO4_IO30      0x41
+                       IMX8QXP_ENET0_RGMII_TXC_LSIO_GPIO4_IO29         0x41
+                       IMX8QXP_ENET0_RGMII_TXD0_LSIO_GPIO4_IO31        0x41
+                       IMX8QXP_ENET0_RGMII_TXD1_LSIO_GPIO5_IO00        0x41
+                       IMX8QXP_ENET0_RGMII_RX_CTL_LSIO_GPIO5_IO04      0x41
+                       IMX8QXP_ENET0_RGMII_RXD0_LSIO_GPIO5_IO05        0x41
+                       IMX8QXP_ENET0_RGMII_RXD1_LSIO_GPIO5_IO06        0x41
+                       IMX8QXP_ENET0_RGMII_RXD2_LSIO_GPIO5_IO07        0x41
+               >;
+       };
+
+       /* Colibri optional CAN on UART_B RTS/CTS */
+       pinctrl_flexcan1: flexcan0grp {
+               fsl,pins = <
+                       IMX8QXP_FLEXCAN0_TX_ADMA_FLEXCAN0_TX            0x21            /* SODIMM  32 */
+                       IMX8QXP_FLEXCAN0_RX_ADMA_FLEXCAN0_RX            0x21            /* SODIMM  34 */
+               >;
+       };
+
+       /* Colibri optional CAN on PS2 */
+       pinctrl_flexcan2: flexcan1grp {
+               fsl,pins = <
+                       IMX8QXP_FLEXCAN1_TX_ADMA_FLEXCAN1_TX            0x21            /* SODIMM  55 */
+                       IMX8QXP_FLEXCAN1_RX_ADMA_FLEXCAN1_RX            0x21            /* SODIMM  63 */
+               >;
+       };
+
+       /* Colibri optional CAN on UART_A TXD/RXD */
+       pinctrl_flexcan3: flexcan2grp {
+               fsl,pins = <
+                       IMX8QXP_FLEXCAN2_TX_ADMA_FLEXCAN2_TX            0x21            /* SODIMM  35 */
+                       IMX8QXP_FLEXCAN2_RX_ADMA_FLEXCAN2_RX            0x21            /* SODIMM  33 */
+               >;
+       };
+
+       /* Colibri LCD Back-Light GPIO */
+       pinctrl_gpio_bl_on: gpioblongrp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_DATA3_LSIO_GPIO3_IO12            0x60            /* SODIMM  71 */
+               >;
+       };
+
+       pinctrl_gpiokeys: gpiokeysgrp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_DATA1_LSIO_GPIO3_IO10            0x06700041      /* SODIMM  45 */
+               >;
+       };
+
+       pinctrl_hog0: hog0grp {
+               fsl,pins = <
+                       IMX8QXP_ENET0_RGMII_TXD3_LSIO_GPIO5_IO02        0x06000020      /* SODIMM  65 */
+                       IMX8QXP_CSI_D07_CI_PI_D09                       0x61            /* SODIMM  65 */
+                       IMX8QXP_QSPI0A_DATA2_LSIO_GPIO3_IO11            0x20            /* SODIMM  69 */
+                       IMX8QXP_SAI0_TXC_LSIO_GPIO0_IO26                0x20            /* SODIMM  79 */
+                       IMX8QXP_CSI_D02_CI_PI_D04                       0x61            /* SODIMM  79 */
+                       IMX8QXP_ENET0_RGMII_RXC_LSIO_GPIO5_IO03         0x06000020      /* SODIMM  85 */
+                       IMX8QXP_CSI_D06_CI_PI_D08                       0x61            /* SODIMM  85 */
+                       IMX8QXP_QSPI0B_SCLK_LSIO_GPIO3_IO17             0x20            /* SODIMM  95 */
+                       IMX8QXP_SAI0_RXD_LSIO_GPIO0_IO27                0x20            /* SODIMM  97 */
+                       IMX8QXP_CSI_D03_CI_PI_D05                       0x61            /* SODIMM  97 */
+                       IMX8QXP_QSPI0B_DATA0_LSIO_GPIO3_IO18            0x20            /* SODIMM  99 */
+                       IMX8QXP_SAI0_TXFS_LSIO_GPIO0_IO28               0x20            /* SODIMM 101 */
+                       IMX8QXP_CSI_D00_CI_PI_D02                       0x61            /* SODIMM 101 */
+                       IMX8QXP_SAI0_TXD_LSIO_GPIO0_IO25                0x20            /* SODIMM 103 */
+                       IMX8QXP_CSI_D01_CI_PI_D03                       0x61            /* SODIMM 103 */
+                       IMX8QXP_QSPI0B_DATA1_LSIO_GPIO3_IO19            0x20            /* SODIMM 105 */
+                       IMX8QXP_QSPI0B_DATA2_LSIO_GPIO3_IO20            0x20            /* SODIMM 107 */
+                       IMX8QXP_USB_SS3_TC2_LSIO_GPIO4_IO05             0x20            /* SODIMM 127 */
+                       IMX8QXP_USB_SS3_TC3_LSIO_GPIO4_IO06             0x20            /* SODIMM 131 */
+                       IMX8QXP_USB_SS3_TC1_LSIO_GPIO4_IO04             0x20            /* SODIMM 133 */
+                       IMX8QXP_CSI_PCLK_LSIO_GPIO3_IO00                0x20            /* SODIMM  96 */
+                       IMX8QXP_QSPI0B_DATA3_LSIO_GPIO3_IO21            0x20            /* SODIMM  98 */
+                       IMX8QXP_SAI1_RXFS_LSIO_GPIO0_IO31               0x20            /* SODIMM 100 */
+                       IMX8QXP_QSPI0B_DQS_LSIO_GPIO3_IO22              0x20            /* SODIMM 102 */
+                       IMX8QXP_QSPI0B_SS0_B_LSIO_GPIO3_IO23            0x20            /* SODIMM 104 */
+                       IMX8QXP_QSPI0B_SS1_B_LSIO_GPIO3_IO24            0x20            /* SODIMM 106 */
+               >;
+       };
+
+       pinctrl_hog1: hog1grp {
+               fsl,pins = <
+                       IMX8QXP_CSI_MCLK_LSIO_GPIO3_IO01                0x20            /* SODIMM  75 */
+                       IMX8QXP_QSPI0A_SCLK_LSIO_GPIO3_IO16             0x20            /* SODIMM  93 */
+               >;
+       };
+
+       /*
+        * This pin is used in the SCFW as a UART. Using it from
+        * Linux would require rewritting the SCFW board file.
+        */
+       pinctrl_hog_scfw: hogscfwgrp {
+               fsl,pins = <
+                       IMX8QXP_SCU_GPIO0_00_LSIO_GPIO2_IO03            0x20            /* SODIMM 144 */
+               >;
+       };
+
+       /* On Module I2C */
+       pinctrl_i2c0: i2c0grp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_CSI0_GPIO0_00_ADMA_I2C0_SCL        0x06000021
+                       IMX8QXP_MIPI_CSI0_GPIO0_01_ADMA_I2C0_SDA        0x06000021
+               >;
+       };
+
+       /* MIPI DSI I2C accessible on SODIMM (X1) and FFC (X2) */
+       pinctrl_i2c0_mipi_lvds0: i2c0mipilvds0grp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_DSI0_I2C0_SCL_MIPI_DSI0_I2C0_SCL   0xc6000020      /* SODIMM 140 */
+                       IMX8QXP_MIPI_DSI0_I2C0_SDA_MIPI_DSI0_I2C0_SDA   0xc6000020      /* SODIMM 142 */
+               >;
+       };
+
+       /* MIPI CSI I2C accessible on SODIMM (X1) and FFC (X3) */
+       pinctrl_i2c0_mipi_lvds1: i2c0mipilvds1grp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_DSI1_I2C0_SCL_MIPI_DSI1_I2C0_SCL   0xc6000020      /* SODIMM 186 */
+                       IMX8QXP_MIPI_DSI1_I2C0_SDA_MIPI_DSI1_I2C0_SDA   0xc6000020      /* SODIMM 188 */
+               >;
+       };
+
+       /* Colibri I2C */
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_DSI0_GPIO0_00_ADMA_I2C1_SCL        0x06000021      /* SODIMM 196 */
+                       IMX8QXP_MIPI_DSI0_GPIO0_01_ADMA_I2C1_SDA        0x06000021      /* SODIMM 194 */
+               >;
+       };
+
+       /* Colibri Parallel RGB LCD Interface */
+       pinctrl_lcdif: lcdifgrp {
+               fsl,pins = <
+                       IMX8QXP_MCLK_OUT0_ADMA_LCDIF_CLK                0x60            /* SODIMM  56 */
+                       IMX8QXP_SPI3_CS0_ADMA_LCDIF_HSYNC               0x60            /* SODIMM  68 */
+                       IMX8QXP_MCLK_IN0_ADMA_LCDIF_VSYNC               0x60            /* SODIMM  82 */
+                       IMX8QXP_MCLK_IN1_ADMA_LCDIF_EN                  0x60            /* SODIMM  44 */
+                       IMX8QXP_USDHC1_RESET_B_LSIO_GPIO4_IO19          0x60            /* SODIMM  44 */
+                       IMX8QXP_ESAI0_FSR_ADMA_LCDIF_D00                0x60            /* SODIMM  76 */
+                       IMX8QXP_USDHC1_WP_LSIO_GPIO4_IO21               0x60            /* SODIMM  76 */
+                       IMX8QXP_ESAI0_FST_ADMA_LCDIF_D01                0x60            /* SODIMM  70 */
+                       IMX8QXP_ESAI0_SCKR_ADMA_LCDIF_D02               0x60            /* SODIMM  60 */
+                       IMX8QXP_ESAI0_SCKT_ADMA_LCDIF_D03               0x60            /* SODIMM  58 */
+                       IMX8QXP_ESAI0_TX0_ADMA_LCDIF_D04                0x60            /* SODIMM  78 */
+                       IMX8QXP_ESAI0_TX1_ADMA_LCDIF_D05                0x60            /* SODIMM  72 */
+                       IMX8QXP_ESAI0_TX2_RX3_ADMA_LCDIF_D06            0x60            /* SODIMM  80 */
+                       IMX8QXP_ESAI0_TX3_RX2_ADMA_LCDIF_D07            0x60            /* SODIMM  46 */
+                       IMX8QXP_ESAI0_TX4_RX1_ADMA_LCDIF_D08            0x60            /* SODIMM  62 */
+                       IMX8QXP_ESAI0_TX5_RX0_ADMA_LCDIF_D09            0x60            /* SODIMM  48 */
+                       IMX8QXP_SPDIF0_RX_ADMA_LCDIF_D10                0x60            /* SODIMM  74 */
+                       IMX8QXP_SPDIF0_TX_ADMA_LCDIF_D11                0x60            /* SODIMM  50 */
+                       IMX8QXP_SPDIF0_EXT_CLK_ADMA_LCDIF_D12           0x60            /* SODIMM  52 */
+                       IMX8QXP_SPI3_SCK_ADMA_LCDIF_D13                 0x60            /* SODIMM  54 */
+                       IMX8QXP_SPI3_SDO_ADMA_LCDIF_D14                 0x60            /* SODIMM  66 */
+                       IMX8QXP_SPI3_SDI_ADMA_LCDIF_D15                 0x60            /* SODIMM  64 */
+                       IMX8QXP_SPI3_CS1_ADMA_LCDIF_D16                 0x60            /* SODIMM  57 */
+                       IMX8QXP_ENET0_RGMII_TXD2_LSIO_GPIO5_IO01        0x60            /* SODIMM  57 */
+                       IMX8QXP_UART1_CTS_B_ADMA_LCDIF_D17              0x60            /* SODIMM  61 */
+               >;
+       };
+
+       /* Colibri SPI */
+       pinctrl_lpspi2: lpspi2grp {
+               fsl,pins = <
+                       IMX8QXP_SPI2_CS0_LSIO_GPIO1_IO00                0x21            /* SODIMM  86 */
+                       IMX8QXP_SPI2_SDO_ADMA_SPI2_SDO                  0x06000040      /* SODIMM  92 */
+                       IMX8QXP_SPI2_SDI_ADMA_SPI2_SDI                  0x06000040      /* SODIMM  90 */
+                       IMX8QXP_SPI2_SCK_ADMA_SPI2_SCK                  0x06000040      /* SODIMM  88 */
+               >;
+       };
+
+       /* Colibri UART_B */
+       pinctrl_lpuart0: lpuart0grp {
+               fsl,pins = <
+                       IMX8QXP_UART0_RX_ADMA_UART0_RX                  0x06000020      /* SODIMM  36 */
+                       IMX8QXP_UART0_TX_ADMA_UART0_TX                  0x06000020      /* SODIMM  38 */
+                       IMX8QXP_FLEXCAN0_RX_ADMA_UART0_RTS_B            0x06000020      /* SODIMM  34 */
+                       IMX8QXP_FLEXCAN0_TX_ADMA_UART0_CTS_B            0x06000020      /* SODIMM  32 */
+               >;
+       };
+
+       /* Colibri UART_C */
+       pinctrl_lpuart2: lpuart2grp {
+               fsl,pins = <
+                       IMX8QXP_UART2_RX_ADMA_UART2_RX                  0x06000020      /* SODIMM  19 */
+                       IMX8QXP_UART2_TX_ADMA_UART2_TX                  0x06000020      /* SODIMM  21 */
+               >;
+       };
+
+       /* Colibri UART_A */
+       pinctrl_lpuart3: lpuart3grp {
+               fsl,pins = <
+                       IMX8QXP_FLEXCAN2_RX_ADMA_UART3_RX               0x06000020      /* SODIMM  33 */
+                       IMX8QXP_FLEXCAN2_TX_ADMA_UART3_TX               0x06000020      /* SODIMM  35 */
+               >;
+       };
+
+       /* Colibri UART_A Control */
+       pinctrl_lpuart3_ctrl: lpuart3ctrlgrp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_DSI1_GPIO0_01_LSIO_GPIO2_IO00      0x20            /* SODIMM  23 */
+                       IMX8QXP_SAI1_RXD_LSIO_GPIO0_IO29                0x20            /* SODIMM  25 */
+                       IMX8QXP_SAI1_RXC_LSIO_GPIO0_IO30                0x20            /* SODIMM  27 */
+                       IMX8QXP_CSI_RESET_LSIO_GPIO3_IO03               0x20            /* SODIMM  29 */
+                       IMX8QXP_USDHC1_CD_B_LSIO_GPIO4_IO22             0x20            /* SODIMM  31 */
+                       IMX8QXP_CSI_EN_LSIO_GPIO3_IO02                  0x20            /* SODIMM  37 */
+               >;
+       };
+
+       /* On module wifi module */
+       pinctrl_pcieb: pciebgrp {
+               fsl,pins = <
+                       IMX8QXP_PCIE_CTRL0_CLKREQ_B_LSIO_GPIO4_IO01     0x04000061      /* SODIMM 178 */
+                       IMX8QXP_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO02       0x04000061      /* SODIMM  94 */
+                       IMX8QXP_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO00      0x60            /* SODIMM  81 */
+               >;
+       };
+
+       /* Colibri PWM_A */
+       pinctrl_pwm_a: pwmagrp {
+       /* both pins are connected together, reserve the unused CSI_D05 */
+               fsl,pins = <
+                       IMX8QXP_CSI_D05_CI_PI_D07                       0x61            /* SODIMM  59 */
+                       IMX8QXP_SPI0_CS1_ADMA_LCD_PWM0_OUT              0x60            /* SODIMM  59 */
+               >;
+       };
+
+       /* Colibri PWM_B */
+       pinctrl_pwm_b: pwmbgrp {
+               fsl,pins = <
+                       IMX8QXP_UART1_TX_LSIO_PWM0_OUT                  0x60            /* SODIMM  28 */
+               >;
+       };
+
+       /* Colibri PWM_C */
+       pinctrl_pwm_c: pwmcgrp {
+               fsl,pins = <
+                       IMX8QXP_UART1_RX_LSIO_PWM1_OUT                  0x60            /* SODIMM  30 */
+               >;
+       };
+
+       /* Colibri PWM_D */
+       pinctrl_pwm_d: pwmdgrp {
+       /* both pins are connected together, reserve the unused CSI_D04 */
+               fsl,pins = <
+                       IMX8QXP_CSI_D04_CI_PI_D06                       0x61            /* SODIMM  67 */
+                       IMX8QXP_UART1_RTS_B_LSIO_PWM2_OUT               0x60            /* SODIMM  67 */
+               >;
+       };
+
+       /* On-module I2S */
+       pinctrl_sai0: sai0grp {
+               fsl,pins = <
+                       IMX8QXP_SPI0_SDI_ADMA_SAI0_TXD                  0x06000040
+                       IMX8QXP_SPI0_CS0_ADMA_SAI0_RXD                  0x06000040
+                       IMX8QXP_SPI0_SCK_ADMA_SAI0_TXC                  0x06000040
+                       IMX8QXP_SPI0_SDO_ADMA_SAI0_TXFS                 0x06000040
+               >;
+       };
+
+       /* Colibri Audio Analogue Microphone GND */
+       pinctrl_sgtl5000: sgtl5000grp {
+               fsl,pins = <
+                       /* MIC GND EN */
+                       IMX8QXP_MIPI_CSI0_I2C0_SDA_LSIO_GPIO3_IO06      0x41
+               >;
+       };
+
+       /* On-module SGTL5000 clock */
+       pinctrl_sgtl5000_usb_clk: sgtl5000usbclkgrp {
+               fsl,pins = <
+                       IMX8QXP_ADC_IN3_ADMA_ACM_MCLK_OUT0              0x21
+               >;
+       };
+
+       /* On-module USB interrupt */
+       pinctrl_usb3503a: usb3503agrp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_CSI0_MCLK_OUT_LSIO_GPIO3_IO04      0x61
+               >;
+       };
+
+       /* Colibri USB Client Cable Detect */
+       pinctrl_usbc_det: usbcdetgrp {
+               fsl,pins = <
+                       IMX8QXP_ENET0_REFCLK_125M_25M_LSIO_GPIO5_IO09   0x06000040      /* SODIMM 137 */
+               >;
+       };
+
+       /* USB Host Power Enable */
+       pinctrl_usbh1_reg: usbh1reggrp {
+               fsl,pins = <
+                       IMX8QXP_USB_SS3_TC0_LSIO_GPIO4_IO03             0x06000040      /* SODIMM 129 */
+               >;
+       };
+
+       /* On-module eMMC */
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK                0x06000041
+                       IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD                0x21
+                       IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0            0x21
+                       IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1            0x21
+                       IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2            0x21
+                       IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3            0x21
+                       IMX8QXP_EMMC0_DATA4_CONN_EMMC0_DATA4            0x21
+                       IMX8QXP_EMMC0_DATA5_CONN_EMMC0_DATA5            0x21
+                       IMX8QXP_EMMC0_DATA6_CONN_EMMC0_DATA6            0x21
+                       IMX8QXP_EMMC0_DATA7_CONN_EMMC0_DATA7            0x21
+                       IMX8QXP_EMMC0_STROBE_CONN_EMMC0_STROBE          0x41
+                       IMX8QXP_EMMC0_RESET_B_CONN_EMMC0_RESET_B        0x21
+               >;
+       };
+
+       pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+               fsl,pins = <
+                       IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK                0x06000041
+                       IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD                0x21
+                       IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0            0x21
+                       IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1            0x21
+                       IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2            0x21
+                       IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3            0x21
+                       IMX8QXP_EMMC0_DATA4_CONN_EMMC0_DATA4            0x21
+                       IMX8QXP_EMMC0_DATA5_CONN_EMMC0_DATA5            0x21
+                       IMX8QXP_EMMC0_DATA6_CONN_EMMC0_DATA6            0x21
+                       IMX8QXP_EMMC0_DATA7_CONN_EMMC0_DATA7            0x21
+                       IMX8QXP_EMMC0_STROBE_CONN_EMMC0_STROBE          0x41
+                       IMX8QXP_EMMC0_RESET_B_CONN_EMMC0_RESET_B        0x21
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+               fsl,pins = <
+                       IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK                0x06000041
+                       IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD                0x21
+                       IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0            0x21
+                       IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1            0x21
+                       IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2            0x21
+                       IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3            0x21
+                       IMX8QXP_EMMC0_DATA4_CONN_EMMC0_DATA4            0x21
+                       IMX8QXP_EMMC0_DATA5_CONN_EMMC0_DATA5            0x21
+                       IMX8QXP_EMMC0_DATA6_CONN_EMMC0_DATA6            0x21
+                       IMX8QXP_EMMC0_DATA7_CONN_EMMC0_DATA7            0x21
+                       IMX8QXP_EMMC0_STROBE_CONN_EMMC0_STROBE          0x41
+                       IMX8QXP_EMMC0_RESET_B_CONN_EMMC0_RESET_B        0x21
+               >;
+       };
+
+       /* Colibri SD/MMC Card Detect */
+       pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_DATA0_LSIO_GPIO3_IO09            0x06000021      /* SODIMM  43 */
+               >;
+       };
+
+       pinctrl_usdhc2_gpio_sleep: usdhc2gpioslpgrp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_DATA0_LSIO_GPIO3_IO09            0x60            /* SODIMM  43 */
+               >;
+       };
+
+       /* Colibri SD/MMC Card */
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK              0x06000041      /* SODIMM  47 */
+                       IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD              0x21            /* SODIMM 190 */
+                       IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0          0x21            /* SODIMM 192 */
+                       IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1          0x21            /* SODIMM  49 */
+                       IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2          0x21            /* SODIMM  51 */
+                       IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3          0x21            /* SODIMM  53 */
+                       IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT      0x21
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+               fsl,pins = <
+                       IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK              0x06000041      /* SODIMM  47 */
+                       IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD              0x21            /* SODIMM 190 */
+                       IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0          0x21            /* SODIMM 192 */
+                       IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1          0x21            /* SODIMM  49 */
+                       IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2          0x21            /* SODIMM  51 */
+                       IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3          0x21            /* SODIMM  53 */
+                       IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT      0x21
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+               fsl,pins = <
+                       IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK              0x06000041      /* SODIMM  47 */
+                       IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD              0x21            /* SODIMM 190 */
+                       IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0          0x21            /* SODIMM 192 */
+                       IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1          0x21            /* SODIMM  49 */
+                       IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2          0x21            /* SODIMM  51 */
+                       IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3          0x21            /* SODIMM  53 */
+                       IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT      0x21
+               >;
+       };
+
+       pinctrl_usdhc2_sleep: usdhc2slpgrp {
+               fsl,pins = <
+                       IMX8QXP_USDHC1_CLK_LSIO_GPIO4_IO23              0x60            /* SODIMM  47 */
+                       IMX8QXP_USDHC1_CMD_LSIO_GPIO4_IO24              0x60            /* SODIMM 190 */
+                       IMX8QXP_USDHC1_DATA0_LSIO_GPIO4_IO25            0x60            /* SODIMM 192 */
+                       IMX8QXP_USDHC1_DATA1_LSIO_GPIO4_IO26            0x60            /* SODIMM  49 */
+                       IMX8QXP_USDHC1_DATA2_LSIO_GPIO4_IO27            0x60            /* SODIMM  51 */
+                       IMX8QXP_USDHC1_DATA3_LSIO_GPIO4_IO28            0x60            /* SODIMM  53 */
+                       IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT      0x21
+               >;
+       };
+
+       pinctrl_wifi: wifigrp {
+               fsl,pins = <
+                       IMX8QXP_SCU_BOOT_MODE3_SCU_DSC_RTC_CLOCK_OUTPUT_32K     0x20
+               >;
+       };
+};
index 1946805..d3d26cc 100644 (file)
 };
 
 &usdhc1 {
+       assigned-clocks = <&clk IMX_CONN_SDHC0_CLK>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
        bus-width = <8>;
 };
 
 &usdhc2 {
+       assigned-clocks = <&clk IMX_CONN_SDHC1_CLK>;
+       assigned-clock-rates = <200000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
 &adma_dsp {
        status = "okay";
 };
+
+&scu_key {
+       status = "okay";
+};
index 1133b41..9646a41 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/clock/imx8-clock.h>
 #include <dt-bindings/firmware/imx/rsrc.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/pinctrl/pads-imx8qxp.h>
 
                        #power-domain-cells = <1>;
                };
 
+               scu_key: scu-key {
+                       compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key";
+                       linux,keycodes = <KEY_POWER>;
+                       status = "disabled";
+               };
+
                rtc: rtc {
                        compatible = "fsl,imx8qxp-sc-rtc";
                };
                                 <&conn_lpcg IMX_CONN_LPCG_SDHC0_PER_CLK>,
                                 <&conn_lpcg IMX_CONN_LPCG_SDHC0_HCLK>;
                        clock-names = "ipg", "per", "ahb";
-                       assigned-clocks = <&clk IMX_CONN_SDHC0_CLK>;
-                       assigned-clock-rates = <200000000>;
                        power-domains = <&pd IMX_SC_R_SDHC_0>;
                        status = "disabled";
                };
                                 <&conn_lpcg IMX_CONN_LPCG_SDHC1_PER_CLK>,
                                 <&conn_lpcg IMX_CONN_LPCG_SDHC1_HCLK>;
                        clock-names = "ipg", "per", "ahb";
-                       assigned-clocks = <&clk IMX_CONN_SDHC1_CLK>;
-                       assigned-clock-rates = <200000000>;
                        power-domains = <&pd IMX_SC_R_SDHC_1>;
                        fsl,tuning-start-tap = <20>;
                        fsl,tuning-step= <2>;
                                 <&conn_lpcg IMX_CONN_LPCG_SDHC2_PER_CLK>,
                                 <&conn_lpcg IMX_CONN_LPCG_SDHC2_HCLK>;
                        clock-names = "ipg", "per", "ahb";
-                       assigned-clocks = <&clk IMX_CONN_SDHC2_CLK>;
-                       assigned-clock-rates = <200000000>;
                        power-domains = <&pd IMX_SC_R_SDHC_2>;
                        status = "disabled";
                };
diff --git a/arch/arm64/boot/dts/freescale/s32v234-evb.dts b/arch/arm64/boot/dts/freescale/s32v234-evb.dts
new file mode 100644 (file)
index 0000000..4b80251
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ */
+
+/dts-v1/;
+#include "s32v234.dtsi"
+
+/ {
+       model = "NXP S32V234-EVB2 Board";
+       compatible = "fsl,s32v234-evb", "fsl,s32v234";
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/s32v234.dtsi b/arch/arm64/boot/dts/freescale/s32v234.dtsi
new file mode 100644 (file)
index 0000000..e746b9c
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2018 NXP
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+       compatible = "fsl,s32v234";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+       };
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x80000000>;
+                       next-level-cache = <&cluster0_l2_cache>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x1>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x80000000>;
+                       next-level-cache = <&cluster0_l2_cache>;
+               };
+
+               cpu2: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x100>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x80000000>;
+                       next-level-cache = <&cluster1_l2_cache>;
+               };
+
+               cpu3: cpu@101 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x101>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x80000000>;
+                       next-level-cache = <&cluster1_l2_cache>;
+               };
+
+               cluster0_l2_cache: l2-cache0 {
+                       compatible = "cache";
+               };
+
+               cluster1_l2_cache: l2-cache1 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+                                         IRQ_TYPE_LEVEL_LOW)>;
+               /* clock-frequency might be modified by u-boot, depending on the
+                * chip version.
+                */
+               clock-frequency = <10000000>;
+       };
+
+       gic: interrupt-controller@7d001000 {
+               compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0 0x7d001000 0 0x1000>,
+                     <0 0x7d002000 0 0x2000>,
+                     <0 0x7d004000 0 0x2000>,
+                     <0 0x7d006000 0 0x2000>;
+               interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
+                                        IRQ_TYPE_LEVEL_HIGH)>;
+       };
+
+       soc {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+               aips0: aips-bus@40000000 {
+                       compatible = "simple-bus";
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       interrupt-parent = <&gic>;
+                       reg = <0x0 0x40000000 0x0 0x7d000>;
+                       ranges;
+
+                       uart0: serial@40053000 {
+                               compatible = "fsl,s32v234-linflexuart";
+                               reg = <0x0 0x40053000 0x0 0x1000>;
+                               interrupts = <GIC_SPI 59 IRQ_TYPE_EDGE_RISING>;
+                               status = "disabled";
+                       };
+               };
+
+               aips1: aips-bus@40080000 {
+                       compatible = "simple-bus";
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       interrupt-parent = <&gic>;
+                       reg = <0x0 0x40080000 0x0 0x70000>;
+                       ranges;
+
+                       uart1: serial@400bc000 {
+                               compatible = "fsl,s32v234-linflexuart";
+                               reg = <0x0 0x400bc000 0x0 0x1000>;
+                               interrupts = <GIC_SPI 60 IRQ_TYPE_EDGE_RISING>;
+                               status = "disabled";
+                       };
+               };
+       };
+};
index 108e2a4..2072b63 100644 (file)
                        compatible = "hisilicon,hi6220-aoctrl", "syscon";
                        reg = <0x0 0xf7800000 0x0 0x2000>;
                        #clock-cells = <1>;
+                       #reset-cells = <1>;
                };
 
                sys_ctrl: sys_ctrl@f7030000 {
                        clock-names = "apb_pclk";
                        cpu = <&cpu7>;
                };
+
+               mali: gpu@f4080000 {
+                       compatible = "hisilicon,hi6220-mali", "arm,mali-450";
+                       reg = <0x0 0xf4080000 0x0 0x00040000>;
+                       interrupt-parent = <&gic>;
+                       interrupts =    <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_PPI 126 IRQ_TYPE_LEVEL_HIGH>;
+
+                       interrupt-names = "gp",
+                                         "gpmmu",
+                                         "pp",
+                                         "pp0",
+                                         "ppmmu0",
+                                         "pp1",
+                                         "ppmmu1",
+                                         "pp2",
+                                         "ppmmu2",
+                                         "pp3",
+                                         "ppmmu3";
+                       clocks = <&media_ctrl HI6220_G3D_CLK>,
+                                <&media_ctrl HI6220_G3D_PCLK>;
+                       clock-names = "core", "bus";
+                       assigned-clocks = <&media_ctrl HI6220_G3D_CLK>,
+                                         <&media_ctrl HI6220_G3D_PCLK>;
+                       assigned-clock-rates = <500000000>, <144000000>;
+                       reset-names = "ao_g3d", "media_g3d";
+                       resets = <&ao_ctrl AO_G3D>, <&media_ctrl MEDIA_G3D>;
+               };
        };
 };
 
index 36abc25..94090c6 100644 (file)
        #address-cells = <2>;
        #size-cells = <2>;
 
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               service_reserved: svcbuffer@0 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x0 0x0 0x0 0x1000000>;
+                       alignment = <0x1000>;
+                       no-map;
+               };
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                interrupt-parent = <&intc>;
                ranges = <0 0 0 0xffffffff>;
 
+               base_fpga_region {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x1>;
+                       compatible = "fpga-region";
+                       fpga-mgr = <&fpga_mgr>;
+               };
+
                gmac0: ethernet@ff800000 {
                        compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff800000 0x2000>;
 
                        status = "disabled";
                };
+
+               firmware {
+                       svc {
+                               compatible = "intel,stratix10-svc";
+                               method = "smc";
+                               memory-region = <&service_reserved>;
+
+                               fpga_mgr: fpga-mgr {
+                                       compatible = "intel,stratix10-soc-fpga-mgr";
+                               };
+                       };
+               };
        };
 };
index 7814a9e..e794a12 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
+       leds {
+               compatible = "gpio-leds";
+               hps0 {
+                       label = "hps_led0";
+                       gpios = <&portb 20 GPIO_ACTIVE_HIGH>;
+               };
+
+               hps1 {
+                       label = "hps_led1";
+                       gpios = <&portb 19 GPIO_ACTIVE_HIGH>;
+               };
+
+               hps2 {
+                       label = "hps_led2";
+                       gpios = <&portb 21 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
        memory {
                device_type = "memory";
                /* We expect the bootloader to fill in the reg */
        status = "okay";
 };
 
+&usb0 {
+       status = "okay";
+       disable-over-current;
+};
+
 &watchdog0 {
        status = "okay";
 };
+
+&qspi {
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "mt25qu02g";
+               reg = <0>;
+               spi-max-frequency = <100000000>;
+
+               m25p,fast-read;
+               cdns,page-size = <256>;
+               cdns,block-size = <16>;
+               cdns,read-delay = <1>;
+               cdns,tshsl-ns = <50>;
+               cdns,tsd2d-ns = <50>;
+               cdns,tchsh-ns = <4>;
+               cdns,tslch-ns = <4>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       qspi_boot: partition@0 {
+                               label = "Boot and fpga data";
+                               reg = <0x0 0x034B0000>;
+                       };
+
+                       qspi_rootfs: partition@34B0000 {
+                               label = "Root Filesystem - JFFS2";
+                               reg = <0x034B0000 0x0EB50000>;
+                       };
+               };
+       };
+};
index c8dc9c2..64f3b13 100644 (file)
        amba {
                #address-cells = <2>;
                #size-cells = <1>;
-               #interrupts-cells = <3>;
+               #interrupt-cells = <3>;
 
                compatible = "simple-bus";
                interrupt-parent = <&gic>;
index 82c6645..ac23592 100644 (file)
        amba {
                #address-cells = <2>;
                #size-cells = <1>;
-               #interrupts-cells = <3>;
+               #interrupt-cells = <3>;
 
                compatible = "simple-bus";
                interrupt-parent = <&gic>;
index 243338c..f1b5127 100644 (file)
@@ -10,3 +10,6 @@ dtb-$(CONFIG_ARCH_MVEBU) += armada-8040-db.dtb
 dtb-$(CONFIG_ARCH_MVEBU) += armada-8040-mcbin.dtb
 dtb-$(CONFIG_ARCH_MVEBU) += armada-8040-mcbin-singleshot.dtb
 dtb-$(CONFIG_ARCH_MVEBU) += armada-8080-db.dtb
+dtb-$(CONFIG_ARCH_MVEBU) += cn9130-db.dtb
+dtb-$(CONFIG_ARCH_MVEBU) += cn9131-db.dtb
+dtb-$(CONFIG_ARCH_MVEBU) += cn9132-db.dtb
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-emmc.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-emmc.dts
new file mode 100644 (file)
index 0000000..bd9ed9d
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree file for Globalscale Marvell ESPRESSOBin Board with eMMC
+ * Copyright (C) 2018 Marvell
+ *
+ * Romain Perier <romain.perier@free-electrons.com>
+ * Konstantin Porotchkin <kostap@marvell.com>
+ *
+ */
+/*
+ * Schematic available at http://espressobin.net/wp-content/uploads/2017/08/ESPRESSObin_V5_Schematics.pdf
+ */
+
+#include "armada-3720-espressobin.dtsi"
+
+/ {
+       model = "Globalscale Marvell ESPRESSOBin Board (eMMC)";
+       compatible = "globalscale,espressobin-emmc", "globalscale,espressobin",
+                    "marvell,armada3720", "marvell,armada3710";
+};
+
+/* U11 */
+&sdhci0 {
+       non-removable;
+       bus-width = <8>;
+       mmc-ddr-1_8v;
+       mmc-hs400-1_8v;
+       marvell,xenon-emmc;
+       marvell,xenon-tun-count = <9>;
+       marvell,pad-type = "fixed-1-8v";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc_pins>;
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       mmccard: mmccard@0 {
+               compatible = "mmc-card";
+               reg = <0>;
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-v7-emmc.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-v7-emmc.dts
new file mode 100644 (file)
index 0000000..6e876a6
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree file for Globalscale Marvell ESPRESSOBin Board V7 with eMMC
+ * Copyright (C) 2018 Marvell
+ *
+ * Romain Perier <romain.perier@free-electrons.com>
+ * Konstantin Porotchkin <kostap@marvell.com>
+ *
+ */
+/*
+ * Schematic available at http://wiki.espressobin.net/tiki-download_file.php?fileId=200
+ */
+
+#include "armada-3720-espressobin.dtsi"
+
+/ {
+       model = "Globalscale Marvell ESPRESSOBin Board V7 (eMMC)";
+       compatible = "globalscale,espressobin-v7-emmc", "globalscale,espressobin-v7",
+                    "globalscale,espressobin", "marvell,armada3720",
+                    "marvell,armada3710";
+};
+
+&switch0 {
+       ports {
+               port@1 {
+                       reg = <1>;
+                       label = "lan1";
+                       phy-handle = <&switch0phy0>;
+               };
+
+               port@3 {
+                       reg = <3>;
+                       label = "wan";
+                       phy-handle = <&switch0phy2>;
+               };
+       };
+};
+
+/* U11 */
+&sdhci0 {
+       non-removable;
+       bus-width = <8>;
+       mmc-ddr-1_8v;
+       mmc-hs400-1_8v;
+       marvell,xenon-emmc;
+       marvell,xenon-tun-count = <9>;
+       marvell,pad-type = "fixed-1-8v";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc_pins>;
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       mmccard: mmccard@0 {
+               compatible = "mmc-card";
+               reg = <0>;
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-v7.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-v7.dts
new file mode 100644 (file)
index 0000000..0f8405d
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree file for Globalscale Marvell ESPRESSOBin Board V7
+ * Copyright (C) 2018 Marvell
+ *
+ * Romain Perier <romain.perier@free-electrons.com>
+ * Konstantin Porotchkin <kostap@marvell.com>
+ *
+ */
+/*
+ * Schematic available at http://wiki.espressobin.net/tiki-download_file.php?fileId=200
+ */
+
+#include "armada-3720-espressobin.dtsi"
+
+/ {
+       model = "Globalscale Marvell ESPRESSOBin Board V7";
+       compatible = "globalscale,espressobin-v7", "globalscale,espressobin",
+                    "marvell,armada3720", "marvell,armada3710";
+};
+
+&switch0 {
+       ports {
+               port@1 {
+                       reg = <1>;
+                       label = "lan1";
+                       phy-handle = <&switch0phy0>;
+               };
+
+               port@3 {
+                       reg = <3>;
+                       label = "wan";
+                       phy-handle = <&switch0phy2>;
+               };
+       };
+};
index fbcf03f..1542d83 100644 (file)
 
 /dts-v1/;
 
-#include <dt-bindings/gpio/gpio.h>
-#include "armada-372x.dtsi"
+#include "armada-3720-espressobin.dtsi"
 
 / {
        model = "Globalscale Marvell ESPRESSOBin Board";
        compatible = "globalscale,espressobin", "marvell,armada3720", "marvell,armada3710";
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       memory@0 {
-               device_type = "memory";
-               reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
-       };
-
-       vcc_sd_reg1: regulator {
-               compatible = "regulator-gpio";
-               regulator-name = "vcc_sd1";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <3300000>;
-               regulator-boot-on;
-
-               gpios = <&gpionb 4 GPIO_ACTIVE_HIGH>;
-               gpios-states = <0>;
-               states = <1800000 0x1
-                         3300000 0x0>;
-               enable-active-high;
-       };
-};
-
-/* J9 */
-&pcie0 {
-       status = "okay";
-       phys = <&comphy1 0>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pcie_reset_pins &pcie_clkreq_pins>;
-};
-
-/* J6 */
-&sata {
-       status = "okay";
-       phys = <&comphy2 0>;
-       phy-names = "sata-phy";
-};
-
-/* J1 */
-&sdhci1 {
-       wp-inverted;
-       bus-width = <4>;
-       cd-gpios = <&gpionb 3 GPIO_ACTIVE_LOW>;
-       marvell,pad-type = "sd";
-       vqmmc-supply = <&vcc_sd_reg1>;
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&sdio_pins>;
-       status = "okay";
-};
-
-/* U11 */
-&sdhci0 {
-       non-removable;
-       bus-width = <8>;
-       mmc-ddr-1_8v;
-       mmc-hs400-1_8v;
-       marvell,xenon-emmc;
-       marvell,xenon-tun-count = <9>;
-       marvell,pad-type = "fixed-1-8v";
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&mmc_pins>;
-/*
- * This eMMC is not populated on all boards, so disable it by
- * default and let the bootloader enable it, if it is present
- */
-       status = "disabled";
-};
-
-&spi0 {
-       status = "okay";
-
-       flash@0 {
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <104000000>;
-               m25p,fast-read;
-       };
-};
-
-/* Exported on the micro USB connector J5 through an FTDI */
-&uart0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&uart1_pins>;
-       status = "okay";
-};
-
-/*
- * Connector J17 and J18 expose a number of different features. Some pins are
- * multiplexed. This is the case for instance for the following features:
- * - UART1 (pin 24 = RX, pin 26 = TX). See armada-3720-db.dts for an example of
- *   how to enable it. Beware that the signals are 1.8V TTL.
- * - I2C
- * - SPI
- * - MMC
- */
-
-/* J7 */
-&usb3 {
-       status = "okay";
-};
-
-/* J8 */
-&usb2 {
-       status = "okay";
-};
-
-&mdio {
-       switch0: switch0@1 {
-               compatible = "marvell,mv88e6085";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <1>;
-
-               dsa,member = <0 0>;
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-                               label = "cpu";
-                               ethernet = <&eth0>;
-                               phy-mode = "rgmii-id";
-                               fixed-link {
-                                       speed = <1000>;
-                                       full-duplex;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-                               label = "wan";
-                               phy-handle = <&switch0phy0>;
-                       };
-
-                       port@2 {
-                               reg = <2>;
-                               label = "lan0";
-                               phy-handle = <&switch0phy1>;
-                       };
-
-                       port@3 {
-                               reg = <3>;
-                               label = "lan1";
-                               phy-handle = <&switch0phy2>;
-                       };
-
-               };
-
-               mdio {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       switch0phy0: switch0phy0@11 {
-                               reg = <0x11>;
-                       };
-                       switch0phy1: switch0phy1@12 {
-                               reg = <0x12>;
-                       };
-                       switch0phy2: switch0phy2@13 {
-                               reg = <0x13>;
-                       };
-               };
-       };
-};
-
-&eth0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&rgmii_pins>, <&smi_pins>;
-       phy-mode = "rgmii-id";
-       status = "okay";
-
-       fixed-link {
-               speed = <1000>;
-               full-duplex;
-       };
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
new file mode 100644 (file)
index 0000000..53b8ac5
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree file for Globalscale Marvell ESPRESSOBin Board
+ * Copyright (C) 2016 Marvell
+ *
+ * Romain Perier <romain.perier@free-electrons.com>
+ *
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "armada-372x.dtsi"
+
+/ {
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
+       };
+
+       vcc_sd_reg1: regulator {
+               compatible = "regulator-gpio";
+               regulator-name = "vcc_sd1";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+
+               gpios = <&gpionb 4 GPIO_ACTIVE_HIGH>;
+               gpios-states = <0>;
+               states = <1800000 0x1
+                         3300000 0x0>;
+               enable-active-high;
+       };
+};
+
+/* J9 */
+&pcie0 {
+       status = "okay";
+       phys = <&comphy1 0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_reset_pins &pcie_clkreq_pins>;
+};
+
+/* J6 */
+&sata {
+       status = "okay";
+       phys = <&comphy2 0>;
+       phy-names = "sata-phy";
+};
+
+/* J1 */
+&sdhci1 {
+       wp-inverted;
+       bus-width = <4>;
+       cd-gpios = <&gpionb 3 GPIO_ACTIVE_LOW>;
+       marvell,pad-type = "sd";
+       vqmmc-supply = <&vcc_sd_reg1>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio_pins>;
+       status = "okay";
+};
+
+&spi0 {
+       status = "okay";
+
+       flash@0 {
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <104000000>;
+               m25p,fast-read;
+       };
+};
+
+/* Exported on the micro USB connector J5 through an FTDI */
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_pins>;
+       status = "okay";
+};
+
+/*
+ * Connector J17 and J18 expose a number of different features. Some pins are
+ * multiplexed. This is the case for instance for the following features:
+ * - UART1 (pin 24 = RX, pin 26 = TX). See armada-3720-db.dts for an example of
+ *   how to enable it. Beware that the signals are 1.8V TTL.
+ * - I2C
+ * - SPI
+ * - MMC
+ */
+
+/* J7 */
+&usb3 {
+       status = "okay";
+};
+
+/* J8 */
+&usb2 {
+       status = "okay";
+};
+
+&mdio {
+       switch0: switch0@1 {
+               compatible = "marvell,mv88e6085";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <1>;
+
+               dsa,member = <0 0>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               label = "cpu";
+                               ethernet = <&eth0>;
+                               phy-mode = "rgmii-id";
+                               fixed-link {
+                                       speed = <1000>;
+                                       full-duplex;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               label = "wan";
+                               phy-handle = <&switch0phy0>;
+                       };
+
+                       port@2 {
+                               reg = <2>;
+                               label = "lan0";
+                               phy-handle = <&switch0phy1>;
+                       };
+
+                       port@3 {
+                               reg = <3>;
+                               label = "lan1";
+                               phy-handle = <&switch0phy2>;
+                       };
+
+               };
+
+               mdio {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       switch0phy0: switch0phy0@11 {
+                               reg = <0x11>;
+                       };
+                       switch0phy1: switch0phy1@12 {
+                               reg = <0x12>;
+                       };
+                       switch0phy2: switch0phy2@13 {
+                               reg = <0x13>;
+                       };
+               };
+       };
+};
+
+&eth0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins>, <&smi_pins>;
+       phy-mode = "rgmii-id";
+       status = "okay";
+
+       fixed-link {
+               speed = <1000>;
+               full-duplex;
+       };
+};
index 5f350cc..bb42d1e 100644 (file)
                /* enabled by U-Boot if SFP module is present */
                status = "disabled";
        };
+
+       firmware {
+               turris-mox-rwtm {
+                       compatible = "cznic,turris-mox-rwtm";
+                       mboxes = <&rwtm 0>;
+                       status = "okay";
+               };
+       };
 };
 
 &i2c0 {
index e5c6d7c..293403a 100644 (file)
 /*
  * Instantiate the CP110
  */
-#define CP110_NAME             cp0
-#define CP110_BASE             f2000000
-#define CP110_PCIE_IO_BASE     0xf9000000
-#define CP110_PCIE_MEM_BASE    0xf6000000
-#define CP110_PCIE0_BASE       f2600000
-#define CP110_PCIE1_BASE       f2620000
-#define CP110_PCIE2_BASE       f2640000
+#define CP11X_NAME             cp0
+#define CP11X_BASE             f2000000
+#define CP11X_PCIEx_MEM_BASE(iface) (0xf6000000 + (iface * 0x1000000))
+#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
+#define CP11X_PCIE0_BASE       f2600000
+#define CP11X_PCIE1_BASE       f2620000
+#define CP11X_PCIE2_BASE       f2640000
 
 #include "armada-cp110.dtsi"
 
-#undef CP110_NAME
-#undef CP110_BASE
-#undef CP110_PCIE_IO_BASE
-#undef CP110_PCIE_MEM_BASE
-#undef CP110_PCIE0_BASE
-#undef CP110_PCIE1_BASE
-#undef CP110_PCIE2_BASE
+#undef CP11X_NAME
+#undef CP11X_BASE
+#undef CP11X_PCIEx_MEM_BASE
+#undef CP11X_PCIEx_MEM_SIZE
+#undef CP11X_PCIE0_BASE
+#undef CP11X_PCIE1_BASE
+#undef CP11X_PCIE2_BASE
 
 &cp0_gpio1 {
        status = "okay";
index d250f4b..572e261 100644 (file)
        num-lanes = <4>;
        num-viewport = <8>;
        reset-gpios = <&cp0_gpio2 20 GPIO_ACTIVE_LOW>;
-       ranges = <0x81000000 0x0 0xf9010000 0x0 0xf9010000 0x0 0x10000
-                 0x82000000 0x0 0xc0000000 0x0 0xc0000000 0x0 0x20000000>;
+       ranges = <0x82000000 0x0 0xc0000000 0x0 0xc0000000 0x0 0x20000000>;
        phys = <&cp0_comphy0 0>, <&cp0_comphy1 0>,
               <&cp0_comphy2 0>, <&cp0_comphy3 0>;
        phy-names = "cp0-pcie0-x4-lane0-phy", "cp0-pcie0-x4-lane1-phy",
index 8129b40..ee67c70 100644 (file)
 /*
  * Instantiate the master CP110
  */
-#define CP110_NAME             cp0
-#define CP110_BASE             f2000000
-#define CP110_PCIE_IO_BASE     0xf9000000
-#define CP110_PCIE_MEM_BASE    0xf6000000
-#define CP110_PCIE0_BASE       f2600000
-#define CP110_PCIE1_BASE       f2620000
-#define CP110_PCIE2_BASE       f2640000
+#define CP11X_NAME             cp0
+#define CP11X_BASE             f2000000
+#define CP11X_PCIEx_MEM_BASE(iface) (0xf6000000 + (iface * 0x1000000))
+#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
+#define CP11X_PCIE0_BASE       f2600000
+#define CP11X_PCIE1_BASE       f2620000
+#define CP11X_PCIE2_BASE       f2640000
 
 #include "armada-cp110.dtsi"
 
-#undef CP110_NAME
-#undef CP110_BASE
-#undef CP110_PCIE_IO_BASE
-#undef CP110_PCIE_MEM_BASE
-#undef CP110_PCIE0_BASE
-#undef CP110_PCIE1_BASE
-#undef CP110_PCIE2_BASE
+#undef CP11X_NAME
+#undef CP11X_BASE
+#undef CP11X_PCIEx_MEM_BASE
+#undef CP11X_PCIEx_MEM_SIZE
+#undef CP11X_PCIE0_BASE
+#undef CP11X_PCIE1_BASE
+#undef CP11X_PCIE2_BASE
 
 /*
  * Instantiate the slave CP110
  */
-#define CP110_NAME             cp1
-#define CP110_BASE             f4000000
-#define CP110_PCIE_IO_BASE     0xfd000000
-#define CP110_PCIE_MEM_BASE    0xfa000000
-#define CP110_PCIE0_BASE       f4600000
-#define CP110_PCIE1_BASE       f4620000
-#define CP110_PCIE2_BASE       f4640000
+#define CP11X_NAME             cp1
+#define CP11X_BASE             f4000000
+#define CP11X_PCIEx_MEM_BASE(iface) (0xfa000000 + (iface * 0x1000000))
+#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
+#define CP11X_PCIE0_BASE       f4600000
+#define CP11X_PCIE1_BASE       f4620000
+#define CP11X_PCIE2_BASE       f4640000
 
 #include "armada-cp110.dtsi"
 
-#undef CP110_NAME
-#undef CP110_BASE
-#undef CP110_PCIE_IO_BASE
-#undef CP110_PCIE_MEM_BASE
-#undef CP110_PCIE0_BASE
-#undef CP110_PCIE1_BASE
-#undef CP110_PCIE2_BASE
+#undef CP11X_NAME
+#undef CP11X_BASE
+#undef CP11X_PCIEx_MEM_BASE
+#undef CP11X_PCIEx_MEM_SIZE
+#undef CP11X_PCIE0_BASE
+#undef CP11X_PCIE1_BASE
+#undef CP11X_PCIE2_BASE
 
 /* The 80x0 has two CP blocks, but uses only one block from each. */
 &cp1_gpio1 {
index 9024a2d..0984955 100644 (file)
                        reg = <0x000>;
                        enable-method = "psci";
                        #cooling-cells = <2>;
+                       clocks = <&cpu_clk 0>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2>;
                };
                cpu1: cpu@1 {
                        device_type = "cpu";
                        reg = <0x001>;
                        enable-method = "psci";
                        #cooling-cells = <2>;
+                       clocks = <&cpu_clk 0>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2>;
+               };
+
+               l2: l2-cache {
+                       compatible = "cache";
+                       cache-size = <0x80000>;
+                       cache-line-size = <64>;
+                       cache-sets = <512>;
                };
        };
 };
index c25bc65..3db4271 100644 (file)
                        enable-method = "psci";
                        #cooling-cells = <2>;
                        clocks = <&cpu_clk 0>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_0>;
                };
                cpu1: cpu@1 {
                        device_type = "cpu";
                        enable-method = "psci";
                        #cooling-cells = <2>;
                        clocks = <&cpu_clk 0>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_0>;
                };
                cpu2: cpu@100 {
                        device_type = "cpu";
                        enable-method = "psci";
                        #cooling-cells = <2>;
                        clocks = <&cpu_clk 1>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_1>;
                };
                cpu3: cpu@101 {
                        device_type = "cpu";
                        enable-method = "psci";
                        #cooling-cells = <2>;
                        clocks = <&cpu_clk 1>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_1>;
+               };
+
+               l2_0: l2-cache0 {
+                       compatible = "cache";
+                       cache-size = <0x80000>;
+                       cache-line-size = <64>;
+                       cache-sets = <512>;
+               };
+
+               l2_1: l2-cache1 {
+                       compatible = "cache";
+                       cache-size = <0x80000>;
+                       cache-line-size = <64>;
+                       cache-sets = <512>;
                };
        };
 };
index d06dd19..8666286 100644 (file)
  * Device Tree file for Marvell Armada AP806.
  */
 
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <dt-bindings/thermal/thermal.h>
-
-/dts-v1/;
+#define AP_NAME                ap806
+#include "armada-ap80x.dtsi"
 
 / {
        model = "Marvell Armada AP806";
        compatible = "marvell,armada-ap806";
-       #address-cells = <2>;
-       #size-cells = <2>;
-
-       aliases {
-               serial0 = &uart0;
-               serial1 = &uart1;
-               gpio0 = &ap_gpio;
-               spi0 = &spi0;
-       };
-
-       psci {
-               compatible = "arm,psci-0.2";
-               method = "smc";
-       };
-
-       reserved-memory {
-               #address-cells = <2>;
-               #size-cells = <2>;
-               ranges;
-
-               /*
-                * This area matches the mapping done with a
-                * mainline U-Boot, and should be updated by the
-                * bootloader.
-                */
-
-               psci-area@4000000 {
-                       reg = <0x0 0x4000000 0x0 0x200000>;
-                       no-map;
-               };
-       };
-
-       ap806 {
-               #address-cells = <2>;
-               #size-cells = <2>;
-               compatible = "simple-bus";
-               interrupt-parent = <&gic>;
-               ranges;
-
-               config-space@f0000000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "simple-bus";
-                       ranges = <0x0 0x0 0xf0000000 0x1000000>;
-
-                       gic: interrupt-controller@210000 {
-                               compatible = "arm,gic-400";
-                               #interrupt-cells = <3>;
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-                               ranges;
-                               interrupt-controller;
-                               interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
-                               reg = <0x210000 0x10000>,
-                                     <0x220000 0x20000>,
-                                     <0x240000 0x20000>,
-                                     <0x260000 0x20000>;
-
-                               gic_v2m0: v2m@280000 {
-                                       compatible = "arm,gic-v2m-frame";
-                                       msi-controller;
-                                       reg = <0x280000 0x1000>;
-                                       arm,msi-base-spi = <160>;
-                                       arm,msi-num-spis = <32>;
-                               };
-                               gic_v2m1: v2m@290000 {
-                                       compatible = "arm,gic-v2m-frame";
-                                       msi-controller;
-                                       reg = <0x290000 0x1000>;
-                                       arm,msi-base-spi = <192>;
-                                       arm,msi-num-spis = <32>;
-                               };
-                               gic_v2m2: v2m@2a0000 {
-                                       compatible = "arm,gic-v2m-frame";
-                                       msi-controller;
-                                       reg = <0x2a0000 0x1000>;
-                                       arm,msi-base-spi = <224>;
-                                       arm,msi-num-spis = <32>;
-                               };
-                               gic_v2m3: v2m@2b0000 {
-                                       compatible = "arm,gic-v2m-frame";
-                                       msi-controller;
-                                       reg = <0x2b0000 0x1000>;
-                                       arm,msi-base-spi = <256>;
-                                       arm,msi-num-spis = <32>;
-                               };
-                       };
-
-                       timer {
-                               compatible = "arm,armv8-timer";
-                               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
-                       };
-
-                       pmu {
-                               compatible = "arm,cortex-a72-pmu";
-                               interrupt-parent = <&pic>;
-                               interrupts = <17>;
-                       };
-
-                       odmi: odmi@300000 {
-                               compatible = "marvell,odmi-controller";
-                               interrupt-controller;
-                               msi-controller;
-                               marvell,odmi-frames = <4>;
-                               reg = <0x300000 0x4000>,
-                                     <0x304000 0x4000>,
-                                     <0x308000 0x4000>,
-                                     <0x30C000 0x4000>;
-                               marvell,spi-base = <128>, <136>, <144>, <152>;
-                       };
-
-                       gicp: gicp@3f0040 {
-                               compatible = "marvell,ap806-gicp";
-                               reg = <0x3f0040 0x10>;
-                               marvell,spi-ranges = <64 64>, <288 64>;
-                               msi-controller;
-                       };
-
-                       pic: interrupt-controller@3f0100 {
-                               compatible = "marvell,armada-8k-pic";
-                               reg = <0x3f0100 0x10>;
-                               #interrupt-cells = <1>;
-                               interrupt-controller;
-                               interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
-                       };
-
-                       sei: interrupt-controller@3f0200 {
-                               compatible = "marvell,ap806-sei";
-                               reg = <0x3f0200 0x40>;
-                               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
-                               #interrupt-cells = <1>;
-                               interrupt-controller;
-                               msi-controller;
-                       };
-
-                       xor@400000 {
-                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
-                               reg = <0x400000 0x1000>,
-                                     <0x410000 0x1000>;
-                               msi-parent = <&gic_v2m0>;
-                               clocks = <&ap_clk 3>;
-                               dma-coherent;
-                       };
-
-                       xor@420000 {
-                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
-                               reg = <0x420000 0x1000>,
-                                     <0x430000 0x1000>;
-                               msi-parent = <&gic_v2m0>;
-                               clocks = <&ap_clk 3>;
-                               dma-coherent;
-                       };
-
-                       xor@440000 {
-                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
-                               reg = <0x440000 0x1000>,
-                                     <0x450000 0x1000>;
-                               msi-parent = <&gic_v2m0>;
-                               clocks = <&ap_clk 3>;
-                               dma-coherent;
-                       };
-
-                       xor@460000 {
-                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
-                               reg = <0x460000 0x1000>,
-                                     <0x470000 0x1000>;
-                               msi-parent = <&gic_v2m0>;
-                               clocks = <&ap_clk 3>;
-                               dma-coherent;
-                       };
-
-                       spi0: spi@510600 {
-                               compatible = "marvell,armada-380-spi";
-                               reg = <0x510600 0x50>;
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&ap_clk 3>;
-                               status = "disabled";
-                       };
-
-                       i2c0: i2c@511000 {
-                               compatible = "marvell,mv78230-i2c";
-                               reg = <0x511000 0x20>;
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-                               timeout-ms = <1000>;
-                               clocks = <&ap_clk 3>;
-                               status = "disabled";
-                       };
-
-                       uart0: serial@512000 {
-                               compatible = "snps,dw-apb-uart";
-                               reg = <0x512000 0x100>;
-                               reg-shift = <2>;
-                               interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-                               reg-io-width = <1>;
-                               clocks = <&ap_clk 3>;
-                               status = "disabled";
-                       };
-
-                       uart1: serial@512100 {
-                               compatible = "snps,dw-apb-uart";
-                               reg = <0x512100 0x100>;
-                               reg-shift = <2>;
-                               interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-                               reg-io-width = <1>;
-                               clocks = <&ap_clk 3>;
-                               status = "disabled";
-
-                       };
-
-                       watchdog: watchdog@610000 {
-                               compatible = "arm,sbsa-gwdt";
-                               reg = <0x610000 0x1000>, <0x600000 0x1000>;
-                               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-                       };
-
-                       ap_sdhci0: sdhci@6e0000 {
-                               compatible = "marvell,armada-ap806-sdhci";
-                               reg = <0x6e0000 0x300>;
-                               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
-                               clock-names = "core";
-                               clocks = <&ap_clk 4>;
-                               dma-coherent;
-                               marvell,xenon-phy-slow-mode;
-                               status = "disabled";
-                       };
-
-                       ap_syscon: system-controller@6f4000 {
-                               compatible = "syscon", "simple-mfd";
-                               reg = <0x6f4000 0x2000>;
-
-                               ap_clk: clock {
-                                       compatible = "marvell,ap806-clock";
-                                       #clock-cells = <1>;
-                               };
-
-                               ap_pinctrl: pinctrl {
-                                       compatible = "marvell,ap806-pinctrl";
-
-                                       uart0_pins: uart0-pins {
-                                               marvell,pins = "mpp11", "mpp19";
-                                               marvell,function = "uart0";
-                                       };
-                               };
-
-                               ap_gpio: gpio@1040 {
-                                       compatible = "marvell,armada-8k-gpio";
-                                       offset = <0x1040>;
-                                       ngpios = <20>;
-                                       gpio-controller;
-                                       #gpio-cells = <2>;
-                                       gpio-ranges = <&ap_pinctrl 0 0 20>;
-                               };
-                       };
-
-                       ap_syscon1: system-controller@6f8000 {
-                               compatible = "syscon", "simple-mfd";
-                               reg = <0x6f8000 0x1000>;
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-
-                               cpu_clk: clock-cpu@278 {
-                                       compatible = "marvell,ap806-cpu-clock";
-                                       clocks = <&ap_clk 0>, <&ap_clk 1>;
-                                       #clock-cells = <1>;
-                                       reg = <0x278 0xa30>;
-                               };
+};
 
-                               ap_thermal: thermal-sensor@80 {
-                                       compatible = "marvell,armada-ap806-thermal";
-                                       reg = <0x80 0x10>;
-                                       interrupt-parent = <&sei>;
-                                       interrupts = <18>;
-                                       #thermal-sensor-cells = <1>;
-                               };
-                       };
-               };
+&ap_syscon0 {
+       ap_clk: clock {
+               compatible = "marvell,ap806-clock";
+               #clock-cells = <1>;
        };
+};
 
-       /*
-        * The thermal IP features one internal sensor plus, if applicable, one
-        * remote channel wired to one sensor per CPU.
-        *
-        * Only one thermal zone per AP/CP may trigger interrupts at a time, the
-        * first one that will have a critical trip point will be chosen.
-        */
-       thermal-zones {
-               ap_thermal_ic: ap-thermal-ic {
-                       polling-delay-passive = <0>; /* Interrupt driven */
-                       polling-delay = <0>; /* Interrupt driven */
-
-                       thermal-sensors = <&ap_thermal 0>;
-
-                       trips {
-                               ap_crit: ap-crit {
-                                       temperature = <100000>; /* mC degrees */
-                                       hysteresis = <2000>; /* mC degrees */
-                                       type = "critical";
-                               };
-                       };
-
-                       cooling-maps { };
-               };
-
-               ap_thermal_cpu0: ap-thermal-cpu0 {
-                       polling-delay-passive = <1000>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&ap_thermal 1>;
-
-                       trips {
-                               cpu0_hot: cpu0-hot {
-                                       temperature = <85000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu0_emerg: cpu0-emerg {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                       };
-
-                       cooling-maps {
-                               map0_hot: map0-hot {
-                                       trip = <&cpu0_hot>;
-                                       cooling-device = <&cpu0 1 2>,
-                                               <&cpu1 1 2>;
-                               };
-                               map0_emerg: map0-ermerg {
-                                       trip = <&cpu0_emerg>;
-                                       cooling-device = <&cpu0 3 3>,
-                                               <&cpu1 3 3>;
-                               };
-                       };
-               };
-
-               ap_thermal_cpu1: ap-thermal-cpu1 {
-                       polling-delay-passive = <1000>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&ap_thermal 2>;
-
-                       trips {
-                               cpu1_hot: cpu1-hot {
-                                       temperature = <85000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu1_emerg: cpu1-emerg {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                       };
-
-                       cooling-maps {
-                               map1_hot: map1-hot {
-                                       trip = <&cpu1_hot>;
-                                       cooling-device = <&cpu0 1 2>,
-                                               <&cpu1 1 2>;
-                               };
-                               map1_emerg: map1-emerg {
-                                       trip = <&cpu1_emerg>;
-                                       cooling-device = <&cpu0 3 3>,
-                                               <&cpu1 3 3>;
-                               };
-                       };
-               };
-
-               ap_thermal_cpu2: ap-thermal-cpu2 {
-                       polling-delay-passive = <1000>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&ap_thermal 3>;
-
-                       trips {
-                               cpu2_hot: cpu2-hot {
-                                       temperature = <85000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu2_emerg: cpu2-emerg {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                       };
-
-                       cooling-maps {
-                               map2_hot: map2-hot {
-                                       trip = <&cpu2_hot>;
-                                       cooling-device = <&cpu2 1 2>,
-                                               <&cpu3 1 2>;
-                               };
-                               map2_emerg: map2-emerg {
-                                       trip = <&cpu2_emerg>;
-                                       cooling-device = <&cpu2 3 3>,
-                                               <&cpu3 3 3>;
-                               };
-                       };
-               };
-
-               ap_thermal_cpu3: ap-thermal-cpu3 {
-                       polling-delay-passive = <1000>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&ap_thermal 4>;
-
-                       trips {
-                               cpu3_hot: cpu3-hot {
-                                       temperature = <85000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu3_emerg: cpu3-emerg {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                       };
-
-                       cooling-maps {
-                               map3_hot: map3-bhot {
-                                       trip = <&cpu3_hot>;
-                                       cooling-device = <&cpu2 1 2>,
-                                               <&cpu3 1 2>;
-                               };
-                               map3_emerg: map3-emerg {
-                                       trip = <&cpu3_emerg>;
-                                       cooling-device = <&cpu2 3 3>,
-                                               <&cpu3 3 3>;
-                               };
-                       };
-               };
+&ap_syscon1 {
+       cpu_clk: clock-cpu@278 {
+               compatible = "marvell,ap806-cpu-clock";
+               clocks = <&ap_clk 0>, <&ap_clk 1>;
+               #clock-cells = <1>;
+               reg = <0x278 0xa30>;
        };
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi
new file mode 100644 (file)
index 0000000..840466e
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree file for Marvell Armada AP807 Quad
+ *
+ * Copyright (C) 2019 Marvell Technology Group Ltd.
+ */
+
+#include "armada-ap807.dtsi"
+
+/ {
+       model = "Marvell Armada AP807 Quad";
+       compatible = "marvell,armada-ap807-quad", "marvell,armada-ap807";
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72", "arm,armv8";
+                       reg = <0x000>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+                       clocks = <&cpu_clk 0>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_0>;
+               };
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72", "arm,armv8";
+                       reg = <0x001>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+                       clocks = <&cpu_clk 0>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_0>;
+               };
+               cpu2: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72", "arm,armv8";
+                       reg = <0x100>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+                       clocks = <&cpu_clk 1>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_1>;
+               };
+               cpu3: cpu@101 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72", "arm,armv8";
+                       reg = <0x101>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+                       clocks = <&cpu_clk 1>;
+                       i-cache-size = <0xc000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_1>;
+               };
+
+               l2_0: l2-cache0 {
+                       compatible = "cache";
+                       cache-size = <0x80000>;
+                       cache-line-size = <64>;
+                       cache-sets = <512>;
+               };
+
+               l2_1: l2-cache1 {
+                       compatible = "cache";
+                       cache-size = <0x80000>;
+                       cache-line-size = <64>;
+                       cache-sets = <512>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap807.dtsi b/arch/arm64/boot/dts/marvell/armada-ap807.dtsi
new file mode 100644 (file)
index 0000000..623010f
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree file for Marvell Armada AP807
+ *
+ * Copyright (C) 2019 Marvell Technology Group Ltd.
+ */
+
+#define AP_NAME                ap807
+#include "armada-ap80x.dtsi"
+
+/ {
+       model = "Marvell Armada AP807";
+       compatible = "marvell,armada-ap807";
+};
+
+&ap_syscon0 {
+       ap_clk: clock {
+               compatible = "marvell,ap807-clock";
+               #clock-cells = <1>;
+       };
+};
+
+&ap_syscon1 {
+       cpu_clk: clock-cpu {
+               compatible = "marvell,ap807-cpu-clock";
+               clocks = <&ap_clk 0>, <&ap_clk 1>;
+               #clock-cells = <1>;
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi b/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi
new file mode 100644 (file)
index 0000000..e7438c2
--- /dev/null
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marvell Technology Group Ltd.
+ *
+ * Device Tree file for Marvell Armada AP80x.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
+
+/dts-v1/;
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+               gpio0 = &ap_gpio;
+               spi0 = &spi0;
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               /*
+                * This area matches the mapping done with a
+                * mainline U-Boot, and should be updated by the
+                * bootloader.
+                */
+
+               psci-area@4000000 {
+                       reg = <0x0 0x4000000 0x0 0x200000>;
+                       no-map;
+               };
+       };
+
+       AP_NAME {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+               config-space@f0000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "simple-bus";
+                       ranges = <0x0 0x0 0xf0000000 0x1000000>;
+
+                       gic: interrupt-controller@210000 {
+                               compatible = "arm,gic-400";
+                               #interrupt-cells = <3>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges;
+                               interrupt-controller;
+                               interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                               reg = <0x210000 0x10000>,
+                                     <0x220000 0x20000>,
+                                     <0x240000 0x20000>,
+                                     <0x260000 0x20000>;
+
+                               gic_v2m0: v2m@280000 {
+                                       compatible = "arm,gic-v2m-frame";
+                                       msi-controller;
+                                       reg = <0x280000 0x1000>;
+                                       arm,msi-base-spi = <160>;
+                                       arm,msi-num-spis = <32>;
+                               };
+                               gic_v2m1: v2m@290000 {
+                                       compatible = "arm,gic-v2m-frame";
+                                       msi-controller;
+                                       reg = <0x290000 0x1000>;
+                                       arm,msi-base-spi = <192>;
+                                       arm,msi-num-spis = <32>;
+                               };
+                               gic_v2m2: v2m@2a0000 {
+                                       compatible = "arm,gic-v2m-frame";
+                                       msi-controller;
+                                       reg = <0x2a0000 0x1000>;
+                                       arm,msi-base-spi = <224>;
+                                       arm,msi-num-spis = <32>;
+                               };
+                               gic_v2m3: v2m@2b0000 {
+                                       compatible = "arm,gic-v2m-frame";
+                                       msi-controller;
+                                       reg = <0x2b0000 0x1000>;
+                                       arm,msi-base-spi = <256>;
+                                       arm,msi-num-spis = <32>;
+                               };
+                       };
+
+                       timer {
+                               compatible = "arm,armv8-timer";
+                               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+                       };
+
+                       pmu {
+                               compatible = "arm,cortex-a72-pmu";
+                               interrupt-parent = <&pic>;
+                               interrupts = <17>;
+                       };
+
+                       odmi: odmi@300000 {
+                               compatible = "marvell,odmi-controller";
+                               interrupt-controller;
+                               msi-controller;
+                               marvell,odmi-frames = <4>;
+                               reg = <0x300000 0x4000>,
+                                     <0x304000 0x4000>,
+                                     <0x308000 0x4000>,
+                                     <0x30C000 0x4000>;
+                               marvell,spi-base = <128>, <136>, <144>, <152>;
+                       };
+
+                       gicp: gicp@3f0040 {
+                               compatible = "marvell,ap806-gicp";
+                               reg = <0x3f0040 0x10>;
+                               marvell,spi-ranges = <64 64>, <288 64>;
+                               msi-controller;
+                       };
+
+                       pic: interrupt-controller@3f0100 {
+                               compatible = "marvell,armada-8k-pic";
+                               reg = <0x3f0100 0x10>;
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       sei: interrupt-controller@3f0200 {
+                               compatible = "marvell,ap806-sei";
+                               reg = <0x3f0200 0x40>;
+                               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               msi-controller;
+                       };
+
+                       xor@400000 {
+                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+                               reg = <0x400000 0x1000>,
+                                     <0x410000 0x1000>;
+                               msi-parent = <&gic_v2m0>;
+                               clocks = <&ap_clk 3>;
+                               dma-coherent;
+                       };
+
+                       xor@420000 {
+                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+                               reg = <0x420000 0x1000>,
+                                     <0x430000 0x1000>;
+                               msi-parent = <&gic_v2m0>;
+                               clocks = <&ap_clk 3>;
+                               dma-coherent;
+                       };
+
+                       xor@440000 {
+                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+                               reg = <0x440000 0x1000>,
+                                     <0x450000 0x1000>;
+                               msi-parent = <&gic_v2m0>;
+                               clocks = <&ap_clk 3>;
+                               dma-coherent;
+                       };
+
+                       xor@460000 {
+                               compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+                               reg = <0x460000 0x1000>,
+                                     <0x470000 0x1000>;
+                               msi-parent = <&gic_v2m0>;
+                               clocks = <&ap_clk 3>;
+                               dma-coherent;
+                       };
+
+                       spi0: spi@510600 {
+                               compatible = "marvell,armada-380-spi";
+                               reg = <0x510600 0x50>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&ap_clk 3>;
+                               status = "disabled";
+                       };
+
+                       i2c0: i2c@511000 {
+                               compatible = "marvell,mv78230-i2c";
+                               reg = <0x511000 0x20>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                               timeout-ms = <1000>;
+                               clocks = <&ap_clk 3>;
+                               status = "disabled";
+                       };
+
+                       uart0: serial@512000 {
+                               compatible = "snps,dw-apb-uart";
+                               reg = <0x512000 0x100>;
+                               reg-shift = <2>;
+                               interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-io-width = <1>;
+                               clocks = <&ap_clk 3>;
+                               status = "disabled";
+                       };
+
+                       uart1: serial@512100 {
+                               compatible = "snps,dw-apb-uart";
+                               reg = <0x512100 0x100>;
+                               reg-shift = <2>;
+                               interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-io-width = <1>;
+                               clocks = <&ap_clk 3>;
+                               status = "disabled";
+
+                       };
+
+                       watchdog: watchdog@610000 {
+                               compatible = "arm,sbsa-gwdt";
+                               reg = <0x610000 0x1000>, <0x600000 0x1000>;
+                               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       ap_sdhci0: sdhci@6e0000 {
+                               compatible = "marvell,armada-ap806-sdhci";
+                               reg = <0x6e0000 0x300>;
+                               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+                               clock-names = "core";
+                               clocks = <&ap_clk 4>;
+                               dma-coherent;
+                               marvell,xenon-phy-slow-mode;
+                               status = "disabled";
+                       };
+
+                       ap_syscon0: system-controller@6f4000 {
+                               compatible = "syscon", "simple-mfd";
+                               reg = <0x6f4000 0x2000>;
+
+                               ap_pinctrl: pinctrl {
+                                       compatible = "marvell,ap806-pinctrl";
+
+                                       uart0_pins: uart0-pins {
+                                               marvell,pins = "mpp11", "mpp19";
+                                               marvell,function = "uart0";
+                                       };
+                               };
+
+                               ap_gpio: gpio@1040 {
+                                       compatible = "marvell,armada-8k-gpio";
+                                       offset = <0x1040>;
+                                       ngpios = <20>;
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       gpio-ranges = <&ap_pinctrl 0 0 20>;
+                               };
+                       };
+
+                       ap_syscon1: system-controller@6f8000 {
+                               compatible = "syscon", "simple-mfd";
+                               reg = <0x6f8000 0x1000>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               ap_thermal: thermal-sensor@80 {
+                                       compatible = "marvell,armada-ap806-thermal";
+                                       reg = <0x80 0x10>;
+                                       interrupt-parent = <&sei>;
+                                       interrupts = <18>;
+                                       #thermal-sensor-cells = <1>;
+                               };
+                       };
+               };
+       };
+
+       /*
+        * The thermal IP features one internal sensor plus, if applicable, one
+        * remote channel wired to one sensor per CPU.
+        *
+        * Only one thermal zone per AP/CP may trigger interrupts at a time, the
+        * first one that will have a critical trip point will be chosen.
+        */
+       thermal-zones {
+               ap_thermal_ic: ap-thermal-ic {
+                       polling-delay-passive = <0>; /* Interrupt driven */
+                       polling-delay = <0>; /* Interrupt driven */
+
+                       thermal-sensors = <&ap_thermal 0>;
+
+                       trips {
+                               ap_crit: ap-crit {
+                                       temperature = <100000>; /* mC degrees */
+                                       hysteresis = <2000>; /* mC degrees */
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps { };
+               };
+
+               ap_thermal_cpu0: ap-thermal-cpu0 {
+                       polling-delay-passive = <1000>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&ap_thermal 1>;
+
+                       trips {
+                               cpu0_hot: cpu0-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu0_emerg: cpu0-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0_hot: map0-hot {
+                                       trip = <&cpu0_hot>;
+                                       cooling-device = <&cpu0 1 2>,
+                                               <&cpu1 1 2>;
+                               };
+                               map0_emerg: map0-ermerg {
+                                       trip = <&cpu0_emerg>;
+                                       cooling-device = <&cpu0 3 3>,
+                                               <&cpu1 3 3>;
+                               };
+                       };
+               };
+
+               ap_thermal_cpu1: ap-thermal-cpu1 {
+                       polling-delay-passive = <1000>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&ap_thermal 2>;
+
+                       trips {
+                               cpu1_hot: cpu1-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu1_emerg: cpu1-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map1_hot: map1-hot {
+                                       trip = <&cpu1_hot>;
+                                       cooling-device = <&cpu0 1 2>,
+                                               <&cpu1 1 2>;
+                               };
+                               map1_emerg: map1-emerg {
+                                       trip = <&cpu1_emerg>;
+                                       cooling-device = <&cpu0 3 3>,
+                                               <&cpu1 3 3>;
+                               };
+                       };
+               };
+
+               ap_thermal_cpu2: ap-thermal-cpu2 {
+                       polling-delay-passive = <1000>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&ap_thermal 3>;
+
+                       trips {
+                               cpu2_hot: cpu2-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu2_emerg: cpu2-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map2_hot: map2-hot {
+                                       trip = <&cpu2_hot>;
+                                       cooling-device = <&cpu2 1 2>,
+                                               <&cpu3 1 2>;
+                               };
+                               map2_emerg: map2-emerg {
+                                       trip = <&cpu2_emerg>;
+                                       cooling-device = <&cpu2 3 3>,
+                                               <&cpu3 3 3>;
+                               };
+                       };
+               };
+
+               ap_thermal_cpu3: ap-thermal-cpu3 {
+                       polling-delay-passive = <1000>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&ap_thermal 4>;
+
+                       trips {
+                               cpu3_hot: cpu3-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu3_emerg: cpu3-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map3_hot: map3-bhot {
+                                       trip = <&cpu3_hot>;
+                                       cooling-device = <&cpu2 1 2>,
+                                               <&cpu3 1 2>;
+                               };
+                               map3_emerg: map3-emerg {
+                                       trip = <&cpu3_emerg>;
+                                       cooling-device = <&cpu2 3 3>,
+                                               <&cpu3 3 3>;
+                               };
+                       };
+               };
+       };
+};
index b29c640..c04c6c4 100644 (file)
@@ -6,6 +6,6 @@
 /* Common definitions used by Armada 7K/8K DTs */
 #define PASTER(x, y) x ## y
 #define EVALUATOR(x, y) PASTER(x, y)
-#define CP110_LABEL(name) EVALUATOR(CP110_NAME, EVALUATOR(_, name))
-#define CP110_NODE_NAME(name) EVALUATOR(CP110_NAME, EVALUATOR(-, name))
+#define CP11X_LABEL(name) EVALUATOR(CP11X_NAME, EVALUATOR(_, name))
+#define CP11X_NODE_NAME(name) EVALUATOR(CP11X_NAME, EVALUATOR(-, name))
 #define ADDRESSIFY(addr) EVALUATOR(0x, addr)
index d819449..4fd33b0 100644 (file)
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright (C) 2016 Marvell Technology Group Ltd.
+ * Copyright (C) 2019 Marvell Technology Group Ltd.
  *
  * Device Tree file for Marvell Armada CP110.
  */
 
-#include <dt-bindings/interrupt-controller/mvebu-icu.h>
-#include <dt-bindings/thermal/thermal.h>
+#define CP11X_TYPE cp110
 
-#include "armada-common.dtsi"
+#include "armada-cp11x.dtsi"
 
-#define CP110_PCIEx_IO_BASE(iface)     (CP110_PCIE_IO_BASE + (iface *  0x10000))
-#define CP110_PCIEx_MEM_BASE(iface)    (CP110_PCIE_MEM_BASE + (iface *  0x1000000))
-#define CP110_PCIEx_CONF_BASE(iface)   (CP110_PCIEx_MEM_BASE(iface) + 0xf00000)
-
-/ {
-       /*
-        * The contents of the node are defined below, in order to
-        * save one indentation level
-        */
-       CP110_NAME: CP110_NAME { };
-
-       /*
-        * CPs only have one sensor in the thermal IC.
-        *
-        * The cooling maps are empty as there are no cooling devices.
-        */
-       thermal-zones {
-               CP110_LABEL(thermal_ic): CP110_NODE_NAME(thermal-ic) {
-                       polling-delay-passive = <0>; /* Interrupt driven */
-                       polling-delay = <0>; /* Interrupt driven */
-
-                       thermal-sensors = <&CP110_LABEL(thermal) 0>;
-
-                       trips {
-                               CP110_LABEL(crit): crit {
-                                       temperature = <100000>; /* mC degrees */
-                                       hysteresis = <2000>; /* mC degrees */
-                                       type = "critical";
-                               };
-                       };
-
-                       cooling-maps { };
-               };
-       };
-};
-
-&CP110_NAME {
-       #address-cells = <2>;
-       #size-cells = <2>;
-       compatible = "simple-bus";
-       interrupt-parent = <&CP110_LABEL(icu_nsr)>;
-       ranges;
-
-       config-space@CP110_BASE {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "simple-bus";
-               ranges = <0x0 0x0 ADDRESSIFY(CP110_BASE) 0x2000000>;
-
-               CP110_LABEL(ethernet): ethernet@0 {
-                       compatible = "marvell,armada-7k-pp22";
-                       reg = <0x0 0x100000>, <0x129000 0xb000>;
-                       clocks = <&CP110_LABEL(clk) 1 3>, <&CP110_LABEL(clk) 1 9>,
-                                <&CP110_LABEL(clk) 1 5>, <&CP110_LABEL(clk) 1 6>,
-                                <&CP110_LABEL(clk) 1 18>;
-                       clock-names = "pp_clk", "gop_clk",
-                                     "mg_clk", "mg_core_clk", "axi_clk";
-                       marvell,system-controller = <&CP110_LABEL(syscon0)>;
-                       status = "disabled";
-                       dma-coherent;
-
-                       CP110_LABEL(eth0): eth0 {
-                               interrupts = <39 IRQ_TYPE_LEVEL_HIGH>,
-                                       <43 IRQ_TYPE_LEVEL_HIGH>,
-                                       <47 IRQ_TYPE_LEVEL_HIGH>,
-                                       <51 IRQ_TYPE_LEVEL_HIGH>,
-                                       <55 IRQ_TYPE_LEVEL_HIGH>,
-                                       <59 IRQ_TYPE_LEVEL_HIGH>,
-                                       <63 IRQ_TYPE_LEVEL_HIGH>,
-                                       <67 IRQ_TYPE_LEVEL_HIGH>,
-                                       <71 IRQ_TYPE_LEVEL_HIGH>,
-                                       <129 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "hif0", "hif1", "hif2",
-                                       "hif3", "hif4", "hif5", "hif6", "hif7",
-                                       "hif8", "link";
-                               port-id = <0>;
-                               gop-port-id = <0>;
-                               status = "disabled";
-                       };
-
-                       CP110_LABEL(eth1): eth1 {
-                               interrupts = <40 IRQ_TYPE_LEVEL_HIGH>,
-                                       <44 IRQ_TYPE_LEVEL_HIGH>,
-                                       <48 IRQ_TYPE_LEVEL_HIGH>,
-                                       <52 IRQ_TYPE_LEVEL_HIGH>,
-                                       <56 IRQ_TYPE_LEVEL_HIGH>,
-                                       <60 IRQ_TYPE_LEVEL_HIGH>,
-                                       <64 IRQ_TYPE_LEVEL_HIGH>,
-                                       <68 IRQ_TYPE_LEVEL_HIGH>,
-                                       <72 IRQ_TYPE_LEVEL_HIGH>,
-                                       <128 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "hif0", "hif1", "hif2",
-                                       "hif3", "hif4", "hif5", "hif6", "hif7",
-                                       "hif8", "link";
-                               port-id = <1>;
-                               gop-port-id = <2>;
-                               status = "disabled";
-                       };
-
-                       CP110_LABEL(eth2): eth2 {
-                               interrupts = <41 IRQ_TYPE_LEVEL_HIGH>,
-                                       <45 IRQ_TYPE_LEVEL_HIGH>,
-                                       <49 IRQ_TYPE_LEVEL_HIGH>,
-                                       <53 IRQ_TYPE_LEVEL_HIGH>,
-                                       <57 IRQ_TYPE_LEVEL_HIGH>,
-                                       <61 IRQ_TYPE_LEVEL_HIGH>,
-                                       <65 IRQ_TYPE_LEVEL_HIGH>,
-                                       <69 IRQ_TYPE_LEVEL_HIGH>,
-                                       <73 IRQ_TYPE_LEVEL_HIGH>,
-                                       <127 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "hif0", "hif1", "hif2",
-                                       "hif3", "hif4", "hif5", "hif6", "hif7",
-                                       "hif8", "link";
-                               port-id = <2>;
-                               gop-port-id = <3>;
-                               status = "disabled";
-                       };
-               };
-
-               CP110_LABEL(comphy): phy@120000 {
-                       compatible = "marvell,comphy-cp110";
-                       reg = <0x120000 0x6000>;
-                       marvell,system-controller = <&CP110_LABEL(syscon0)>;
-                       clocks = <&CP110_LABEL(clk) 1 5>, <&CP110_LABEL(clk) 1 6>,
-                                <&CP110_LABEL(clk) 1 18>;
-                       clock-names = "mg_clk", "mg_core_clk", "axi_clk";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       CP110_LABEL(comphy0): phy@0 {
-                               reg = <0>;
-                               #phy-cells = <1>;
-                       };
-
-                       CP110_LABEL(comphy1): phy@1 {
-                               reg = <1>;
-                               #phy-cells = <1>;
-                       };
-
-                       CP110_LABEL(comphy2): phy@2 {
-                               reg = <2>;
-                               #phy-cells = <1>;
-                       };
-
-                       CP110_LABEL(comphy3): phy@3 {
-                               reg = <3>;
-                               #phy-cells = <1>;
-                       };
-
-                       CP110_LABEL(comphy4): phy@4 {
-                               reg = <4>;
-                               #phy-cells = <1>;
-                       };
-
-                       CP110_LABEL(comphy5): phy@5 {
-                               reg = <5>;
-                               #phy-cells = <1>;
-                       };
-               };
-
-               CP110_LABEL(mdio): mdio@12a200 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "marvell,orion-mdio";
-                       reg = <0x12a200 0x10>;
-                       clocks = <&CP110_LABEL(clk) 1 9>, <&CP110_LABEL(clk) 1 5>,
-                                <&CP110_LABEL(clk) 1 6>, <&CP110_LABEL(clk) 1 18>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(xmdio): mdio@12a600 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "marvell,xmdio";
-                       reg = <0x12a600 0x10>;
-                       clocks = <&CP110_LABEL(clk) 1 5>,
-                                <&CP110_LABEL(clk) 1 6>, <&CP110_LABEL(clk) 1 18>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(icu): interrupt-controller@1e0000 {
-                       compatible = "marvell,cp110-icu";
-                       reg = <0x1e0000 0x440>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       CP110_LABEL(icu_nsr): interrupt-controller@10 {
-                               compatible = "marvell,cp110-icu-nsr";
-                               reg = <0x10 0x20>;
-                               #interrupt-cells = <2>;
-                               interrupt-controller;
-                               msi-parent = <&gicp>;
-                       };
-
-                       CP110_LABEL(icu_sei): interrupt-controller@50 {
-                               compatible = "marvell,cp110-icu-sei";
-                               reg = <0x50 0x10>;
-                               #interrupt-cells = <2>;
-                               interrupt-controller;
-                               msi-parent = <&sei>;
-                       };
-               };
-
-               CP110_LABEL(rtc): rtc@284000 {
-                       compatible = "marvell,armada-8k-rtc";
-                       reg = <0x284000 0x20>, <0x284080 0x24>;
-                       reg-names = "rtc", "rtc-soc";
-                       interrupts = <77 IRQ_TYPE_LEVEL_HIGH>;
-               };
-
-               CP110_LABEL(syscon0): system-controller@440000 {
-                       compatible = "syscon", "simple-mfd";
-                       reg = <0x440000 0x2000>;
-
-                       CP110_LABEL(clk): clock {
-                               compatible = "marvell,cp110-clock";
-                               #clock-cells = <2>;
-                       };
-
-                       CP110_LABEL(gpio1): gpio@100 {
-                               compatible = "marvell,armada-8k-gpio";
-                               offset = <0x100>;
-                               ngpios = <32>;
-                               gpio-controller;
-                               #gpio-cells = <2>;
-                               gpio-ranges = <&CP110_LABEL(pinctrl) 0 0 32>;
-                               interrupt-controller;
-                               interrupts = <86 IRQ_TYPE_LEVEL_HIGH>,
-                                       <85 IRQ_TYPE_LEVEL_HIGH>,
-                                       <84 IRQ_TYPE_LEVEL_HIGH>,
-                                       <83 IRQ_TYPE_LEVEL_HIGH>;
-                               #interrupt-cells = <2>;
-                               status = "disabled";
-                       };
-
-                       CP110_LABEL(gpio2): gpio@140 {
-                               compatible = "marvell,armada-8k-gpio";
-                               offset = <0x140>;
-                               ngpios = <31>;
-                               gpio-controller;
-                               #gpio-cells = <2>;
-                               gpio-ranges = <&CP110_LABEL(pinctrl) 0 32 31>;
-                               interrupt-controller;
-                               interrupts = <82 IRQ_TYPE_LEVEL_HIGH>,
-                                       <81 IRQ_TYPE_LEVEL_HIGH>,
-                                       <80 IRQ_TYPE_LEVEL_HIGH>,
-                                       <79 IRQ_TYPE_LEVEL_HIGH>;
-                               #interrupt-cells = <2>;
-                               status = "disabled";
-                       };
-               };
-
-               CP110_LABEL(syscon1): system-controller@400000 {
-                       compatible = "syscon", "simple-mfd";
-                       reg = <0x400000 0x1000>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       CP110_LABEL(thermal): thermal-sensor@70 {
-                               compatible = "marvell,armada-cp110-thermal";
-                               reg = <0x70 0x10>;
-                               interrupts-extended =
-                                       <&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;
-                               #thermal-sensor-cells = <1>;
-                       };
-               };
-
-               CP110_LABEL(usb3_0): usb3@500000 {
-                       compatible = "marvell,armada-8k-xhci",
-                       "generic-xhci";
-                       reg = <0x500000 0x4000>;
-                       dma-coherent;
-                       interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 22>,
-                                <&CP110_LABEL(clk) 1 16>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(usb3_1): usb3@510000 {
-                       compatible = "marvell,armada-8k-xhci",
-                       "generic-xhci";
-                       reg = <0x510000 0x4000>;
-                       dma-coherent;
-                       interrupts = <105 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 23>,
-                                <&CP110_LABEL(clk) 1 16>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(sata0): sata@540000 {
-                       compatible = "marvell,armada-8k-ahci",
-                       "generic-ahci";
-                       reg = <0x540000 0x30000>;
-                       dma-coherent;
-                       interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&CP110_LABEL(clk) 1 15>,
-                                <&CP110_LABEL(clk) 1 16>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       status = "disabled";
-
-                       sata-port@0 {
-                               reg = <0>;
-                       };
-
-                       sata-port@1 {
-                               reg = <1>;
-                       };
-               };
-
-               CP110_LABEL(xor0): xor@6a0000 {
-                       compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
-                       reg = <0x6a0000 0x1000>, <0x6b0000 0x1000>;
-                       dma-coherent;
-                       msi-parent = <&gic_v2m0>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 8>,
-                                <&CP110_LABEL(clk) 1 14>;
-               };
-
-               CP110_LABEL(xor1): xor@6c0000 {
-                       compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
-                       reg = <0x6c0000 0x1000>, <0x6d0000 0x1000>;
-                       dma-coherent;
-                       msi-parent = <&gic_v2m0>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 7>,
-                                <&CP110_LABEL(clk) 1 14>;
-               };
-
-               CP110_LABEL(spi0): spi@700600 {
-                       compatible = "marvell,armada-380-spi";
-                       reg = <0x700600 0x50>;
-                       #address-cells = <0x1>;
-                       #size-cells = <0x0>;
-                       clock-names = "core", "axi";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(spi1): spi@700680 {
-                       compatible = "marvell,armada-380-spi";
-                       reg = <0x700680 0x50>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       clock-names = "core", "axi";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(i2c0): i2c@701000 {
-                       compatible = "marvell,mv78230-i2c";
-                       reg = <0x701000 0x20>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <120 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(i2c1): i2c@701100 {
-                       compatible = "marvell,mv78230-i2c";
-                       reg = <0x701100 0x20>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <121 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(uart0): serial@702000 {
-                       compatible = "snps,dw-apb-uart";
-                       reg = <0x702000 0x100>;
-                       reg-shift = <2>;
-                       interrupts = <122 IRQ_TYPE_LEVEL_HIGH>;
-                       reg-io-width = <1>;
-                       clock-names = "baudclk", "apb_pclk";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(uart1): serial@702100 {
-                       compatible = "snps,dw-apb-uart";
-                       reg = <0x702100 0x100>;
-                       reg-shift = <2>;
-                       interrupts = <123 IRQ_TYPE_LEVEL_HIGH>;
-                       reg-io-width = <1>;
-                       clock-names = "baudclk", "apb_pclk";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(uart2): serial@702200 {
-                       compatible = "snps,dw-apb-uart";
-                       reg = <0x702200 0x100>;
-                       reg-shift = <2>;
-                       interrupts = <124 IRQ_TYPE_LEVEL_HIGH>;
-                       reg-io-width = <1>;
-                       clock-names = "baudclk", "apb_pclk";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(uart3): serial@702300 {
-                       compatible = "snps,dw-apb-uart";
-                       reg = <0x702300 0x100>;
-                       reg-shift = <2>;
-                       interrupts = <125 IRQ_TYPE_LEVEL_HIGH>;
-                       reg-io-width = <1>;
-                       clock-names = "baudclk", "apb_pclk";
-                       clocks = <&CP110_LABEL(clk) 1 21>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(nand_controller): nand@720000 {
-                       /*
-                       * Due to the limitation of the pins available
-                       * this controller is only usable on the CPM
-                       * for A7K and on the CPS for A8K.
-                       */
-                       compatible = "marvell,armada-8k-nand-controller",
-                               "marvell,armada370-nand-controller";
-                       reg = <0x720000 0x54>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <115 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 2>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       marvell,system-controller = <&CP110_LABEL(syscon0)>;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(trng): trng@760000 {
-                       compatible = "marvell,armada-8k-rng",
-                       "inside-secure,safexcel-eip76";
-                       reg = <0x760000 0x7d>;
-                       interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 25>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       status = "okay";
-               };
-
-               CP110_LABEL(sdhci0): sdhci@780000 {
-                       compatible = "marvell,armada-cp110-sdhci";
-                       reg = <0x780000 0x300>;
-                       interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
-                       clock-names = "core", "axi";
-                       clocks = <&CP110_LABEL(clk) 1 4>, <&CP110_LABEL(clk) 1 18>;
-                       dma-coherent;
-                       status = "disabled";
-               };
-
-               CP110_LABEL(crypto): crypto@800000 {
-                       compatible = "inside-secure,safexcel-eip197b";
-                       reg = <0x800000 0x200000>;
-                       interrupts = <87 IRQ_TYPE_LEVEL_HIGH>,
-                               <88 IRQ_TYPE_LEVEL_HIGH>,
-                               <89 IRQ_TYPE_LEVEL_HIGH>,
-                               <90 IRQ_TYPE_LEVEL_HIGH>,
-                               <91 IRQ_TYPE_LEVEL_HIGH>,
-                               <92 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "mem", "ring0", "ring1",
-                               "ring2", "ring3", "eip";
-                       clock-names = "core", "reg";
-                       clocks = <&CP110_LABEL(clk) 1 26>,
-                                <&CP110_LABEL(clk) 1 17>;
-                       dma-coherent;
-               };
-       };
-
-       CP110_LABEL(pcie0): pcie@CP110_PCIE0_BASE {
-               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
-               reg = <0 ADDRESSIFY(CP110_PCIE0_BASE) 0 0x10000>,
-                     <0 CP110_PCIEx_CONF_BASE(0) 0 0x80000>;
-               reg-names = "ctrl", "config";
-               #address-cells = <3>;
-               #size-cells = <2>;
-               #interrupt-cells = <1>;
-               device_type = "pci";
-               dma-coherent;
-               msi-parent = <&gic_v2m0>;
-
-               bus-range = <0 0xff>;
-               ranges =
-               /* downstream I/O */
-               <0x81000000 0 CP110_PCIEx_IO_BASE(0) 0  CP110_PCIEx_IO_BASE(0) 0 0x10000
-               /* non-prefetchable memory */
-               0x82000000 0 CP110_PCIEx_MEM_BASE(0) 0  CP110_PCIEx_MEM_BASE(0) 0 0xf00000>;
-               interrupt-map-mask = <0 0 0 0>;
-               interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 22 IRQ_TYPE_LEVEL_HIGH>;
-               interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
-               num-lanes = <1>;
-               clock-names = "core", "reg";
-               clocks = <&CP110_LABEL(clk) 1 13>, <&CP110_LABEL(clk) 1 14>;
-               status = "disabled";
-       };
-
-       CP110_LABEL(pcie1): pcie@CP110_PCIE1_BASE {
-               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
-               reg = <0 ADDRESSIFY(CP110_PCIE1_BASE) 0 0x10000>,
-                     <0 CP110_PCIEx_CONF_BASE(1) 0 0x80000>;
-               reg-names = "ctrl", "config";
-               #address-cells = <3>;
-               #size-cells = <2>;
-               #interrupt-cells = <1>;
-               device_type = "pci";
-               dma-coherent;
-               msi-parent = <&gic_v2m0>;
-
-               bus-range = <0 0xff>;
-               ranges =
-               /* downstream I/O */
-               <0x81000000 0 CP110_PCIEx_IO_BASE(1) 0  CP110_PCIEx_IO_BASE(1) 0 0x10000
-               /* non-prefetchable memory */
-               0x82000000 0 CP110_PCIEx_MEM_BASE(1) 0  CP110_PCIEx_MEM_BASE(1) 0 0xf00000>;
-               interrupt-map-mask = <0 0 0 0>;
-               interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 24 IRQ_TYPE_LEVEL_HIGH>;
-               interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
-
-               num-lanes = <1>;
-               clock-names = "core", "reg";
-               clocks = <&CP110_LABEL(clk) 1 11>, <&CP110_LABEL(clk) 1 14>;
-               status = "disabled";
-       };
-
-       CP110_LABEL(pcie2): pcie@CP110_PCIE2_BASE {
-               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
-               reg = <0 ADDRESSIFY(CP110_PCIE2_BASE) 0 0x10000>,
-                     <0 CP110_PCIEx_CONF_BASE(2) 0 0x80000>;
-               reg-names = "ctrl", "config";
-               #address-cells = <3>;
-               #size-cells = <2>;
-               #interrupt-cells = <1>;
-               device_type = "pci";
-               dma-coherent;
-               msi-parent = <&gic_v2m0>;
-
-               bus-range = <0 0xff>;
-               ranges =
-               /* downstream I/O */
-               <0x81000000 0 CP110_PCIEx_IO_BASE(2) 0  CP110_PCIEx_IO_BASE(2) 0 0x10000
-               /* non-prefetchable memory */
-               0x82000000 0 CP110_PCIEx_MEM_BASE(2) 0  CP110_PCIEx_MEM_BASE(2) 0 0xf00000>;
-               interrupt-map-mask = <0 0 0 0>;
-               interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 23 IRQ_TYPE_LEVEL_HIGH>;
-               interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
-
-               num-lanes = <1>;
-               clock-names = "core", "reg";
-               clocks = <&CP110_LABEL(clk) 1 12>, <&CP110_LABEL(clk) 1 14>;
-               status = "disabled";
-       };
-};
+#undef CP11X_TYPE
diff --git a/arch/arm64/boot/dts/marvell/armada-cp115.dtsi b/arch/arm64/boot/dts/marvell/armada-cp115.dtsi
new file mode 100644 (file)
index 0000000..1d0a965
--- /dev/null
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marvell Technology Group Ltd.
+ *
+ * Device Tree file for Marvell Armada CP115.
+ */
+
+#define CP11X_TYPE cp115
+
+#include "armada-cp11x.dtsi"
+
+#undef CP11X_TYPE
diff --git a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi
new file mode 100644 (file)
index 0000000..9dcf16b
--- /dev/null
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2016 Marvell Technology Group Ltd.
+ *
+ * Device Tree file for Marvell Armada CP11x.
+ */
+
+#include <dt-bindings/interrupt-controller/mvebu-icu.h>
+#include <dt-bindings/thermal/thermal.h>
+
+#include "armada-common.dtsi"
+
+#define CP11X_PCIEx_CONF_BASE(iface)   (CP11X_PCIEx_MEM_BASE(iface) + CP11X_PCIEx_MEM_SIZE(iface))
+
+/ {
+       /*
+        * The contents of the node are defined below, in order to
+        * save one indentation level
+        */
+       CP11X_NAME: CP11X_NAME { };
+
+       /*
+        * CPs only have one sensor in the thermal IC.
+        *
+        * The cooling maps are empty as there are no cooling devices.
+        */
+       thermal-zones {
+               CP11X_LABEL(thermal_ic): CP11X_NODE_NAME(thermal-ic) {
+                       polling-delay-passive = <0>; /* Interrupt driven */
+                       polling-delay = <0>; /* Interrupt driven */
+
+                       thermal-sensors = <&CP11X_LABEL(thermal) 0>;
+
+                       trips {
+                               CP11X_LABEL(crit): crit {
+                                       temperature = <100000>; /* mC degrees */
+                                       hysteresis = <2000>; /* mC degrees */
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps { };
+               };
+       };
+};
+
+&CP11X_NAME {
+       #address-cells = <2>;
+       #size-cells = <2>;
+       compatible = "simple-bus";
+       interrupt-parent = <&CP11X_LABEL(icu_nsr)>;
+       ranges;
+
+       config-space@CP11X_BASE {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               ranges = <0x0 0x0 ADDRESSIFY(CP11X_BASE) 0x2000000>;
+
+               CP11X_LABEL(ethernet): ethernet@0 {
+                       compatible = "marvell,armada-7k-pp22";
+                       reg = <0x0 0x100000>, <0x129000 0xb000>;
+                       clocks = <&CP11X_LABEL(clk) 1 3>, <&CP11X_LABEL(clk) 1 9>,
+                                <&CP11X_LABEL(clk) 1 5>, <&CP11X_LABEL(clk) 1 6>,
+                                <&CP11X_LABEL(clk) 1 18>;
+                       clock-names = "pp_clk", "gop_clk",
+                                     "mg_clk", "mg_core_clk", "axi_clk";
+                       marvell,system-controller = <&CP11X_LABEL(syscon0)>;
+                       status = "disabled";
+                       dma-coherent;
+
+                       CP11X_LABEL(eth0): eth0 {
+                               interrupts = <39 IRQ_TYPE_LEVEL_HIGH>,
+                                       <43 IRQ_TYPE_LEVEL_HIGH>,
+                                       <47 IRQ_TYPE_LEVEL_HIGH>,
+                                       <51 IRQ_TYPE_LEVEL_HIGH>,
+                                       <55 IRQ_TYPE_LEVEL_HIGH>,
+                                       <59 IRQ_TYPE_LEVEL_HIGH>,
+                                       <63 IRQ_TYPE_LEVEL_HIGH>,
+                                       <67 IRQ_TYPE_LEVEL_HIGH>,
+                                       <71 IRQ_TYPE_LEVEL_HIGH>,
+                                       <129 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "hif0", "hif1", "hif2",
+                                       "hif3", "hif4", "hif5", "hif6", "hif7",
+                                       "hif8", "link";
+                               port-id = <0>;
+                               gop-port-id = <0>;
+                               status = "disabled";
+                       };
+
+                       CP11X_LABEL(eth1): eth1 {
+                               interrupts = <40 IRQ_TYPE_LEVEL_HIGH>,
+                                       <44 IRQ_TYPE_LEVEL_HIGH>,
+                                       <48 IRQ_TYPE_LEVEL_HIGH>,
+                                       <52 IRQ_TYPE_LEVEL_HIGH>,
+                                       <56 IRQ_TYPE_LEVEL_HIGH>,
+                                       <60 IRQ_TYPE_LEVEL_HIGH>,
+                                       <64 IRQ_TYPE_LEVEL_HIGH>,
+                                       <68 IRQ_TYPE_LEVEL_HIGH>,
+                                       <72 IRQ_TYPE_LEVEL_HIGH>,
+                                       <128 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "hif0", "hif1", "hif2",
+                                       "hif3", "hif4", "hif5", "hif6", "hif7",
+                                       "hif8", "link";
+                               port-id = <1>;
+                               gop-port-id = <2>;
+                               status = "disabled";
+                       };
+
+                       CP11X_LABEL(eth2): eth2 {
+                               interrupts = <41 IRQ_TYPE_LEVEL_HIGH>,
+                                       <45 IRQ_TYPE_LEVEL_HIGH>,
+                                       <49 IRQ_TYPE_LEVEL_HIGH>,
+                                       <53 IRQ_TYPE_LEVEL_HIGH>,
+                                       <57 IRQ_TYPE_LEVEL_HIGH>,
+                                       <61 IRQ_TYPE_LEVEL_HIGH>,
+                                       <65 IRQ_TYPE_LEVEL_HIGH>,
+                                       <69 IRQ_TYPE_LEVEL_HIGH>,
+                                       <73 IRQ_TYPE_LEVEL_HIGH>,
+                                       <127 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "hif0", "hif1", "hif2",
+                                       "hif3", "hif4", "hif5", "hif6", "hif7",
+                                       "hif8", "link";
+                               port-id = <2>;
+                               gop-port-id = <3>;
+                               status = "disabled";
+                       };
+               };
+
+               CP11X_LABEL(comphy): phy@120000 {
+                       compatible = "marvell,comphy-cp110";
+                       reg = <0x120000 0x6000>;
+                       marvell,system-controller = <&CP11X_LABEL(syscon0)>;
+                       clocks = <&CP11X_LABEL(clk) 1 5>, <&CP11X_LABEL(clk) 1 6>,
+                                <&CP11X_LABEL(clk) 1 18>;
+                       clock-names = "mg_clk", "mg_core_clk", "axi_clk";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       CP11X_LABEL(comphy0): phy@0 {
+                               reg = <0>;
+                               #phy-cells = <1>;
+                       };
+
+                       CP11X_LABEL(comphy1): phy@1 {
+                               reg = <1>;
+                               #phy-cells = <1>;
+                       };
+
+                       CP11X_LABEL(comphy2): phy@2 {
+                               reg = <2>;
+                               #phy-cells = <1>;
+                       };
+
+                       CP11X_LABEL(comphy3): phy@3 {
+                               reg = <3>;
+                               #phy-cells = <1>;
+                       };
+
+                       CP11X_LABEL(comphy4): phy@4 {
+                               reg = <4>;
+                               #phy-cells = <1>;
+                       };
+
+                       CP11X_LABEL(comphy5): phy@5 {
+                               reg = <5>;
+                               #phy-cells = <1>;
+                       };
+               };
+
+               CP11X_LABEL(mdio): mdio@12a200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "marvell,orion-mdio";
+                       reg = <0x12a200 0x10>;
+                       clocks = <&CP11X_LABEL(clk) 1 9>, <&CP11X_LABEL(clk) 1 5>,
+                                <&CP11X_LABEL(clk) 1 6>, <&CP11X_LABEL(clk) 1 18>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(xmdio): mdio@12a600 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "marvell,xmdio";
+                       reg = <0x12a600 0x10>;
+                       clocks = <&CP11X_LABEL(clk) 1 5>,
+                                <&CP11X_LABEL(clk) 1 6>, <&CP11X_LABEL(clk) 1 18>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(icu): interrupt-controller@1e0000 {
+                       compatible = "marvell,cp110-icu";
+                       reg = <0x1e0000 0x440>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       CP11X_LABEL(icu_nsr): interrupt-controller@10 {
+                               compatible = "marvell,cp110-icu-nsr";
+                               reg = <0x10 0x20>;
+                               #interrupt-cells = <2>;
+                               interrupt-controller;
+                               msi-parent = <&gicp>;
+                       };
+
+                       CP11X_LABEL(icu_sei): interrupt-controller@50 {
+                               compatible = "marvell,cp110-icu-sei";
+                               reg = <0x50 0x10>;
+                               #interrupt-cells = <2>;
+                               interrupt-controller;
+                               msi-parent = <&sei>;
+                       };
+               };
+
+               CP11X_LABEL(rtc): rtc@284000 {
+                       compatible = "marvell,armada-8k-rtc";
+                       reg = <0x284000 0x20>, <0x284080 0x24>;
+                       reg-names = "rtc", "rtc-soc";
+                       interrupts = <77 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               CP11X_LABEL(syscon0): system-controller@440000 {
+                       compatible = "syscon", "simple-mfd";
+                       reg = <0x440000 0x2000>;
+
+                       CP11X_LABEL(clk): clock {
+                               compatible = "marvell,cp110-clock";
+                               #clock-cells = <2>;
+                       };
+
+                       CP11X_LABEL(gpio1): gpio@100 {
+                               compatible = "marvell,armada-8k-gpio";
+                               offset = <0x100>;
+                               ngpios = <32>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&CP11X_LABEL(pinctrl) 0 0 32>;
+                               interrupt-controller;
+                               interrupts = <86 IRQ_TYPE_LEVEL_HIGH>,
+                                       <85 IRQ_TYPE_LEVEL_HIGH>,
+                                       <84 IRQ_TYPE_LEVEL_HIGH>,
+                                       <83 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       CP11X_LABEL(gpio2): gpio@140 {
+                               compatible = "marvell,armada-8k-gpio";
+                               offset = <0x140>;
+                               ngpios = <31>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&CP11X_LABEL(pinctrl) 0 32 31>;
+                               interrupt-controller;
+                               interrupts = <82 IRQ_TYPE_LEVEL_HIGH>,
+                                       <81 IRQ_TYPE_LEVEL_HIGH>,
+                                       <80 IRQ_TYPE_LEVEL_HIGH>,
+                                       <79 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <2>;
+                               status = "disabled";
+                       };
+               };
+
+               CP11X_LABEL(syscon1): system-controller@400000 {
+                       compatible = "syscon", "simple-mfd";
+                       reg = <0x400000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       CP11X_LABEL(thermal): thermal-sensor@70 {
+                               compatible = "marvell,armada-cp110-thermal";
+                               reg = <0x70 0x10>;
+                               interrupts-extended =
+                                       <&CP11X_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;
+                               #thermal-sensor-cells = <1>;
+                       };
+               };
+
+               CP11X_LABEL(usb3_0): usb3@500000 {
+                       compatible = "marvell,armada-8k-xhci",
+                       "generic-xhci";
+                       reg = <0x500000 0x4000>;
+                       dma-coherent;
+                       interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 22>,
+                                <&CP11X_LABEL(clk) 1 16>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(usb3_1): usb3@510000 {
+                       compatible = "marvell,armada-8k-xhci",
+                       "generic-xhci";
+                       reg = <0x510000 0x4000>;
+                       dma-coherent;
+                       interrupts = <105 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 23>,
+                                <&CP11X_LABEL(clk) 1 16>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(sata0): sata@540000 {
+                       compatible = "marvell,armada-8k-ahci",
+                       "generic-ahci";
+                       reg = <0x540000 0x30000>;
+                       dma-coherent;
+                       interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&CP11X_LABEL(clk) 1 15>,
+                                <&CP11X_LABEL(clk) 1 16>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+
+                       sata-port@0 {
+                               reg = <0>;
+                       };
+
+                       sata-port@1 {
+                               reg = <1>;
+                       };
+               };
+
+               CP11X_LABEL(xor0): xor@6a0000 {
+                       compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+                       reg = <0x6a0000 0x1000>, <0x6b0000 0x1000>;
+                       dma-coherent;
+                       msi-parent = <&gic_v2m0>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 8>,
+                                <&CP11X_LABEL(clk) 1 14>;
+               };
+
+               CP11X_LABEL(xor1): xor@6c0000 {
+                       compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+                       reg = <0x6c0000 0x1000>, <0x6d0000 0x1000>;
+                       dma-coherent;
+                       msi-parent = <&gic_v2m0>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 7>,
+                                <&CP11X_LABEL(clk) 1 14>;
+               };
+
+               CP11X_LABEL(spi0): spi@700600 {
+                       compatible = "marvell,armada-380-spi";
+                       reg = <0x700600 0x50>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       clock-names = "core", "axi";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(spi1): spi@700680 {
+                       compatible = "marvell,armada-380-spi";
+                       reg = <0x700680 0x50>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       clock-names = "core", "axi";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(i2c0): i2c@701000 {
+                       compatible = "marvell,mv78230-i2c";
+                       reg = <0x701000 0x20>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <120 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(i2c1): i2c@701100 {
+                       compatible = "marvell,mv78230-i2c";
+                       reg = <0x701100 0x20>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <121 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(uart0): serial@702000 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x702000 0x100>;
+                       reg-shift = <2>;
+                       interrupts = <122 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-io-width = <1>;
+                       clock-names = "baudclk", "apb_pclk";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(uart1): serial@702100 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x702100 0x100>;
+                       reg-shift = <2>;
+                       interrupts = <123 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-io-width = <1>;
+                       clock-names = "baudclk", "apb_pclk";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(uart2): serial@702200 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x702200 0x100>;
+                       reg-shift = <2>;
+                       interrupts = <124 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-io-width = <1>;
+                       clock-names = "baudclk", "apb_pclk";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(uart3): serial@702300 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x702300 0x100>;
+                       reg-shift = <2>;
+                       interrupts = <125 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-io-width = <1>;
+                       clock-names = "baudclk", "apb_pclk";
+                       clocks = <&CP11X_LABEL(clk) 1 21>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(nand_controller): nand@720000 {
+                       /*
+                        * Due to the limitation of the pins available
+                        * this controller is only usable on the CPM
+                        * for A7K and on the CPS for A8K.
+                        */
+                       compatible = "marvell,armada-8k-nand-controller",
+                               "marvell,armada370-nand-controller";
+                       reg = <0x720000 0x54>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <115 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 2>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       marvell,system-controller = <&CP11X_LABEL(syscon0)>;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(trng): trng@760000 {
+                       compatible = "marvell,armada-8k-rng",
+                       "inside-secure,safexcel-eip76";
+                       reg = <0x760000 0x7d>;
+                       interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 25>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       status = "okay";
+               };
+
+               CP11X_LABEL(sdhci0): sdhci@780000 {
+                       compatible = "marvell,armada-cp110-sdhci";
+                       reg = <0x780000 0x300>;
+                       interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "core", "axi";
+                       clocks = <&CP11X_LABEL(clk) 1 4>, <&CP11X_LABEL(clk) 1 18>;
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               CP11X_LABEL(crypto): crypto@800000 {
+                       compatible = "inside-secure,safexcel-eip197b";
+                       reg = <0x800000 0x200000>;
+                       interrupts = <87 IRQ_TYPE_LEVEL_HIGH>,
+                               <88 IRQ_TYPE_LEVEL_HIGH>,
+                               <89 IRQ_TYPE_LEVEL_HIGH>,
+                               <90 IRQ_TYPE_LEVEL_HIGH>,
+                               <91 IRQ_TYPE_LEVEL_HIGH>,
+                               <92 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "mem", "ring0", "ring1",
+                               "ring2", "ring3", "eip";
+                       clock-names = "core", "reg";
+                       clocks = <&CP11X_LABEL(clk) 1 26>,
+                                <&CP11X_LABEL(clk) 1 17>;
+                       dma-coherent;
+               };
+       };
+
+       CP11X_LABEL(pcie0): pcie@CP11X_PCIE0_BASE {
+               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+               reg = <0 ADDRESSIFY(CP11X_PCIE0_BASE) 0 0x10000>,
+                     <0 CP11X_PCIEx_CONF_BASE(0) 0 0x80000>;
+               reg-names = "ctrl", "config";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               dma-coherent;
+               msi-parent = <&gic_v2m0>;
+
+               bus-range = <0 0xff>;
+               /* non-prefetchable memory */
+               ranges = <0x82000000 0 CP11X_PCIEx_MEM_BASE(0) 0  CP11X_PCIEx_MEM_BASE(0) 0 CP11X_PCIEx_MEM_SIZE(0)>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &CP11X_LABEL(icu_nsr) 22 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
+               num-lanes = <1>;
+               clock-names = "core", "reg";
+               clocks = <&CP11X_LABEL(clk) 1 13>, <&CP11X_LABEL(clk) 1 14>;
+               status = "disabled";
+       };
+
+       CP11X_LABEL(pcie1): pcie@CP11X_PCIE1_BASE {
+               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+               reg = <0 ADDRESSIFY(CP11X_PCIE1_BASE) 0 0x10000>,
+                     <0 CP11X_PCIEx_CONF_BASE(1) 0 0x80000>;
+               reg-names = "ctrl", "config";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               dma-coherent;
+               msi-parent = <&gic_v2m0>;
+
+               bus-range = <0 0xff>;
+               /* non-prefetchable memory */
+               ranges = <0x82000000 0 CP11X_PCIEx_MEM_BASE(1) 0  CP11X_PCIEx_MEM_BASE(1) 0 CP11X_PCIEx_MEM_SIZE(1)>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &CP11X_LABEL(icu_nsr) 24 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
+
+               num-lanes = <1>;
+               clock-names = "core", "reg";
+               clocks = <&CP11X_LABEL(clk) 1 11>, <&CP11X_LABEL(clk) 1 14>;
+               status = "disabled";
+       };
+
+       CP11X_LABEL(pcie2): pcie@CP11X_PCIE2_BASE {
+               compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+               reg = <0 ADDRESSIFY(CP11X_PCIE2_BASE) 0 0x10000>,
+                     <0 CP11X_PCIEx_CONF_BASE(2) 0 0x80000>;
+               reg-names = "ctrl", "config";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               dma-coherent;
+               msi-parent = <&gic_v2m0>;
+
+               bus-range = <0 0xff>;
+               /* non-prefetchable memory */
+               ranges = <0x82000000 0 CP11X_PCIEx_MEM_BASE(2) 0  CP11X_PCIEx_MEM_BASE(2) 0 CP11X_PCIEx_MEM_SIZE(2)>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &CP11X_LABEL(icu_nsr) 23 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
+
+               num-lanes = <1>;
+               clock-names = "core", "reg";
+               clocks = <&CP11X_LABEL(clk) 1 12>, <&CP11X_LABEL(clk) 1 14>;
+               status = "disabled";
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/cn9130-db.dts b/arch/arm64/boot/dts/marvell/cn9130-db.dts
new file mode 100644 (file)
index 0000000..ce49a70
--- /dev/null
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * Device tree for the CN9130-DB board.
+ */
+
+#include "cn9130.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Marvell Armada CN9130-DB";
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       aliases {
+               gpio1 = &cp0_gpio1;
+               gpio2 = &cp0_gpio2;
+               i2c0 = &cp0_i2c0;
+               ethernet0 = &cp0_eth0;
+               ethernet1 = &cp0_eth1;
+               ethernet2 = &cp0_eth2;
+               spi1 = &cp0_spi0;
+               spi2 = &cp0_spi1;
+       };
+
+       memory@00000000 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x80000000>;
+       };
+
+       ap0_reg_sd_vccq: ap0_sd_vccq@0 {
+               compatible = "regulator-gpio";
+               regulator-name = "ap0_sd_vccq";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               gpios = <&expander0 8 GPIO_ACTIVE_HIGH>;
+               states = <1800000 0x1 3300000 0x0>;
+       };
+
+       cp0_reg_usb3_vbus0: cp0_usb3_vbus@0 {
+               compatible = "regulator-fixed";
+               regulator-name = "cp0-xhci0-vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               gpio = <&expander0 0 GPIO_ACTIVE_HIGH>;
+       };
+
+       cp0_usb3_0_phy0: cp0_usb3_phy@0 {
+               compatible = "usb-nop-xceiv";
+               vcc-supply = <&cp0_reg_usb3_vbus0>;
+       };
+
+       cp0_reg_usb3_vbus1: cp0_usb3_vbus@1 {
+               compatible = "regulator-fixed";
+               regulator-name = "cp0-xhci1-vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               gpio = <&expander0 1 GPIO_ACTIVE_HIGH>;
+       };
+
+       cp0_usb3_0_phy1: cp0_usb3_phy@1 {
+               compatible = "usb-nop-xceiv";
+               vcc-supply = <&cp0_reg_usb3_vbus1>;
+       };
+
+       cp0_reg_sd_vccq: cp0_sd_vccq@0 {
+               compatible = "regulator-gpio";
+               regulator-name = "cp0_sd_vccq";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               gpios = <&expander0 15 GPIO_ACTIVE_HIGH>;
+               states = <1800000 0x1
+                         3300000 0x0>;
+       };
+
+       cp0_reg_sd_vcc: cp0_sd_vcc@0 {
+               compatible = "regulator-fixed";
+               regulator-name = "cp0_sd_vcc";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&expander0 14 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       cp0_sfp_eth0: sfp-eth@0 {
+               compatible = "sff,sfp";
+               i2c-bus = <&cp0_sfpp0_i2c>;
+               los-gpio = <&cp0_module_expander1 11 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpio = <&cp0_module_expander1 10 GPIO_ACTIVE_LOW>;
+               tx-disable-gpio = <&cp0_module_expander1 9 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&cp0_module_expander1 8 GPIO_ACTIVE_HIGH>;
+               /*
+                * SFP cages are unconnected on early PCBs because of an the I2C
+                * lanes not being connected. Prevent the port for being
+                * unusable by disabling the SFP node.
+                */
+               status = "disabled";
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
+
+/* on-board eMMC - U9 */
+&ap_sdhci0 {
+       pinctrl-names = "default";
+       bus-width = <8>;
+       vqmmc-supply = <&ap0_reg_sd_vccq>;
+       status = "okay";
+};
+
+&cp0_crypto {
+       status = "disabled";
+};
+
+&cp0_ethernet {
+       status = "okay";
+};
+
+/* SLM-1521-V2, CON9 */
+&cp0_eth0 {
+       status = "disabled";
+       phy-mode = "10gbase-kr";
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp0_comphy4 0>;
+       managed = "in-band-status";
+       sfp = <&cp0_sfp_eth0>;
+};
+
+/* CON56 */
+&cp0_eth1 {
+       status = "okay";
+       phy = <&phy0>;
+       phy-mode = "rgmii-id";
+};
+
+/* CON57 */
+&cp0_eth2 {
+       status = "okay";
+       phy = <&phy1>;
+       phy-mode = "rgmii-id";
+};
+
+&cp0_gpio1 {
+       status = "okay";
+};
+
+&cp0_gpio2 {
+       status = "okay";
+};
+
+&cp0_i2c0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp0_i2c0_pins>;
+       clock-frequency = <100000>;
+
+       /* U36 */
+       expander0: pca953x@21 {
+               compatible = "nxp,pca9555";
+               pinctrl-names = "default";
+               gpio-controller;
+               #gpio-cells = <2>;
+               reg = <0x21>;
+               status = "okay";
+       };
+
+       /* U42 */
+       eeprom0: eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+               pagesize = <0x20>;
+       };
+
+       /* U38 */
+       eeprom1: eeprom@57 {
+               compatible = "atmel,24c64";
+               reg = <0x57>;
+               pagesize = <0x20>;
+       };
+};
+
+&cp0_i2c1 {
+       status = "okay";
+       clock-frequency = <100000>;
+
+       /* SLM-1521-V2 - U3 */
+       i2c-mux@72 { /* verify address - depends on dpr */
+               compatible = "nxp,pca9544";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x72>;
+               cp0_sfpp0_i2c: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+                       /* U12 */
+                       cp0_module_expander1: pca9555@21 {
+                               compatible = "nxp,pca9555";
+                               pinctrl-names = "default";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               reg = <0x21>;
+                       };
+
+               };
+       };
+};
+
+&cp0_mdio {
+       status = "okay";
+
+       phy0: ethernet-phy@0 {
+               reg = <0>;
+       };
+
+       phy1: ethernet-phy@1 {
+               reg = <1>;
+       };
+};
+
+/* U54 */
+&cp0_nand_controller {
+       pinctrl-names = "default";
+       pinctrl-0 = <&nand_pins &nand_rb>;
+
+       nand@0 {
+               reg = <0>;
+               label = "main-storage";
+               nand-rb = <0>;
+               nand-ecc-mode = "hw";
+               nand-on-flash-bbt;
+               nand-ecc-strength = <8>;
+               nand-ecc-step-size = <512>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "U-Boot";
+                               reg = <0 0x200000>;
+                       };
+                       partition@200000 {
+                               label = "Linux";
+                               reg = <0x200000 0xd00000>;
+                       };
+                       partition@1000000 {
+                               label = "Filesystem";
+                               reg = <0x1000000 0x3f000000>;
+                       };
+               };
+       };
+};
+
+/* SLM-1521-V2, CON6 */
+&cp0_pcie0 {
+       status = "okay";
+       num-lanes = <4>;
+       num-viewport = <8>;
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp0_comphy0 0
+               &cp0_comphy1 0
+               &cp0_comphy2 0
+               &cp0_comphy3 0>;
+};
+
+&cp0_sata0 {
+       status = "okay";
+
+       /* SLM-1521-V2, CON2 */
+       sata-port@1 {
+               status = "okay";
+               /* Generic PHY, providing serdes lanes */
+               phys = <&cp0_comphy5 1>;
+       };
+};
+
+/* CON 28 */
+&cp0_sdhci0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp0_sdhci_pins
+                    &cp0_sdhci_cd_pins>;
+       bus-width = <4>;
+       cd-gpios = <&cp0_gpio2 11 GPIO_ACTIVE_LOW>;
+       no-1-8-v;
+       vqmmc-supply = <&cp0_reg_sd_vccq>;
+       vmmc-supply = <&cp0_reg_sd_vcc>;
+};
+
+/* U55 */
+&cp0_spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp0_spi0_pins>;
+       reg = <0x700680 0x50>;
+
+       spi-flash@0 {
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+               compatible = "jedec,spi-nor";
+               reg = <0x0>;
+               /* On-board MUX does not allow higher frequencies */
+               spi-max-frequency = <40000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "U-Boot-0";
+                               reg = <0x0 0x200000>;
+                       };
+
+                       partition@400000 {
+                               label = "Filesystem-0";
+                               reg = <0x200000 0xe00000>;
+                       };
+               };
+       };
+};
+
+&cp0_syscon0 {
+       cp0_pinctrl: pinctrl {
+               compatible = "marvell,cp115-standalone-pinctrl";
+
+               cp0_i2c0_pins: cp0-i2c-pins-0 {
+                       marvell,pins = "mpp37", "mpp38";
+                       marvell,function = "i2c0";
+               };
+               cp0_i2c1_pins: cp0-i2c-pins-1 {
+                       marvell,pins = "mpp35", "mpp36";
+                       marvell,function = "i2c1";
+               };
+               cp0_ge1_rgmii_pins: cp0-ge-rgmii-pins-0 {
+                       marvell,pins = "mpp0", "mpp1", "mpp2",
+                                      "mpp3", "mpp4", "mpp5",
+                                      "mpp6", "mpp7", "mpp8",
+                                      "mpp9", "mpp10", "mpp11";
+                       marvell,function = "ge0";
+               };
+               cp0_ge2_rgmii_pins: cp0-ge-rgmii-pins-1 {
+                       marvell,pins = "mpp44", "mpp45", "mpp46",
+                                      "mpp47", "mpp48", "mpp49",
+                                      "mpp50", "mpp51", "mpp52",
+                                      "mpp53", "mpp54", "mpp55";
+                       marvell,function = "ge1";
+               };
+               cp0_sdhci_cd_pins: cp0-sdhci-cd-pins-0 {
+                       marvell,pins = "mpp43";
+                       marvell,function = "gpio";
+               };
+               cp0_sdhci_pins: cp0-sdhi-pins-0 {
+                       marvell,pins = "mpp56", "mpp57", "mpp58",
+                                      "mpp59", "mpp60", "mpp61";
+                       marvell,function = "sdio";
+               };
+               cp0_spi0_pins: cp0-spi-pins-0 {
+                       marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16";
+                       marvell,function = "spi1";
+               };
+               nand_pins: nand-pins {
+                       marvell,pins = "mpp15", "mpp16", "mpp17", "mpp18",
+                                      "mpp19", "mpp20", "mpp21", "mpp22",
+                                      "mpp23", "mpp24", "mpp25", "mpp26",
+                                      "mpp27";
+                       marvell,function = "dev";
+               };
+               nand_rb: nand-rb {
+                       marvell,pins = "mpp13";
+                       marvell,function = "nf";
+               };
+       };
+};
+
+&cp0_usb3_0 {
+       status = "okay";
+       usb-phy = <&cp0_usb3_0_phy0>;
+       phy-names = "usb";
+};
+
+&cp0_usb3_1 {
+       status = "okay";
+       usb-phy = <&cp0_usb3_0_phy1>;
+       phy-names = "usb";
+};
diff --git a/arch/arm64/boot/dts/marvell/cn9130.dtsi b/arch/arm64/boot/dts/marvell/cn9130.dtsi
new file mode 100644 (file)
index 0000000..a2b7e5e
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * Device tree for the CN9130 SoC.
+ */
+
+#include "armada-ap807-quad.dtsi"
+
+/ {
+       model = "Marvell Armada CN9130 SoC";
+       compatible = "marvell,cn9130", "marvell,armada-ap807-quad",
+                    "marvell,armada-ap807";
+};
+
+/*
+ * Instantiate the internal CP115
+ */
+
+#define CP11X_NAME             cp0
+#define CP11X_BASE             f2000000
+#define CP11X_PCIEx_MEM_BASE(iface) ((iface == 0) ? 0xc0000000 : \
+                                                   0xe0000000 + ((iface - 1) * 0x1000000))
+#define CP11X_PCIEx_MEM_SIZE(iface) ((iface == 0) ? 0x1ff00000 : 0xf00000)
+#define CP11X_PCIE0_BASE       f2600000
+#define CP11X_PCIE1_BASE       f2620000
+#define CP11X_PCIE2_BASE       f2640000
+
+#include "armada-cp115.dtsi"
+
+#undef CP11X_NAME
+#undef CP11X_BASE
+#undef CP11X_PCIEx_MEM_BASE
+#undef CP11X_PCIEx_MEM_SIZE
+#undef CP11X_PCIE0_BASE
+#undef CP11X_PCIE1_BASE
+#undef CP11X_PCIE2_BASE
diff --git a/arch/arm64/boot/dts/marvell/cn9131-db.dts b/arch/arm64/boot/dts/marvell/cn9131-db.dts
new file mode 100644 (file)
index 0000000..3c975f9
--- /dev/null
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * Device tree for the CN9131-DB board.
+ */
+
+#include "cn9130-db.dts"
+
+/ {
+       model = "Marvell Armada CN9131-DB";
+       compatible = "marvell,cn9131", "marvell,cn9130",
+                    "marvell,armada-ap807-quad", "marvell,armada-ap807";
+
+       aliases {
+               gpio3 = &cp1_gpio1;
+               gpio4 = &cp1_gpio2;
+               ethernet3 = &cp1_eth0;
+               ethernet4 = &cp1_eth1;
+       };
+
+       cp1_reg_usb3_vbus0: cp1_usb3_vbus@0 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&cp1_xhci0_vbus_pins>;
+               regulator-name = "cp1-xhci0-vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               gpio = <&cp1_gpio1 3 GPIO_ACTIVE_HIGH>;
+       };
+
+       cp1_usb3_0_phy0: cp1_usb3_phy0 {
+               compatible = "usb-nop-xceiv";
+               vcc-supply = <&cp1_reg_usb3_vbus0>;
+       };
+
+       cp1_sfp_eth1: sfp-eth1 {
+               compatible = "sff,sfp";
+               i2c-bus = <&cp1_i2c0>;
+               los-gpio = <&cp1_gpio1 11 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpio = <&cp1_gpio1 10 GPIO_ACTIVE_LOW>;
+               tx-disable-gpio = <&cp1_gpio1 9 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&cp1_gpio1 8 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&cp1_sfp_pins>;
+               /*
+                * SFP cages are unconnected on early PCBs because of an the I2C
+                * lanes not being connected. Prevent the port for being
+                * unusable by disabling the SFP node.
+                */
+               status = "disabled";
+       };
+};
+
+/*
+ * Instantiate the first slave CP115
+ */
+
+#define CP11X_NAME             cp1
+#define CP11X_BASE             f4000000
+#define CP11X_PCIEx_MEM_BASE(iface) (0xe2000000 + (iface * 0x1000000))
+#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
+#define CP11X_PCIE0_BASE       f4600000
+#define CP11X_PCIE1_BASE       f4620000
+#define CP11X_PCIE2_BASE       f4640000
+
+#include "armada-cp115.dtsi"
+
+#undef CP11X_NAME
+#undef CP11X_BASE
+#undef CP11X_PCIEx_MEM_BASE
+#undef CP11X_PCIEx_MEM_SIZE
+#undef CP11X_PCIE0_BASE
+#undef CP11X_PCIE1_BASE
+#undef CP11X_PCIE2_BASE
+
+&cp1_crypto {
+       status = "disabled";
+};
+
+&cp1_ethernet {
+       status = "okay";
+};
+
+/* CON50 */
+&cp1_eth0 {
+       status = "disabled";
+       phy-mode = "10gbase-kr";
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp1_comphy4 0>;
+       managed = "in-band-status";
+       sfp = <&cp1_sfp_eth1>;
+};
+
+&cp1_gpio1 {
+       status = "okay";
+};
+
+&cp1_gpio2 {
+       status = "okay";
+};
+
+&cp1_i2c0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp1_i2c0_pins>;
+       clock-frequency = <100000>;
+};
+
+/* CON40 */
+&cp1_pcie0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp1_pcie_reset_pins>;
+       num-lanes = <2>;
+       num-viewport = <8>;
+       marvell,reset-gpio = <&cp1_gpio1 0 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp1_comphy0 0
+               &cp1_comphy1 0>;
+};
+
+&cp1_sata0 {
+       status = "okay";
+
+       /* CON32 */
+       sata-port@1 {
+               /* Generic PHY, providing serdes lanes */
+               phys = <&cp1_comphy5 1>;
+       };
+};
+
+/* U24 */
+&cp1_spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp1_spi0_pins>;
+       reg = <0x700680 0x50>;
+
+       spi-flash@0 {
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+               compatible = "jedec,spi-nor";
+               reg = <0x0>;
+               /* On-board MUX does not allow higher frequencies */
+               spi-max-frequency = <40000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "U-Boot-1";
+                               reg = <0x0 0x200000>;
+                       };
+
+                       partition@400000 {
+                               label = "Filesystem-1";
+                               reg = <0x200000 0xe00000>;
+                       };
+               };
+       };
+
+};
+
+&cp1_syscon0 {
+       cp1_pinctrl: pinctrl {
+               compatible = "marvell,cp115-standalone-pinctrl";
+
+               cp1_i2c0_pins: cp1-i2c-pins-0 {
+                       marvell,pins = "mpp37", "mpp38";
+                       marvell,function = "i2c0";
+               };
+               cp1_spi0_pins: cp1-spi-pins-0 {
+                       marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16";
+                       marvell,function = "spi1";
+               };
+               cp1_xhci0_vbus_pins: cp1-xhci0-vbus-pins {
+                       marvell,pins = "mpp3";
+                       marvell,function = "gpio";
+               };
+               cp1_sfp_pins: sfp-pins {
+                       marvell,pins = "mpp8", "mpp9", "mpp10", "mpp11";
+                       marvell,function = "gpio";
+               };
+               cp1_pcie_reset_pins: cp1-pcie-reset-pins {
+                       marvell,pins = "mpp0";
+                       marvell,function = "gpio";
+               };
+       };
+};
+
+/* CON58 */
+&cp1_usb3_1 {
+       status = "okay";
+       usb-phy = <&cp1_usb3_0_phy0>;
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp1_comphy3 1>;
+       phy-names = "usb";
+};
diff --git a/arch/arm64/boot/dts/marvell/cn9132-db.dts b/arch/arm64/boot/dts/marvell/cn9132-db.dts
new file mode 100644 (file)
index 0000000..4ef0df3
--- /dev/null
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * Device tree for the CN9132-DB board.
+ */
+
+#include "cn9131-db.dts"
+
+/ {
+       model = "Marvell Armada CN9132-DB";
+       compatible = "marvell,cn9132", "marvell,cn9131", "marvell,cn9130",
+                    "marvell,armada-ap807-quad", "marvell,armada-ap807";
+
+       aliases {
+               gpio5 = &cp2_gpio1;
+               gpio6 = &cp2_gpio2;
+               ethernet5 = &cp2_eth0;
+       };
+
+       cp2_reg_usb3_vbus0: cp2_usb3_vbus@0 {
+               compatible = "regulator-fixed";
+               regulator-name = "cp2-xhci0-vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               gpio = <&cp2_gpio1 2 GPIO_ACTIVE_HIGH>;
+       };
+
+       cp2_usb3_0_phy0: cp2_usb3_phy0 {
+               compatible = "usb-nop-xceiv";
+               vcc-supply = <&cp2_reg_usb3_vbus0>;
+       };
+
+       cp2_reg_usb3_vbus1: cp2_usb3_vbus@1 {
+               compatible = "regulator-fixed";
+               regulator-name = "cp2-xhci1-vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               gpio = <&cp2_gpio1 3 GPIO_ACTIVE_HIGH>;
+       };
+
+       cp2_usb3_0_phy1: cp2_usb3_phy1 {
+               compatible = "usb-nop-xceiv";
+               vcc-supply = <&cp2_reg_usb3_vbus1>;
+       };
+
+       cp2_reg_sd_vccq: cp2_sd_vccq@0 {
+               compatible = "regulator-gpio";
+               regulator-name = "cp2_sd_vcc";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               gpios = <&cp2_gpio2 17 GPIO_ACTIVE_HIGH>;
+               states = <1800000 0x1 3300000 0x0>;
+       };
+
+       cp2_sfp_eth0: sfp-eth0 {
+               compatible = "sff,sfp";
+               i2c-bus = <&cp2_sfpp0_i2c>;
+               los-gpio = <&cp2_module_expander1 11 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpio = <&cp2_module_expander1 10 GPIO_ACTIVE_LOW>;
+               tx-disable-gpio = <&cp2_module_expander1 9 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&cp2_module_expander1 8 GPIO_ACTIVE_HIGH>;
+               /*
+                * SFP cages are unconnected on early PCBs because of an the I2C
+                * lanes not being connected. Prevent the port for being
+                * unusable by disabling the SFP node.
+                */
+               status = "disabled";
+       };
+};
+
+/*
+ * Instantiate the second slave CP115
+ */
+
+#define CP11X_NAME             cp2
+#define CP11X_BASE             f6000000
+#define CP11X_PCIEx_MEM_BASE(iface) (0xe5000000 + (iface * 0x1000000))
+#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
+#define CP11X_PCIE0_BASE       f6600000
+#define CP11X_PCIE1_BASE       f6620000
+#define CP11X_PCIE2_BASE       f6640000
+
+#include "armada-cp115.dtsi"
+
+#undef CP11X_NAME
+#undef CP11X_BASE
+#undef CP11X_PCIEx_MEM_BASE
+#undef CP11X_PCIEx_MEM_SIZE
+#undef CP11X_PCIE0_BASE
+#undef CP11X_PCIE1_BASE
+#undef CP11X_PCIE2_BASE
+
+&cp2_crypto {
+       status = "disabled";
+};
+
+&cp2_ethernet {
+       status = "okay";
+};
+
+/* SLM-1521-V2, CON9 */
+&cp2_eth0 {
+       status = "disabled";
+       phy-mode = "10gbase-kr";
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp2_comphy4 0>;
+       managed = "in-band-status";
+       sfp = <&cp2_sfp_eth0>;
+};
+
+&cp2_gpio1 {
+       status = "okay";
+};
+
+&cp2_gpio2 {
+       status = "okay";
+};
+
+&cp2_i2c0 {
+       clock-frequency = <100000>;
+
+       /* SLM-1521-V2 - U3 */
+       i2c-mux@72 {
+               compatible = "nxp,pca9544";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x72>;
+               cp2_sfpp0_i2c: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+                       /* U12 */
+                       cp2_module_expander1: pca9555@21 {
+                               compatible = "nxp,pca9555";
+                               pinctrl-names = "default";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               reg = <0x21>;
+                       };
+               };
+       };
+};
+
+/* SLM-1521-V2, CON6 */
+&cp2_pcie0 {
+       status = "okay";
+       num-lanes = <2>;
+       num-viewport = <8>;
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp2_comphy0 0
+               &cp2_comphy1 0>;
+};
+
+/* SLM-1521-V2, CON8 */
+&cp2_pcie2 {
+       status = "okay";
+       num-lanes = <1>;
+       num-viewport = <8>;
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp2_comphy5 2>;
+};
+
+&cp2_sata0 {
+       status = "okay";
+
+       /* SLM-1521-V2, CON4 */
+       sata-port@0 {
+               /* Generic PHY, providing serdes lanes */
+               phys = <&cp2_comphy2 0>;
+       };
+};
+
+/* CON 2 on SLM-1683 - microSD */
+&cp2_sdhci0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&cp2_sdhci_pins>;
+       bus-width = <4>;
+       cd-gpios = <&cp2_gpio2 23 GPIO_ACTIVE_LOW>;
+       vqmmc-supply = <&cp2_reg_sd_vccq>;
+};
+
+&cp2_syscon0 {
+       cp2_pinctrl: pinctrl {
+               compatible = "marvell,cp115-standalone-pinctrl";
+
+               cp2_i2c0_pins: cp2-i2c-pins-0 {
+                       marvell,pins = "mpp37", "mpp38";
+                       marvell,function = "i2c0";
+               };
+               cp2_sdhci_pins: cp2-sdhi-pins-0 {
+                       marvell,pins = "mpp56", "mpp57", "mpp58",
+                                      "mpp59", "mpp60", "mpp61";
+                       marvell,function = "sdio";
+               };
+       };
+};
+
+&cp2_usb3_0 {
+       status = "okay";
+       usb-phy = <&cp2_usb3_0_phy0>;
+       phy-names = "usb";
+};
+
+/* SLM-1521-V2, CON11 */
+&cp2_usb3_1 {
+       status = "okay";
+       usb-phy = <&cp2_usb3_0_phy1>;
+       phy-names = "usb";
+       /* Generic PHY, providing serdes lanes */
+       phys = <&cp2_comphy3 1>;
+};
index 97f84aa..10b3247 100644 (file)
                        clock-names = "spi", "wrap";
                };
 
+               systimer: timer@10017000 {
+                       compatible = "mediatek,mt8183-timer",
+                                    "mediatek,mt6765-timer";
+                       reg = <0 0x10017000 0 0x1000>;
+                       interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&topckgen CLK_TOP_CLK13M>;
+                       clock-names = "clk13m";
+               };
+
                auxadc: auxadc@11001000 {
                        compatible = "mediatek,mt8183-auxadc",
                                     "mediatek,mt8173-auxadc";
index bdace01..f1de4ff 100644 (file)
        };
 
        padctl@3520000 {
-               status = "disabled";
+               status = "okay";
 
                avdd-pll-erefeut-supply = <&vdd_1v8_pll>;
                avdd-usb-supply = <&vdd_3v3_sys>;
        };
 
        usb@3530000 {
-               status = "disabled";
+               status = "okay";
 
                phys = <&{/padctl@3520000/pads/usb2/lanes/usb2-0}>,
                       <&{/padctl@3520000/pads/usb2/lanes/usb2-1}>,
                        status = "disabled";
                };
 
+               /* DP on E3320 */
                sor@15540000 {
-                       status = "disabled";
+                       status = "okay";
+
+                       avdd-io-hdmi-dp-supply = <&vdd_hdmi_1v05>;
+                       vdd-hdmi-dp-pll = <&vdd_1v8_ap>;
 
-                       nvidia,dpaux = <&dpaux1>;
+                       nvidia,dpaux = <&dpaux>;
                };
 
                sor@15580000 {
index 47cd831..7893d78 100644 (file)
                      <0x0 0x03538000 0x0 0x1000>;
                reg-names = "hcd", "fpci";
 
+               iommus = <&smmu TEGRA186_SID_XUSB_HOST>;
                interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
                        reset-names = "vic";
 
                        power-domains = <&bpmp TEGRA186_POWER_DOMAIN_VIC>;
+                       iommus = <&smmu TEGRA186_SID_VIC>;
                };
 
                dsib: dsi@15400000 {
                };
 
                sor1: sor@15580000 {
-                       compatible = "nvidia,tegra186-sor1";
+                       compatible = "nvidia,tegra186-sor";
                        reg = <0x15580000 0x10000>;
                        interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&bpmp TEGRA186_CLK_SOR1>,
index 4c38426..c7f2a20 100644 (file)
@@ -8,17 +8,18 @@
        compatible = "nvidia,p2888", "nvidia,tegra194";
 
        aliases {
-               sdhci0 = "/cbb/sdhci@3460000";
-               sdhci1 = "/cbb/sdhci@3400000";
+               ethernet0 = "/cbb@0/ethernet@2490000";
+               sdhci0 = "/cbb@0/sdhci@3460000";
+               sdhci1 = "/cbb@0/sdhci@3400000";
                serial0 = &tcu;
                i2c0 = "/bpmp/i2c";
-               i2c1 = "/cbb/i2c@3160000";
-               i2c2 = "/cbb/i2c@c240000";
-               i2c3 = "/cbb/i2c@3180000";
-               i2c4 = "/cbb/i2c@3190000";
-               i2c5 = "/cbb/i2c@31c0000";
-               i2c6 = "/cbb/i2c@c250000";
-               i2c7 = "/cbb/i2c@31e0000";
+               i2c1 = "/cbb@0/i2c@3160000";
+               i2c2 = "/cbb@0/i2c@c240000";
+               i2c3 = "/cbb@0/i2c@3180000";
+               i2c4 = "/cbb@0/i2c@3190000";
+               i2c5 = "/cbb@0/i2c@31c0000";
+               i2c6 = "/cbb@0/i2c@c250000";
+               i2c7 = "/cbb@0/i2c@31e0000";
        };
 
        chosen {
@@ -26,7 +27,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       cbb {
+       cbb@0 {
                ethernet@2490000 {
                        status = "okay";
 
                                        in-ldo7-8-supply = <&vdd_1v8ls>;
 
                                        vdd_1v0: sd0 {
-                                               regulator-name = "VDD_1V0";
+                                               regulator-name = "VDDIO_SYS_1V0";
                                                regulator-min-microvolt = <1000000>;
                                                regulator-max-microvolt = <1000000>;
                                                regulator-always-on;
                                        };
 
                                        vdd_1v8hs: sd1 {
-                                               regulator-name = "VDD_1V8HS";
+                                               regulator-name = "VDDIO_SYS_1V8HS";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
                                                regulator-always-on;
                                        };
 
                                        vdd_1v8ls: sd2 {
-                                               regulator-name = "VDD_1V8LS";
+                                               regulator-name = "VDDIO_SYS_1V8LS";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
                                                regulator-always-on;
                                        };
 
                                        vdd_1v8ao: sd3 {
-                                               regulator-name = "VDD_1V8AO";
+                                               regulator-name = "VDDIO_AO_1V8";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
                                                regulator-always-on;
                                        };
 
                                        ldo2 {
-                                               regulator-name = "VDD_AO_3V3";
+                                               regulator-name = "VDDIO_AO_3V3";
                                                regulator-min-microvolt = <3300000>;
                                                regulator-max-microvolt = <3300000>;
                                                regulator-always-on;
                                        };
 
                                        ldo7 {
-                                               regulator-name = "VDD_CSI_1V2";
+                                               regulator-name = "AVDD_CSI_1V2";
                                                regulator-min-microvolt = <1200000>;
                                                regulator-max-microvolt = <1200000>;
                                        };
                        regulator-name = "VDD_12V";
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
-                       gpio = <&gpio TEGRA194_MAIN_GPIO(A, 1) GPIO_ACTIVE_LOW>;
+                       gpio = <&gpio TEGRA194_MAIN_GPIO(A, 1) GPIO_ACTIVE_HIGH>;
                        regulator-boot-on;
-                       enable-active-low;
                };
        };
 };
index d47cd8c..353a6a2 100644 (file)
@@ -10,8 +10,8 @@
        model = "NVIDIA Jetson AGX Xavier Developer Kit";
        compatible = "nvidia,p2972-0000", "nvidia,tegra194";
 
-       cbb {
-               aconnect {
+       cbb@0 {
+               aconnect@2900000 {
                        status = "okay";
 
                        dma-controller@2930000 {
                                status = "okay";
                        };
 
+                       dpaux@155c0000 {
+                               status = "okay";
+                       };
+
+                       dpaux@155d0000 {
+                               status = "okay";
+                       };
+
                        dpaux@155e0000 {
                                status = "okay";
                        };
 
+                       /* DP0 */
+                       sor@15b00000 {
+                               status = "okay";
+
+                               avdd-io-hdmi-dp-supply = <&vdd_1v0>;
+                               vdd-hdmi-dp-pll-supply = <&vdd_1v8hs>;
+
+                               nvidia,dpaux = <&dpaux0>;
+                       };
+
+                       /* DP1 */
+                       sor@15b40000 {
+                               status = "okay";
+
+                               avdd-io-hdmi-dp-supply = <&vdd_1v0>;
+                               vdd-hdmi-dp-pll-supply = <&vdd_1v8hs>;
+
+                               nvidia,dpaux = <&dpaux1>;
+                       };
+
+                       /* HDMI */
                        sor@15b80000 {
                                status = "okay";
 
index 3c0cf54..11220d9 100644 (file)
@@ -15,7 +15,7 @@
        #size-cells = <2>;
 
        /* control backbone */
-       cbb {
+       cbb@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
@@ -39,7 +39,8 @@
                };
 
                ethernet@2490000 {
-                       compatible = "nvidia,tegra186-eqos",
+                       compatible = "nvidia,tegra194-eqos",
+                                    "nvidia,tegra186-eqos",
                                     "snps,dwc-qos-ethernet-4.10";
                        reg = <0x02490000 0x10000>;
                        interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
@@ -60,7 +61,7 @@
                        snps,rxpbl = <8>;
                };
 
-               aconnect {
+               aconnect@2900000 {
                        compatible = "nvidia,tegra194-aconnect",
                                     "nvidia,tegra210-aconnect";
                        clocks = <&bpmp TEGRA194_CLK_APE>,
 
                        sor1: sor@15b40000 {
                                compatible = "nvidia,tegra194-sor";
-                               reg = <0x155c0000 0x40000>;
+                               reg = <0x15b40000 0x40000>;
                                interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&bpmp TEGRA194_CLK_SOR1_REF>,
                                         <&bpmp TEGRA194_CLK_SOR1_OUT>,
 
                nvidia,bpmp = <&bpmp 1>;
 
-               supports-clkreq;
                nvidia,aspm-cmrt-us = <60>;
                nvidia,aspm-pwr-on-t-us = <20>;
                nvidia,aspm-l0s-entrance-latency-us = <3>;
 
                nvidia,bpmp = <&bpmp 2>;
 
-               supports-clkreq;
                nvidia,aspm-cmrt-us = <60>;
                nvidia,aspm-pwr-on-t-us = <20>;
                nvidia,aspm-l0s-entrance-latency-us = <3>;
 
                nvidia,bpmp = <&bpmp 3>;
 
-               supports-clkreq;
                nvidia,aspm-cmrt-us = <60>;
                nvidia,aspm-pwr-on-t-us = <20>;
                nvidia,aspm-l0s-entrance-latency-us = <3>;
 
                nvidia,bpmp = <&bpmp 4>;
 
-               supports-clkreq;
                nvidia,aspm-cmrt-us = <60>;
                nvidia,aspm-pwr-on-t-us = <20>;
                nvidia,aspm-l0s-entrance-latency-us = <3>;
 
                nvidia,bpmp = <&bpmp 0>;
 
-               supports-clkreq;
                nvidia,aspm-cmrt-us = <60>;
                nvidia,aspm-pwr-on-t-us = <20>;
                nvidia,aspm-l0s-entrance-latency-us = <3>;
                interrupt-map-mask = <0 0 0 0>;
                interrupt-map = <0 0 0 0 &gic GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
 
-               supports-clkreq;
                nvidia,aspm-cmrt-us = <60>;
                nvidia,aspm-pwr-on-t-us = <20>;
                nvidia,aspm-l0s-entrance-latency-us = <3>;
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               cpu0_0: cpu@0 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
-                       reg = <0x10000>;
+                       reg = <0x000>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_0>;
                };
 
-               cpu@1 {
+               cpu0_1: cpu@1 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
-                       reg = <0x10001>;
+                       reg = <0x001>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_0>;
                };
 
-               cpu@2 {
+               cpu1_0: cpu@100 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
                        reg = <0x100>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_1>;
                };
 
-               cpu@3 {
+               cpu1_1: cpu@101 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
                        reg = <0x101>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_1>;
                };
 
-               cpu@4 {
+               cpu2_0: cpu@200 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
                        reg = <0x200>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_2>;
                };
 
-               cpu@5 {
+               cpu2_1: cpu@201 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
                        reg = <0x201>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_2>;
                };
 
-               cpu@6 {
+               cpu3_0: cpu@300 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
-                       reg = <0x10300>;
+                       reg = <0x300>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_3>;
                };
 
-               cpu@7 {
+               cpu3_1: cpu@301 {
                        compatible = "nvidia,tegra194-carmel";
                        device_type = "cpu";
-                       reg = <0x10301>;
+                       reg = <0x301>;
                        enable-method = "psci";
+                       i-cache-size = <131072>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <65536>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2c_3>;
+               };
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&cpu0_0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu0_1>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&cpu1_0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu1_1>;
+                               };
+                       };
+
+                       cluster2 {
+                               core0 {
+                                       cpu = <&cpu2_0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu2_1>;
+                               };
+                       };
+
+                       cluster3 {
+                               core0 {
+                                       cpu = <&cpu3_0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu3_1>;
+                               };
+                       };
+               };
+
+               l2c_0: l2-cache0 {
+                       cache-size = <2097152>;
+                       cache-line-size = <64>;
+                       cache-sets = <2048>;
+                       next-level-cache = <&l3c>;
+               };
+
+               l2c_1: l2-cache1 {
+                       cache-size = <2097152>;
+                       cache-line-size = <64>;
+                       cache-sets = <2048>;
+                       next-level-cache = <&l3c>;
+               };
+
+               l2c_2: l2-cache2 {
+                       cache-size = <2097152>;
+                       cache-line-size = <64>;
+                       cache-sets = <2048>;
+                       next-level-cache = <&l3c>;
+               };
+
+               l2c_3: l2-cache3 {
+                       cache-size = <2097152>;
+                       cache-line-size = <64>;
+                       cache-sets = <2048>;
+                       next-level-cache = <&l3c>;
+               };
+
+               l3c: l3-cache {
+                       cache-size = <4194304>;
+                       cache-line-size = <64>;
+                       cache-sets = <4096>;
                };
        };
 
index 2772382..cb58f79 100644 (file)
 
        pmc@7000e400 {
                nvidia,invert-interrupt;
+               nvidia,suspend-mode = <0>;
+               nvidia,cpu-pwr-good-time = <0>;
+               nvidia,cpu-pwr-off-time = <0>;
+               nvidia,core-pwr-good-time = <4587 3876>;
+               nvidia,core-pwr-off-time = <39065>;
+               nvidia,core-power-req-active-high;
+               nvidia,sys-clock-req-active-high;
        };
 
        /* eMMC */
index a7dc319..b009507 100644 (file)
                        regulator-name = "VDD_HDMI_5V0";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
-                       gpio = <&exp1 12 GPIO_ACTIVE_LOW>;
+                       gpio = <&exp1 12 GPIO_ACTIVE_HIGH>;
                        enable-active-high;
                        vin-supply = <&vdd_5v0_sys>;
                };
index 9d17ec7..90381d5 100644 (file)
                        status = "okay";
                };
 
+               sor@54540000 {
+                       status = "okay";
+
+                       avdd-io-hdmi-dp-supply = <&avdd_io_edp_1v05>;
+                       vdd-hdmi-dp-pll-supply = <&vdd_1v8>;
+
+                       nvidia,xbar-cfg = <2 1 0 3 4>;
+                       nvidia,dpaux = <&dpaux>;
+               };
+
                sor@54580000 {
                        status = "okay";
 
                                           GPIO_ACTIVE_LOW>;
                        nvidia,xbar-cfg = <0 1 2 3 4>;
                };
+
+               dpaux@545c0000 {
+                       status = "okay";
+               };
        };
 
        gpu@57000000 {
 
        pmc@7000e400 {
                nvidia,invert-interrupt;
+               nvidia,suspend-mode = <0>;
+               nvidia,cpu-pwr-good-time = <0>;
+               nvidia,cpu-pwr-off-time = <0>;
+               nvidia,core-pwr-good-time = <4587 3876>;
+               nvidia,core-pwr-off-time = <39065>;
+               nvidia,core-power-req-active-high;
+               nvidia,sys-clock-req-active-high;
        };
 
        hda@70030000 {
                        enable-gpios = <&pmic 6 GPIO_ACTIVE_HIGH>;
                        vin-supply = <&vdd_5v0_sys>;
                };
+
+               avdd_io_edp_1v05: regulator@7 {
+                       compatible = "regulator-fixed";
+                       reg = <7>;
+
+                       regulator-name = "AVDD_IO_EDP_1V05";
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1050000>;
+
+                       gpio = <&pmic 7 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&avdd_1v05_pll>;
+               };
        };
 };
index 6597531..48c6325 100644 (file)
                        reg = <0x0 0x54540000 0x0 0x00040000>;
                        interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&tegra_car TEGRA210_CLK_SOR0>,
+                                <&tegra_car TEGRA210_CLK_SOR0_OUT>,
                                 <&tegra_car TEGRA210_CLK_PLL_D_OUT0>,
                                 <&tegra_car TEGRA210_CLK_PLL_DP>,
                                 <&tegra_car TEGRA210_CLK_SOR_SAFE>;
-                       clock-names = "sor", "parent", "dp", "safe";
+                       clock-names = "sor", "out", "parent", "dp", "safe";
                        resets = <&tegra_car 182>;
                        reset-names = "sor";
                        pinctrl-0 = <&state_dpaux_aux>;
        rtc@7000e000 {
                compatible = "nvidia,tegra210-rtc", "nvidia,tegra20-rtc";
                reg = <0x0 0x7000e000 0x0 0x100>;
-               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-parent = <&pmc>;
                clocks = <&tegra_car TEGRA210_CLK_RTC>;
                clock-names = "rtc";
        };
                reg = <0x0 0x7000e400 0x0 0x400>;
                clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
                clock-names = "pclk", "clk32k_in";
+               #interrupt-cells = <2>;
+               interrupt-controller;
 
                powergates {
                        pd_audio: aud {
                };
        };
 
+       pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&{/cpus/cpu@0} &{/cpus/cpu@1}
+                                     &{/cpus/cpu@2} &{/cpus/cpu@3}>;
+       };
+
        timer {
                compatible = "arm,armv8-timer";
                interrupts = <GIC_PPI 13
                reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
                        0x0 0x60006000 0x0 0x400>; /* CAR reg_base */
                reg-names = "soctherm-reg", "car-reg";
-               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "thermal", "edp";
                clocks = <&tegra_car TEGRA210_CLK_TSENSOR>,
                        <&tegra_car TEGRA210_CLK_SOC_THERM>;
                clock-names = "tsensor", "soctherm";
                                };
                        };
                };
+
                mem {
                        polling-delay-passive = <0>;
                        polling-delay = <0>;
                                 */
                        };
                };
+
                gpu {
                        polling-delay-passive = <1000>;
                        polling-delay = <0>;
                                };
                        };
                };
+
                pllx {
                        polling-delay-passive = <0>;
                        polling-delay = <0>;
index 04ad2fb..dba3488 100644 (file)
                                l21 {
                                        regulator-min-microvolt = <2950000>;
                                        regulator-max-microvolt = <2950000>;
+                                       regulator-allow-set-load;
+                                       regulator-system-load = <200000>;
                                };
                                l22 {
                                        regulator-min-microvolt = <3300000>;
index 2b28e38..d1ccb94 100644 (file)
@@ -5,6 +5,7 @@
 #include "msm8916.dtsi"
 #include "pm8916.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
        model = "Longcheer L8150";
                stdout-path = "serial0";
        };
 
+       reserved-memory {
+               // wcnss.mdt is not relocatable, so it must be loaded at 0x8b600000
+               /delete-node/ wcnss@89300000;
+
+               wcnss_mem: wcnss@8b600000 {
+                       reg = <0x0 0x8b600000 0x0 0x600000>;
+                       no-map;
+               };
+       };
+
        soc {
                sdhci@7824000 {
                        status = "okay";
                        };
                };
 
+               wcnss@a21b000 {
+                       status = "okay";
+               };
+
                /*
                 * Attempting to enable these devices causes a "synchronous
                 * external abort". Suspected cause is that the debug power
                pinctrl-names = "default";
                pinctrl-0 = <&usb_vbus_default>;
        };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&gpio_keys_default>;
+
+               label = "GPIO Buttons";
+
+               volume-up {
+                       label = "Volume Up";
+                       gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+               };
+       };
 };
 
 &msmgpio {
+       gpio_keys_default: gpio_keys_default {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio107";
+               };
+               pinconf {
+                       pins = "gpio107";
+                       drive-strength = <2>;
+                       bias-pull-up;
+               };
+       };
+
        usb_vbus_default: usb-vbus-default {
                pinmux {
                        function = "gpio";
        };
 };
 
+&spmi_bus {
+       pm8916@0 {
+               pon@800 {
+                       volume-down {
+                               compatible = "qcom,pm8941-resin";
+                               interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
+                               bias-pull-up;
+                               linux,code = <KEY_VOLUMEDOWN>;
+                       };
+               };
+       };
+};
+
 &smd_rpm_regulators {
        vdd_l1_l2_l3-supply = <&pm8916_s3>;
        vdd_l4_l5_l6-supply = <&pm8916_s4>;
index e675ff4..bd1eb3e 100644 (file)
@@ -3,6 +3,7 @@
 #include "msm8916.dtsi"
 #include "pm8916.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 / {
                        };
                };
 
+               wcnss@a21b000 {
+                       status = "okay";
+               };
+
                /*
                 * Attempting to enable these devices causes a "synchronous
                 * external abort". Suspected cause is that the debug power
                etm@85f000 { status = "disabled"; };
        };
 
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&gpio_keys_default>;
+
+               label = "GPIO Buttons";
+
+               volume-up {
+                       label = "Volume Up";
+                       gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+               };
+
+               home {
+                       label = "Home";
+                       gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_HOMEPAGE>;
+               };
+       };
+
+       gpio-hall-sensor {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&gpio_hall_sensor_default>;
+
+               label = "GPIO Hall Effect Sensor";
+
+               hall-sensor {
+                       label = "Hall Effect Sensor";
+                       gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>;
+                       linux,input-type = <EV_SW>;
+                       linux,code = <SW_LID>;
+                       linux,can-disable;
+               };
+       };
+
        i2c-muic {
                compatible = "i2c-gpio";
                sda-gpios = <&msmgpio 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
 };
 
 &msmgpio {
+       gpio_keys_default: gpio_keys_default {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio107", "gpio109";
+               };
+               pinconf {
+                       pins = "gpio107", "gpio109";
+                       drive-strength = <2>;
+                       bias-pull-up;
+               };
+       };
+
+       gpio_hall_sensor_default: gpio_hall_sensor_default {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio52";
+               };
+               pinconf {
+                       pins = "gpio52";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
        muic_int_default: muic_int_default {
                pinmux {
                        function = "gpio";
                regulator-max-microvolt = <2700000>;
        };
 };
+
+&spmi_bus {
+       pm8916@0 {
+               pon@800 {
+                       volume-down {
+                               compatible = "qcom,pm8941-resin";
+                               interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
+                               bias-pull-up;
+                               linux,code = <KEY_VOLUMEDOWN>;
+                       };
+               };
+       };
+};
index 1aa59da..6629a62 100644 (file)
@@ -8,3 +8,9 @@
        model = "Samsung Galaxy A5U (EUR)";
        compatible = "samsung,a5u-eur", "qcom,msm8916";
 };
+
+&pronto {
+       iris {
+               compatible = "qcom,wcn3680";
+       };
+};
index 5ea9fb8..8686e10 100644 (file)
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens 4>;
+                       thermal-sensors = <&tsens 5>;
 
                        trips {
                                cpu0_1_alert0: trip-point@0 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens 3>;
+                       thermal-sensors = <&tsens 4>;
 
                        trips {
                                cpu2_3_alert0: trip-point@0 {
index 87f4d9c..4ca2e7b 100644 (file)
                        reg = <0x4a9000 0x1000>, /* TM */
                              <0x4a8000 0x1000>; /* SROT */
                        #qcom,sensors = <13>;
+                       interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
                        reg = <0x4ad000 0x1000>, /* TM */
                              <0x4ac000 0x1000>; /* SROT */
                        #qcom,sensors = <8>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
index 9682d4d..6138b58 100644 (file)
        };
 };
 
+&blsp1_uart3 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               vddio-supply = <&vreg_s4a_1p8>;
+               vddxo-supply = <&vreg_l7a_1p8>;
+               vddrf-supply = <&vreg_l17a_1p3>;
+               vddch0-supply = <&vreg_l25a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
+/*
+ * The laptop FW does not appear to support the retention state as it is
+ * not advertised as enabled in ACPI, and enabling it in DT can cause boot
+ * hangs.
+ */
+&CPU0 {
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU1 {
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU2 {
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU3 {
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU4 {
+       cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
+&CPU5 {
+       cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
+&CPU6 {
+       cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
+&CPU7 {
+       cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
 &qusb2phy {
        status = "okay";
 
                vreg_l7a_1p8: l7 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
+                       regulator-allow-set-load;
                };
                vreg_l8a_1p2: l8 {
                        regulator-min-microvolt = <1200000>;
                vreg_l17a_1p3: l17 {
                        regulator-min-microvolt = <1304000>;
                        regulator-max-microvolt = <1304000>;
+                       regulator-allow-set-load;
                };
                vreg_l18a_2p7: l18 {
                        regulator-min-microvolt = <2704000>;
                vreg_l25a_3p3: l25 {
                        regulator-min-microvolt = <3104000>;
                        regulator-max-microvolt = <3312000>;
+                       regulator-allow-set-load;
                };
                vreg_l26a_1p2: l26 {
                        regulator-min-microvolt = <1200000>;
index 108667c..5f101a2 100644 (file)
        };
 };
 
+&blsp1_uart3 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               vddio-supply = <&vreg_s4a_1p8>;
+               vddxo-supply = <&vreg_l7a_1p8>;
+               vddrf-supply = <&vreg_l17a_1p3>;
+               vddch0-supply = <&vreg_l25a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
 &blsp2_uart1 {
        status = "okay";
 };
 
+&etf {
+       status = "okay";
+};
+
+&etm1 {
+       status = "okay";
+};
+
+&etm2 {
+       status = "okay";
+};
+
+&etm3 {
+       status = "okay";
+};
+
+&etm4 {
+       status = "okay";
+};
+
+&etm5 {
+       status = "okay";
+};
+
+&etm6 {
+       status = "okay";
+};
+
+&etm7 {
+       status = "okay";
+};
+
+&etm8 {
+       status = "okay";
+};
+
+&etr {
+       status = "okay";
+};
+
+&funnel1 {
+       status = "okay";
+};
+
+&funnel2 {
+       status = "okay";
+};
+
+&funnel3 {
+       status = "okay";
+};
+
+&funnel4 {
+       status = "okay";
+};
+
+&funnel5 {
+       status = "okay";
+};
+
 &pm8005_lsid1 {
        pm8005-regulators {
                compatible = "qcom,pm8005-regulators";
        vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
 };
 
+&replicator1 {
+       status = "okay";
+};
+
 &rpm_requests {
        pm8998-regulators {
                compatible = "qcom,rpm-pm8998-regulators";
        pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
 };
 
+&stm {
+       status = "okay";
+};
+
 &ufshc {
        vcc-supply = <&vreg_l20a_2p95>;
        vccq-supply = <&vreg_l26a_1p2>;
index 6db70ac..e32d3ab 100644 (file)
                        drive-strength = <2>;   /* 2 mA */
                };
        };
+
+       blsp1_uart3_on: blsp1_uart3_on {
+               mux {
+                       pins = "gpio45", "gpio46", "gpio47", "gpio48";
+                       function = "blsp_uart3_a";
+               };
+
+               config {
+                       pins = "gpio45", "gpio46", "gpio47", "gpio48";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
 };
index c6f8143..fc7838e 100644 (file)
                        compatible = "qcom,msm8998-tsens", "qcom,tsens-v2";
                        reg = <0x010ab000 0x1000>, /* TM */
                              <0x010aa000 0x1000>; /* SROT */
-
                        #qcom,sensors = <14>;
+                       interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
                        compatible = "qcom,msm8998-tsens", "qcom,tsens-v2";
                        reg = <0x010ae000 0x1000>, /* TM */
                              <0x010ad000 0x1000>; /* SROT */
-
                        #qcom,sensors = <8>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
                        #interrupt-cells = <0x2>;
                };
 
-               stm@6002000 {
+               stm: stm@6002000 {
                        compatible = "arm,coresight-stm", "arm,primecell";
                        reg = <0x06002000 0x1000>,
                              <0x16280000 0x180000>;
                        reg-names = "stm-base", "stm-data-base";
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               funnel@6041000 {
+               funnel1: funnel@6041000 {
                        compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x06041000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               funnel@6042000 {
+               funnel2: funnel@6042000 {
                        compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x06042000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               funnel@6045000 {
+               funnel3: funnel@6045000 {
                        compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x06045000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               replicator@6046000 {
+               replicator1: replicator@6046000 {
                        compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
                        reg = <0x06046000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etf@6047000 {
+               etf: etf@6047000 {
                        compatible = "arm,coresight-tmc", "arm,primecell";
                        reg = <0x06047000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etr@6048000 {
+               etr: etr@6048000 {
                        compatible = "arm,coresight-tmc", "arm,primecell";
                        reg = <0x06048000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7840000 {
+               etm1: etm@7840000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07840000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7940000 {
+               etm2: etm@7940000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07940000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7a40000 {
+               etm3: etm@7a40000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07a40000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7b40000 {
+               etm4: etm@7b40000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07b40000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               funnel@7b60000 { /* APSS Funnel */
+               funnel4: funnel@7b60000 { /* APSS Funnel */
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07b60000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               funnel@7b70000 {
+               funnel5: funnel@7b70000 {
                        compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x07b70000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7c40000 {
+               etm5: etm@7c40000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07c40000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7d40000 {
+               etm6: etm@7d40000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07d40000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7e40000 {
+               etm7: etm@7e40000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07e40000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        };
                };
 
-               etm@7f40000 {
+               etm8: etm@7f40000 {
                        compatible = "arm,coresight-etm4x", "arm,primecell";
                        reg = <0x07f40000 0x1000>;
+                       status = "disabled";
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                        clock-names = "apb_pclk", "atclk";
                        status = "disabled";
                };
 
+               blsp1_dma: dma@c144000 {
+                       compatible = "qcom,bam-v1.7.0";
+                       reg = <0x0c144000 0x25000>;
+                       interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&gcc GCC_BLSP1_AHB_CLK>;
+                       clock-names = "bam_clk";
+                       #dma-cells = <1>;
+                       qcom,ee = <0>;
+                       qcom,controlled-remotely;
+                       num-channels = <18>;
+                       qcom,num-ees = <4>;
+               };
+
+               blsp1_uart3: serial@c171000 {
+                       compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+                       reg = <0x0c171000 0x1000>;
+                       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&gcc GCC_BLSP1_UART3_APPS_CLK>,
+                                <&gcc GCC_BLSP1_AHB_CLK>;
+                       clock-names = "core", "iface";
+                       dmas = <&blsp1_dma 4>, <&blsp1_dma 5>;
+                       dma-names = "tx", "rx";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp1_uart3_on>;
+                       status = "disabled";
+               };
+
                blsp1_i2c1: i2c@c175000 {
                        compatible = "qcom,i2c-qup-v2.2.1";
                        reg = <0x0c175000 0x600>;
index a97eeb4..f5f0c4c 100644 (file)
                        #clock-cells = <0>;
                        clock-frequency = <19200000>;
                };
+
+               sleep_clk: sleep-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+               };
        };
 
        cpus {
                        clock-names = "core";
                };
 
+               bimc: interconnect@400000 {
+                       reg = <0x00400000 0x80000>;
+                       compatible = "qcom,qcs404-bimc";
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+                               <&rpmcc RPM_SMD_BIMC_A_CLK>;
+               };
+
                tsens: thermal-sensor@4a9000 {
                        compatible = "qcom,qcs404-tsens", "qcom,tsens-v1";
                        reg = <0x004a9000 0x1000>, /* TM */
                        nvmem-cells = <&tsens_caldata>;
                        nvmem-cell-names = "calib";
                        #qcom,sensors = <10>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
+               pcnoc: interconnect@500000 {
+                       reg = <0x00500000 0x15080>;
+                       compatible = "qcom,qcs404-pcnoc";
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
+                               <&rpmcc RPM_SMD_PNOC_A_CLK>;
+               };
+
+               snoc: interconnect@580000 {
+                       reg = <0x00580000 0x23080>;
+                       compatible = "qcom,qcs404-snoc";
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+                               <&rpmcc RPM_SMD_SNOC_A_CLK>;
+               };
+
                remoteproc_cdsp: remoteproc@b00000 {
                        compatible = "qcom,qcs404-cdsp-pas";
                        reg = <0x00b00000 0x4040>;
                        #mbox-cells = <1>;
                };
 
+               watchdog@b017000 {
+                       compatible = "qcom,kpss-wdt";
+                       reg = <0x0b017000 0x1000>;
+                       clocks = <&sleep_clk>;
+               };
+
                timer@b120000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
index 34881c0..9a4ff57 100644 (file)
 /delete-node/ &venus_mem;
 /delete-node/ &cdsp_mem;
 /delete-node/ &cdsp_pas;
+/delete-node/ &zap_shader;
+/delete-node/ &gpu_mem;
 
 /* Increase the size from 120 MB to 128 MB */
 &mpss_region {
@@ -701,9 +703,8 @@ ap_ts_i2c: &i2c14 {
 
 &ufs_mem_hc {
        status = "okay";
-       pinctrl-names = "init", "default";
-       pinctrl-0 = <&ufs_dev_reset_assert>;
-       pinctrl-1 = <&ufs_dev_reset_deassert>;
+
+       reset-gpios = <&tlmm 150 GPIO_ACTIVE_LOW>;
 
        vcc-supply = <&src_pp2950_l20a>;
        vcc-max-microamp = <600000>;
@@ -1258,52 +1259,6 @@ ap_ts_i2c: &i2c14 {
                };
        };
 
-       ufs_dev_reset_assert: ufs_dev_reset_assert {
-               config {
-                       pins = "ufs_reset";
-                       bias-pull-down;         /* default: pull down */
-                       /*
-                        * UFS_RESET driver strengths are having
-                        * different values/steps compared to typical
-                        * GPIO drive strengths.
-                        *
-                        * Following table clarifies:
-                        *
-                        * HDRV value | UFS_RESET | Typical GPIO
-                        *   (dec)    |   (mA)    |    (mA)
-                        *     0      |   0.8     |    2
-                        *     1      |   1.55    |    4
-                        *     2      |   2.35    |    6
-                        *     3      |   3.1     |    8
-                        *     4      |   3.9     |    10
-                        *     5      |   4.65    |    12
-                        *     6      |   5.4     |    14
-                        *     7      |   6.15    |    16
-                        *
-                        * POR value for UFS_RESET HDRV is 3 which means
-                        * 3.1mA and we want to use that. Hence just
-                        * specify 8mA to "drive-strength" binding and
-                        * that should result into writing 3 to HDRV
-                        * field.
-                        */
-                       drive-strength = <8>;   /* default: 3.1 mA */
-                       output-low; /* active low reset */
-               };
-       };
-
-       ufs_dev_reset_deassert: ufs_dev_reset_deassert {
-               config {
-                       pins = "ufs_reset";
-                       bias-pull-down;         /* default: pull down */
-                       /*
-                        * default: 3.1 mA
-                        * check comments under ufs_dev_reset_assert
-                        */
-                       drive-strength = <8>;
-                       output-high; /* active low reset */
-               };
-       };
-
        ap_suspend_l_assert: ap_suspend_l_assert {
                config {
                        pins = "gpio126";
index f5a85ca..d100f46 100644 (file)
                        regulator-max-microvolt = <1200000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                };
+
+               vreg_lvs1a_1p8: lvs1 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-always-on;
+               };
+
+               vreg_lvs2a_1p8: lvs2 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-always-on;
+               };
        };
 
        pmi8998-rpmh-regulators {
index f406a43..ddb1f23 100644 (file)
 
                        qcom,gmu = <&gmu>;
 
-                       zap-shader {
+                       zap_shader: zap-shader {
                                memory-region = <&gpu_mem>;
                        };
 
                        reg = <0 0x0c263000 0 0x1ff>, /* TM */
                              <0 0x0c222000 0 0x1ff>; /* SROT */
                        #qcom,sensors = <13>;
+                       interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
                        reg = <0 0x0c265000 0 0x1ff>, /* TM */
                              <0 0x0c223000 0 0x1ff>; /* SROT */
                        #qcom,sensors = <8>;
+                       interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow";
                        #thermal-sensor-cells = <1>;
                };
 
                        status = "disabled";
                };
 
+               watchdog@17980000 {
+                       compatible = "qcom,apss-wdt-sdm845", "qcom,kpss-wdt";
+                       reg = <0 0x17980000 0 0x1000>;
+                       clocks = <&sleep_clk>;
+               };
+
                apss_shared: mailbox@17990000 {
                        compatible = "qcom,sdm845-apss-shared";
                        reg = <0 0x17990000 0 0x1000>;
index ded120d..13dc619 100644 (file)
        };
 };
 
+&adsp_pas {
+       firmware-name = "qcom/LENOVO/81JL/qcadsp850.mbn";
+       status = "okay";
+};
+
 &apps_rsc {
        pm8998-rpmh-regulators {
                compatible = "qcom,pm8998-rpmh-regulators";
        status = "disabled";
 };
 
+&cdsp_pas {
+       firmware-name = "qcom/LENOVO/81JL/qccdsp850.mbn";
+       status = "okay";
+};
+
 &gcc {
        protected-clocks = <GCC_QSPI_CORE_CLK>,
                           <GCC_QSPI_CORE_CLK_SRC>,
        };
 };
 
+&mss_pil {
+       firmware-name = "qcom/LENOVO/81JL/qcdsp1v2850.mbn", "qcom/LENOVO/81JL/qcdsp2850.mbn";
+};
+
 &qup_i2c12_default {
        drive-strength = <2>;
        bias-disable;
index 90c897a..555638a 100644 (file)
@@ -1,4 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
+
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1293-ds418j.dtb
+
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-mele-v9.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-probox2-ava.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-zidoo-x9s.dtb
+
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1296-ds418.dtb
diff --git a/arch/arm64/boot/dts/realtek/rtd1293-ds418j.dts b/arch/arm64/boot/dts/realtek/rtd1293-ds418j.dts
new file mode 100644 (file)
index 0000000..b2dd583
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (c) 2017 Andreas Färber
+ */
+
+/dts-v1/;
+
+#include "rtd1293.dtsi"
+
+/ {
+       compatible = "synology,ds418j", "realtek,rtd1293";
+       model = "Synology DiskStation DS418j";
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x40000000>;
+       };
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1293.dtsi b/arch/arm64/boot/dts/realtek/rtd1293.dtsi
new file mode 100644 (file)
index 0000000..bd4e227
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1293 SoC
+ *
+ * Copyright (c) 2017-2019 Andreas Färber
+ */
+
+#include "rtd129x.dtsi"
+
+/ {
+       compatible = "realtek,rtd1293";
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&l2>;
+               };
+
+               l2: l2-cache {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+};
+
+&arm_pmu {
+       interrupt-affinity = <&cpu0>, <&cpu1>;
+};
index da19faa..e98e508 100644 (file)
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * Copyright (c) 2016-2017 Andreas Färber
- *
- * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  */
 
 /dts-v1/;
index 41d7858..93f0e1d 100644 (file)
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * Realtek RTD1295 SoC
  *
  * Copyright (c) 2016-2017 Andreas Färber
- *
- * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  */
 
 #include "rtd129x.dtsi"
diff --git a/arch/arm64/boot/dts/realtek/rtd1296-ds418.dts b/arch/arm64/boot/dts/realtek/rtd1296-ds418.dts
new file mode 100644 (file)
index 0000000..5a051a5
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Copyright (c) 2017-2019 Andreas Färber
+ */
+
+/dts-v1/;
+
+#include "rtd1296.dtsi"
+
+/ {
+       compatible = "synology,ds418", "realtek,rtd1296";
+       model = "Synology DiskStation DS418";
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x80000000>;
+       };
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1296.dtsi b/arch/arm64/boot/dts/realtek/rtd1296.dtsi
new file mode 100644 (file)
index 0000000..0f9e59c
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1296 SoC
+ *
+ * Copyright (c) 2017-2019 Andreas Färber
+ */
+
+#include "rtd129x.dtsi"
+
+/ {
+       compatible = "realtek,rtd1296";
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x2>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0 0x3>;
+                       next-level-cache = <&l2>;
+               };
+
+               l2: l2-cache {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10
+                       (GIC_CPU_MASK_RAW(0xf) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+};
+
+&arm_pmu {
+       interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+};
index b9cb924..4433114 100644 (file)
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * Realtek RTD1293/RTD1295/RTD1296 SoC
  *
  * Copyright (c) 2016-2017 Andreas Färber
- *
- * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  */
 
 /memreserve/   0x0000000000000000 0x0000000000030000;
@@ -13,6 +12,7 @@
 /memreserve/   0x0000000001ffe000 0x0000000000004000;
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/realtek,rtd1295.h>
 
 / {
        interrupt-parent = <&gic>;
                interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
        };
 
+       osc27M: osc {
+               compatible = "fixed-clock";
+               clock-frequency = <27000000>;
+               #clock-cells = <0>;
+               clock-output-names = "osc27M";
+       };
+
        soc {
                compatible = "simple-bus";
                #address-cells = <1>;
                /* Exclude up to 2 GiB of RAM */
                ranges = <0x80000000 0x80000000 0x80000000>;
 
+               reset1: reset-controller@98000000 {
+                       compatible = "snps,dw-low-reset";
+                       reg = <0x98000000 0x4>;
+                       #reset-cells = <1>;
+               };
+
+               reset2: reset-controller@98000004 {
+                       compatible = "snps,dw-low-reset";
+                       reg = <0x98000004 0x4>;
+                       #reset-cells = <1>;
+               };
+
+               reset3: reset-controller@98000008 {
+                       compatible = "snps,dw-low-reset";
+                       reg = <0x98000008 0x4>;
+                       #reset-cells = <1>;
+               };
+
+               reset4: reset-controller@98000050 {
+                       compatible = "snps,dw-low-reset";
+                       reg = <0x98000050 0x4>;
+                       #reset-cells = <1>;
+               };
+
+               iso_reset: reset-controller@98007088 {
+                       compatible = "snps,dw-low-reset";
+                       reg = <0x98007088 0x4>;
+                       #reset-cells = <1>;
+               };
+
+               wdt: watchdog@98007680 {
+                       compatible = "realtek,rtd1295-watchdog";
+                       reg = <0x98007680 0x100>;
+                       clocks = <&osc27M>;
+               };
+
                uart0: serial@98007800 {
                        compatible = "snps,dw-apb-uart";
                        reg = <0x98007800 0x400>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clock-frequency = <27000000>;
+                       resets = <&iso_reset RTD1295_ISO_RSTN_UR0>;
                        status = "disabled";
                };
 
@@ -46,6 +90,7 @@
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clock-frequency = <432000000>;
+                       resets = <&reset2 RTD1295_RSTN_UR1>;
                        status = "disabled";
                };
 
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clock-frequency = <432000000>;
+                       resets = <&reset2 RTD1295_RSTN_UR2>;
                        status = "disabled";
                };
 
index 42b74c2..8fdbd22 100644 (file)
@@ -1,6 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_R8A774A1) += r8a774a1-hihope-rzg2m.dtb
 dtb-$(CONFIG_ARCH_R8A774A1) += r8a774a1-hihope-rzg2m-ex.dtb
+dtb-$(CONFIG_ARCH_R8A774B1) += r8a774b1-hihope-rzg2n.dtb
+dtb-$(CONFIG_ARCH_R8A774B1) += r8a774b1-hihope-rzg2n-ex.dtb
 dtb-$(CONFIG_ARCH_R8A774C0) += r8a774c0-cat874.dtb r8a774c0-ek874.dtb
 dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x.dtb r8a7795-h3ulcb.dtb
 dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-kf.dtb
@@ -10,6 +12,10 @@ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-es1-h3ulcb-kf.dtb
 dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-x.dtb r8a7796-m3ulcb.dtb
 dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-kf.dtb
 dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-xs.dtb
+dtb-$(CONFIG_ARCH_R8A77960) += r8a7796-salvator-x.dtb r8a7796-m3ulcb.dtb
+dtb-$(CONFIG_ARCH_R8A77960) += r8a7796-m3ulcb-kf.dtb
+dtb-$(CONFIG_ARCH_R8A77960) += r8a7796-salvator-xs.dtb
+dtb-$(CONFIG_ARCH_R8A77961) += r8a77961-salvator-xs.dtb
 dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-salvator-x.dtb r8a77965-salvator-xs.dtb
 dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-m3nulcb.dtb
 dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-m3nulcb-kf.dtb
index 3e376d2..2c942a7 100644 (file)
@@ -86,7 +86,7 @@
 
                label = "rcar-sound";
 
-               dais = <&rsnd_port0>;
+               dais = <&rsnd_port>;
        };
 
        vbus0_usb2: regulator-vbus0-usb2 {
 };
 
 &du {
-       clocks = <&cpg CPG_MOD 724>,
-                <&cpg CPG_MOD 723>,
-                <&cpg CPG_MOD 722>,
-                <&versaclock5 1>,
-                <&x302_clk>,
-                <&versaclock5 2>;
-       clock-names = "du.0", "du.1", "du.2",
-                     "dclkin.0", "dclkin.1", "dclkin.2";
        status = "okay";
 };
 
                port@2 {
                        reg = <2>;
                        dw_hdmi0_snd_in: endpoint {
-                               remote-endpoint = <&rsnd_endpoint0>;
+                               remote-endpoint = <&rsnd_endpoint>;
                        };
                };
        };
        /* Single DAI */
        #sound-dai-cells = <0>;
 
-       ports {
-               rsnd_port0: port@0 {
-                       rsnd_endpoint0: endpoint {
-                               remote-endpoint = <&dw_hdmi0_snd_in>;
+       rsnd_port: port {
+               rsnd_endpoint: endpoint {
+                       remote-endpoint = <&dw_hdmi0_snd_in>;
 
-                               dai-format = "i2s";
-                               bitclock-master = <&rsnd_endpoint0>;
-                               frame-master = <&rsnd_endpoint0>;
+                       dai-format = "i2s";
+                       bitclock-master = <&rsnd_endpoint>;
+                       frame-master = <&rsnd_endpoint>;
 
-                               playback = <&ssi2>;
-                       };
+                       playback = <&ssi2>;
                };
        };
 };
index 4280b19..28fe17e 100644 (file)
        chosen {
                bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
        };
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm0 0 50000>;
+
+               brightness-levels = <0 2 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+       };
 };
 
 &avb {
        status = "okay";
 };
 
-&pciec0 {
-       status = "okay";
+&gpio1 {
+       /*
+        * When GP1_20 is LOW LVDS0 is connected to the LVDS connector
+        * When GP1_20 is HIGH LVDS0 is connected to the LT8918L
+        */
+       lvds-connector-en-gpio {
+               gpio-hog;
+               gpios = <20 GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "lvds-connector-en-gpio";
+       };
+};
+
+&lvds0 {
+       /*
+        * Please include the LVDS panel .dtsi file and uncomment the below line
+        * to enable LVDS panel connected to RZ/G2[MN] boards.
+        */
+
+       /* status = "okay"; */
+
+       ports {
+               port@1 {
+                       lvds_connector: endpoint {
+                       };
+               };
+       };
 };
 
-&pciec1 {
+&pciec0 {
        status = "okay";
 };
 
                groups = "can1_data";
                function = "can1";
        };
+
+       pwm0_pins: pwm0 {
+               groups = "pwm0";
+               function = "pwm0";
+       };
+};
+
+&pwm0 {
+       pinctrl-0 = <&pwm0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
 };
index 6e33a3b..c754fca 100644 (file)
@@ -13,3 +13,7 @@
        compatible = "hoperun,hihope-rzg2-ex", "hoperun,hihope-rzg2m",
                     "renesas,r8a774a1";
 };
+
+&pciec1 {
+       status = "okay";
+};
index 93ca973..96f2fb0 100644 (file)
                reg = <0x6 0x00000000 0x0 0x80000000>;
        };
 };
+
+&du {
+       clocks = <&cpg CPG_MOD 724>,
+                <&cpg CPG_MOD 723>,
+                <&cpg CPG_MOD 722>,
+                <&versaclock5 1>,
+                <&x302_clk>,
+                <&versaclock5 2>;
+       clock-names = "du.0", "du.1", "du.2",
+                     "dclkin.0", "dclkin.1", "dclkin.2";
+};
index 06c7c84..34a9f47 100644 (file)
                                      "ssi.1", "ssi.0";
                        status = "disabled";
 
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               port@0 {
-                                       reg = <0>;
-                               };
-                               port@1 {
-                                       reg = <1>;
-                               };
-                       };
-
                        rcar_sound,ctu {
                                ctu00: ctu-0 { };
                                ctu01: ctu-1 { };
                        clock-names = "du.0", "du.1", "du.2";
                        status = "disabled";
 
-                       vsps = <&vspd0 &vspd1 &vspd2>;
+                       vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>;
 
                        ports {
                                #address-cells = <1>;
diff --git a/arch/arm64/boot/dts/renesas/r8a774b1-hihope-rzg2n-ex.dts b/arch/arm64/boot/dts/renesas/r8a774b1-hihope-rzg2n-ex.dts
new file mode 100644 (file)
index 0000000..ab47c0b
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the HiHope RZ/G2N sub board
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+#include "r8a774b1-hihope-rzg2n.dts"
+#include "hihope-rzg2-ex.dtsi"
+
+/ {
+       model = "HopeRun HiHope RZ/G2N with sub board";
+       compatible = "hoperun,hihope-rzg2-ex", "hoperun,hihope-rzg2n",
+                    "renesas,r8a774b1";
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a774b1-hihope-rzg2n.dts b/arch/arm64/boot/dts/renesas/r8a774b1-hihope-rzg2n.dts
new file mode 100644 (file)
index 0000000..9910c1a
--- /dev/null
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the HiHope RZ/G2N main board
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+#include "r8a774b1.dtsi"
+#include "hihope-common.dtsi"
+
+/ {
+       model = "HopeRun HiHope RZ/G2N main board based on r8a774b1";
+       compatible = "hoperun,hihope-rzg2n", "renesas,r8a774b1";
+
+       memory@48000000 {
+               device_type = "memory";
+               /* first 128MB is reserved for secure area. */
+               reg = <0x0 0x48000000 0x0 0x78000000>;
+       };
+
+       memory@480000000 {
+               device_type = "memory";
+               reg = <0x4 0x80000000 0x0 0x80000000>;
+       };
+};
+
+&du {
+       clocks = <&cpg CPG_MOD 724>,
+                <&cpg CPG_MOD 723>,
+                <&cpg CPG_MOD 721>,
+                <&versaclock5 1>,
+                <&x302_clk>,
+                <&versaclock5 2>;
+       clock-names = "du.0", "du.1", "du.3",
+                     "dclkin.0", "dclkin.1", "dclkin.3";
+};
+
+&sdhi3 {
+       mmc-hs400-1_8v;
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a774b1.dtsi b/arch/arm64/boot/dts/renesas/r8a774b1.dtsi
new file mode 100644 (file)
index 0000000..fe78387
--- /dev/null
@@ -0,0 +1,2627 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the r8a774b1 SoC
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/r8a774b1-cpg-mssr.h>
+#include <dt-bindings/power/r8a774b1-sysc.h>
+
+/ {
+       compatible = "renesas,r8a774b1";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       /*
+        * The external audio clocks are configured as 0 Hz fixed frequency
+        * clocks by default.
+        * Boards that provide audio clocks should override them.
+        */
+       audio_clk_a: audio_clk_a {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       audio_clk_b: audio_clk_b {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       audio_clk_c: audio_clk_c {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       /* External CAN clock - to be overridden by boards that provide it */
+       can_clk: can {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       cluster0_opp: opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-500000000 {
+                       opp-hz = /bits/ 64 <500000000>;
+                       opp-microvolt = <830000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <830000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1500000000 {
+                       opp-hz = /bits/ 64 <1500000000>;
+                       opp-microvolt = <830000>;
+                       clock-latency-ns = <300000>;
+                       opp-suspend;
+               };
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               a57_0: cpu@0 {
+                       compatible = "arm,cortex-a57";
+                       reg = <0x0>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A774B1_PD_CA57_CPU0>;
+                       next-level-cache = <&L2_CA57>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <854>;
+                       clocks = <&cpg CPG_CORE R8A774B1_CLK_Z>;
+                       operating-points-v2 = <&cluster0_opp>;
+               };
+
+               a57_1: cpu@1 {
+                       compatible = "arm,cortex-a57";
+                       reg = <0x1>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A774B1_PD_CA57_CPU1>;
+                       next-level-cache = <&L2_CA57>;
+                       enable-method = "psci";
+                       clocks = <&cpg CPG_CORE R8A774B1_CLK_Z>;
+                       operating-points-v2 = <&cluster0_opp>;
+               };
+
+               L2_CA57: cache-controller-0 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A774B1_PD_CA57_SCU>;
+                       cache-unified;
+                       cache-level = <2>;
+               };
+       };
+
+       extal_clk: extal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       extalr_clk: extalr {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       /* External PCIe clock - can be overridden by the board */
+       pcie_bus_clk: pcie_bus {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       pmu_a57 {
+               compatible = "arm,cortex-a57-pmu";
+               interrupts-extended = <&gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&a57_0>, <&a57_1>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0", "arm,psci-0.2";
+               method = "smc";
+       };
+
+       /* External SCIF clock - to be overridden by boards that provide it */
+       scif_clk: scif {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               rwdt: watchdog@e6020000 {
+                       compatible = "renesas,r8a774b1-wdt",
+                                    "renesas,rcar-gen3-wdt";
+                       reg = <0 0xe6020000 0 0x0c>;
+                       clocks = <&cpg CPG_MOD 402>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 402>;
+                       status = "disabled";
+               };
+
+               gpio0: gpio@e6050000 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6050000 0 0x50>;
+                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 0 16>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 912>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 912>;
+               };
+
+               gpio1: gpio@e6051000 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6051000 0 0x50>;
+                       interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 32 29>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 911>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 911>;
+               };
+
+               gpio2: gpio@e6052000 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6052000 0 0x50>;
+                       interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 64 15>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 910>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 910>;
+               };
+
+               gpio3: gpio@e6053000 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6053000 0 0x50>;
+                       interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 96 16>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 909>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 909>;
+               };
+
+               gpio4: gpio@e6054000 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6054000 0 0x50>;
+                       interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 128 18>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 908>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 908>;
+               };
+
+               gpio5: gpio@e6055000 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6055000 0 0x50>;
+                       interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 160 26>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 907>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 907>;
+               };
+
+               gpio6: gpio@e6055400 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6055400 0 0x50>;
+                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 192 32>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 906>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 906>;
+               };
+
+               gpio7: gpio@e6055800 {
+                       compatible = "renesas,gpio-r8a774b1",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6055800 0 0x50>;
+                       interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 224 4>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 905>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 905>;
+               };
+
+               pfc: pin-controller@e6060000 {
+                       compatible = "renesas,pfc-r8a774b1";
+                       reg = <0 0xe6060000 0 0x50c>;
+               };
+
+               cmt0: timer@e60f0000 {
+                       compatible = "renesas,r8a774b1-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 R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 303>;
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a774b1-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 R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 302>;
+                       status = "disabled";
+               };
+
+               cmt2: timer@e6140000 {
+                       compatible = "renesas,r8a774b1-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 R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 301>;
+                       status = "disabled";
+               };
+
+               cmt3: timer@e6148000 {
+                       compatible = "renesas,r8a774b1-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 R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 300>;
+                       status = "disabled";
+               };
+
+               cpg: clock-controller@e6150000 {
+                       compatible = "renesas,r8a774b1-cpg-mssr";
+                       reg = <0 0xe6150000 0 0x1000>;
+                       clocks = <&extal_clk>, <&extalr_clk>;
+                       clock-names = "extal", "extalr";
+                       #clock-cells = <2>;
+                       #power-domain-cells = <0>;
+                       #reset-cells = <1>;
+               };
+
+               rst: reset-controller@e6160000 {
+                       compatible = "renesas,r8a774b1-rst";
+                       reg = <0 0xe6160000 0 0x0200>;
+               };
+
+               sysc: system-controller@e6180000 {
+                       compatible = "renesas,r8a774b1-sysc";
+                       reg = <0 0xe6180000 0 0x0400>;
+                       #power-domain-cells = <1>;
+               };
+
+               tsc: thermal@e6198000 {
+                       compatible = "renesas,r8a774b1-thermal";
+                       reg = <0 0xe6198000 0 0x100>,
+                             <0 0xe61a0000 0 0x100>,
+                             <0 0xe61a8000 0 0x100>;
+                       interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 522>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 522>;
+                       #thermal-sensor-cells = <1>;
+               };
+
+               intc_ex: interrupt-controller@e61c0000 {
+                       compatible = "renesas,intc-ex-r8a774b1", "renesas,irqc";
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       reg = <0 0xe61c0000 0 0x200>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 407>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 407>;
+               };
+
+               tmu0: timer@e61e0000 {
+                       compatible = "renesas,tmu-r8a774b1", "renesas,tmu";
+                       reg = <0 0xe61e0000 0 0x30>;
+                       interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 125>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 125>;
+                       status = "disabled";
+               };
+
+               tmu1: timer@e6fc0000 {
+                       compatible = "renesas,tmu-r8a774b1", "renesas,tmu";
+                       reg = <0 0xe6fc0000 0 0x30>;
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 124>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 124>;
+                       status = "disabled";
+               };
+
+               tmu2: timer@e6fd0000 {
+                       compatible = "renesas,tmu-r8a774b1", "renesas,tmu";
+                       reg = <0 0xe6fd0000 0 0x30>;
+                       interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 123>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 123>;
+                       status = "disabled";
+               };
+
+               tmu3: timer@e6fe0000 {
+                       compatible = "renesas,tmu-r8a774b1", "renesas,tmu";
+                       reg = <0 0xe6fe0000 0 0x30>;
+                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 122>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 122>;
+                       status = "disabled";
+               };
+
+               tmu4: timer@ffc00000 {
+                       compatible = "renesas,tmu-r8a774b1", "renesas,tmu";
+                       reg = <0 0xffc00000 0 0x30>;
+                       interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 121>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 121>;
+                       status = "disabled";
+               };
+
+               i2c0: i2c@e6500000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6500000 0 0x40>;
+                       interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 931>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 931>;
+                       dmas = <&dmac1 0x91>, <&dmac1 0x90>,
+                              <&dmac2 0x91>, <&dmac2 0x90>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       status = "disabled";
+               };
+
+               i2c1: i2c@e6508000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6508000 0 0x40>;
+                       interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 930>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 930>;
+                       dmas = <&dmac1 0x93>, <&dmac1 0x92>,
+                              <&dmac2 0x93>, <&dmac2 0x92>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c2: i2c@e6510000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6510000 0 0x40>;
+                       interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 929>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 929>;
+                       dmas = <&dmac1 0x95>, <&dmac1 0x94>,
+                              <&dmac2 0x95>, <&dmac2 0x94>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c3: i2c@e66d0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66d0000 0 0x40>;
+                       interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 928>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 928>;
+                       dmas = <&dmac0 0x97>, <&dmac0 0x96>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       status = "disabled";
+               };
+
+               i2c4: i2c@e66d8000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66d8000 0 0x40>;
+                       interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 927>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 927>;
+                       dmas = <&dmac0 0x99>, <&dmac0 0x98>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       status = "disabled";
+               };
+
+               i2c5: i2c@e66e0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66e0000 0 0x40>;
+                       interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 919>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 919>;
+                       dmas = <&dmac0 0x9b>, <&dmac0 0x9a>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       status = "disabled";
+               };
+
+               i2c6: i2c@e66e8000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774b1",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66e8000 0 0x40>;
+                       interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 918>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 918>;
+                       dmas = <&dmac0 0x9d>, <&dmac0 0x9c>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c_dvfs: i2c@e60b0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,iic-r8a774b1",
+                                    "renesas,rcar-gen3-iic",
+                                    "renesas,rmobile-iic";
+                       reg = <0 0xe60b0000 0 0x425>;
+                       interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 926>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 926>;
+                       dmas = <&dmac0 0x11>, <&dmac0 0x10>;
+                       dma-names = "tx", "rx";
+                       status = "disabled";
+               };
+
+               hscif0: serial@e6540000 {
+                       compatible = "renesas,hscif-r8a774b1",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe6540000 0 0x60>;
+                       interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 520>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x31>, <&dmac1 0x30>,
+                              <&dmac2 0x31>, <&dmac2 0x30>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 520>;
+                       status = "disabled";
+               };
+
+               hscif1: serial@e6550000 {
+                       compatible = "renesas,hscif-r8a774b1",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe6550000 0 0x60>;
+                       interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 519>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x33>, <&dmac1 0x32>,
+                              <&dmac2 0x33>, <&dmac2 0x32>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 519>;
+                       status = "disabled";
+               };
+
+               hscif2: serial@e6560000 {
+                       compatible = "renesas,hscif-r8a774b1",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe6560000 0 0x60>;
+                       interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 518>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x35>, <&dmac1 0x34>,
+                              <&dmac2 0x35>, <&dmac2 0x34>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 518>;
+                       status = "disabled";
+               };
+
+               hscif3: serial@e66a0000 {
+                       compatible = "renesas,hscif-r8a774b1",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe66a0000 0 0x60>;
+                       interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 517>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x37>, <&dmac0 0x36>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 517>;
+                       status = "disabled";
+               };
+
+               hscif4: serial@e66b0000 {
+                       compatible = "renesas,hscif-r8a774b1",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe66b0000 0 0x60>;
+                       interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 516>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x39>, <&dmac0 0x38>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 516>;
+                       status = "disabled";
+               };
+
+               hsusb: usb@e6590000 {
+                       compatible = "renesas,usbhs-r8a774b1",
+                                    "renesas,rcar-gen3-usbhs";
+                       reg = <0 0xe6590000 0 0x200>;
+                       interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 704>, <&cpg CPG_MOD 703>;
+                       dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+                              <&usb_dmac1 0>, <&usb_dmac1 1>;
+                       dma-names = "ch0", "ch1", "ch2", "ch3";
+                       renesas,buswait = <11>;
+                       phys = <&usb2_phy0 3>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 704>, <&cpg 703>;
+                       status = "disabled";
+               };
+
+               usb_dmac0: dma-controller@e65a0000 {
+                       compatible = "renesas,r8a774b1-usb-dmac",
+                                    "renesas,usb-dmac";
+                       reg = <0 0xe65a0000 0 0x100>;
+                       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1";
+                       clocks = <&cpg CPG_MOD 330>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 330>;
+                       #dma-cells = <1>;
+                       dma-channels = <2>;
+               };
+
+               usb_dmac1: dma-controller@e65b0000 {
+                       compatible = "renesas,r8a774b1-usb-dmac",
+                                    "renesas,usb-dmac";
+                       reg = <0 0xe65b0000 0 0x100>;
+                       interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1";
+                       clocks = <&cpg CPG_MOD 331>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 331>;
+                       #dma-cells = <1>;
+                       dma-channels = <2>;
+               };
+
+               usb3_phy0: usb-phy@e65ee000 {
+                       compatible = "renesas,r8a774b1-usb3-phy",
+                                    "renesas,rcar-gen3-usb3-phy";
+                       reg = <0 0xe65ee000 0 0x90>;
+                       clocks = <&cpg CPG_MOD 328>, <&usb3s0_clk>,
+                                <&usb_extal_clk>;
+                       clock-names = "usb3-if", "usb3s_clk", "usb_extal";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 328>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               dmac0: dma-controller@e6700000 {
+                       compatible = "renesas,dmac-r8a774b1",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xe6700000 0 0x10000>;
+                       interrupts = <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 219>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 219>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_ds0 0>, <&ipmmu_ds0 1>,
+                              <&ipmmu_ds0 2>, <&ipmmu_ds0 3>,
+                              <&ipmmu_ds0 4>, <&ipmmu_ds0 5>,
+                              <&ipmmu_ds0 6>, <&ipmmu_ds0 7>,
+                              <&ipmmu_ds0 8>, <&ipmmu_ds0 9>,
+                              <&ipmmu_ds0 10>, <&ipmmu_ds0 11>,
+                              <&ipmmu_ds0 12>, <&ipmmu_ds0 13>,
+                              <&ipmmu_ds0 14>, <&ipmmu_ds0 15>;
+               };
+
+               dmac1: dma-controller@e7300000 {
+                       compatible = "renesas,dmac-r8a774b1",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xe7300000 0 0x10000>;
+                       interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 218>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 218>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_ds1 0>, <&ipmmu_ds1 1>,
+                              <&ipmmu_ds1 2>, <&ipmmu_ds1 3>,
+                              <&ipmmu_ds1 4>, <&ipmmu_ds1 5>,
+                              <&ipmmu_ds1 6>, <&ipmmu_ds1 7>,
+                              <&ipmmu_ds1 8>, <&ipmmu_ds1 9>,
+                              <&ipmmu_ds1 10>, <&ipmmu_ds1 11>,
+                              <&ipmmu_ds1 12>, <&ipmmu_ds1 13>,
+                              <&ipmmu_ds1 14>, <&ipmmu_ds1 15>;
+               };
+
+               dmac2: dma-controller@e7310000 {
+                       compatible = "renesas,dmac-r8a774b1",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xe7310000 0 0x10000>;
+                       interrupts = <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 217>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 217>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_ds1 16>, <&ipmmu_ds1 17>,
+                              <&ipmmu_ds1 18>, <&ipmmu_ds1 19>,
+                              <&ipmmu_ds1 20>, <&ipmmu_ds1 21>,
+                              <&ipmmu_ds1 22>, <&ipmmu_ds1 23>,
+                              <&ipmmu_ds1 24>, <&ipmmu_ds1 25>,
+                              <&ipmmu_ds1 26>, <&ipmmu_ds1 27>,
+                              <&ipmmu_ds1 28>, <&ipmmu_ds1 29>,
+                              <&ipmmu_ds1 30>, <&ipmmu_ds1 31>;
+               };
+
+               ipmmu_ds0: mmu@e6740000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xe6740000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 0>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_ds1: mmu@e7740000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xe7740000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 1>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_hc: mmu@e6570000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xe6570000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 2>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_mm: mmu@e67b0000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xe67b0000 0 0x1000>;
+                       interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_mp: mmu@ec670000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xec670000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 4>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_pv0: mmu@fd800000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xfd800000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 6>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_vc0: mmu@fe6b0000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xfe6b0000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 12>;
+                       power-domains = <&sysc R8A774B1_PD_A3VC>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_vi0: mmu@febd0000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xfebd0000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 14>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_vp0: mmu@fe990000 {
+                       compatible = "renesas,ipmmu-r8a774b1";
+                       reg = <0 0xfe990000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 16>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       #iommu-cells = <1>;
+               };
+
+               avb: ethernet@e6800000 {
+                       compatible = "renesas,etheravb-r8a774b1",
+                                    "renesas,etheravb-rcar-gen3";
+                       reg = <0 0xe6800000 0 0x800>;
+                       interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+                                    <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>,
+                                    <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+                                    <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>,
+                                    <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>,
+                                    <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1", "ch2", "ch3",
+                                         "ch4", "ch5", "ch6", "ch7",
+                                         "ch8", "ch9", "ch10", "ch11",
+                                         "ch12", "ch13", "ch14", "ch15",
+                                         "ch16", "ch17", "ch18", "ch19",
+                                         "ch20", "ch21", "ch22", "ch23",
+                                         "ch24";
+                       clocks = <&cpg CPG_MOD 812>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 812>;
+                       phy-mode = "rgmii";
+                       iommus = <&ipmmu_ds0 16>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               can0: can@e6c30000 {
+                       compatible = "renesas,can-r8a774b1",
+                                    "renesas,rcar-gen3-can";
+                       reg = <0 0xe6c30000 0 0x1000>;
+                       interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 916>,
+                                <&cpg CPG_CORE R8A774B1_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774B1_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 916>;
+                       status = "disabled";
+               };
+
+               can1: can@e6c38000 {
+                       compatible = "renesas,can-r8a774b1",
+                                    "renesas,rcar-gen3-can";
+                       reg = <0 0xe6c38000 0 0x1000>;
+                       interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 915>,
+                                <&cpg CPG_CORE R8A774B1_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774B1_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 915>;
+                       status = "disabled";
+               };
+
+               canfd: can@e66c0000 {
+                       compatible = "renesas,r8a774b1-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 R8A774B1_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "fck", "canfd", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774B1_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 914>;
+                       status = "disabled";
+
+                       channel0 {
+                               status = "disabled";
+                       };
+
+                       channel1 {
+                               status = "disabled";
+                       };
+               };
+
+               pwm0: pwm@e6e30000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e30000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               pwm1: pwm@e6e31000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e31000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               pwm2: pwm@e6e32000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e32000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               pwm3: pwm@e6e33000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e33000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               pwm4: pwm@e6e34000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e34000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               pwm5: pwm@e6e35000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e35000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               pwm6: pwm@e6e36000 {
+                       compatible = "renesas,pwm-r8a774b1", "renesas,pwm-rcar";
+                       reg = <0 0xe6e36000 0 0x8>;
+                       #pwm-cells = <2>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       resets = <&cpg 523>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       status = "disabled";
+               };
+
+               scif0: serial@e6e60000 {
+                       compatible = "renesas,scif-r8a774b1",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e60000 0 0x40>;
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 207>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x51>, <&dmac1 0x50>,
+                              <&dmac2 0x51>, <&dmac2 0x50>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 207>;
+                       status = "disabled";
+               };
+
+               scif1: serial@e6e68000 {
+                       compatible = "renesas,scif-r8a774b1",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e68000 0 0x40>;
+                       interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 206>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x53>, <&dmac1 0x52>,
+                              <&dmac2 0x53>, <&dmac2 0x52>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 206>;
+                       status = "disabled";
+               };
+
+               scif2: serial@e6e88000 {
+                       compatible = "renesas,scif-r8a774b1",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e88000 0 0x40>;
+                       interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 310>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x13>, <&dmac1 0x12>,
+                              <&dmac2 0x13>, <&dmac2 0x12>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 310>;
+                       status = "disabled";
+               };
+
+               scif3: serial@e6c50000 {
+                       compatible = "renesas,scif-r8a774b1",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6c50000 0 0x40>;
+                       interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 204>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x57>, <&dmac0 0x56>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 204>;
+                       status = "disabled";
+               };
+
+               scif4: serial@e6c40000 {
+                       compatible = "renesas,scif-r8a774b1",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6c40000 0 0x40>;
+                       interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 203>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x59>, <&dmac0 0x58>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 203>;
+                       status = "disabled";
+               };
+
+               scif5: serial@e6f30000 {
+                       compatible = "renesas,scif-r8a774b1",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6f30000 0 0x40>;
+                       interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 202>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x5b>, <&dmac1 0x5a>,
+                              <&dmac2 0x5b>, <&dmac2 0x5a>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 202>;
+                       status = "disabled";
+               };
+
+               msiof0: spi@e6e90000 {
+                       compatible = "renesas,msiof-r8a774b1",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6e90000 0 0x0064>;
+                       interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 211>;
+                       dmas = <&dmac1 0x41>, <&dmac1 0x40>,
+                              <&dmac2 0x41>, <&dmac2 0x40>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 211>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               msiof1: spi@e6ea0000 {
+                       compatible = "renesas,msiof-r8a774b1",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6ea0000 0 0x0064>;
+                       interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 210>;
+                       dmas = <&dmac1 0x43>, <&dmac1 0x42>,
+                              <&dmac2 0x43>, <&dmac2 0x42>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 210>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               msiof2: spi@e6c00000 {
+                       compatible = "renesas,msiof-r8a774b1",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6c00000 0 0x0064>;
+                       interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 209>;
+                       dmas = <&dmac0 0x45>, <&dmac0 0x44>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 209>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               msiof3: spi@e6c10000 {
+                       compatible = "renesas,msiof-r8a774b1",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6c10000 0 0x0064>;
+                       interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 208>;
+                       dmas = <&dmac0 0x47>, <&dmac0 0x46>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 208>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               vin0: video@e6ef0000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef0000 0 0x1000>;
+                       interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 811>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 811>;
+                       renesas,id = <0>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin0csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin0>;
+                                       };
+                                       vin0csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin0>;
+                                       };
+                               };
+                       };
+               };
+
+               vin1: video@e6ef1000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef1000 0 0x1000>;
+                       interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 810>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 810>;
+                       renesas,id = <1>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin1csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin1>;
+                                       };
+                                       vin1csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin1>;
+                                       };
+                               };
+                       };
+               };
+
+               vin2: video@e6ef2000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef2000 0 0x1000>;
+                       interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 809>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 809>;
+                       renesas,id = <2>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin2csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin2>;
+                                       };
+                                       vin2csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin2>;
+                                       };
+                               };
+                       };
+               };
+
+               vin3: video@e6ef3000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef3000 0 0x1000>;
+                       interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 808>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 808>;
+                       renesas,id = <3>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin3csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin3>;
+                                       };
+                                       vin3csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin3>;
+                                       };
+                               };
+                       };
+               };
+
+               vin4: video@e6ef4000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef4000 0 0x1000>;
+                       interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 807>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 807>;
+                       renesas,id = <4>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin4csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin4>;
+                                       };
+                                       vin4csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin4>;
+                                       };
+                               };
+                       };
+               };
+
+               vin5: video@e6ef5000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef5000 0 0x1000>;
+                       interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 806>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 806>;
+                       renesas,id = <5>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin5csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin5>;
+                                       };
+                                       vin5csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin5>;
+                                       };
+                               };
+                       };
+               };
+
+               vin6: video@e6ef6000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef6000 0 0x1000>;
+                       interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 805>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 805>;
+                       renesas,id = <6>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin6csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin6>;
+                                       };
+                                       vin6csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin6>;
+                                       };
+                               };
+                       };
+               };
+
+               vin7: video@e6ef7000 {
+                       compatible = "renesas,vin-r8a774b1";
+                       reg = <0 0xe6ef7000 0 0x1000>;
+                       interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 804>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 804>;
+                       renesas,id = <7>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin7csi20: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&csi20vin7>;
+                                       };
+                                       vin7csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&csi40vin7>;
+                                       };
+                               };
+                       };
+               };
+
+               rcar_sound: sound@ec500000 {
+                       /*
+                        * #sound-dai-cells is required
+                        *
+                        * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
+                        * Multi  DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
+                        */
+                       /*
+                        * #clock-cells is required for audio_clkout0/1/2/3
+                        *
+                        * clkout       : #clock-cells = <0>;   <&rcar_sound>;
+                        * clkout0/1/2/3: #clock-cells = <1>;   <&rcar_sound N>;
+                        */
+                       compatible =  "renesas,rcar_sound-r8a774b1", "renesas,rcar_sound-gen3";
+                       reg = <0 0xec500000 0 0x1000>, /* SCU */
+                             <0 0xec5a0000 0 0x100>,  /* ADG */
+                             <0 0xec540000 0 0x1000>, /* SSIU */
+                             <0 0xec541000 0 0x280>,  /* SSI */
+                             <0 0xec760000 0 0x200>;  /* Audio DMAC peri peri*/
+                       reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+                       clocks = <&cpg CPG_MOD 1005>,
+                                <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+                                <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+                                <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+                                <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+                                <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+                                <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+                                <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+                                <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+                                <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+                                <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+                                <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
+                                <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
+                                <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+                                <&audio_clk_a>, <&audio_clk_b>,
+                                <&audio_clk_c>,
+                                <&cpg CPG_CORE R8A774B1_CLK_S0D4>;
+                       clock-names = "ssi-all",
+                                     "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+                                     "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+                                     "ssi.1", "ssi.0",
+                                     "src.9", "src.8", "src.7", "src.6",
+                                     "src.5", "src.4", "src.3", "src.2",
+                                     "src.1", "src.0",
+                                     "mix.1", "mix.0",
+                                     "ctu.1", "ctu.0",
+                                     "dvc.0", "dvc.1",
+                                     "clk_a", "clk_b", "clk_c", "clk_i";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 1005>,
+                                <&cpg 1006>, <&cpg 1007>,
+                                <&cpg 1008>, <&cpg 1009>,
+                                <&cpg 1010>, <&cpg 1011>,
+                                <&cpg 1012>, <&cpg 1013>,
+                                <&cpg 1014>, <&cpg 1015>;
+                       reset-names = "ssi-all",
+                                     "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+                                     "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+                                     "ssi.1", "ssi.0";
+                       status = "disabled";
+
+                       rcar_sound,ctu {
+                               ctu00: ctu-0 { };
+                               ctu01: ctu-1 { };
+                               ctu02: ctu-2 { };
+                               ctu03: ctu-3 { };
+                               ctu10: ctu-4 { };
+                               ctu11: ctu-5 { };
+                               ctu12: ctu-6 { };
+                               ctu13: ctu-7 { };
+                       };
+
+                       rcar_sound,dvc {
+                               dvc0: dvc-0 {
+                                       dmas = <&audma1 0xbc>;
+                                       dma-names = "tx";
+                               };
+                               dvc1: dvc-1 {
+                                       dmas = <&audma1 0xbe>;
+                                       dma-names = "tx";
+                               };
+                       };
+
+                       rcar_sound,mix {
+                               mix0: mix-0 { };
+                               mix1: mix-1 { };
+                       };
+
+                       rcar_sound,src {
+                               src0: src-0 {
+                                       interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x85>, <&audma1 0x9a>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src1: src-1 {
+                                       interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x87>, <&audma1 0x9c>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src2: src-2 {
+                                       interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x89>, <&audma1 0x9e>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src3: src-3 {
+                                       interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src4: src-4 {
+                                       interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src5: src-5 {
+                                       interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src6: src-6 {
+                                       interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x91>, <&audma1 0xb4>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src7: src-7 {
+                                       interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x93>, <&audma1 0xb6>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src8: src-8 {
+                                       interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x95>, <&audma1 0xb8>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src9: src-9 {
+                                       interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x97>, <&audma1 0xba>;
+                                       dma-names = "rx", "tx";
+                               };
+                       };
+
+                       rcar_sound,ssi {
+                               ssi0: ssi-0 {
+                                       interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+                                       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>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssi2: ssi-2 {
+                                       interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+                                       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>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssi4: ssi-4 {
+                                       interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+                                       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>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssi6: ssi-6 {
+                                       interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+                                       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>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssi8: ssi-8 {
+                                       interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+                                       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>;
+                                       dma-names = "rx", "tx";
+                               };
+                       };
+
+                       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";
+                               };
+                       };
+               };
+
+               audma0: dma-controller@ec700000 {
+                       compatible = "renesas,dmac-r8a774b1",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xec700000 0 0x10000>;
+                       interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 502>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 502>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+               };
+
+               audma1: dma-controller@ec720000 {
+                       compatible = "renesas,dmac-r8a774b1",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xec720000 0 0x10000>;
+                       interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH
+                                     GIC_SPI 383 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 501>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 501>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+               };
+
+               xhci0: usb@ee000000 {
+                       compatible = "renesas,xhci-r8a774b1",
+                                    "renesas,rcar-gen3-xhci";
+                       reg = <0 0xee000000 0 0xc00>;
+                       interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 328>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 328>;
+                       status = "disabled";
+               };
+
+               usb3_peri0: usb@ee020000 {
+                       compatible = "renesas,r8a774b1-usb3-peri",
+                                    "renesas,rcar-gen3-usb3-peri";
+                       reg = <0 0xee020000 0 0x400>;
+                       interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 328>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 328>;
+                       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>, <&cpg CPG_MOD 704>;
+                       phys = <&usb2_phy0 1>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       status = "disabled";
+               };
+
+               ohci1: usb@ee0a0000 {
+                       compatible = "generic-ohci";
+                       reg = <0 0xee0a0000 0 0x100>;
+                       interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 702>;
+                       phys = <&usb2_phy1 1>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 702>;
+                       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>, <&cpg CPG_MOD 704>;
+                       phys = <&usb2_phy0 2>;
+                       phy-names = "usb";
+                       companion = <&ohci0>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       status = "disabled";
+               };
+
+               ehci1: usb@ee0a0100 {
+                       compatible = "generic-ehci";
+                       reg = <0 0xee0a0100 0 0x100>;
+                       interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 702>;
+                       phys = <&usb2_phy1 2>;
+                       phy-names = "usb";
+                       companion = <&ohci1>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 702>;
+                       status = "disabled";
+               };
+
+               usb2_phy0: usb-phy@ee080200 {
+                       compatible = "renesas,usb2-phy-r8a774b1",
+                                    "renesas,rcar-gen3-usb2-phy";
+                       reg = <0 0xee080200 0 0x700>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       #phy-cells = <1>;
+                       status = "disabled";
+               };
+
+               usb2_phy1: usb-phy@ee0a0200 {
+                       compatible = "renesas,usb2-phy-r8a774b1",
+                                    "renesas,rcar-gen3-usb2-phy";
+                       reg = <0 0xee0a0200 0 0x700>;
+                       clocks = <&cpg CPG_MOD 702>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 702>;
+                       #phy-cells = <1>;
+                       status = "disabled";
+               };
+
+               sdhi0: sd@ee100000 {
+                       compatible = "renesas,sdhi-r8a774b1",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee100000 0 0x2000>;
+                       interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 314>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 314>;
+                       status = "disabled";
+               };
+
+               sdhi1: sd@ee120000 {
+                       compatible = "renesas,sdhi-r8a774b1",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee120000 0 0x2000>;
+                       interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 313>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 313>;
+                       status = "disabled";
+               };
+
+               sdhi2: sd@ee140000 {
+                       compatible = "renesas,sdhi-r8a774b1",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee140000 0 0x2000>;
+                       interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 312>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 312>;
+                       status = "disabled";
+               };
+
+               sdhi3: sd@ee160000 {
+                       compatible = "renesas,sdhi-r8a774b1",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee160000 0 0x2000>;
+                       interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 311>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 311>;
+                       status = "disabled";
+               };
+
+               sata: sata@ee300000 {
+                       compatible = "renesas,sata-r8a774b1",
+                                    "renesas,rcar-gen3-sata";
+                       reg = <0 0xee300000 0 0x200000>;
+                       interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 815>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 815>;
+                       status = "disabled";
+               };
+
+               gic: interrupt-controller@f1010000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x0 0xf1010000 0 0x1000>,
+                             <0x0 0xf1020000 0 0x20000>,
+                             <0x0 0xf1040000 0 0x20000>,
+                             <0x0 0xf1060000 0 0x20000>;
+                       interrupts = <GIC_PPI 9
+                                       (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+                       clocks = <&cpg CPG_MOD 408>;
+                       clock-names = "clk";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 408>;
+               };
+
+               pciec0: pcie@fe000000 {
+                       compatible = "renesas,pcie-r8a774b1",
+                                    "renesas,pcie-rcar-gen3";
+                       reg = <0 0xfe000000 0 0x80000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       bus-range = <0x00 0xff>;
+                       device_type = "pci";
+                       ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+                                 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+                                 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+                                 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+                       /* Map all possible DDR as inbound ranges */
+                       dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000>;
+                       interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
+                       clock-names = "pcie", "pcie_bus";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 319>;
+                       status = "disabled";
+               };
+
+               pciec1: pcie@ee800000 {
+                       compatible = "renesas,pcie-r8a774b1",
+                                    "renesas,pcie-rcar-gen3";
+                       reg = <0 0xee800000 0 0x80000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       bus-range = <0x00 0xff>;
+                       device_type = "pci";
+                       ranges = <0x01000000 0 0x00000000 0 0xee900000 0 0x00100000
+                                 0x02000000 0 0xeea00000 0 0xeea00000 0 0x00200000
+                                 0x02000000 0 0xc0000000 0 0xc0000000 0 0x08000000
+                                 0x42000000 0 0xc8000000 0 0xc8000000 0 0x08000000>;
+                       /* Map all possible DDR as inbound ranges */
+                       dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000>;
+                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 318>, <&pcie_bus_clk>;
+                       clock-names = "pcie", "pcie_bus";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 318>;
+                       status = "disabled";
+               };
+
+               fdp1@fe940000 {
+                       compatible = "renesas,fdp1";
+                       reg = <0 0xfe940000 0 0x2400>;
+                       interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 119>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       resets = <&cpg 119>;
+                       renesas,fcp = <&fcpf0>;
+               };
+
+               fcpf0: fcp@fe950000 {
+                       compatible = "renesas,fcpf";
+                       reg = <0 0xfe950000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 615>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       resets = <&cpg 615>;
+               };
+
+               vspb: vsp@fe960000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfe960000 0 0x8000>;
+                       interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 626>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       resets = <&cpg 626>;
+
+                       renesas,fcp = <&fcpvb0>;
+               };
+
+               vspi0: vsp@fe9a0000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfe9a0000 0 0x8000>;
+                       interrupts = <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 631>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       resets = <&cpg 631>;
+
+                       renesas,fcp = <&fcpvi0>;
+               };
+
+               vspd0: vsp@fea20000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea20000 0 0x5000>;
+                       interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 623>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 623>;
+
+                       renesas,fcp = <&fcpvd0>;
+               };
+
+               vspd1: vsp@fea28000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea28000 0 0x5000>;
+                       interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 622>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 622>;
+
+                       renesas,fcp = <&fcpvd1>;
+               };
+
+               fcpvb0: fcp@fe96f000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfe96f000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 607>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       resets = <&cpg 607>;
+               };
+
+               fcpvd0: fcp@fea27000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfea27000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 603>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 603>;
+               };
+
+               fcpvd1: fcp@fea2f000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfea2f000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 602>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 602>;
+               };
+
+               fcpvi0: fcp@fe9af000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfe9af000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 611>;
+                       power-domains = <&sysc R8A774B1_PD_A3VP>;
+                       resets = <&cpg 611>;
+               };
+
+               csi20: csi2@fea80000 {
+                       compatible = "renesas,r8a774b1-csi2";
+                       reg = <0 0xfea80000 0 0x10000>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 714>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 714>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       csi20vin0: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&vin0csi20>;
+                                       };
+                                       csi20vin1: endpoint@1 {
+                                               reg = <1>;
+                                               remote-endpoint = <&vin1csi20>;
+                                       };
+                                       csi20vin2: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&vin2csi20>;
+                                       };
+                                       csi20vin3: endpoint@3 {
+                                               reg = <3>;
+                                               remote-endpoint = <&vin3csi20>;
+                                       };
+                                       csi20vin4: endpoint@4 {
+                                               reg = <4>;
+                                               remote-endpoint = <&vin4csi20>;
+                                       };
+                                       csi20vin5: endpoint@5 {
+                                               reg = <5>;
+                                               remote-endpoint = <&vin5csi20>;
+                                       };
+                                       csi20vin6: endpoint@6 {
+                                               reg = <6>;
+                                               remote-endpoint = <&vin6csi20>;
+                                       };
+                                       csi20vin7: endpoint@7 {
+                                               reg = <7>;
+                                               remote-endpoint = <&vin7csi20>;
+                                       };
+                               };
+                       };
+               };
+
+               csi40: csi2@feaa0000 {
+                       compatible = "renesas,r8a774b1-csi2";
+                       reg = <0 0xfeaa0000 0 0x10000>;
+                       interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 716>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 716>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       csi40vin0: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&vin0csi40>;
+                                       };
+                                       csi40vin1: endpoint@1 {
+                                               reg = <1>;
+                                               remote-endpoint = <&vin1csi40>;
+                                       };
+                                       csi40vin2: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint = <&vin2csi40>;
+                                       };
+                                       csi40vin3: endpoint@3 {
+                                               reg = <3>;
+                                               remote-endpoint = <&vin3csi40>;
+                                       };
+                                       csi40vin4: endpoint@4 {
+                                               reg = <4>;
+                                               remote-endpoint = <&vin4csi40>;
+                                       };
+                                       csi40vin5: endpoint@5 {
+                                               reg = <5>;
+                                               remote-endpoint = <&vin5csi40>;
+                                       };
+                                       csi40vin6: endpoint@6 {
+                                               reg = <6>;
+                                               remote-endpoint = <&vin6csi40>;
+                                       };
+                                       csi40vin7: endpoint@7 {
+                                               reg = <7>;
+                                               remote-endpoint = <&vin7csi40>;
+                                       };
+                               };
+                       };
+               };
+
+               hdmi0: hdmi@fead0000 {
+                       compatible = "renesas,r8a774b1-hdmi",
+                                    "renesas,rcar-gen3-hdmi";
+                       reg = <0 0xfead0000 0 0x10000>;
+                       interrupts = <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 729>,
+                                <&cpg CPG_CORE R8A774B1_CLK_HDMI>;
+                       clock-names = "iahb", "isfr";
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 729>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       dw_hdmi0_in: endpoint {
+                                               remote-endpoint = <&du_out_hdmi0>;
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                               };
+                               port@2 {
+                                       /* HDMI sound */
+                                       reg = <2>;
+                               };
+                       };
+               };
+
+               du: display@feb00000 {
+                       compatible = "renesas,du-r8a774b1";
+                       reg = <0 0xfeb00000 0 0x80000>;
+                       interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 724>,
+                                <&cpg CPG_MOD 723>,
+                                <&cpg CPG_MOD 721>;
+                       clock-names = "du.0", "du.1", "du.3";
+                       status = "disabled";
+
+                       vsps = <&vspd0 0>, <&vspd1 0>, <&vspd0 1>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_rgb: endpoint {
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                                       du_out_hdmi0: endpoint {
+                                               remote-endpoint = <&dw_hdmi0_in>;
+                                       };
+                               };
+                               port@2 {
+                                       reg = <2>;
+                                       du_out_lvds0: endpoint {
+                                               remote-endpoint = <&lvds0_in>;
+                                       };
+                               };
+                       };
+               };
+
+               lvds0: lvds@feb90000 {
+                       compatible = "renesas,r8a774b1-lvds";
+                       reg = <0 0xfeb90000 0 0x14>;
+                       clocks = <&cpg CPG_MOD 727>;
+                       power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
+                       resets = <&cpg 727>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       lvds0_in: endpoint {
+                                               remote-endpoint = <&du_out_lvds0>;
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                                       lvds0_out: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               prr: chipid@fff00044 {
+                       compatible = "renesas,prr";
+                       reg = <0 0xfff00044 0 4>;
+               };
+       };
+
+       thermal-zones {
+               sensor_thermal1: sensor-thermal1 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 0>;
+                       sustainable-power = <2439>;
+
+                       trips {
+                               sensor1_crit: sensor1-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               sensor_thermal2: sensor-thermal2 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 1>;
+                       sustainable-power = <2439>;
+
+                       trips {
+                               sensor2_crit: sensor2-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               sensor_thermal3: sensor-thermal3 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 2>;
+                       sustainable-power = <2439>;
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&target>;
+                                       cooling-device = <&a57_0 0 2>;
+                                       contribution = <1024>;
+                               };
+                       };
+                       trips {
+                               target: trip-point1 {
+                                       temperature = <100000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+
+                               sensor3_crit: sensor3-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       /* External USB clocks - can be overridden by the board */
+       usb3s0_clk: usb3s0 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       usb_extal_clk: usb_extal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+};
index a1c2de9..c7bdc36 100644 (file)
                        compatible = "arm,cortex-a53";
                        reg = <0>;
                        device_type = "cpu";
+                       #cooling-cells = <2>;
                        power-domains = <&sysc R8A774C0_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       dynamic-power-coefficient = <277>;
                        clocks = <&cpg CPG_CORE R8A774C0_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                };
        thermal-zones {
                cpu-thermal {
                        polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-                       thermal-sensors = <&thermal>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&thermal 0>;
+                       sustainable-power = <717>;
 
                        cooling-maps {
+                               map0 {
+                                       trip = <&target>;
+                                       cooling-device = <&a53_0 0 2>;
+                                       contribution = <1024>;
+                               };
                        };
 
                        trips {
-                               cpu-crit {
+                               sensor1_crit: sensor1-crit {
                                        temperature = <120000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                };
+
+                               target: trip-point1 {
+                                       temperature = <100000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
                        };
                };
        };
index e4650ae..14d8513 100644 (file)
@@ -30,7 +30,7 @@
 };
 
 &du {
-       vsps = <&vspd0 &vspd1 &vspd2 &vspd3>;
+       vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd3 0>;
 };
 
 &fcpvb1 {
index 95deff6..fde6ec1 100644 (file)
                        power-domains = <&sysc R8A7795_PD_CA57_CPU0>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        dynamic-power-coefficient = <854>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        power-domains = <&sysc R8A7795_PD_CA57_CPU1>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        capacity-dmips-mhz = <1024>;
                        power-domains = <&sysc R8A7795_PD_CA57_CPU2>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        capacity-dmips-mhz = <1024>;
                        power-domains = <&sysc R8A7795_PD_CA57_CPU3>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        capacity-dmips-mhz = <1024>;
                        power-domains = <&sysc R8A7795_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        #cooling-cells = <2>;
                        dynamic-power-coefficient = <277>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z2>;
                        power-domains = <&sysc R8A7795_PD_CA53_CPU1>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                        power-domains = <&sysc R8A7795_PD_CA53_CPU2>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                        power-domains = <&sysc R8A7795_PD_CA53_CPU3>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                        cache-unified;
                        cache-level = <2>;
                };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <400>;
+                               exit-latency-us = <500>;
+                               min-residency-us = <4000>;
+                       };
+
+                       CPU_SLEEP_1: cpu-sleep-1 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <700>;
+                               exit-latency-us = <700>;
+                               min-residency-us = <5000>;
+                       };
+               };
        };
 
        extal_clk: extal {
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 314>;
+                       iommus = <&ipmmu_ds1 32>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 313>;
+                       iommus = <&ipmmu_ds1 33>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 312>;
+                       iommus = <&ipmmu_ds1 34>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 311>;
+                       iommus = <&ipmmu_ds1 35>;
                        status = "disabled";
                };
 
                        iommus = <&ipmmu_vi1 10>;
                };
 
+               cmm0: cmm@fea40000 {
+                       compatible = "renesas,r8a7795-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea40000 0 0x1000>;
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 711>;
+                       resets = <&cpg 711>;
+               };
+
+               cmm1: cmm@fea50000 {
+                       compatible = "renesas,r8a7795-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea50000 0 0x1000>;
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 710>;
+                       resets = <&cpg 710>;
+               };
+
+               cmm2: cmm@fea60000 {
+                       compatible = "renesas,r8a7795-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea60000 0 0x1000>;
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 709>;
+                       resets = <&cpg 709>;
+               };
+
+               cmm3: cmm@fea70000 {
+                       compatible = "renesas,r8a7795-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea70000 0 0x1000>;
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 708>;
+                       resets = <&cpg 708>;
+               };
+
                csi20: csi2@fea80000 {
                        compatible = "renesas,r8a7795-csi2";
                        reg = <0 0xfea80000 0 0x10000>;
                                 <&cpg CPG_MOD 722>,
                                 <&cpg CPG_MOD 721>;
                        clock-names = "du.0", "du.1", "du.2", "du.3";
+
+                       renesas,cmms = <&cmm0>, <&cmm1>, <&cmm2>, <&cmm3>;
                        vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
+
                        status = "disabled";
 
                        ports {
index 3dc9d73..b9db882 100644 (file)
                        power-domains = <&sysc R8A7796_PD_CA57_CPU0>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        dynamic-power-coefficient = <854>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        power-domains = <&sysc R8A7796_PD_CA57_CPU1>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        capacity-dmips-mhz = <1024>;
                        power-domains = <&sysc R8A7796_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        #cooling-cells = <2>;
                        dynamic-power-coefficient = <277>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z2>;
                        power-domains = <&sysc R8A7796_PD_CA53_CPU1>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                        power-domains = <&sysc R8A7796_PD_CA53_CPU2>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                        power-domains = <&sysc R8A7796_PD_CA53_CPU3>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                        cache-unified;
                        cache-level = <2>;
                };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <400>;
+                               exit-latency-us = <500>;
+                               min-residency-us = <4000>;
+                       };
+
+                       CPU_SLEEP_1: cpu-sleep-1 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <700>;
+                               exit-latency-us = <700>;
+                               min-residency-us = <5000>;
+                       };
+               };
        };
 
        extal_clk: extal {
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 314>;
+                       iommus = <&ipmmu_ds1 32>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 313>;
+                       iommus = <&ipmmu_ds1 33>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 312>;
+                       iommus = <&ipmmu_ds1 34>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 311>;
+                       iommus = <&ipmmu_ds1 35>;
                        status = "disabled";
                };
 
                        renesas,fcp = <&fcpvi0>;
                };
 
+               cmm0: cmm@fea40000 {
+                       compatible = "renesas,r8a7796-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea40000 0 0x1000>;
+                       power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 711>;
+                       resets = <&cpg 711>;
+               };
+
+               cmm1: cmm@fea50000 {
+                       compatible = "renesas,r8a7796-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea50000 0 0x1000>;
+                       power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 710>;
+                       resets = <&cpg 710>;
+               };
+
+               cmm2: cmm@fea60000 {
+                       compatible = "renesas,r8a7796-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea60000 0 0x1000>;
+                       power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 709>;
+                       resets = <&cpg 709>;
+               };
+
                csi20: csi2@fea80000 {
                        compatible = "renesas,r8a7796-csi2";
                        reg = <0 0xfea80000 0 0x10000>;
                                 <&cpg CPG_MOD 723>,
                                 <&cpg CPG_MOD 722>;
                        clock-names = "du.0", "du.1", "du.2";
-                       status = "disabled";
 
-                       vsps = <&vspd0 &vspd1 &vspd2>;
+                       renesas,cmms = <&cmm0>, <&cmm1>, <&cmm2>;
+                       vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>;
+
+                       status = "disabled";
 
                        ports {
                                #address-cells = <1>;
diff --git a/arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77961-salvator-xs.dts
new file mode 100644 (file)
index 0000000..4abd78a
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the Salvator-X 2nd version board with R-Car M3-W+
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+#include "r8a77961.dtsi"
+#include "salvator-xs.dtsi"
+
+/ {
+       model = "Renesas Salvator-X 2nd version board based on r8a77961";
+       compatible = "renesas,salvator-xs", "renesas,r8a77961";
+
+       memory@48000000 {
+               device_type = "memory";
+               /* first 128MB is reserved for secure area. */
+               reg = <0x0 0x48000000 0x0 0x78000000>;
+       };
+
+       memory@400000000 {
+               device_type = "memory";
+               reg = <0x4 0x80000000 0x0 0x80000000>;
+       };
+
+       memory@600000000 {
+               device_type = "memory";
+               reg = <0x6 0x00000000 0x1 0x00000000>;
+       };
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a77961.dtsi b/arch/arm64/boot/dts/renesas/r8a77961.dtsi
new file mode 100644 (file)
index 0000000..64466c8
--- /dev/null
@@ -0,0 +1,723 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the R-Car M3-W+ (R8A77961) SoC
+ *
+ * Copyright (C) 2016-2017 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/clock/r8a77961-cpg-mssr.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/r8a77961-sysc.h>
+
+#define CPG_AUDIO_CLK_I                R8A77961_CLK_S0D4
+
+/ {
+       compatible = "renesas,r8a77961";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       /*
+        * The external audio clocks are configured as 0 Hz fixed frequency
+        * clocks by default.
+        * Boards that provide audio clocks should override them.
+        */
+       audio_clk_a: audio_clk_a {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       audio_clk_b: audio_clk_b {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       audio_clk_c: audio_clk_c {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       /* External CAN clock - to be overridden by boards that provide it */
+       can_clk: can {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       cluster0_opp: opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-500000000 {
+                       opp-hz = /bits/ 64 <500000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1500000000 {
+                       opp-hz = /bits/ 64 <1500000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1600000000 {
+                       opp-hz = /bits/ 64 <1600000000>;
+                       opp-microvolt = <900000>;
+                       clock-latency-ns = <300000>;
+                       turbo-mode;
+               };
+               opp-1700000000 {
+                       opp-hz = /bits/ 64 <1700000000>;
+                       opp-microvolt = <900000>;
+                       clock-latency-ns = <300000>;
+                       turbo-mode;
+               };
+               opp-1800000000 {
+                       opp-hz = /bits/ 64 <1800000000>;
+                       opp-microvolt = <960000>;
+                       clock-latency-ns = <300000>;
+                       turbo-mode;
+               };
+       };
+
+       cluster1_opp: opp_table1 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1300000000 {
+                       opp-hz = /bits/ 64 <1300000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+                       turbo-mode;
+               };
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&a57_0>;
+                               };
+                               core1 {
+                                       cpu = <&a57_1>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&a53_0>;
+                               };
+                               core1 {
+                                       cpu = <&a53_1>;
+                               };
+                               core2 {
+                                       cpu = <&a53_2>;
+                               };
+                               core3 {
+                                       cpu = <&a53_3>;
+                               };
+                       };
+               };
+
+               a57_0: cpu@0 {
+                       compatible = "arm,cortex-a57";
+                       reg = <0x0>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A77961_PD_CA57_CPU0>;
+                       next-level-cache = <&L2_CA57>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       dynamic-power-coefficient = <854>;
+                       clocks = <&cpg CPG_CORE R8A77961_CLK_Z>;
+                       operating-points-v2 = <&cluster0_opp>;
+                       capacity-dmips-mhz = <1024>;
+                       #cooling-cells = <2>;
+               };
+
+               a57_1: cpu@1 {
+                       compatible = "arm,cortex-a57";
+                       reg = <0x1>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A77961_PD_CA57_CPU1>;
+                       next-level-cache = <&L2_CA57>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A77961_CLK_Z>;
+                       operating-points-v2 = <&cluster0_opp>;
+                       capacity-dmips-mhz = <1024>;
+                       #cooling-cells = <2>;
+               };
+
+               a53_0: cpu@100 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0x100>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A77961_PD_CA53_CPU0>;
+                       next-level-cache = <&L2_CA53>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <277>;
+                       clocks = <&cpg CPG_CORE R8A77961_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <535>;
+               };
+
+               a53_1: cpu@101 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0x101>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A77961_PD_CA53_CPU1>;
+                       next-level-cache = <&L2_CA53>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
+                       clocks = <&cpg CPG_CORE R8A77961_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <535>;
+               };
+
+               a53_2: cpu@102 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0x102>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A77961_PD_CA53_CPU2>;
+                       next-level-cache = <&L2_CA53>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
+                       clocks = <&cpg CPG_CORE R8A77961_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <535>;
+               };
+
+               a53_3: cpu@103 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0x103>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A77961_PD_CA53_CPU3>;
+                       next-level-cache = <&L2_CA53>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_1>;
+                       clocks = <&cpg CPG_CORE R8A77961_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <535>;
+               };
+
+               L2_CA57: cache-controller-0 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A77961_PD_CA57_SCU>;
+                       cache-unified;
+                       cache-level = <2>;
+               };
+
+               L2_CA53: cache-controller-1 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A77961_PD_CA53_SCU>;
+                       cache-unified;
+                       cache-level = <2>;
+               };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <400>;
+                               exit-latency-us = <500>;
+                               min-residency-us = <4000>;
+                       };
+
+                       CPU_SLEEP_1: cpu-sleep-1 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <700>;
+                               exit-latency-us = <700>;
+                               min-residency-us = <5000>;
+                       };
+               };
+       };
+
+       extal_clk: extal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       extalr_clk: extalr {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       /* External PCIe clock - can be overridden by the board */
+       pcie_bus_clk: pcie_bus {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       pmu_a53 {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts-extended = <&gic GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&gic GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&gic GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&gic GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&a53_0>, <&a53_1>, <&a53_2>, <&a53_3>;
+       };
+
+       pmu_a57 {
+               compatible = "arm,cortex-a57-pmu";
+               interrupts-extended = <&gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&a57_0>, <&a57_1>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0", "arm,psci-0.2";
+               method = "smc";
+       };
+
+       /* External SCIF clock - to be overridden by boards that provide it */
+       scif_clk: scif {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               rwdt: watchdog@e6020000 {
+                       reg = <0 0xe6020000 0 0x0c>;
+                       /* placeholder */
+               };
+
+               gpio2: gpio@e6052000 {
+                       reg = <0 0xe6052000 0 0x50>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       /* placeholder */
+               };
+
+               gpio3: gpio@e6053000 {
+                       reg = <0 0xe6053000 0 0x50>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       /* placeholder */
+               };
+
+               gpio4: gpio@e6054000 {
+                       reg = <0 0xe6054000 0 0x50>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       /* placeholder */
+               };
+
+               gpio5: gpio@e6055000 {
+                       reg = <0 0xe6055000 0 0x50>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       /* placeholder */
+               };
+
+               gpio6: gpio@e6055400 {
+                       reg = <0 0xe6055400 0 0x50>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       /* placeholder */
+               };
+
+               pfc: pin-controller@e6060000 {
+                       compatible = "renesas,pfc-r8a77961";
+                       reg = <0 0xe6060000 0 0x50c>;
+               };
+
+               cpg: clock-controller@e6150000 {
+                       compatible = "renesas,r8a77961-cpg-mssr";
+                       reg = <0 0xe6150000 0 0x1000>;
+                       clocks = <&extal_clk>, <&extalr_clk>;
+                       clock-names = "extal", "extalr";
+                       #clock-cells = <2>;
+                       #power-domain-cells = <0>;
+                       #reset-cells = <1>;
+               };
+
+               rst: reset-controller@e6160000 {
+                       compatible = "renesas,r8a77961-rst";
+                       reg = <0 0xe6160000 0 0x0200>;
+               };
+
+               sysc: system-controller@e6180000 {
+                       compatible = "renesas,r8a77961-sysc";
+                       reg = <0 0xe6180000 0 0x0400>;
+                       #power-domain-cells = <1>;
+               };
+
+               intc_ex: interrupt-controller@e61c0000 {
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       reg = <0 0xe61c0000 0 0x200>;
+                       /* placeholder */
+               };
+
+               i2c2: i2c@e6510000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0xe6510000 0 0x40>;
+                       /* placeholder */
+               };
+
+               i2c4: i2c@e66d8000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0xe66d8000 0 0x40>;
+                       /* placeholder */
+               };
+
+               i2c_dvfs: i2c@e60b0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0xe60b0000 0 0x425>;
+                       /* placeholder */
+               };
+
+               hscif1: serial@e6550000 {
+                       reg = <0 0xe6550000 0 0x60>;
+                       /* placeholder */
+               };
+
+               hsusb: usb@e6590000 {
+                       reg = <0 0xe6590000 0 0x200>;
+                       /* placeholder */
+               };
+
+               usb3_phy0: usb-phy@e65ee000 {
+                       reg = <0 0xe65ee000 0 0x90>;
+                       #phy-cells = <0>;
+                       /* placeholder */
+               };
+
+               avb: ethernet@e6800000 {
+                       reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       /* placeholder */
+               };
+
+               pwm1: pwm@e6e31000 {
+                       reg = <0 0xe6e31000 0 8>;
+                       #pwm-cells = <2>;
+                       /* placeholder */
+               };
+
+               scif1: serial@e6e68000 {
+                       reg = <0 0xe6e68000 0 64>;
+                       /* placeholder */
+               };
+
+               scif2: serial@e6e88000 {
+                       compatible = "renesas,scif-r8a77961",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e88000 0 64>;
+                       interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 310>,
+                                <&cpg CPG_CORE R8A77961_CLK_S3D1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
+                       resets = <&cpg 310>;
+                       status = "disabled";
+               };
+
+               vin0: video@e6ef0000 {
+                       reg = <0 0xe6ef0000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin1: video@e6ef1000 {
+                       reg = <0 0xe6ef1000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin2: video@e6ef2000 {
+                       reg = <0 0xe6ef2000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin3: video@e6ef3000 {
+                       reg = <0 0xe6ef3000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin4: video@e6ef4000 {
+                       reg = <0 0xe6ef4000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin5: video@e6ef5000 {
+                       reg = <0 0xe6ef5000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin6: video@e6ef6000 {
+                       reg = <0 0xe6ef6000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               vin7: video@e6ef7000 {
+                       reg = <0 0xe6ef7000 0 0x1000>;
+                       /* placeholder */
+               };
+
+               rcar_sound: sound@ec500000 {
+                       reg = <0 0xec500000 0 0x1000>, /* SCU */
+                             <0 0xec5a0000 0 0x100>,  /* ADG */
+                             <0 0xec540000 0 0x1000>, /* SSIU */
+                             <0 0xec541000 0 0x280>,  /* SSI */
+                             <0 0xec760000 0 0x200>;  /* Audio DMAC peri peri*/
+                       /* placeholder */
+                       rcar_sound,dvc {
+                               dvc0: dvc-0 { };
+                               dvc1: dvc-1 { };
+                       };
+
+                       rcar_sound,src {
+                               src0: src-0 { };
+                               src1: src-1 { };
+                       };
+
+                       rcar_sound,ssi {
+                               ssi0: ssi-0 { };
+                               ssi1: ssi-1 { };
+                       };
+               };
+
+               xhci0: usb@ee000000 {
+                       reg = <0 0xee000000 0 0xc00>;
+                       /* placeholder */
+               };
+
+               usb3_peri0: usb@ee020000 {
+                       reg = <0 0xee020000 0 0x400>;
+                       /* placeholder */
+               };
+
+               ohci0: usb@ee080000 {
+                       reg = <0 0xee080000 0 0x100>;
+                       /* placeholder */
+               };
+
+               ohci1: usb@ee0a0000 {
+                       reg = <0 0xee0a0000 0 0x100>;
+                       /* placeholder */
+               };
+
+               ehci0: usb@ee080100 {
+                       reg = <0 0xee080100 0 0x100>;
+                       /* placeholder */
+               };
+
+               ehci1: usb@ee0a0100 {
+                       reg = <0 0xee0a0100 0 0x100>;
+                       /* placeholder */
+               };
+
+               usb2_phy0: usb-phy@ee080200 {
+                       reg = <0 0xee080200 0 0x700>;
+                       /* placeholder */
+               };
+
+               usb2_phy1: usb-phy@ee0a0200 {
+                       reg = <0 0xee0a0200 0 0x700>;
+                       /* placeholder */
+               };
+
+               sdhi0: sd@ee100000 {
+                       reg = <0 0xee100000 0 0x2000>;
+                       /* placeholder */
+               };
+
+               sdhi2: sd@ee140000 {
+                       reg = <0 0xee140000 0 0x2000>;
+                       /* placeholder */
+               };
+
+               sdhi3: sd@ee160000 {
+                       reg = <0 0xee160000 0 0x2000>;
+                       /* placeholder */
+               };
+
+               gic: interrupt-controller@f1010000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x0 0xf1010000 0 0x1000>,
+                             <0x0 0xf1020000 0 0x20000>,
+                             <0x0 0xf1040000 0 0x20000>,
+                             <0x0 0xf1060000 0 0x20000>;
+                       interrupts = <GIC_PPI 9
+                                       (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
+                       clocks = <&cpg CPG_MOD 408>;
+                       clock-names = "clk";
+                       power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
+                       resets = <&cpg 408>;
+               };
+
+               pciec0: pcie@fe000000 {
+                       reg = <0 0xfe000000 0 0x80000>;
+                       /* placeholder */
+               };
+
+               pciec1: pcie@ee800000 {
+                       reg = <0 0xee800000 0 0x80000>;
+                       /* placeholder */
+               };
+
+               csi20: csi2@fea80000 {
+                       reg = <0 0xfea80000 0 0x10000>;
+                       /* placeholder */
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       reg = <1>;
+                               };
+                       };
+               };
+
+               csi40: csi2@feaa0000 {
+                       reg = <0 0xfeaa0000 0 0x10000>;
+                       /* placeholder */
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+                               };
+                       };
+               };
+
+               hdmi0: hdmi@fead0000 {
+                       reg = <0 0xfead0000 0 0x10000>;
+                       /* placeholder */
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               port@0 {
+                                       reg = <0>;
+                               };
+                               port@1 {
+                                       reg = <1>;
+                               };
+                               port@2 {
+                                       /* HDMI sound */
+                                       reg = <2>;
+                               };
+                       };
+               };
+
+               du: display@feb00000 {
+                       reg = <0 0xfeb00000 0 0x70000>;
+                       /* placeholder */
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_rgb: endpoint {
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                                       du_out_hdmi0: endpoint {
+                                       };
+                               };
+                               port@2 {
+                                       reg = <2>;
+                                       du_out_lvds0: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               prr: chipid@fff00044 {
+                       compatible = "renesas,prr";
+                       reg = <0 0xfff00044 0 4>;
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       /* External USB clocks - can be overridden by the board */
+       usb3s0_clk: usb3s0 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       usb_extal_clk: usb_extal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+};
index 4ae1632..bdbe197 100644 (file)
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 314>;
+                       iommus = <&ipmmu_ds1 32>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 313>;
+                       iommus = <&ipmmu_ds1 33>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 312>;
+                       iommus = <&ipmmu_ds1 34>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 311>;
+                       iommus = <&ipmmu_ds1 35>;
                        status = "disabled";
                };
 
                        resets = <&cpg 611>;
                };
 
+               cmm0: cmm@fea40000 {
+                       compatible = "renesas,r8a77965-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea40000 0 0x1000>;
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 711>;
+                       resets = <&cpg 711>;
+               };
+
+               cmm1: cmm@fea50000 {
+                       compatible = "renesas,r8a77965-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea50000 0 0x1000>;
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 710>;
+                       resets = <&cpg 710>;
+               };
+
+               cmm3: cmm@fea70000 {
+                       compatible = "renesas,r8a77965-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea70000 0 0x1000>;
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 708>;
+                       resets = <&cpg 708>;
+               };
+
                csi20: csi2@fea80000 {
                        compatible = "renesas,r8a77965-csi2";
                        reg = <0 0xfea80000 0 0x10000>;
                                 <&cpg CPG_MOD 723>,
                                 <&cpg CPG_MOD 721>;
                        clock-names = "du.0", "du.1", "du.3";
-                       status = "disabled";
 
+                       renesas,cmms = <&cmm0>, <&cmm1>, <&cmm3>;
                        vsps = <&vspd0 0>, <&vspd1 0>, <&vspd0 1>;
 
+                       status = "disabled";
+
                        ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
index 0cd3b37..0d0558e 100644 (file)
                };
 
                pwm3: pwm@e6e33000 {
-                       compatible = "renesas,pwm-r8a7790", "renesas,pwm-rcar";
+                       compatible = "renesas,pwm-r8a77970", "renesas,pwm-rcar";
                        reg = <0 0xe6e33000 0 8>;
                        #pwm-cells = <2>;
                        clocks = <&cpg CPG_MOD 523>;
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
                        resets = <&cpg 314>;
                        max-frequency = <200000000>;
+                       iommus = <&ipmmu_ds1 32>;
                        status = "disabled";
                };
 
                        clock-names = "du.0";
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
                        resets = <&cpg 724>;
-                       vsps = <&vspd0>;
+                       vsps = <&vspd0 0>;
                        status = "disabled";
 
                        ports {
index 461a47e..4d86669 100644 (file)
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 314>;
                        max-frequency = <200000000>;
+                       iommus = <&ipmmu_ds1 32>;
                        status = "disabled";
                };
 
                        clock-names = "du.0";
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 724>;
-                       vsps = <&vspd0>;
+                       vsps = <&vspd0 0>;
                        status = "disabled";
 
                        ports {
index 455954c..67a6824 100644 (file)
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        resets = <&cpg 314>;
+                       iommus = <&ipmmu_ds1 32>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        resets = <&cpg 313>;
+                       iommus = <&ipmmu_ds1 33>;
                        status = "disabled";
                };
 
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        resets = <&cpg 311>;
+                       iommus = <&ipmmu_ds1 35>;
                        status = "disabled";
                };
 
                        iommus = <&ipmmu_vi0 9>;
                };
 
+               cmm0: cmm@fea40000 {
+                       compatible = "renesas,r8a77990-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea40000 0 0x1000>;
+                       power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 711>;
+                       resets = <&cpg 711>;
+               };
+
+               cmm1: cmm@fea50000 {
+                       compatible = "renesas,r8a77990-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea50000 0 0x1000>;
+                       power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 710>;
+                       resets = <&cpg 710>;
+               };
+
                csi40: csi2@feaa0000 {
                        compatible = "renesas,r8a77990-csi2";
                        reg = <0 0xfeaa0000 0 0x10000>;
                        clock-names = "du.0", "du.1";
                        resets = <&cpg 724>;
                        reset-names = "du.0";
+
+                       renesas,cmms = <&cmm0>, <&cmm1>;
                        vsps = <&vspd0 0>, <&vspd1 0>;
+
                        status = "disabled";
 
                        ports {
index 183fef8..e6ee2b7 100644 (file)
                        max-frequency = <200000000>;
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        resets = <&cpg 312>;
+                       iommus = <&ipmmu_ds1 34>;
                        status = "disabled";
                };
 
                        iommus = <&ipmmu_vi0 9>;
                };
 
+               cmm0: cmm@fea40000 {
+                       compatible = "renesas,r8a77995-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea40000 0 0x1000>;
+                       power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 711>;
+                       resets = <&cpg 711>;
+               };
+
+               cmm1: cmm@fea50000 {
+                       compatible = "renesas,r8a77995-cmm",
+                                    "renesas,rcar-gen3-cmm";
+                       reg = <0 0xfea50000 0 0x1000>;
+                       power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+                       clocks = <&cpg CPG_MOD 710>;
+                       resets = <&cpg 710>;
+               };
+
                du: display@feb00000 {
                        compatible = "renesas,du-r8a77995";
                        reg = <0 0xfeb00000 0 0x40000>;
                        clock-names = "du.0", "du.1";
                        resets = <&cpg 724>;
                        reset-names = "du.0";
+
+                       renesas,cmms = <&cmm0>, <&cmm1>;
                        vsps = <&vspd0 0>, <&vspd1 0>;
+
                        status = "disabled";
 
                        ports {
diff --git a/arch/arm64/boot/dts/renesas/rzg2-advantech-idk-1110wr-panel.dtsi b/arch/arm64/boot/dts/renesas/rzg2-advantech-idk-1110wr-panel.dtsi
new file mode 100644 (file)
index 0000000..bcc2117
--- /dev/null
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the Advantech idk-1110wr LVDS panel connected
+ * to RZ/G2 boards
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+/ {
+       panel-lvds {
+               compatible = "advantech,idk-1110wr", "panel-lvds";
+
+               width-mm = <223>;
+               height-mm = <125>;
+
+               data-mapping = "jeida-24";
+
+               panel-timing {
+                       /* 1024x600 @60Hz */
+                       clock-frequency = <51200000>;
+                       hactive = <1024>;
+                       vactive = <600>;
+                       hsync-len = <240>;
+                       hfront-porch = <40>;
+                       hback-porch = <40>;
+                       vfront-porch = <15>;
+                       vback-porch = <10>;
+                       vsync-len = <10>;
+               };
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&lvds_connector>;
+                       };
+               };
+       };
+};
+
+&lvds_connector {
+       remote-endpoint = <&panel_in>;
+};
index 1f18a93..48fb631 100644 (file)
@@ -1,5 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-a1.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rock64.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-roc-cc.dtb
@@ -27,6 +30,7 @@ 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-roc-pc-mezzanine.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rock-pi-4.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rock960.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rockpro64.dtb
index 6eb7407..936ed7d 100644 (file)
@@ -14,7 +14,7 @@
        compatible = "rockchip,px30-evb", "rockchip,px30";
 
        chosen {
-               stdout-path = "serial2:1500000n8";
+               stdout-path = "serial5:115200n8";
        };
 
        adc-keys {
        backlight: backlight {
                compatible = "pwm-backlight";
                pwms = <&pwm1 0 25000 0>;
+               power-supply = <&vcc3v3_lcd>;
+       };
+
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               pinctrl-0 = <&emmc_reset>;
+               pinctrl-names = "default";
+               reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
        };
 
        sdio_pwrseq: sdio-pwrseq {
                reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */
        };
 
-       vcc_phy: vcc-phy-regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc_phy";
-               regulator-always-on;
-               regulator-boot-on;
-       };
-
        vcc5v0_sys: vccsys {
                compatible = "regulator-fixed";
                regulator-name = "vcc5v0_sys";
        };
 };
 
+&cpu0 {
+       cpu-supply = <&vdd_arm>;
+};
+
+&cpu1 {
+       cpu-supply = <&vdd_arm>;
+};
+
+&cpu2 {
+       cpu-supply = <&vdd_arm>;
+};
+
+&cpu3 {
+       cpu-supply = <&vdd_arm>;
+};
+
 &display_subsystem {
        status = "okay";
 };
        cap-mmc-highspeed;
        mmc-hs200-1_8v;
        non-removable;
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vcc_3v0>;
+       vqmmc-supply = <&vccio_flash>;
        status = "okay";
 };
 
 &gmac {
        clock_in_out = "output";
-       phy-supply = <&vcc_phy>;
+       phy-supply = <&vcc_rmii>;
        snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>;
        snps,reset-active-low;
        snps,reset-delays-us = <0 50000 50000>;
 
 &i2c0 {
        status = "okay";
+
+       rk809: pmic@20 {
+               compatible = "rockchip,rk809";
+               reg = <0x20>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int>;
+               rockchip,system-power-controller;
+               wakeup-source;
+               #clock-cells = <0>;
+               clock-output-names = "xin32k";
+
+               vcc1-supply = <&vcc5v0_sys>;
+               vcc2-supply = <&vcc5v0_sys>;
+               vcc3-supply = <&vcc5v0_sys>;
+               vcc4-supply = <&vcc5v0_sys>;
+               vcc5-supply = <&vcc3v3_sys>;
+               vcc6-supply = <&vcc3v3_sys>;
+               vcc7-supply = <&vcc3v3_sys>;
+               vcc8-supply = <&vcc3v3_sys>;
+               vcc9-supply = <&vcc5v0_sys>;
+
+               regulators {
+                       vdd_log: DCDC_REG1 {
+                               regulator-name = "vdd_log";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <950000>;
+                               };
+                       };
+
+                       vdd_arm: DCDC_REG2 {
+                               regulator-name = "vdd_arm";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <950000>;
+                               };
+                       };
+
+                       vcc_ddr: DCDC_REG3 {
+                               regulator-name = "vcc_ddr";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_3v0: vcc_rmii: DCDC_REG4 {
+                               regulator-name = "vcc_3v0";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc3v3_sys: DCDC_REG5 {
+                               regulator-name = "vcc3v3_sys";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vcc_1v0: LDO_REG1 {
+                               regulator-name = "vcc_1v0";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1000000>;
+                               };
+                       };
+
+                       vcc_1v8: vccio_flash: vccio_sdio: LDO_REG2 {
+                               regulator-name = "vcc_1v8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_1v0: LDO_REG3 {
+                               regulator-name = "vdd_1v0";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1000000>;
+                               };
+                       };
+
+                       vcc3v0_pmu: LDO_REG4 {
+                               regulator-name = "vcc3v0_pmu";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vccio_sd: LDO_REG5 {
+                               regulator-name = "vccio_sd";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vcc_sd: LDO_REG6 {
+                               regulator-name = "vcc_sd";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vcc2v8_dvp: LDO_REG7 {
+                               regulator-name = "vcc2v8_dvp";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <2800000>;
+                               };
+                       };
+
+                       vcc1v8_dvp: LDO_REG8 {
+                               regulator-name = "vcc1v8_dvp";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc1v5_dvp: LDO_REG9 {
+                               regulator-name = "vcc1v5_dvp";
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <1500000>;
+                               };
+                       };
+
+                       vcc3v3_lcd: SWITCH_REG1 {
+                               regulator-name = "vcc3v3_lcd";
+                               regulator-boot-on;
+                       };
+
+                       vcc5v0_host: SWITCH_REG2 {
+                               regulator-name = "vcc5v0_host";
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+               };
+       };
+};
+
+&i2c1 {
+       status = "okay";
+
+       sensor@d {
+               compatible = "asahi-kasei,ak8963";
+               reg = <0x0d>;
+               gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
+               vdd-supply = <&vcc3v0_pmu>;
+               mount-matrix = "1", /* x0 */
+                              "0", /* y0 */
+                              "0", /* z0 */
+                              "0", /* x1 */
+                              "1", /* y1 */
+                              "0", /* z1 */
+                              "0", /* x2 */
+                              "0", /* y2 */
+                              "1"; /* z2 */
+       };
+
+       touchscreen@14 {
+               compatible = "goodix,gt1151";
+               reg = <0x14>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
+               irq-gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+               VDDIO-supply = <&vcc3v3_lcd>;
+       };
+
+       sensor@4c {
+               compatible = "fsl,mma7660";
+               reg = <0x4c>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PB7 IRQ_TYPE_LEVEL_LOW>;
+       };
 };
 
 &i2s1_2ch {
 
 &io_domains {
        status = "okay";
+
+       vccio1-supply = <&vccio_sdio>;
+       vccio2-supply = <&vccio_sd>;
+       vccio3-supply = <&vcc_3v0>;
+       vccio4-supply = <&vcc3v0_pmu>;
+       vccio5-supply = <&vcc_3v0>;
+       vccio6-supply = <&vccio_flash>;
 };
 
 &pinctrl {
                };
        };
 
+       emmc {
+               emmc_reset: emmc-reset {
+                       rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
        pmic {
                pmic_int: pmic_int {
                        rockchip,pins =
 
 &pmu_io_domains {
        status = "okay";
+
+       pmuio1-supply = <&vcc3v0_pmu>;
+       pmuio2-supply = <&vcc3v0_pmu>;
 };
 
 &pwm1 {
 };
 
 &saradc {
+       vref-supply = <&vcc_1v8>;
        status = "okay";
 };
 
        sd-uhs-sdr25;
        sd-uhs-sdr50;
        sd-uhs-sdr104;
+       vmmc-supply = <&vcc_sd>;
+       vqmmc-supply = <&vccio_sd>;
        status = "okay";
 };
 
        status = "okay";
 };
 
+&u2phy {
+       status = "okay";
+
+       u2phy_host: host-port {
+               status = "okay";
+       };
+
+       u2phy_otg: otg-port {
+               status = "okay";
+       };
+};
+
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart1_xfer &uart1_cts>;
        status = "okay";
 };
 
-&uart2 {
+&uart5 {
        status = "okay";
 };
 
index eb992d6..8812b70 100644 (file)
                status = "disabled";
        };
 
-       firmware {
-               optee {
-                       compatible = "linaro,optee-tz";
-                       method = "smc";
-               };
-       };
-
        gmac_clkin: external-gmac-clock {
                compatible = "fixed-clock";
                clock-frequency = <50000000>;
                clock-output-names = "xin24m";
        };
 
-       xin32k: xin32k {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <32768>;
-               clock-output-names = "xin32k";
-       };
-
        pmu: power-management@ff000000 {
                compatible = "rockchip,px30-pmu", "syscon", "simple-mfd";
                reg = <0x0 0xff000000 0x0 0x1000>;
                status = "disabled";
        };
 
+       otp: nvmem@ff290000 {
+               compatible = "rockchip,px30-otp";
+               reg = <0x0 0xff290000 0x0 0x4000>;
+               clocks = <&cru SCLK_OTP_USR>, <&cru PCLK_OTP_NS>,
+                        <&cru PCLK_OTP_PHY>;
+               clock-names = "otp", "apb_pclk", "phy";
+               resets = <&cru SRST_OTP_PHY>;
+               reset-names = "phy";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               /* Data cells */
+               cpu_id: id@7 {
+                       reg = <0x07 0x10>;
+               };
+               cpu_leakage: cpu-leakage@17 {
+                       reg = <0x17 0x1>;
+               };
+               performance: performance@1e {
+                       reg = <0x1e 0x1>;
+                       bits = <4 3>;
+               };
+       };
+
        cru: clock-controller@ff2b0000 {
                compatible = "rockchip,px30-cru";
                reg = <0x0 0xff2b0000 0x0 0x1000>;
+               clocks = <&xin24m>, <&pmucru PLL_GPLL>;
+               clock-names = "xin24m", "gpll";
                rockchip,grf = <&grf>;
                #clock-cells = <1>;
                #reset-cells = <1>;
 
-               assigned-clocks = <&cru PLL_NPLL>;
-               assigned-clock-rates = <1188000000>;
+               assigned-clocks = <&cru PLL_NPLL>,
+                       <&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>,
+                       <&cru HCLK_BUS_PRE>, <&cru HCLK_PERI_PRE>,
+                       <&cru PCLK_BUS_PRE>, <&cru SCLK_GPU>;
+
+               assigned-clock-rates = <1188000000>,
+                       <200000000>, <200000000>,
+                       <150000000>, <150000000>,
+                       <100000000>, <200000000>;
        };
 
        pmucru: clock-controller@ff2bc000 {
                compatible = "rockchip,px30-pmucru";
                reg = <0x0 0xff2bc000 0x0 0x1000>;
+               clocks = <&xin24m>;
+               clock-names = "xin24m";
                rockchip,grf = <&grf>;
                #clock-cells = <1>;
                #reset-cells = <1>;
 
                assigned-clocks =
                        <&pmucru PLL_GPLL>, <&pmucru PCLK_PMU_PRE>,
-                       <&pmucru SCLK_WIFI_PMU>, <&cru ARMCLK>,
-                       <&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>,
-                       <&cru HCLK_BUS_PRE>, <&cru HCLK_PERI_PRE>,
-                       <&cru PCLK_BUS_PRE>, <&cru SCLK_GPU>;
+                       <&pmucru SCLK_WIFI_PMU>;
                assigned-clock-rates =
                        <1200000000>, <100000000>,
-                       <26000000>, <600000000>,
-                       <200000000>, <200000000>,
-                       <150000000>, <150000000>,
-                       <100000000>, <200000000>;
+                       <26000000>;
+       };
+
+       usb2phy_grf: syscon@ff2c0000 {
+               compatible = "rockchip,px30-usb2phy-grf", "syscon",
+                            "simple-mfd";
+               reg = <0x0 0xff2c0000 0x0 0x10000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               u2phy: usb2-phy@100 {
+                       compatible = "rockchip,px30-usb2phy";
+                       reg = <0x100 0x20>;
+                       clocks = <&pmucru SCLK_USBPHY_REF>;
+                       clock-names = "phyclk";
+                       #clock-cells = <0>;
+                       assigned-clocks = <&cru USB480M>;
+                       assigned-clock-parents = <&u2phy>;
+                       clock-output-names = "usb480m_phy";
+                       status = "disabled";
+
+                       u2phy_host: host-port {
+                               #phy-cells = <0>;
+                               interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "linestate";
+                               status = "disabled";
+                       };
+
+                       u2phy_otg: otg-port {
+                               #phy-cells = <0>;
+                               interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "otg-bvalid", "otg-id",
+                                                 "linestate";
+                               status = "disabled";
+                       };
+               };
        };
 
        usb20_otg: usb@ff300000 {
                g-rx-fifo-size = <280>;
                g-tx-fifo-size = <256 128 128 64 32 16>;
                g-use-dma;
+               phys = <&u2phy_otg>;
+               phy-names = "usb2-phy";
                power-domains = <&power PX30_PD_USB>;
                status = "disabled";
        };
                interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_HOST>;
                clock-names = "usbhost";
+               phys = <&u2phy_host>;
+               phy-names = "usb";
                power-domains = <&power PX30_PD_USB>;
                status = "disabled";
        };
                interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_HOST>;
                clock-names = "usbhost";
+               phys = <&u2phy_host>;
+               phy-names = "usb";
                power-domains = <&power PX30_PD_USB>;
                status = "disabled";
        };
                clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
                fifo-depth = <0x100>;
                max-frequency = <150000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
                power-domains = <&power PX30_PD_MMC_NAND>;
                status = "disabled";
        };
                interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-names = "vopb_mmu";
                clocks = <&cru ACLK_VOPB>, <&cru HCLK_VOPB>;
-               clock-names = "aclk", "hclk";
+               clock-names = "aclk", "iface";
                power-domains = <&power PX30_PD_VO>;
                #iommu-cells = <0>;
                status = "disabled";
                interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-names = "vopl_mmu";
                clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
-               clock-names = "aclk", "hclk";
+               clock-names = "aclk", "iface";
                power-domains = <&power PX30_PD_VO>;
                #iommu-cells = <0>;
                status = "disabled";
                                rockchip,pins =
                                        <0 RK_PB5 1 &pcfg_pull_none>;
                        };
-
-                       uart0_rts_gpio: uart0-rts-gpio {
-                               rockchip,pins =
-                                       <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-                       };
                };
 
                uart1 {
                                rockchip,pins =
                                        <1 RK_PC3 1 &pcfg_pull_none>;
                        };
-
-                       uart1_rts_gpio: uart1-rts-gpio {
-                               rockchip,pins =
-                                       <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
-                       };
                };
 
                uart2-m0 {
                                rockchip,pins =
                                        <0 RK_PC3 2 &pcfg_pull_none>;
                        };
-
-                       uart3m0_rts_gpio: uart3m0-rts-gpio {
-                               rockchip,pins =
-                                       <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
-                       };
                };
 
                uart3-m1 {
                                rockchip,pins =
                                        <1 RK_PB5 2 &pcfg_pull_none>;
                        };
-
-                       uart3m1_rts_gpio: uart3m1-rts-gpio {
-                               rockchip,pins =
-                                       <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-                       };
                };
 
                uart4 {
                                        <1 RK_PD4 1 &pcfg_pull_up_8ma>,
                                        <1 RK_PD5 1 &pcfg_pull_up_8ma>;
                        };
-
-                       sdmmc_gpio: sdmmc-gpio {
-                               rockchip,pins =
-                                       <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
-                                       <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
-                                       <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
-                                       <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
-                                       <1 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
-                                       <1 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up_4ma>;
-                       };
                };
 
                sdio {
                                        <1 RK_PD0 1 &pcfg_pull_up>,
                                        <1 RK_PD1 1 &pcfg_pull_up>;
                        };
-
-                       sdio_gpio: sdio-gpio {
-                               rockchip,pins =
-                                       <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>,
-                                       <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>,
-                                       <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>,
-                                       <1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
-                                       <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
-                                       <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
-                       };
                };
 
                emmc {
                                        <1 RK_PB2 2 &pcfg_pull_up_8ma>;
                        };
 
-                       emmc_pwren: emmc-pwren {
-                               rockchip,pins =
-                                       <1 RK_PB0 2 &pcfg_pull_none>;
-                       };
-
                        emmc_rstnout: emmc-rstnout {
                                rockchip,pins =
                                        <1 RK_PB3 2 &pcfg_pull_none>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3308-evb.dts b/arch/arm64/boot/dts/rockchip/rk3308-evb.dts
new file mode 100644 (file)
index 0000000..9b4f855
--- /dev/null
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include "rk3308.dtsi"
+
+/ {
+       model = "Rockchip RK3308 EVB";
+       compatible = "rockchip,rk3308-evb", "rockchip,rk3308";
+
+       chosen {
+               stdout-path = "serial4:1500000n8";
+       };
+
+       adc-keys0 {
+               compatible = "adc-keys";
+               io-channels = <&saradc 0>;
+               io-channel-names = "buttons";
+               poll-interval = <100>;
+               keyup-threshold-microvolt = <1800000>;
+
+               func-key {
+                       linux,code = <KEY_FN>;
+                       label = "function";
+                       press-threshold-microvolt = <18000>;
+               };
+       };
+
+       adc-keys1 {
+               compatible = "adc-keys";
+               io-channels = <&saradc 1>;
+               io-channel-names = "buttons";
+               poll-interval = <100>;
+               keyup-threshold-microvolt = <1800000>;
+
+               esc-key {
+                       linux,code = <KEY_MICMUTE>;
+                       label = "micmute";
+                       press-threshold-microvolt = <1130000>;
+               };
+
+               home-key {
+                       linux,code = <KEY_MODE>;
+                       label = "mode";
+                       press-threshold-microvolt = <901000>;
+               };
+
+               menu-key {
+                       linux,code = <KEY_PLAY>;
+                       label = "play";
+                       press-threshold-microvolt = <624000>;
+               };
+
+               vol-down-key {
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       label = "volume down";
+                       press-threshold-microvolt = <300000>;
+               };
+
+               vol-up-key {
+                       linux,code = <KEY_VOLUMEUP>;
+                       label = "volume up";
+                       press-threshold-microvolt = <18000>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwr_key>;
+
+               power {
+                       gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+                       label = "GPIO Key Power";
+                       debounce-interval = <100>;
+                       wakeup-source;
+               };
+       };
+
+       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;
+       };
+
+       vcc5v0_sys: vcc5v0-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc12v_dcin>;
+       };
+
+       vccio_sdio: vcc_1v8: vcc-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc_io>;
+       };
+
+       vcc_ddr: vcc-ddr {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_ddr";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc_io: vcc-io {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_io";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vccio_flash: vccio-flash {
+               compatible = "regulator-fixed";
+               regulator-name = "vccio_flash";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc_io>;
+       };
+
+       vcc5v0_host: vcc5v0-host {
+               compatible = "regulator-fixed";
+               gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&usb_drv>;
+               regulator-name = "vbus_host";
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vdd_core: vdd-core {
+               compatible = "pwm-regulator";
+               pwms = <&pwm0 0 5000 1>;
+               regulator-name = "vdd_core";
+               regulator-min-microvolt = <827000>;
+               regulator-max-microvolt = <1340000>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-settling-time-up-us = <250>;
+               pwm-supply = <&vcc5v0_sys>;
+       };
+
+       vdd_log: vdd-log {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_log";
+               regulator-min-microvolt = <1050000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vdd_1v0: vdd-1v0 {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_1v0";
+               regulator-min-microvolt = <1000000>;
+               regulator-max-microvolt = <1000000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&cpu0 {
+       cpu-supply = <&vdd_core>;
+};
+
+&saradc {
+       status = "okay";
+       vref-supply = <&vcc_1v8>;
+};
+
+&pinctrl {
+       pinctrl-names = "default";
+       pinctrl-0 = <&rtc_32k>;
+
+       buttons {
+               pwr_key: pwr-key {
+                       rockchip,pins = <0 RK_PA6 0 &pcfg_pull_up>;
+               };
+       };
+
+       usb {
+               usb_drv: usb-drv {
+                       rockchip,pins = <0 RK_PC5 0 &pcfg_pull_none>;
+               };
+       };
+
+       sdio-pwrseq {
+               wifi_enable_h: wifi-enable-h {
+                       rockchip,pins = <0 RK_PA2 0 &pcfg_pull_none>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+       pinctrl-0 = <&pwm0_pin_pull_down>;
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart4_xfer>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
new file mode 100644 (file)
index 0000000..aa25635
--- /dev/null
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
+ */
+
+/dts-v1/;
+#include "rk3308.dtsi"
+
+/ {
+       model = "Firefly ROC-RK3308-CC board";
+       compatible = "firefly,roc-rk3308-cc", "rockchip,rk3308";
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       ir_rx {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ir_recv_pin>;
+       };
+
+       ir_tx {
+               compatible = "pwm-ir-tx";
+               pwms = <&pwm5 0 25000 0>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               power {
+                       label = "firefly:red:power";
+                       linux,default-trigger = "ir-power-click";
+                       default-state = "on";
+                       gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+               };
+
+               user {
+                       label = "firefly:blue:user";
+                       linux,default-trigger = "ir-user-click";
+                       default-state = "off";
+                       gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       typec_vcc5v: typec-vcc5v {
+               compatible = "regulator-fixed";
+               regulator-name = "typec_vcc5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vcc5v0_sys: vcc5v0-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&typec_vcc5v>;
+       };
+
+       vcc_io: vcc-io {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_io";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc_sdmmc: vcc-sdmmc {
+               compatible = "regulator-gpio";
+               regulator-name = "vcc_sdmmc";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_HIGH>;
+               states = <1800000 0x0
+                         3300000 0x1>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc_sd: vcc-sd {
+               compatible = "regulator-fixed";
+               gpio = <&gpio4 RK_PD6 GPIO_ACTIVE_LOW>;
+               regulator-name = "vcc_sd";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vim-supply = <&vcc_io>;
+       };
+
+       vdd_core: vdd-core {
+               compatible = "pwm-regulator";
+               pwms = <&pwm0 0 5000 1>;
+               regulator-name = "vdd_core";
+               regulator-min-microvolt = <827000>;
+               regulator-max-microvolt = <1340000>;
+               regulator-init-microvolt = <1015000>;
+               regulator-settling-time-up-us = <250>;
+               regulator-always-on;
+               regulator-boot-on;
+               pwm-supply = <&vcc5v0_sys>;
+       };
+
+       vdd_log: vdd-log {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_log";
+               regulator-min-microvolt = <1050000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&cpu0 {
+       cpu-supply = <&vdd_core>;
+};
+
+&emmc {
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       disable-wp;
+       mmc-hs200-1_8v;
+       non-removable;
+       status = "okay";
+};
+
+&i2c1 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       rtc: rtc@51 {
+               compatible = "nxp,pcf8563";
+               reg = <0x51>;
+               #clock-cells = <0>;
+       };
+};
+
+&pwm5 {
+       status = "okay";
+       pinctrl-names = "active";
+       pinctrl-0 = <&pwm5_pin_pull_down>;
+};
+
+&pinctrl {
+       pinctrl-names = "default";
+       pinctrl-0 = <&rtc_32k>;
+
+       ir-receiver {
+               ir_recv_pin: ir-recv-pin  {
+                       rockchip,pins = <0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       buttons {
+               pwr_key: pwr-key {
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+       pinctrl-0 = <&pwm0_pin_pull_down>;
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       card-detect-delay = <300>;
+       sd-uhs-sdr25;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       vmmc-supply = <&vcc_sd>;
+       vqmmc-supply = <&vcc_sdmmc>;
+       status = "okay";
+};
+
+&uart2 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
new file mode 100644 (file)
index 0000000..8bdc66c
--- /dev/null
@@ -0,0 +1,1739 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ */
+
+#include <dt-bindings/clock/rk3308-cru.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,boot-mode.h>
+#include <dt-bindings/thermal/thermal.h>
+
+/ {
+       compatible = "rockchip,rk3308";
+
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               serial0 = &uart0;
+               serial1 = &uart1;
+               serial2 = &uart2;
+               serial3 = &uart3;
+               serial4 = &uart4;
+               spi0 = &spi0;
+               spi1 = &spi1;
+               spi2 = &spi2;
+       };
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35", "arm,armv8";
+                       reg = <0x0 0x0>;
+                       enable-method = "psci";
+                       clocks = <&cru ARMCLK>;
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <90>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35", "arm,armv8";
+                       reg = <0x0 0x1>;
+                       enable-method = "psci";
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35", "arm,armv8";
+                       reg = <0x0 0x2>;
+                       enable-method = "psci";
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&l2>;
+               };
+
+               cpu3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35", "arm,armv8";
+                       reg = <0x0 0x3>;
+                       enable-method = "psci";
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&l2>;
+               };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP: cpu-sleep {
+                               compatible = "arm,idle-state";
+                               local-timer-stop;
+                               arm,psci-suspend-param = <0x0010000>;
+                               entry-latency-us = <120>;
+                               exit-latency-us = <250>;
+                               min-residency-us = <900>;
+                       };
+               };
+
+               l2: l2-cache {
+                       compatible = "cache";
+               };
+       };
+
+       cpu0_opp_table: cpu0-opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-408000000 {
+                       opp-hz = /bits/ 64 <408000000>;
+                       opp-microvolt = <950000 950000 1340000>;
+                       clock-latency-ns = <40000>;
+                       opp-suspend;
+               };
+               opp-600000000 {
+                       opp-hz = /bits/ 64 <600000000>;
+                       opp-microvolt = <950000 950000 1340000>;
+                       clock-latency-ns = <40000>;
+               };
+               opp-816000000 {
+                       opp-hz = /bits/ 64 <816000000>;
+                       opp-microvolt = <1025000 1025000 1340000>;
+                       clock-latency-ns = <40000>;
+               };
+               opp-1008000000 {
+                       opp-hz = /bits/ 64 <1008000000>;
+                       opp-microvolt = <1125000 1125000 1340000>;
+                       clock-latency-ns = <40000>;
+               };
+       };
+
+       arm-pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
+       mac_clkin: external-mac-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <50000000>;
+               clock-output-names = "mac_clkin";
+               #clock-cells = <0>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+       };
+
+       xin24m: xin24m {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24000000>;
+               clock-output-names = "xin24m";
+       };
+
+       grf: grf@ff000000 {
+               compatible = "rockchip,rk3308-grf", "syscon", "simple-mfd";
+               reg = <0x0 0xff000000 0x0 0x10000>;
+
+               reboot-mode {
+                       compatible = "syscon-reboot-mode";
+                       offset = <0x500>;
+                       mode-bootloader = <BOOT_BL_DOWNLOAD>;
+                       mode-loader = <BOOT_BL_DOWNLOAD>;
+                       mode-normal = <BOOT_NORMAL>;
+                       mode-recovery = <BOOT_RECOVERY>;
+                       mode-fastboot = <BOOT_FASTBOOT>;
+               };
+       };
+
+       detect_grf: syscon@ff00b000 {
+               compatible = "rockchip,rk3308-detect-grf", "syscon", "simple-mfd";
+               reg = <0x0 0xff00b000 0x0 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+
+       core_grf: syscon@ff00c000 {
+               compatible = "rockchip,rk3308-core-grf", "syscon", "simple-mfd";
+               reg = <0x0 0xff00c000 0x0 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+
+       i2c0: i2c@ff040000 {
+               compatible = "rockchip,rk3308-i2c", "rockchip,rk3399-i2c";
+               reg = <0x0 0xff040000 0x0 0x1000>;
+               clocks = <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
+               clock-names = "i2c", "pclk";
+               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c0_xfer>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       i2c1: i2c@ff050000 {
+               compatible = "rockchip,rk3308-i2c", "rockchip,rk3399-i2c";
+               reg = <0x0 0xff050000 0x0 0x1000>;
+               clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
+               clock-names = "i2c", "pclk";
+               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c1_xfer>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       i2c2: i2c@ff060000 {
+               compatible = "rockchip,rk3308-i2c", "rockchip,rk3399-i2c";
+               reg = <0x0 0xff060000 0x0 0x1000>;
+               clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
+               clock-names = "i2c", "pclk";
+               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_xfer>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       i2c3: i2c@ff070000 {
+               compatible = "rockchip,rk3308-i2c", "rockchip,rk3399-i2c";
+               reg = <0x0 0xff070000 0x0 0x1000>;
+               clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
+               clock-names = "i2c", "pclk";
+               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c3m0_xfer>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       wdt: watchdog@ff080000 {
+               compatible = "snps,dw-wdt";
+               reg = <0x0 0xff080000 0x0 0x100>;
+               clocks = <&cru PCLK_WDT>;
+               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               status = "disabled";
+       };
+
+       uart0: serial@ff0a0000 {
+               compatible = "rockchip,rk3308-uart", "snps,dw-apb-uart";
+               reg = <0x0 0xff0a0000 0x0 0x100>;
+               interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
+               clock-names = "baudclk", "apb_pclk";
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+               status = "disabled";
+       };
+
+       uart1: serial@ff0b0000 {
+               compatible = "rockchip,rk3308-uart", "snps,dw-apb-uart";
+               reg = <0x0 0xff0b0000 0x0 0x100>;
+               interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
+               clock-names = "baudclk", "apb_pclk";
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>;
+               status = "disabled";
+       };
+
+       uart2: serial@ff0c0000 {
+               compatible = "rockchip,rk3308-uart", "snps,dw-apb-uart";
+               reg = <0x0 0xff0c0000 0x0 0x100>;
+               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
+               clock-names = "baudclk", "apb_pclk";
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&uart2m0_xfer>;
+               status = "disabled";
+       };
+
+       uart3: serial@ff0d0000 {
+               compatible = "rockchip,rk3308-uart", "snps,dw-apb-uart";
+               reg = <0x0 0xff0d0000 0x0 0x100>;
+               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
+               clock-names = "baudclk", "apb_pclk";
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&uart3_xfer>;
+               status = "disabled";
+       };
+
+       uart4: serial@ff0e0000 {
+               compatible = "rockchip,rk3308-uart", "snps,dw-apb-uart";
+               reg = <0x0 0xff0e0000 0x0 0x100>;
+               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>;
+               clock-names = "baudclk", "apb_pclk";
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&uart4_xfer &uart4_cts &uart4_rts>;
+               status = "disabled";
+       };
+
+       spi0: spi@ff120000 {
+               compatible = "rockchip,rk3308-spi", "rockchip,rk3066-spi";
+               reg = <0x0 0xff120000 0x0 0x1000>;
+               interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
+               clock-names = "spiclk", "apb_pclk";
+               dmas = <&dmac0 0>, <&dmac0 1>;
+               dma-names = "tx", "rx";
+               pinctrl-names = "default";
+               pinctrl-0 = <&spi0_clk &spi0_csn0 &spi0_miso &spi0_mosi>;
+               status = "disabled";
+       };
+
+       spi1: spi@ff130000 {
+               compatible = "rockchip,rk3308-spi", "rockchip,rk3066-spi";
+               reg = <0x0 0xff130000 0x0 0x1000>;
+               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
+               clock-names = "spiclk", "apb_pclk";
+               dmas = <&dmac0 2>, <&dmac0 3>;
+               dma-names = "tx", "rx";
+               pinctrl-names = "default";
+               pinctrl-0 = <&spi1_clk &spi1_csn0 &spi1_miso &spi1_mosi>;
+               status = "disabled";
+       };
+
+       spi2: spi@ff140000 {
+               compatible = "rockchip,rk3308-spi", "rockchip,rk3066-spi";
+               reg = <0x0 0xff140000 0x0 0x1000>;
+               interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&cru SCLK_SPI2>, <&cru PCLK_SPI2>;
+               clock-names = "spiclk", "apb_pclk";
+               dmas = <&dmac1 16>, <&dmac1 17>;
+               dma-names = "tx", "rx";
+               pinctrl-names = "default";
+               pinctrl-0 = <&spi2_clk &spi2_csn0 &spi2_miso &spi2_mosi>;
+               status = "disabled";
+       };
+
+       pwm8: pwm@ff160000 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff160000 0x0 0x10>;
+               clocks = <&cru SCLK_PWM2>, <&cru PCLK_PWM2>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm8_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm9: pwm@ff160010 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff160010 0x0 0x10>;
+               clocks = <&cru SCLK_PWM2>, <&cru PCLK_PWM2>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm9_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm10: pwm@ff160020 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff160020 0x0 0x10>;
+               clocks = <&cru SCLK_PWM2>, <&cru PCLK_PWM2>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm10_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm11: pwm@ff160030 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff160030 0x0 0x10>;
+               clocks = <&cru SCLK_PWM2>, <&cru PCLK_PWM2>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm11_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm4: pwm@ff170000 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff170000 0x0 0x10>;
+               clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm4_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm5: pwm@ff170010 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff170010 0x0 0x10>;
+               clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm5_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm6: pwm@ff170020 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff170020 0x0 0x10>;
+               clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm6_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm7: pwm@ff170030 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff170030 0x0 0x10>;
+               clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm7_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm0: pwm@ff180000 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff180000 0x0 0x10>;
+               clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm0_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm1: pwm@ff180010 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff180010 0x0 0x10>;
+               clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm1_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm2: pwm@ff180020 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff180020 0x0 0x10>;
+               clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm2_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       pwm3: pwm@ff180030 {
+               compatible = "rockchip,rk3308-pwm", "rockchip,rk3328-pwm";
+               reg = <0x0 0xff180030 0x0 0x10>;
+               clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
+               clock-names = "pwm", "pclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm3_pin>;
+               #pwm-cells = <3>;
+               status = "disabled";
+       };
+
+       rktimer: rktimer@ff1a0000 {
+               compatible = "rockchip,rk3288-timer";
+               reg = <0x0 0xff1a0000 0x0 0x20>;
+               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER0>;
+               clock-names = "pclk", "timer";
+       };
+
+       saradc: saradc@ff1e0000 {
+               compatible = "rockchip,rk3308-saradc", "rockchip,rk3399-saradc";
+               reg = <0x0 0xff1e0000 0x0 0x100>;
+               interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
+               clock-names = "saradc", "apb_pclk";
+               #io-channel-cells = <1>;
+               resets = <&cru SRST_SARADC_P>;
+               reset-names = "saradc-apb";
+               status = "disabled";
+       };
+
+       amba {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               dmac0: dma-controller@ff2c0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x0 0xff2c0000 0x0 0x4000>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru ACLK_DMAC0>;
+                       clock-names = "apb_pclk";
+                       #dma-cells = <1>;
+               };
+
+               dmac1: dma-controller@ff2d0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x0 0xff2d0000 0x0 0x4000>;
+                       interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru ACLK_DMAC1>;
+                       clock-names = "apb_pclk";
+                       #dma-cells = <1>;
+               };
+       };
+
+       i2s_2ch_0: i2s@ff350000 {
+               compatible = "rockchip,rk3308-i2s", "rockchip,rk3066-i2s";
+               reg = <0x0 0xff350000 0x0 0x1000>;
+               interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_I2S0_2CH>, <&cru HCLK_I2S0_2CH>;
+               clock-names = "i2s_clk", "i2s_hclk";
+               dmas = <&dmac1 8>, <&dmac1 9>;
+               dma-names = "tx", "rx";
+               resets = <&cru SRST_I2S0_2CH_M>, <&cru SRST_I2S0_2CH_H>;
+               reset-names = "reset-m", "reset-h";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2s_2ch_0_sclk
+                            &i2s_2ch_0_lrck
+                            &i2s_2ch_0_sdi
+                            &i2s_2ch_0_sdo>;
+               status = "disabled";
+       };
+
+       i2s_2ch_1: i2s@ff360000 {
+               compatible = "rockchip,rk3308-i2s", "rockchip,rk3066-i2s";
+               reg = <0x0 0xff360000 0x0 0x1000>;
+               interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_I2S1_2CH>, <&cru HCLK_I2S1_2CH>;
+               clock-names = "i2s_clk", "i2s_hclk";
+               dmas = <&dmac1 11>;
+               dma-names = "rx";
+               resets = <&cru SRST_I2S1_2CH_M>, <&cru SRST_I2S1_2CH_H>;
+               reset-names = "reset-m", "reset-h";
+               status = "disabled";
+       };
+
+       spdif_tx: spdif-tx@ff3a0000 {
+               compatible = "rockchip,rk3308-spdif", "rockchip,rk3328-spdif";
+               reg = <0x0 0xff3a0000 0x0 0x1000>;
+               interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_SPDIF_TX>, <&cru HCLK_SPDIFTX>;
+               clock-names = "mclk", "hclk";
+               dmas = <&dmac1 13>;
+               dma-names = "tx";
+               pinctrl-names = "default";
+               pinctrl-0 = <&spdif_out>;
+               status = "disabled";
+       };
+
+       sdmmc: dwmmc@ff480000 {
+               compatible = "rockchip,rk3308-dw-mshc", "rockchip,rk3288-dw-mshc";
+               reg = <0x0 0xff480000 0x0 0x4000>;
+               interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+               bus-width = <4>;
+               clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
+                        <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
+               clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
+               fifo-depth = <0x100>;
+               max-frequency = <150000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_det &sdmmc_bus4>;
+               status = "disabled";
+       };
+
+       emmc: dwmmc@ff490000 {
+               compatible = "rockchip,rk3308-dw-mshc", "rockchip,rk3288-dw-mshc";
+               reg = <0x0 0xff490000 0x0 0x4000>;
+               interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+               bus-width = <8>;
+               clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
+                        <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
+               clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
+               fifo-depth = <0x100>;
+               max-frequency = <150000000>;
+               status = "disabled";
+       };
+
+       sdio: dwmmc@ff4a0000 {
+               compatible = "rockchip,rk3308-dw-mshc", "rockchip,rk3288-dw-mshc";
+               reg = <0x0 0xff4a0000 0x0 0x4000>;
+               interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+               bus-width = <4>;
+               clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
+                        <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
+               clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
+               fifo-depth = <0x100>;
+               max-frequency = <150000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdio_bus4 &sdio_cmd &sdio_clk>;
+               status = "disabled";
+       };
+
+       cru: clock-controller@ff500000 {
+               compatible = "rockchip,rk3308-cru";
+               reg = <0x0 0xff500000 0x0 0x1000>;
+               #clock-cells = <1>;
+               #reset-cells = <1>;
+               rockchip,grf = <&grf>;
+
+               assigned-clocks = <&cru SCLK_RTC32K>;
+               assigned-clock-rates = <32768>;
+       };
+
+       gic: interrupt-controller@ff580000 {
+               compatible = "arm,gic-400";
+               reg = <0x0 0xff581000 0x0 0x1000>,
+                     <0x0 0xff582000 0x0 0x2000>,
+                     <0x0 0xff584000 0x0 0x2000>,
+                     <0x0 0xff586000 0x0 0x2000>;
+               interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               #address-cells = <0>;
+       };
+
+       sram: sram@fff80000 {
+               compatible = "mmio-sram";
+               reg = <0x0 0xfff80000 0x0 0x40000>;
+               ranges = <0 0x0 0xfff80000 0x40000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               /* reserved for ddr dvfs and system suspend/resume */
+               ddr-sram@0 {
+                       reg = <0x0 0x8000>;
+               };
+
+               /* reserved for vad audio buffer */
+               vad_sram: vad-sram@8000 {
+                       reg = <0x8000 0x38000>;
+               };
+       };
+
+       pinctrl: pinctrl {
+               compatible = "rockchip,rk3308-pinctrl";
+               rockchip,grf = <&grf>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               gpio0: gpio0@ff220000 {
+                       compatible = "rockchip,gpio-bank";
+                       reg = <0x0 0xff220000 0x0 0x100>;
+                       interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru PCLK_GPIO0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio1: gpio1@ff230000 {
+                       compatible = "rockchip,gpio-bank";
+                       reg = <0x0 0xff230000 0x0 0x100>;
+                       interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru PCLK_GPIO1>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio2: gpio2@ff240000 {
+                       compatible = "rockchip,gpio-bank";
+                       reg = <0x0 0xff240000 0x0 0x100>;
+                       interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru PCLK_GPIO2>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio3: gpio3@ff250000 {
+                       compatible = "rockchip,gpio-bank";
+                       reg = <0x0 0xff250000 0x0 0x100>;
+                       interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru PCLK_GPIO3>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio4: gpio4@ff260000 {
+                       compatible = "rockchip,gpio-bank";
+                       reg = <0x0 0xff260000 0x0 0x100>;
+                       interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cru PCLK_GPIO4>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               pcfg_pull_up: pcfg-pull-up {
+                       bias-pull-up;
+               };
+
+               pcfg_pull_down: pcfg-pull-down {
+                       bias-pull-down;
+               };
+
+               pcfg_pull_none: pcfg-pull-none {
+                       bias-disable;
+               };
+
+               pcfg_pull_none_2ma: pcfg-pull-none-2ma {
+                       bias-disable;
+                       drive-strength = <2>;
+               };
+
+               pcfg_pull_up_2ma: pcfg-pull-up-2ma {
+                       bias-pull-up;
+                       drive-strength = <2>;
+               };
+
+               pcfg_pull_up_4ma: pcfg-pull-up-4ma {
+                       bias-pull-up;
+                       drive-strength = <4>;
+               };
+
+               pcfg_pull_none_4ma: pcfg-pull-none-4ma {
+                       bias-disable;
+                       drive-strength = <4>;
+               };
+
+               pcfg_pull_down_4ma: pcfg-pull-down-4ma {
+                       bias-pull-down;
+                       drive-strength = <4>;
+               };
+
+               pcfg_pull_none_8ma: pcfg-pull-none-8ma {
+                       bias-disable;
+                       drive-strength = <8>;
+               };
+
+               pcfg_pull_up_8ma: pcfg-pull-up-8ma {
+                       bias-pull-up;
+                       drive-strength = <8>;
+               };
+
+               pcfg_pull_none_12ma: pcfg-pull-none-12ma {
+                       bias-disable;
+                       drive-strength = <12>;
+               };
+
+               pcfg_pull_up_12ma: pcfg-pull-up-12ma {
+                       bias-pull-up;
+                       drive-strength = <12>;
+               };
+
+               pcfg_pull_none_smt: pcfg-pull-none-smt {
+                       bias-disable;
+                       input-schmitt-enable;
+               };
+
+               pcfg_output_high: pcfg-output-high {
+                       output-high;
+               };
+
+               pcfg_output_low: pcfg-output-low {
+                       output-low;
+               };
+
+               pcfg_input_high: pcfg-input-high {
+                       bias-pull-up;
+                       input-enable;
+               };
+
+               pcfg_input: pcfg-input {
+                       input-enable;
+               };
+
+               emmc {
+                       emmc_clk: emmc-clk {
+                               rockchip,pins =
+                                       <3 RK_PB1 2 &pcfg_pull_none_8ma>;
+                       };
+
+                       emmc_cmd: emmc-cmd {
+                               rockchip,pins =
+                                       <3 RK_PB0 2 &pcfg_pull_up_8ma>;
+                       };
+
+                       emmc_pwren: emmc-pwren {
+                               rockchip,pins =
+                                       <3 RK_PB3 2 &pcfg_pull_none>;
+                       };
+
+                       emmc_rstn: emmc-rstn {
+                               rockchip,pins =
+                                       <3 RK_PB2 2 &pcfg_pull_none>;
+                       };
+
+                       emmc_bus1: emmc-bus1 {
+                               rockchip,pins =
+                                       <3 RK_PA0 2 &pcfg_pull_up_8ma>;
+                       };
+
+                       emmc_bus4: emmc-bus4 {
+                               rockchip,pins =
+                                       <3 RK_PA0 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA1 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA2 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA3 2 &pcfg_pull_up_8ma>;
+                       };
+
+                       emmc_bus8: emmc-bus8 {
+                               rockchip,pins =
+                                       <3 RK_PA0 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA1 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA2 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA3 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA4 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA5 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA6 2 &pcfg_pull_up_8ma>,
+                                       <3 RK_PA7 2 &pcfg_pull_up_8ma>;
+                       };
+               };
+
+               flash {
+                       flash_csn0: flash-csn0 {
+                               rockchip,pins =
+                                       <3 RK_PB5 1 &pcfg_pull_none>;
+                       };
+
+                       flash_rdy: flash-rdy {
+                               rockchip,pins =
+                                       <3 RK_PB4 1 &pcfg_pull_none>;
+                       };
+
+                       flash_ale: flash-ale {
+                               rockchip,pins =
+                                       <3 RK_PB3 1 &pcfg_pull_none>;
+                       };
+
+                       flash_cle: flash-cle {
+                               rockchip,pins =
+                                       <3 RK_PB1 1 &pcfg_pull_none>;
+                       };
+
+                       flash_wrn: flash-wrn {
+                               rockchip,pins =
+                                       <3 RK_PB0 1 &pcfg_pull_none>;
+                       };
+
+                       flash_rdn: flash-rdn {
+                               rockchip,pins =
+                                       <3 RK_PB2 1 &pcfg_pull_none>;
+                       };
+
+                       flash_bus8: flash-bus8 {
+                               rockchip,pins =
+                                       <3 RK_PA0 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA1 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA2 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA3 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA4 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA5 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA6 1 &pcfg_pull_up_12ma>,
+                                       <3 RK_PA7 1 &pcfg_pull_up_12ma>;
+                       };
+               };
+
+               gmac {
+                       rmii_pins: rmii-pins {
+                               rockchip,pins =
+                                       /* mac_txen */
+                                       <1 RK_PC1 3 &pcfg_pull_none_12ma>,
+                                       /* mac_txd1 */
+                                       <1 RK_PC3 3 &pcfg_pull_none_12ma>,
+                                       /* mac_txd0 */
+                                       <1 RK_PC2 3 &pcfg_pull_none_12ma>,
+                                       /* mac_rxd0 */
+                                       <1 RK_PC4 3 &pcfg_pull_none>,
+                                       /* mac_rxd1 */
+                                       <1 RK_PC5 3 &pcfg_pull_none>,
+                                       /* mac_rxer */
+                                       <1 RK_PB7 3 &pcfg_pull_none>,
+                                       /* mac_rxdv */
+                                       <1 RK_PC0 3 &pcfg_pull_none>,
+                                       /* mac_mdio */
+                                       <1 RK_PB6 3 &pcfg_pull_none>,
+                                       /* mac_mdc */
+                                       <1 RK_PB5 3 &pcfg_pull_none>;
+                       };
+
+                       mac_refclk_12ma: mac-refclk-12ma {
+                               rockchip,pins =
+                                       <1 RK_PB4 3 &pcfg_pull_none_12ma>;
+                       };
+
+                       mac_refclk: mac-refclk {
+                               rockchip,pins =
+                                       <1 RK_PB4 3 &pcfg_pull_none>;
+                       };
+               };
+
+               gmac-m1 {
+                       rmiim1_pins: rmiim1-pins {
+                               rockchip,pins =
+                                       /* mac_txen */
+                                       <4 RK_PB7 2 &pcfg_pull_none_12ma>,
+                                       /* mac_txd1 */
+                                       <4 RK_PA5 2 &pcfg_pull_none_12ma>,
+                                       /* mac_txd0 */
+                                       <4 RK_PA4 2 &pcfg_pull_none_12ma>,
+                                       /* mac_rxd0 */
+                                       <4 RK_PA2 2 &pcfg_pull_none>,
+                                       /* mac_rxd1 */
+                                       <4 RK_PA3 2 &pcfg_pull_none>,
+                                       /* mac_rxer */
+                                       <4 RK_PA0 2 &pcfg_pull_none>,
+                                       /* mac_rxdv */
+                                       <4 RK_PA1 2 &pcfg_pull_none>,
+                                       /* mac_mdio */
+                                       <4 RK_PB6 2 &pcfg_pull_none>,
+                                       /* mac_mdc */
+                                       <4 RK_PB5 2 &pcfg_pull_none>;
+                       };
+
+                       macm1_refclk_12ma: macm1-refclk-12ma {
+                               rockchip,pins =
+                                       <4 RK_PB4 2 &pcfg_pull_none_12ma>;
+                       };
+
+                       macm1_refclk: macm1-refclk {
+                               rockchip,pins =
+                                       <4 RK_PB4 2 &pcfg_pull_none>;
+                       };
+               };
+
+               i2c0 {
+                       i2c0_xfer: i2c0-xfer {
+                               rockchip,pins =
+                                       <1 RK_PD0 2 &pcfg_pull_none_smt>,
+                                       <1 RK_PD1 2 &pcfg_pull_none_smt>;
+                       };
+               };
+
+               i2c1 {
+                       i2c1_xfer: i2c1-xfer {
+                               rockchip,pins =
+                                       <0 RK_PB3 1 &pcfg_pull_none_smt>,
+                                       <0 RK_PB4 1 &pcfg_pull_none_smt>;
+                       };
+               };
+
+               i2c2 {
+                       i2c2_xfer: i2c2-xfer {
+                               rockchip,pins =
+                                       <2 RK_PA2 3 &pcfg_pull_none_smt>,
+                                       <2 RK_PA3 3 &pcfg_pull_none_smt>;
+                       };
+               };
+
+               i2c3-m0 {
+                       i2c3m0_xfer: i2c3m0-xfer {
+                               rockchip,pins =
+                                       <0 RK_PB7 2 &pcfg_pull_none_smt>,
+                                       <0 RK_PC0 2 &pcfg_pull_none_smt>;
+                       };
+               };
+
+               i2c3-m1 {
+                       i2c3m1_xfer: i2c3m1-xfer {
+                               rockchip,pins =
+                                       <3 RK_PB4 2 &pcfg_pull_none_smt>,
+                                       <3 RK_PB5 2 &pcfg_pull_none_smt>;
+                       };
+               };
+
+               i2c3-m2 {
+                       i2c3m2_xfer: i2c3m2-xfer {
+                               rockchip,pins =
+                                       <2 RK_PA1 3 &pcfg_pull_none_smt>,
+                                       <2 RK_PA0 3 &pcfg_pull_none_smt>;
+                       };
+               };
+
+               i2s_2ch_0 {
+                       i2s_2ch_0_mclk: i2s-2ch-0-mclk {
+                               rockchip,pins =
+                                       <4 RK_PB4 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_2ch_0_sclk: i2s-2ch-0-sclk {
+                               rockchip,pins =
+                                       <4 RK_PB5 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_2ch_0_lrck: i2s-2ch-0-lrck {
+                               rockchip,pins =
+                                       <4 RK_PB6 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_2ch_0_sdo: i2s-2ch-0-sdo {
+                               rockchip,pins =
+                                       <4 RK_PB7 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_2ch_0_sdi: i2s-2ch-0-sdi {
+                               rockchip,pins =
+                                       <4 RK_PC0 1 &pcfg_pull_none>;
+                       };
+               };
+
+               i2s_8ch_0 {
+                       i2s_8ch_0_mclk: i2s-8ch-0-mclk {
+                               rockchip,pins =
+                                       <2 RK_PA4 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sclktx: i2s-8ch-0-sclktx {
+                               rockchip,pins =
+                                       <2 RK_PA5 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sclkrx: i2s-8ch-0-sclkrx {
+                               rockchip,pins =
+                                       <2 RK_PA6 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_lrcktx: i2s-8ch-0-lrcktx {
+                               rockchip,pins =
+                                       <2 RK_PA7 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_lrckrx: i2s-8ch-0-lrckrx {
+                               rockchip,pins =
+                                       <2 RK_PB0 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdo0: i2s-8ch-0-sdo0 {
+                               rockchip,pins =
+                                       <2 RK_PB1 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdo1: i2s-8ch-0-sdo1 {
+                               rockchip,pins =
+                                       <2 RK_PB2 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdo2: i2s-8ch-0-sdo2 {
+                               rockchip,pins =
+                                       <2 RK_PB3 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdo3: i2s-8ch-0-sdo3 {
+                               rockchip,pins =
+                                       <2 RK_PB4 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdi0: i2s-8ch-0-sdi0 {
+                               rockchip,pins =
+                                       <2 RK_PB5 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdi1: i2s-8ch-0-sdi1 {
+                               rockchip,pins =
+                                       <2 RK_PB6 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdi2: i2s-8ch-0-sdi2 {
+                               rockchip,pins =
+                                       <2 RK_PB7 1 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_0_sdi3: i2s-8ch-0-sdi3 {
+                               rockchip,pins =
+                                       <2 RK_PC0 1 &pcfg_pull_none>;
+                       };
+               };
+
+               i2s_8ch_1_m0 {
+                       i2s_8ch_1_m0_mclk: i2s-8ch-1-m0-mclk {
+                               rockchip,pins =
+                                       <1 RK_PA2 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sclktx: i2s-8ch-1-m0-sclktx {
+                               rockchip,pins =
+                                       <1 RK_PA3 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sclkrx: i2s-8ch-1-m0-sclkrx {
+                               rockchip,pins =
+                                       <1 RK_PA4 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_lrcktx: i2s-8ch-1-m0-lrcktx {
+                               rockchip,pins =
+                                       <1 RK_PA5 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_lrckrx: i2s-8ch-1-m0-lrckrx {
+                               rockchip,pins =
+                                       <1 RK_PA6 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sdo0: i2s-8ch-1-m0-sdo0 {
+                               rockchip,pins =
+                                       <1 RK_PA7 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sdo1_sdi3: i2s-8ch-1-m0-sdo1-sdi3 {
+                               rockchip,pins =
+                                       <1 RK_PB0 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sdo2_sdi2: i2s-8ch-1-m0-sdo2-sdi2 {
+                               rockchip,pins =
+                                       <1 RK_PB1 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sdo3_sdi1: i2s-8ch-1-m0-sdo3_sdi1 {
+                               rockchip,pins =
+                                       <1 RK_PB2 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m0_sdi0: i2s-8ch-1-m0-sdi0 {
+                               rockchip,pins =
+                                       <1 RK_PB3 2 &pcfg_pull_none>;
+                       };
+               };
+
+               i2s_8ch_1_m1 {
+                       i2s_8ch_1_m1_mclk: i2s-8ch-1-m1-mclk {
+                               rockchip,pins =
+                                       <1 RK_PB4 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sclktx: i2s-8ch-1-m1-sclktx {
+                               rockchip,pins =
+                                       <1 RK_PB5 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sclkrx: i2s-8ch-1-m1-sclkrx {
+                               rockchip,pins =
+                                       <1 RK_PB6 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_lrcktx: i2s-8ch-1-m1-lrcktx {
+                               rockchip,pins =
+                                       <1 RK_PB7 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_lrckrx: i2s-8ch-1-m1-lrckrx {
+                               rockchip,pins =
+                                       <1 RK_PC0 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sdo0: i2s-8ch-1-m1-sdo0 {
+                               rockchip,pins =
+                                       <1 RK_PC1 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sdo1_sdi3: i2s-8ch-1-m1-sdo1-sdi3 {
+                               rockchip,pins =
+                                       <1 RK_PC2 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sdo2_sdi2: i2s-8ch-1-m1-sdo2-sdi2 {
+                               rockchip,pins =
+                                       <1 RK_PC3 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sdo3_sdi1: i2s-8ch-1-m1-sdo3_sdi1 {
+                               rockchip,pins =
+                                       <1 RK_PC4 2 &pcfg_pull_none>;
+                       };
+
+                       i2s_8ch_1_m1_sdi0: i2s-8ch-1-m1-sdi0 {
+                               rockchip,pins =
+                                       <1 RK_PC5 2 &pcfg_pull_none>;
+                       };
+               };
+
+               pdm_m0 {
+                       pdm_m0_clk: pdm-m0-clk {
+                               rockchip,pins =
+                                       <1 RK_PA4 3 &pcfg_pull_none>;
+                       };
+
+                       pdm_m0_sdi0: pdm-m0-sdi0 {
+                               rockchip,pins =
+                                       <1 RK_PB3 3 &pcfg_pull_none>;
+                       };
+
+                       pdm_m0_sdi1: pdm-m0-sdi1 {
+                               rockchip,pins =
+                                       <1 RK_PB2 3 &pcfg_pull_none>;
+                       };
+
+                       pdm_m0_sdi2: pdm-m0-sdi2 {
+                               rockchip,pins =
+                                       <1 RK_PB1 3 &pcfg_pull_none>;
+                       };
+
+                       pdm_m0_sdi3: pdm-m0-sdi3 {
+                               rockchip,pins =
+                                       <1 RK_PB0 3 &pcfg_pull_none>;
+                       };
+               };
+
+               pdm_m1 {
+                       pdm_m1_clk: pdm-m1-clk {
+                               rockchip,pins =
+                                       <1 RK_PB6 4 &pcfg_pull_none>;
+                       };
+
+                       pdm_m1_sdi0: pdm-m1-sdi0 {
+                               rockchip,pins =
+                                       <1 RK_PC5 4 &pcfg_pull_none>;
+                       };
+
+                       pdm_m1_sdi1: pdm-m1-sdi1 {
+                               rockchip,pins =
+                                       <1 RK_PC4 4 &pcfg_pull_none>;
+                       };
+
+                       pdm_m1_sdi2: pdm-m1-sdi2 {
+                               rockchip,pins =
+                                       <1 RK_PC3 4 &pcfg_pull_none>;
+                       };
+
+                       pdm_m1_sdi3: pdm-m1-sdi3 {
+                               rockchip,pins =
+                                       <1 RK_PC2 4 &pcfg_pull_none>;
+                       };
+               };
+
+               pdm_m2 {
+                       pdm_m2_clkm: pdm-m2-clkm {
+                               rockchip,pins =
+                                       <2 RK_PA4 3 &pcfg_pull_none>;
+                       };
+
+                       pdm_m2_clk: pdm-m2-clk {
+                               rockchip,pins =
+                                       <2 RK_PA6 2 &pcfg_pull_none>;
+                       };
+
+                       pdm_m2_sdi0: pdm-m2-sdi0 {
+                               rockchip,pins =
+                                       <2 RK_PB5 2 &pcfg_pull_none>;
+                       };
+
+                       pdm_m2_sdi1: pdm-m2-sdi1 {
+                               rockchip,pins =
+                                       <2 RK_PB6 2 &pcfg_pull_none>;
+                       };
+
+                       pdm_m2_sdi2: pdm-m2-sdi2 {
+                               rockchip,pins =
+                                       <2 RK_PB7 2 &pcfg_pull_none>;
+                       };
+
+                       pdm_m2_sdi3: pdm-m2-sdi3 {
+                               rockchip,pins =
+                                       <2 RK_PC0 2 &pcfg_pull_none>;
+                       };
+               };
+
+               pwm0 {
+                       pwm0_pin: pwm0-pin {
+                               rockchip,pins =
+                                       <0 RK_PB5 1 &pcfg_pull_none>;
+                       };
+
+                       pwm0_pin_pull_down: pwm0-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PB5 1 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm1 {
+                       pwm1_pin: pwm1-pin {
+                               rockchip,pins =
+                                       <0 RK_PB6 1 &pcfg_pull_none>;
+                       };
+
+                       pwm1_pin_pull_down: pwm1-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PB6 1 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm2 {
+                       pwm2_pin: pwm2-pin {
+                               rockchip,pins =
+                                       <0 RK_PB7 1 &pcfg_pull_none>;
+                       };
+
+                       pwm2_pin_pull_down: pwm2-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PB7 1 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm3 {
+                       pwm3_pin: pwm3-pin {
+                               rockchip,pins =
+                                       <0 RK_PC0 1 &pcfg_pull_none>;
+                       };
+
+                       pwm3_pin_pull_down: pwm3-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PC0 1 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm4 {
+                       pwm4_pin: pwm4-pin {
+                               rockchip,pins =
+                                       <0 RK_PA1 2 &pcfg_pull_none>;
+                       };
+
+                       pwm4_pin_pull_down: pwm4-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PA1 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm5 {
+                       pwm5_pin: pwm5-pin {
+                               rockchip,pins =
+                                       <0 RK_PC1 2 &pcfg_pull_none>;
+                       };
+
+                       pwm5_pin_pull_down: pwm5-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PC1 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm6 {
+                       pwm6_pin: pwm6-pin {
+                               rockchip,pins =
+                                       <0 RK_PC2 2 &pcfg_pull_none>;
+                       };
+
+                       pwm6_pin_pull_down: pwm6-pin-pull-down {
+                               rockchip,pins =
+                                       <0 RK_PC2 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm7 {
+                       pwm7_pin: pwm7-pin {
+                               rockchip,pins =
+                                       <2 RK_PB0 2 &pcfg_pull_none>;
+                       };
+
+                       pwm7_pin_pull_down: pwm7-pin-pull-down {
+                               rockchip,pins =
+                                       <2 RK_PB0 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm8 {
+                       pwm8_pin: pwm8-pin {
+                               rockchip,pins =
+                                       <2 RK_PB2 2 &pcfg_pull_none>;
+                       };
+
+                       pwm8_pin_pull_down: pwm8-pin-pull-down {
+                               rockchip,pins =
+                                       <2 RK_PB2 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm9 {
+                       pwm9_pin: pwm9-pin {
+                               rockchip,pins =
+                                       <2 RK_PB3 2 &pcfg_pull_none>;
+                       };
+
+                       pwm9_pin_pull_down: pwm9-pin-pull-down {
+                               rockchip,pins =
+                                       <2 RK_PB3 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm10 {
+                       pwm10_pin: pwm10-pin {
+                               rockchip,pins =
+                                       <2 RK_PB4 2 &pcfg_pull_none>;
+                       };
+
+                       pwm10_pin_pull_down: pwm10-pin-pull-down {
+                               rockchip,pins =
+                                       <2 RK_PB4 2 &pcfg_pull_down>;
+                       };
+               };
+
+               pwm11 {
+                       pwm11_pin: pwm11-pin {
+                               rockchip,pins =
+                                       <2 RK_PC0 4 &pcfg_pull_none>;
+                       };
+
+                       pwm11_pin_pull_down: pwm11-pin-pull-down {
+                               rockchip,pins =
+                                       <2 RK_PC0 4 &pcfg_pull_down>;
+                       };
+               };
+
+               rtc {
+                       rtc_32k: rtc-32k {
+                               rockchip,pins =
+                                       <0 RK_PC3 1 &pcfg_pull_none>;
+                       };
+               };
+
+               sdmmc {
+                       sdmmc_clk: sdmmc-clk {
+                               rockchip,pins =
+                                       <4 RK_PD5 1 &pcfg_pull_none_4ma>;
+                       };
+
+                       sdmmc_cmd: sdmmc-cmd {
+                               rockchip,pins =
+                                       <4 RK_PD4 1 &pcfg_pull_up_4ma>;
+                       };
+
+                       sdmmc_det: sdmmc-det {
+                               rockchip,pins =
+                                       <0 RK_PA3 1 &pcfg_pull_up_4ma>;
+                       };
+
+                       sdmmc_pwren: sdmmc-pwren {
+                               rockchip,pins =
+                                       <4 RK_PD6 1 &pcfg_pull_none_4ma>;
+                       };
+
+                       sdmmc_bus1: sdmmc-bus1 {
+                               rockchip,pins =
+                                       <4 RK_PD0 1 &pcfg_pull_up_4ma>;
+                       };
+
+                       sdmmc_bus4: sdmmc-bus4 {
+                               rockchip,pins =
+                                       <4 RK_PD0 1 &pcfg_pull_up_4ma>,
+                                       <4 RK_PD1 1 &pcfg_pull_up_4ma>,
+                                       <4 RK_PD2 1 &pcfg_pull_up_4ma>,
+                                       <4 RK_PD3 1 &pcfg_pull_up_4ma>;
+                       };
+               };
+
+               sdio {
+                       sdio_clk: sdio-clk {
+                               rockchip,pins =
+                                       <4 RK_PA5 1 &pcfg_pull_none_8ma>;
+                       };
+
+                       sdio_cmd: sdio-cmd {
+                               rockchip,pins =
+                                       <4 RK_PA4 1 &pcfg_pull_up_8ma>;
+                       };
+
+                       sdio_pwren: sdio-pwren {
+                               rockchip,pins =
+                                       <0 RK_PA2 1 &pcfg_pull_none_8ma>;
+                       };
+
+                       sdio_wrpt: sdio-wrpt {
+                               rockchip,pins =
+                                       <0 RK_PA1 1 &pcfg_pull_none_8ma>;
+                       };
+
+                       sdio_intn: sdio-intn {
+                               rockchip,pins =
+                                       <0 RK_PA0 1 &pcfg_pull_none_8ma>;
+                       };
+
+                       sdio_bus1: sdio-bus1 {
+                               rockchip,pins =
+                                       <4 RK_PA0 1 &pcfg_pull_up_8ma>;
+                       };
+
+                       sdio_bus4: sdio-bus4 {
+                               rockchip,pins =
+                                       <4 RK_PA0 1 &pcfg_pull_up_8ma>,
+                                       <4 RK_PA1 1 &pcfg_pull_up_8ma>,
+                                       <4 RK_PA2 1 &pcfg_pull_up_8ma>,
+                                       <4 RK_PA3 1 &pcfg_pull_up_8ma>;
+                       };
+               };
+
+               spdif_in {
+                       spdif_in: spdif-in {
+                               rockchip,pins =
+                                       <0 RK_PC2 1 &pcfg_pull_none>;
+                       };
+               };
+
+               spdif_out {
+                       spdif_out: spdif-out {
+                               rockchip,pins =
+                                       <0 RK_PC1 1 &pcfg_pull_none>;
+                       };
+               };
+
+               spi0 {
+                       spi0_clk: spi0-clk {
+                               rockchip,pins =
+                                       <2 RK_PA2 2 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi0_csn0: spi0-csn0 {
+                               rockchip,pins =
+                                       <2 RK_PA3 2 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi0_miso: spi0-miso {
+                               rockchip,pins =
+                                       <2 RK_PA0 2 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi0_mosi: spi0-mosi {
+                               rockchip,pins =
+                                       <2 RK_PA1 2 &pcfg_pull_up_4ma>;
+                       };
+               };
+
+               spi1 {
+                       spi1_clk: spi1-clk {
+                               rockchip,pins =
+                                       <3 RK_PB3 3 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi1_csn0: spi1-csn0 {
+                               rockchip,pins =
+                                       <3 RK_PB5 3 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi1_miso: spi1-miso {
+                               rockchip,pins =
+                                       <3 RK_PB2 3 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi1_mosi: spi1-mosi {
+                               rockchip,pins =
+                                       <3 RK_PB4 3 &pcfg_pull_up_4ma>;
+                       };
+               };
+
+               spi1-m1 {
+                       spi1m1_miso: spi1m1-miso {
+                               rockchip,pins =
+                                       <2 RK_PA4 2 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi1m1_mosi: spi1m1-mosi {
+                               rockchip,pins =
+                                       <2 RK_PA5 2 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi1m1_clk: spi1m1-clk {
+                               rockchip,pins =
+                                       <2 RK_PA7 2 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi1m1_csn0: spi1m1-csn0 {
+                               rockchip,pins =
+                                       <2 RK_PB1 2 &pcfg_pull_up_4ma>;
+                       };
+               };
+
+               spi2 {
+                       spi2_clk: spi2-clk {
+                               rockchip,pins =
+                                       <1 RK_PD0 3 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi2_csn0: spi2-csn0 {
+                               rockchip,pins =
+                                       <1 RK_PD1 3 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi2_miso: spi2-miso {
+                               rockchip,pins =
+                                       <1 RK_PC6 3 &pcfg_pull_up_4ma>;
+                       };
+
+                       spi2_mosi: spi2-mosi {
+                               rockchip,pins =
+                                       <1 RK_PC7 3 &pcfg_pull_up_4ma>;
+                       };
+               };
+
+               tsadc {
+                       tsadc_otp_gpio: tsadc-otp-gpio {
+                               rockchip,pins =
+                                       <0 RK_PB2 0 &pcfg_pull_none>;
+                       };
+
+                       tsadc_otp_out: tsadc-otp-out {
+                               rockchip,pins =
+                                       <0 RK_PB2 1 &pcfg_pull_none>;
+                       };
+               };
+
+               uart0 {
+                       uart0_xfer: uart0-xfer {
+                               rockchip,pins =
+                                       <2 RK_PA1 1 &pcfg_pull_up>,
+                                       <2 RK_PA0 1 &pcfg_pull_up>;
+                       };
+
+                       uart0_cts: uart0-cts {
+                               rockchip,pins =
+                                       <2 RK_PA2 1 &pcfg_pull_none>;
+                       };
+
+                       uart0_rts: uart0-rts {
+                               rockchip,pins =
+                                       <2 RK_PA3 1 &pcfg_pull_none>;
+                       };
+
+                       uart0_rts_gpio: uart0-rts-gpio {
+                               rockchip,pins =
+                                       <2 RK_PA3 0 &pcfg_pull_none>;
+                       };
+               };
+
+               uart1 {
+                       uart1_xfer: uart1-xfer {
+                               rockchip,pins =
+                                       <1 RK_PD1 1 &pcfg_pull_up>,
+                                       <1 RK_PD0 1 &pcfg_pull_up>;
+                       };
+
+                       uart1_cts: uart1-cts {
+                               rockchip,pins =
+                                       <1 RK_PC6 1 &pcfg_pull_none>;
+                       };
+
+                       uart1_rts: uart1-rts {
+                               rockchip,pins =
+                                       <1 RK_PC7 1 &pcfg_pull_none>;
+                       };
+               };
+
+               uart2-m0 {
+                       uart2m0_xfer: uart2m0-xfer {
+                               rockchip,pins =
+                                       <1 RK_PC7 2 &pcfg_pull_up>,
+                                       <1 RK_PC6 2 &pcfg_pull_up>;
+                       };
+               };
+
+               uart2-m1 {
+                       uart2m1_xfer: uart2m1-xfer {
+                               rockchip,pins =
+                                       <4 RK_PD3 2 &pcfg_pull_up>,
+                                       <4 RK_PD2 2 &pcfg_pull_up>;
+                       };
+               };
+
+               uart3 {
+                       uart3_xfer: uart3-xfer {
+                               rockchip,pins =
+                                       <3 RK_PB5 4 &pcfg_pull_up>,
+                                       <3 RK_PB4 4 &pcfg_pull_up>;
+                       };
+               };
+
+               uart3-m1 {
+                       uart3m1_xfer: uart3m1-xfer {
+                               rockchip,pins =
+                                       <0 RK_PC2 3 &pcfg_pull_up>,
+                                       <0 RK_PC1 3 &pcfg_pull_up>;
+                       };
+               };
+
+               uart4 {
+                       uart4_xfer: uart4-xfer {
+                               rockchip,pins =
+                                       <4 RK_PB1 1 &pcfg_pull_up>,
+                                       <4 RK_PB0 1 &pcfg_pull_up>;
+                       };
+
+                       uart4_cts: uart4-cts {
+                               rockchip,pins =
+                                       <4 RK_PA6 1 &pcfg_pull_none>;
+                       };
+
+                       uart4_rts: uart4-rts {
+                               rockchip,pins =
+                                       <4 RK_PA7 1 &pcfg_pull_none>;
+                       };
+
+                       uart4_rts_gpio: uart4-rts-gpio {
+                               rockchip,pins =
+                                       <4 RK_PA7 0 &pcfg_pull_none>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
new file mode 100644 (file)
index 0000000..76b49f5
--- /dev/null
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+// Copyright (c) 2017-2019 Arm Ltd.
+
+/dts-v1/;
+#include "rk3328.dtsi"
+
+/ {
+       model = "Beelink A1";
+       compatible = "azw,beelink-a1", "rockchip,rk3328";
+
+       /*
+        * UART pins, as viewed with bottom of case removed:
+        *
+        *           Front
+        *        /-------
+        *  L    / o <- Gnd
+        *  e   / o <-- Rx
+        *  f  / o <--- Tx
+        *  t / o <---- +3.3v
+        *    |
+        */
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       gmac_clkin: external-gmac-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <125000000>;
+               clock-output-names = "gmac_clkin";
+               #clock-cells = <0>;
+       };
+
+       vcc_host_5v: usb3-current-switch {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&usb30_host_drv>;
+               regulator-name = "vcc_host_5v";
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc_sys: vcc-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_sys";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       ir-receiver {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&analog_sound {
+       simple-audio-card,name = "Analog A/V";
+       status = "okay";
+};
+
+&codec {
+       status = "okay";
+};
+
+&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;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       no-sd;
+       no-sdio;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+       vmmc-supply = <&vcc_io>;
+       vqmmc-supply = <&vcc18_emmc>;
+       status = "okay";
+};
+
+&gmac2io {
+       assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
+       assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>;
+       clock_in_out = "input";
+       phy-handle = <&rtl8211f>;
+       phy-mode = "rgmii";
+       phy-supply = <&vcc_io>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmiim1_pins>;
+       snps,aal;
+       snps,pbl = <0x4>;
+       tx_delay = <0x26>;
+       rx_delay = <0x11>;
+       status = "okay";
+
+       mdio {
+               compatible = "snps,dwmac-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtl8211f: phy@0 {
+                       reg = <0>;
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&gpu {
+       mali-supply = <&vdd_logic>;
+};
+
+&hdmi {
+       status = "okay";
+};
+
+&hdmiphy {
+       status = "okay";
+};
+
+&hdmi_sound {
+       status = "okay";
+};
+
+&i2c1 {
+       clock-frequency = <1000000>;
+       i2c-scl-falling-time-ns = <5>;
+       i2c-scl-rising-time-ns = <83>;
+       status = "okay";
+
+       pmic@18 {
+               compatible = "rockchip,rk805";
+               reg = <0x18>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <RK_PA6 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int_l>;
+               rockchip,system-power-controller;
+               wakeup-source;
+
+               vcc1-supply = <&vcc_sys>;
+               vcc2-supply = <&vcc_sys>;
+               vcc3-supply = <&vcc_sys>;
+               vcc4-supply = <&vcc_sys>;
+               vcc5-supply = <&vcc_io>;
+               vcc6-supply = <&vcc_io>;
+
+               regulators {
+                       vdd_logic: DCDC_REG1 {
+                               regulator-name = "vdd_logic";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1000000>;
+                               };
+                       };
+
+                       vdd_arm: DCDC_REG2 {
+                               regulator-name = "vdd_arm";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <950000>;
+                               };
+                       };
+
+                       vcc_ddr: DCDC_REG3 {
+                               regulator-name = "vcc_ddr";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_io: DCDC_REG4 {
+                               regulator-name = "vcc_io";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vdd_18: LDO_REG1 {
+                               regulator-name = "vdd_18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc18_emmc: LDO_REG2 {
+                               regulator-name = "vcc_18emmc";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_11: LDO_REG3 {
+                               regulator-name = "vdd_11";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1100000>;
+                               };
+                       };
+               };
+       };
+};
+
+&i2s0 {
+       status = "okay";
+};
+
+&i2s1 {
+       status = "okay";
+};
+
+&io_domains {
+       vccio1-supply = <&vcc_io>;
+       vccio2-supply = <&vcc18_emmc>;
+       vccio3-supply = <&vcc_io>;
+       vccio4-supply = <&vdd_18>;
+       vccio5-supply = <&vcc_io>;
+       vccio6-supply = <&vdd_18>;
+       pmuio-supply = <&vcc_io>;
+       status = "okay";
+};
+
+&pinctrl {
+       pmic {
+               pmic_int_l: pmic-int-l {
+                       rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       usb3 {
+               usb30_host_drv: usb30-host-drv {
+                       rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       wifi {
+               bt_dis: bt-dis {
+                       rockchip,pins = <2 RK_PC5 RK_FUNC_GPIO &pcfg_output_low>;
+               };
+
+               bt_wake_host: bt-wake-host {
+                       rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+
+               chip_en: chip-en {
+                       rockchip,pins = <2 RK_PC3 RK_FUNC_GPIO &pcfg_output_low>;
+               };
+
+               host_wake_bt: host-wake-bt {
+                       rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_output_high>;
+               };
+
+               wl_dis: wl-dis {
+                       rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_output_low>;
+               };
+
+               wl_wake_host: wl-wake-host {
+                       rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       disable-wp;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>;
+       vmmc-supply = <&vcc_io>;
+       vqmmc-supply = <&vcc_io>;
+       status = "okay";
+};
+
+&tsadc {
+       rockchip,hw-tshut-mode = <0>;
+       rockchip,hw-tshut-polarity = <0>;
+       status = "okay";
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&u2phy {
+       status = "okay";
+};
+
+&u2phy_host {
+       status = "okay";
+};
+
+&u2phy_otg {
+       status = "okay";
+};
+
+&usb20_otg {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       pinctrl-names = "default";
+       pinctrl-0 = <&bt_dis &bt_wake_host &chip_en &host_wake_bt &wl_dis &wl_wake_host>;
+       status = "okay";
+};
+
+&vop {
+       status = "okay";
+};
+
+&vop_mmu {
+       status = "okay";
+};
index bb40c16..8d553c9 100644 (file)
@@ -35,6 +35,7 @@
                gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>;
                pinctrl-names = "default";
                pinctrl-0 = <&sdmmc0m1_gpio>;
+               regulator-boot-on;
                regulator-name = "vcc_sd";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
index 31cc154..91306eb 100644 (file)
                };
        };
 
+       analog_sound: analog-sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,mclk-fs = <256>;
+               simple-audio-card,name = "Analog";
+               status = "disabled";
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s1>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&codec>;
+               };
+       };
+
        arm-pmu {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
                ports = <&vop_out>;
        };
 
+       hdmi_sound: hdmi-sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,mclk-fs = <128>;
+               simple-audio-card,name = "HDMI";
+               status = "disabled";
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s0>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&hdmi>;
+               };
+       };
+
        psci {
                compatible = "arm,psci-1.0", "arm,psci-0.2";
                method = "smc";
index a9f4d6d..9dd3b17 100644 (file)
 
 &spi0 {
        status = "okay";
+
+       cr50@0 {
+               compatible = "google,cr50";
+               reg = <0>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <5 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&h1_int_od_l>;
+               spi-max-frequency = <800000>;
+       };
 };
 
 &pinctrl {
index 50dfab5..4373ed7 100644 (file)
@@ -436,6 +436,16 @@ camera: &i2c7 {
 
 &spi2 {
        status = "okay";
+
+       cr50@0 {
+               compatible = "google,cr50";
+               reg = <0>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <17 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&h1_int_od_l>;
+               spi-max-frequency = <800000>;
+       };
 };
 
 &usb_host0_ohci {
index dd16c80..b788ae4 100644 (file)
        phy-handle = <&rtl8211e>;
        phy-mode = "rgmii";
        phy-supply = <&vcc3v3_s3>;
-       snps,reset-active-low;
-       snps,reset-delays-us = <0 10000 30000>;
-       snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
        tx_delay = <0x28>;
        rx_delay = <0x11>;
        status = "okay";
                        reg = <1>;
                        interrupt-parent = <&gpio3>;
                        interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
                };
        };
 };
        status = "okay";
 };
 
+&hdmi_sound {
+       status = "okay";
+};
+
 &i2c0 {
        clock-frequency = <400000>;
        i2c-scl-rising-time-ns = <160>;
        status = "okay";
 };
 
+&i2s2 {
+       status = "okay";
+};
+
 &io_domains {
        bt656-supply = <&vcc_1v8>;
        audio-supply = <&vcca1v8_codec>;
index 62ea288..c1edca3 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&vdd_gpu>;
+       status = "okay";
+};
+
 &i2c0 {
        status = "okay";
        i2c-scl-rising-time-ns = <168>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts
new file mode 100644 (file)
index 0000000..d6b3042
--- /dev/null
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2017 T-Chip Intelligent Technology Co., Ltd
+ * Copyright (c) 2019 Markus Reichl <m.reichl@fivetechno.de>
+ */
+
+/dts-v1/;
+#include "rk3399-roc-pc.dtsi"
+
+/ {
+       model = "Firefly ROC-RK3399-PC Mezzanine Board";
+       compatible = "firefly,roc-rk3399-pc-mezzanine", "rockchip,rk3399";
+
+       vcc3v3_ngff: vcc3v3-ngff {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_ngff";
+               enable-active-high;
+               gpio = <&gpio4 RK_PD3 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc3v3_ngff_en>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&dc_12v>;
+       };
+
+       vcc3v3_pcie: vcc3v3-pcie {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_pcie";
+               enable-active-high;
+               gpio = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc3v3_pcie_en>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&dc_12v>;
+       };
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
+&pcie0 {
+       ep-gpios = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>;
+       num-lanes = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_perst>;
+       vpcie3v3-supply = <&vcc3v3_pcie>;
+       status = "okay";
+};
+
+&pinctrl {
+       ngff {
+               vcc3v3_ngff_en: vcc3v3-ngff-en {
+                       rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pcie {
+               vcc3v3_pcie_en: vcc3v3-pcie-en {
+                       rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               pcie_perst: pcie-perst {
+                       rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
index 19f7732..cd41954 100644 (file)
@@ -4,677 +4,9 @@
  */
 
 /dts-v1/;
-#include <dt-bindings/pwm/pwm.h>
-#include "rk3399.dtsi"
-#include "rk3399-opp.dtsi"
+#include "rk3399-roc-pc.dtsi"
 
 / {
        model = "Firefly ROC-RK3399-PC Board";
        compatible = "firefly,roc-rk3399-pc", "rockchip,rk3399";
-
-       chosen {
-               stdout-path = "serial2:1500000n8";
-       };
-
-       backlight: backlight {
-               compatible = "pwm-backlight";
-               pwms = <&pwm0 0 25000 0>;
-       };
-
-       clkin_gmac: external-gmac-clock {
-               compatible = "fixed-clock";
-               clock-frequency = <125000000>;
-               clock-output-names = "clkin_gmac";
-               #clock-cells = <0>;
-       };
-
-       sdio_pwrseq: sdio-pwrseq {
-               compatible = "mmc-pwrseq-simple";
-               clocks = <&rk808 1>;
-               clock-names = "ext_clock";
-               pinctrl-names = "default";
-               pinctrl-0 = <&wifi_enable_h>;
-
-               /*
-                * On the module itself this is one of these (depending
-                * on the actual card populated):
-                * - SDIO_RESET_L_WL_REG_ON
-                * - PDN (power down when low)
-                */
-               reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
-       };
-
-       vcc_vbus_typec0: vcc-vbus-typec0 {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc_vbus_typec0";
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-       };
-
-       /*
-        * should be placed inside mp8859, but not until mp8859 has
-        * its own dt-binding.
-        */
-       vcc12v_sys: mp8859-dcdc1 {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc12v_sys";
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <12000000>;
-               regulator-max-microvolt = <12000000>;
-               vin-supply = <&vcc_vbus_typec0>;
-       };
-
-       /* 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>;
-       };
-
-       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 = <&vcc12v_sys>;
-       };
-
-       /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */
-       vcc5v0_host: vcc5v0-host-regulator {
-               compatible = "regulator-fixed";
-               enable-active-high;
-               gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&vcc5v0_host_en &hub_rst>;
-               regulator-name = "vcc5v0_host";
-               regulator-always-on;
-               vin-supply = <&vcc_sys>;
-       };
-
-       vcc_vbus_typec1: vcc-vbus-typec1 {
-               compatible = "regulator-fixed";
-               enable-active-high;
-               gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&vcc_vbus_typec1_en>;
-               regulator-name = "vcc_vbus_typec1";
-               regulator-always-on;
-               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 = <&vcc12v_sys>;
-       };
-
-       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 = <&vcc3v3_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 = <&vcc_lan>;
-       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";
-};
-
-&hdmi {
-       ddc-i2c-bus = <&i2c3>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&hdmi_cec>;
-       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 = "xin32k", "rk808-clkout2";
-               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 = <&vcc1v8_pmu>;
-
-               regulators {
-                       vdd_center: DCDC_REG1 {
-                               regulator-name = "vdd_center";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <750000>;
-                               regulator-max-microvolt = <1350000>;
-                               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 = <750000>;
-                               regulator-max-microvolt = <1350000>;
-                               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 = <1800000>;
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <1800000>;
-                               };
-                       };
-
-                       vcca1v8_codec: LDO_REG1 {
-                               regulator-name = "vcca1v8_codec";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc1v8_hdmi: LDO_REG2 {
-                               regulator-name = "vcc1v8_hdmi";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc1v8_pmu: LDO_REG3 {
-                               regulator-name = "vcc1v8_pmu";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <1800000>;
-                               };
-                       };
-
-                       vcc_sdio: LDO_REG4 {
-                               regulator-name = "vcc_sdio";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3000000>;
-                               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 = <3000000>;
-                               regulator-max-microvolt = <3000000>;
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc_1v5: LDO_REG6 {
-                               regulator-name = "vcc_1v5";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1500000>;
-                               regulator-max-microvolt = <1500000>;
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <1500000>;
-                               };
-                       };
-
-                       vcca0v9_hdmi: LDO_REG7 {
-                               regulator-name = "vcca0v9_hdmi";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <900000>;
-                               regulator-max-microvolt = <900000>;
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc_3v0: LDO_REG8 {
-                               regulator-name = "vcc_3v0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <3000000>;
-                               regulator-max-microvolt = <3000000>;
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <3000000>;
-                               };
-                       };
-
-                       vcc3v3_s3: vcc_lan: 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>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&vsel1_gpio>;
-               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>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&vsel2_gpio>;
-               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 = <300>;
-       i2c-scl-falling-time-ns = <15>;
-       status = "okay";
-};
-
-&i2c3 {
-       i2c-scl-rising-time-ns = <450>;
-       i2c-scl-falling-time-ns = <15>;
-       status = "okay";
-};
-
-&i2c4 {
-       i2c-scl-rising-time-ns = <600>;
-       i2c-scl-falling-time-ns = <20>;
-       status = "okay";
-
-       fusb1: usb-typec@22 {
-               compatible = "fcs,fusb302";
-               reg = <0x22>;
-               interrupt-parent = <&gpio1>;
-               interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&fusb1_int>;
-               vbus-supply = <&vcc_vbus_typec1>;
-               status = "okay";
-       };
-};
-
-&i2c7 {
-       i2c-scl-rising-time-ns = <600>;
-       i2c-scl-falling-time-ns = <20>;
-       status = "okay";
-
-       fusb0: usb-typec@22 {
-               compatible = "fcs,fusb302";
-               reg = <0x22>;
-               interrupt-parent = <&gpio1>;
-               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&fusb0_int>;
-               vbus-supply = <&vcc_vbus_typec0>;
-               status = "okay";
-       };
-};
-
-&i2s0 {
-       rockchip,playback-channels = <8>;
-       rockchip,capture-channels = <8>;
-       status = "okay";
-};
-
-&i2s1 {
-       rockchip,playback-channels = <2>;
-       rockchip,capture-channels = <2>;
-       status = "okay";
-};
-
-&i2s2 {
-       status = "okay";
-};
-
-&io_domains {
-       audio-supply = <&vcca1v8_codec>;
-       bt656-supply = <&vcc_3v0>;
-       gpio1830-supply = <&vcc_3v0>;
-       sdmmc-supply = <&vcc_sdio>;
-       status = "okay";
-};
-
-&pmu_io_domains {
-       pmu1830-supply = <&vcc_3v0>;
-       status = "okay";
-};
-
-&pinctrl {
-       lcd-panel {
-               lcd_panel_reset: lcd-panel-reset {
-                       rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>;
-               };
-       };
-
-       pmic {
-               vsel1_gpio: vsel1-gpio {
-                       rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>;
-               };
-
-               vsel2_gpio: vsel2-gpio {
-                       rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
-               };
-       };
-
-       sdio-pwrseq {
-               wifi_enable_h: wifi-enable-h {
-                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
-               };
-       };
-
-       pmic {
-               pmic_int_l: pmic-int-l {
-                       rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
-               };
-       };
-
-       usb2 {
-               vcc5v0_host_en: vcc5v0-host-en {
-                       rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
-               };
-
-               hub_rst: hub-rst {
-                       rockchip,pins = <2 RK_PA4 RK_FUNC_GPIO &pcfg_output_high>;
-               };
-       };
-
-       usb-typec {
-               vcc_vbus_typec1_en: vcc-vbus-typec1-en {
-                       rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-               };
-       };
-
-       fusb30x {
-               fusb0_int: fusb0-int {
-                       rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
-               };
-
-               fusb1_int: fusb1-int {
-                       rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
-               };
-       };
-};
-
-&pwm0 {
-       status = "okay";
-};
-
-&pwm2 {
-       status = "okay";
-};
-
-&saradc {
-       vref-supply = <&vcca1v8_s3>;
-       status = "okay";
-};
-
-&sdmmc {
-       bus-width = <4>;
-       cap-mmc-highspeed;
-       cap-sd-highspeed;
-       cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
-       disable-wp;
-       max-frequency = <150000000>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;
-       status = "okay";
-};
-
-&sdhci {
-       bus-width = <8>;
-       mmc-hs400-1_8v;
-       mmc-hs400-enhanced-strobe;
-       non-removable;
-       status = "okay";
-};
-
-&tcphy0 {
-       status = "okay";
-};
-
-&tcphy1 {
-       status = "okay";
-};
-
-&tsadc {
-       /* tshut mode 0:CRU 1:GPIO */
-       rockchip,hw-tshut-mode = <1>;
-       /* tshut polarity 0:LOW 1:HIGH */
-       rockchip,hw-tshut-polarity = <1>;
-       status = "okay";
-};
-
-&u2phy0 {
-       status = "okay";
-
-       u2phy0_otg: otg-port {
-               phy-supply = <&vcc_vbus_typec0>;
-               status = "okay";
-       };
-
-       u2phy0_host: host-port {
-               phy-supply = <&vcc5v0_host>;
-               status = "okay";
-       };
-};
-
-&u2phy1 {
-       status = "okay";
-
-       u2phy1_otg: otg-port {
-               phy-supply = <&vcc_vbus_typec1>;
-               status = "okay";
-       };
-
-       u2phy1_host: host-port {
-               phy-supply = <&vcc5v0_host>;
-               status = "okay";
-       };
-};
-
-&uart0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&uart0_xfer &uart0_cts>;
-       status = "okay";
-};
-
-&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";
-};
-
-&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";
 };
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi
new file mode 100644 (file)
index 0000000..7e07dae
--- /dev/null
@@ -0,0 +1,767 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2017 T-Chip Intelligent Technology Co., Ltd
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
+
+/ {
+       model = "Firefly ROC-RK3399-PC Board";
+       compatible = "firefly,roc-rk3399-pc", "rockchip,rk3399";
+
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm0 0 25000 0>;
+       };
+
+       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 = <1500000>;
+               poll-interval = <100>;
+
+               recovery {
+                       label = "Recovery";
+                       linux,code = <KEY_VENDOR>;
+                       press-threshold-microvolt = <18000>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwr_key_l>;
+
+               power {
+                       debounce-interval = <100>;
+                       gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
+                       label = "GPIO Key Power";
+                       linux,code = <KEY_POWER>;
+                       wakeup-source;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&work_led_gpio>, <&diy_led_gpio>, <&yellow_led_gpio>;
+
+               work-led {
+                       label = "green:work";
+                       gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
+                       default-state = "on";
+                       linux,default-trigger = "heartbeat";
+               };
+
+               diy-led {
+                       label = "red:diy";
+                       gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+                       linux,default-trigger = "mmc1";
+               };
+
+               yellow-led {
+                       label = "yellow:yellow-led";
+                       gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+                       linux,default-trigger = "mmc0";
+               };
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_enable_h>;
+
+               /*
+                * On the module itself this is one of these (depending
+                * on the actual card populated):
+                * - SDIO_RESET_L_WL_REG_ON
+                * - PDN (power down when low)
+                */
+               reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+       };
+
+       vcc_vbus_typec0: vcc-vbus-typec0 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_vbus_typec0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       /*
+        * should be placed inside mp8859, but not until mp8859 has
+        * its own dt-binding.
+        */
+       dc_12v: mp8859-dcdc1 {
+               compatible = "regulator-fixed";
+               regulator-name = "dc_12v";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               vin-supply = <&vcc_vbus_typec0>;
+       };
+
+       /* 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>;
+       };
+
+       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 = <&dc_12v>;
+       };
+
+       /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */
+       vcc5v0_host: vcc5v0-host-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_host_en &hub_rst>;
+               regulator-name = "vcc5v0_host";
+               regulator-always-on;
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc_vbus_typec1: vcc-vbus-typec1 {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc_vbus_typec1_en>;
+               regulator-name = "vcc_vbus_typec1";
+               regulator-always-on;
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc_sys: vcc-sys {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 RK_PA6 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc_sys_en>;
+               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 = <&vcc3v3_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 = <&vcc_lan>;
+       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";
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&hdmi_cec>;
+       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 = "xin32k", "rk808-clkout2";
+               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>;
+               vcc13-supply = <&vcc3v3_sys>;
+               vcc14-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 = <750000>;
+                               regulator-max-microvolt = <1350000>;
+                               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 = <750000>;
+                               regulator-max-microvolt = <1350000>;
+                               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 = <1800000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcca1v8_codec: LDO_REG1 {
+                               regulator-name = "vcca1v8_codec";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc1v8_hdmi: LDO_REG2 {
+                               regulator-name = "vcc1v8_hdmi";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc1v8_pmu: LDO_REG3 {
+                               regulator-name = "vcc1v8_pmu";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc_sdio: LDO_REG4 {
+                               regulator-name = "vcc_sdio";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                               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 = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v5: LDO_REG6 {
+                               regulator-name = "vcc_1v5";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1500000>;
+                               };
+                       };
+
+                       vcca0v9_hdmi: LDO_REG7 {
+                               regulator-name = "vcca0v9_hdmi";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_3v0: LDO_REG8 {
+                               regulator-name = "vcc_3v0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc3v3_s3: vcc_lan: 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>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vsel1_gpio>;
+               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>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vsel2_gpio>;
+               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 = <300>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c3 {
+       i2c-scl-rising-time-ns = <450>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c4 {
+       i2c-scl-rising-time-ns = <600>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+
+       fusb1: usb-typec@22 {
+               compatible = "fcs,fusb302";
+               reg = <0x22>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&fusb1_int>;
+               vbus-supply = <&vcc_vbus_typec1>;
+               status = "okay";
+       };
+};
+
+&i2c7 {
+       i2c-scl-rising-time-ns = <600>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+
+       fusb0: usb-typec@22 {
+               compatible = "fcs,fusb302";
+               reg = <0x22>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&fusb0_int>;
+               vbus-supply = <&vcc_vbus_typec0>;
+               status = "okay";
+       };
+};
+
+&i2s0 {
+       rockchip,playback-channels = <8>;
+       rockchip,capture-channels = <8>;
+       status = "okay";
+};
+
+&i2s1 {
+       rockchip,playback-channels = <2>;
+       rockchip,capture-channels = <2>;
+       status = "okay";
+};
+
+&i2s2 {
+       status = "okay";
+};
+
+&io_domains {
+       audio-supply = <&vcca1v8_codec>;
+       bt656-supply = <&vcc_3v0>;
+       gpio1830-supply = <&vcc_3v0>;
+       sdmmc-supply = <&vcc_sdio>;
+       status = "okay";
+};
+
+&pmu_io_domains {
+       pmu1830-supply = <&vcc_3v0>;
+       status = "okay";
+};
+
+&pinctrl {
+       buttons {
+               pwr_key_l: pwr-key-l {
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       lcd-panel {
+               lcd_panel_reset: lcd-panel-reset {
+                       rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       leds {
+               diy_led_gpio: diy_led-gpio {
+                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               work_led_gpio: work_led-gpio {
+                       rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               yellow_led_gpio: yellow_led-gpio {
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pmic {
+               vsel1_gpio: vsel1-gpio {
+                       rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+
+               vsel2_gpio: vsel2-gpio {
+                       rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+       };
+
+       sdio-pwrseq {
+               wifi_enable_h: wifi-enable-h {
+                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pmic {
+               pmic_int_l: pmic-int-l {
+                       rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       usb2 {
+               vcc5v0_host_en: vcc5v0-host-en {
+                       rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               vcc_sys_en: vcc-sys-en {
+                       rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               hub_rst: hub-rst {
+                       rockchip,pins = <2 RK_PA4 RK_FUNC_GPIO &pcfg_output_high>;
+               };
+       };
+
+       usb-typec {
+               vcc_vbus_typec1_en: vcc-vbus-typec1-en {
+                       rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       fusb30x {
+               fusb0_int: fusb0-int {
+                       rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+
+               fusb1_int: fusb1-int {
+                       rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+};
+
+&pwm2 {
+       status = "okay";
+};
+
+&saradc {
+       vref-supply = <&vcca1v8_s3>;
+       status = "okay";
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       max-frequency = <150000000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       non-removable;
+       status = "okay";
+};
+
+&tcphy0 {
+       status = "okay";
+};
+
+&tcphy1 {
+       status = "okay";
+};
+
+&tsadc {
+       /* tshut mode 0:CRU 1:GPIO */
+       rockchip,hw-tshut-mode = <1>;
+       /* tshut polarity 0:LOW 1:HIGH */
+       rockchip,hw-tshut-polarity = <1>;
+       status = "okay";
+};
+
+&u2phy0 {
+       status = "okay";
+
+       u2phy0_otg: otg-port {
+               phy-supply = <&vcc_vbus_typec0>;
+               status = "okay";
+       };
+
+       u2phy0_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+};
+
+&u2phy1 {
+       status = "okay";
+
+       u2phy1_otg: otg-port {
+               phy-supply = <&vcc_vbus_typec1>;
+               status = "okay";
+       };
+
+       u2phy1_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_xfer &uart0_cts>;
+       status = "okay";
+};
+
+&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";
+};
+
+&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 1ae1ebd..188d9df 100644 (file)
 
        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>;
+                       rockchip,pins = <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>;
+                       rockchip,pins = <2 RK_PD0 1 &pcfg_pull_up_20ma>;
                };
 
                sdio0_clk: sdio0-clk {
-                       rockchip,pins =
-                               <2 25 RK_FUNC_1 &pcfg_pull_none_20ma>;
+                       rockchip,pins = <2 RK_PD1 1 &pcfg_pull_none_20ma>;
                };
        };
 
 
        wifi {
                wifi_enable_h: wifi-enable-h {
-                       rockchip,pins =
-                               <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                wifi_host_wake_l: wifi-host-wake-l {
index e544deb..7f4b2eb 100644 (file)
                reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
        };
 
+       sound {
+               compatible = "audio-graph-card";
+               label = "rockchip,rk3399";
+               dais = <&i2s1_p0>;
+       };
+
        vcc12v_dcin: vcc12v-dcin {
                compatible = "regulator-fixed";
                regulator-name = "vcc12v_dcin";
        i2c-scl-rising-time-ns = <300>;
        i2c-scl-falling-time-ns = <15>;
        status = "okay";
+
+       es8316: codec@11 {
+               compatible = "everest,es8316";
+               reg = <0x11>;
+               clocks = <&cru SCLK_I2S_8CH_OUT>;
+               clock-names = "mclk";
+               #sound-dai-cells = <0>;
+
+               port {
+                       es8316_p0_0: endpoint {
+                               remote-endpoint = <&i2s1_p0_0>;
+                       };
+               };
+       };
 };
 
 &i2c3 {
        rockchip,playback-channels = <2>;
        rockchip,capture-channels = <2>;
        status = "okay";
+
+       i2s1_p0: port {
+               i2s1_p0_0: endpoint {
+                       dai-format = "i2s";
+                       mclk-fs = <256>;
+                       remote-endpoint = <&es8316_p0_0>;
+               };
+       };
 };
 
 &i2s2 {
index cede1ad..e62ea0e 100644 (file)
                its: interrupt-controller@fee20000 {
                        compatible = "arm,gic-v3-its";
                        msi-controller;
+                       #msi-cells = <1>;
                        reg = <0x0 0xfee20000 0x0 0x20000>;
                };
 
index 799c75f..efb2457 100644 (file)
                        reg = <0x00 0x30e00000 0x00 0x1000>;
                        #hwlock-cells = <1>;
                };
+
+               mailbox0_cluster0: mailbox@31f80000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f80000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster1: mailbox@31f81000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f81000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster2: mailbox@31f82000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f82000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster3: mailbox@31f83000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f83000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster4: mailbox@31f84000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f84000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster5: mailbox@31f85000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f85000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster6: mailbox@31f86000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f86000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster7: mailbox@31f87000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f87000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster8: mailbox@31f88000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f88000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster9: mailbox@31f89000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f89000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster10: mailbox@31f8a000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f8a000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
+
+               mailbox0_cluster11: mailbox@31f8b000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f8b000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&intr_main_navss>;
+               };
        };
 
        main_gpio0:  main_gpio0@600000 {
index 1102b84..8a85b48 100644 (file)
        bus-width = <8>;
        non-removable;
        ti,driver-strength-ohm = <50>;
+       disable-wp;
 };
 
 &dwc3_1 {
 &pcie1_ep {
        status = "disabled";
 };
+
+&mailbox0_cluster0 {
+       interrupts = <164 0>;
+
+       mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
+               ti,mbox-tx = <1 0 0>;
+               ti,mbox-rx = <0 0 0>;
+       };
+};
+
+&mailbox0_cluster1 {
+       interrupts = <165 0>;
+
+       mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
+               ti,mbox-tx = <1 0 0>;
+               ti,mbox-rx = <0 0 0>;
+       };
+};
+
+&mailbox0_cluster2 {
+       status = "disabled";
+};
+
+&mailbox0_cluster3 {
+       status = "disabled";
+};
+
+&mailbox0_cluster4 {
+       status = "disabled";
+};
+
+&mailbox0_cluster5 {
+       status = "disabled";
+};
+
+&mailbox0_cluster6 {
+       status = "disabled";
+};
+
+&mailbox0_cluster7 {
+       status = "disabled";
+};
+
+&mailbox0_cluster8 {
+       status = "disabled";
+};
+
+&mailbox0_cluster9 {
+       status = "disabled";
+};
+
+&mailbox0_cluster10 {
+       status = "disabled";
+};
+
+&mailbox0_cluster11 {
+       status = "disabled";
+};
index d2894d5..2a3cd61 100644 (file)
                        J721E_IOPAD(0x0, PIN_INPUT, 7) /* (AC18) EXTINTn.GPIO0_0 */
                >;
        };
+
+       main_mmc1_pins_default: main_mmc1_pins_default {
+               pinctrl-single,pins = <
+                       J721E_IOPAD(0x254, PIN_INPUT, 0) /* (R29) MMC1_CMD */
+                       J721E_IOPAD(0x250, PIN_INPUT, 0) /* (P25) MMC1_CLK */
+                       J721E_IOPAD(0x2ac, PIN_INPUT, 0) /* (P25) MMC1_CLKLB */
+                       J721E_IOPAD(0x24c, PIN_INPUT, 0) /* (R24) MMC1_DAT0 */
+                       J721E_IOPAD(0x248, PIN_INPUT, 0) /* (P24) MMC1_DAT1 */
+                       J721E_IOPAD(0x244, PIN_INPUT, 0) /* (R25) MMC1_DAT2 */
+                       J721E_IOPAD(0x240, PIN_INPUT, 0) /* (R26) MMC1_DAT3 */
+                       J721E_IOPAD(0x258, PIN_INPUT, 0) /* (P23) MMC1_SDCD */
+                       J721E_IOPAD(0x25c, PIN_INPUT, 0) /* (R28) MMC1_SDWP */
+               >;
+       };
+
+       main_usbss0_pins_default: main_usbss0_pins_default {
+               pinctrl-single,pins = <
+                       J721E_IOPAD(0x290, PIN_OUTPUT, 0) /* (U6) USB0_DRVVBUS */
+               >;
+       };
+
+       main_usbss1_pins_default: main_usbss1_pins_default {
+               pinctrl-single,pins = <
+                       J721E_IOPAD(0x214, PIN_OUTPUT, 4) /* (V4) MCAN1_TX.USB1_DRVVBUS */
+               >;
+       };
 };
 
 &wkup_pmx0 {
 &wkup_gpio1 {
        status = "disabled";
 };
+
+&mailbox0_cluster0 {
+       interrupts = <214 0>;
+
+       mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
+               ti,mbox-rx = <0 0 0>;
+               ti,mbox-tx = <1 0 0>;
+       };
+
+       mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
+               ti,mbox-rx = <2 0 0>;
+               ti,mbox-tx = <3 0 0>;
+       };
+};
+
+&mailbox0_cluster1 {
+       interrupts = <215 0>;
+
+       mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
+               ti,mbox-rx = <0 0 0>;
+               ti,mbox-tx = <1 0 0>;
+       };
+
+       mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 {
+               ti,mbox-rx = <2 0 0>;
+               ti,mbox-tx = <3 0 0>;
+       };
+};
+
+&mailbox0_cluster2 {
+       interrupts = <216 0>;
+
+       mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
+               ti,mbox-rx = <0 0 0>;
+               ti,mbox-tx = <1 0 0>;
+       };
+
+       mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 {
+               ti,mbox-rx = <2 0 0>;
+               ti,mbox-tx = <3 0 0>;
+       };
+};
+
+&mailbox0_cluster3 {
+       interrupts = <217 0>;
+
+       mbox_c66_0: mbox-c66-0 {
+               ti,mbox-rx = <0 0 0>;
+               ti,mbox-tx = <1 0 0>;
+       };
+
+       mbox_c66_1: mbox-c66-1 {
+               ti,mbox-rx = <2 0 0>;
+               ti,mbox-tx = <3 0 0>;
+       };
+};
+
+&mailbox0_cluster4 {
+       interrupts = <218 0>;
+
+       mbox_c71_0: mbox-c71-0 {
+               ti,mbox-rx = <0 0 0>;
+               ti,mbox-tx = <1 0 0>;
+       };
+};
+
+&mailbox0_cluster5 {
+       status = "disabled";
+};
+
+&mailbox0_cluster6 {
+       status = "disabled";
+};
+
+&mailbox0_cluster7 {
+       status = "disabled";
+};
+
+&mailbox0_cluster8 {
+       status = "disabled";
+};
+
+&mailbox0_cluster9 {
+       status = "disabled";
+};
+
+&mailbox0_cluster10 {
+       status = "disabled";
+};
+
+&mailbox0_cluster11 {
+       status = "disabled";
+};
+
+&main_sdhci0 {
+       /* eMMC */
+       non-removable;
+       ti,driver-strength-ohm = <50>;
+       disable-wp;
+};
+
+&main_sdhci1 {
+       /* SD/MMC */
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mmc1_pins_default>;
+       ti,driver-strength-ohm = <50>;
+       disable-wp;
+};
+
+&main_sdhci2 {
+       /* Unused */
+       status = "disabled";
+};
+
+&usbss0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_usbss0_pins_default>;
+       ti,usb2-only;
+       ti,vbus-divider;
+};
+
+&usb0 {
+       dr_mode = "otg";
+       maximum-speed = "high-speed";
+};
+
+&usbss1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_usbss1_pins_default>;
+       ti,usb2-only;
+};
+
+&usb1 {
+       dr_mode = "host";
+       maximum-speed = "high-speed";
+};
index 698ef9a..1e4c2b7 100644 (file)
                        reg = <0x00 0x30e00000 0x00 0x1000>;
                        #hwlock-cells = <1>;
                };
+
+               mailbox0_cluster0: mailbox@31f80000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f80000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster1: mailbox@31f81000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f81000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster2: mailbox@31f82000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f82000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster3: mailbox@31f83000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f83000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster4: mailbox@31f84000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f84000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster5: mailbox@31f85000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f85000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster6: mailbox@31f86000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f86000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster7: mailbox@31f87000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f87000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster8: mailbox@31f88000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f88000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster9: mailbox@31f89000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f89000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster10: mailbox@31f8a000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f8a000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
+
+               mailbox0_cluster11: mailbox@31f8b000 {
+                       compatible = "ti,am654-mailbox";
+                       reg = <0x00 0x31f8b000 0x00 0x200>;
+                       #mbox-cells = <1>;
+                       ti,mbox-num-users = <4>;
+                       ti,mbox-num-fifos = <16>;
+                       interrupt-parent = <&main_navss_intr>;
+               };
        };
 
        secure_proxy_main: mailbox@32c00000 {
                clocks = <&k3_clks 112 0>;
                clock-names = "gpio";
        };
+
+       main_sdhci0: sdhci@4f80000 {
+               compatible = "ti,j721e-sdhci-8bit";
+               reg = <0x0 0x4f80000 0x0 0x1000>, <0x0 0x4f88000 0x0 0x400>;
+               interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&k3_pds 91 TI_SCI_PD_EXCLUSIVE>;
+               clock-names = "clk_xin", "clk_ahb";
+               clocks = <&k3_clks 91 1>, <&k3_clks 91 0>;
+               assigned-clocks = <&k3_clks 91 1>;
+               assigned-clock-parents = <&k3_clks 91 2>;
+               bus-width = <8>;
+               mmc-hs400-1_8v;
+               mmc-ddr-1_8v;
+               ti,otap-del-sel = <0x2>;
+               ti,trm-icp = <0x8>;
+               ti,strobe-sel = <0x77>;
+               dma-coherent;
+       };
+
+       main_sdhci1: sdhci@4fb0000 {
+               compatible = "ti,j721e-sdhci-4bit";
+               reg = <0x0 0x04fb0000 0x0 0x1000>, <0x0 0x4fb8000 0x0 0x400>;
+               interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&k3_pds 92 TI_SCI_PD_EXCLUSIVE>;
+               clock-names = "clk_xin", "clk_ahb";
+               clocks = <&k3_clks 92 0>, <&k3_clks 92 5>;
+               assigned-clocks = <&k3_clks 92 0>;
+               assigned-clock-parents = <&k3_clks 92 1>;
+               ti,otap-del-sel = <0x2>;
+               ti,trm-icp = <0x8>;
+               ti,clkbuf-sel = <0x7>;
+               dma-coherent;
+               no-1-8-v;
+       };
+
+       main_sdhci2: sdhci@4f98000 {
+               compatible = "ti,j721e-sdhci-4bit";
+               reg = <0x0 0x4f98000 0x0 0x1000>, <0x0 0x4f90000 0x0 0x400>;
+               interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&k3_pds 93 TI_SCI_PD_EXCLUSIVE>;
+               clock-names = "clk_xin", "clk_ahb";
+               clocks = <&k3_clks 93 0>, <&k3_clks 93 5>;
+               assigned-clocks = <&k3_clks 93 0>;
+               assigned-clock-parents = <&k3_clks 93 1>;
+               ti,otap-del-sel = <0x2>;
+               ti,trm-icp = <0x8>;
+               ti,clkbuf-sel = <0x7>;
+               dma-coherent;
+               no-1-8-v;
+       };
+
+       usbss0: cdns_usb@4104000 {
+               compatible = "ti,j721e-usb";
+               reg = <0x00 0x4104000 0x00 0x100>;
+               dma-coherent;
+               power-domains = <&k3_pds 288 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 288 15>, <&k3_clks 288 3>;
+               clock-names = "ref", "lpm";
+               assigned-clocks = <&k3_clks 288 15>;    /* USB2_REFCLK */
+               assigned-clock-parents = <&k3_clks 288 16>; /* HFOSC0 */
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               usb0: usb@6000000 {
+                       compatible = "cdns,usb3";
+                       reg = <0x00 0x6000000 0x00 0x10000>,
+                             <0x00 0x6010000 0x00 0x10000>,
+                             <0x00 0x6020000 0x00 0x10000>;
+                       reg-names = "otg", "xhci", "dev";
+                       interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,  /* irq.0 */
+                                    <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, /* irq.6 */
+                                    <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; /* otgirq.0 */
+                       interrupt-names = "host",
+                                         "peripheral",
+                                         "otg";
+                       maximum-speed = "super-speed";
+                       dr_mode = "otg";
+               };
+       };
+
+       usbss1: cdns_usb@4114000 {
+               compatible = "ti,j721e-usb";
+               reg = <0x00 0x4114000 0x00 0x100>;
+               dma-coherent;
+               power-domains = <&k3_pds 289 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 289 15>, <&k3_clks 289 3>;
+               clock-names = "ref", "lpm";
+               assigned-clocks = <&k3_clks 289 15>;    /* USB2_REFCLK */
+               assigned-clock-parents = <&k3_clks 289 16>; /* HFOSC0 */
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               usb1: usb@6400000 {
+                       compatible = "cdns,usb3";
+                       reg = <0x00 0x6400000 0x00 0x10000>,
+                             <0x00 0x6410000 0x00 0x10000>,
+                             <0x00 0x6420000 0x00 0x10000>;
+                       reg-names = "otg", "xhci", "dev";
+                       interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, /* irq.0 */
+                                    <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, /* irq.6 */
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; /* otgirq.0 */
+                       interrupt-names = "host",
+                                         "peripheral",
+                                         "otg";
+                       maximum-speed = "super-speed";
+                       dr_mode = "otg";
+               };
+       };
 };
index 43ea1ba..ee5470e 100644 (file)
                         <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */
                         <0x00 0x00900000 0x00 0x00900000 0x00 0x00012000>, /* serdes */
                         <0x00 0x00A40000 0x00 0x00A40000 0x00 0x00000800>, /* timesync router */
+                        <0x00 0x06000000 0x00 0x06000000 0x00 0x00400000>, /* USBSS0 */
+                        <0x00 0x06400000 0x00 0x06400000 0x00 0x00400000>, /* USBSS1 */
                         <0x00 0x01000000 0x00 0x01000000 0x00 0x0af02400>, /* Most peripherals */
                         <0x00 0x30800000 0x00 0x30800000 0x00 0x0bc00000>, /* MAIN NAVSS */
                         <0x00 0x0d000000 0x00 0x0d000000 0x00 0x01000000>, /* PCIe Core*/
index 9aa6734..3c731e7 100644 (file)
                method = "smc";
        };
 
+       firmware {
+               zynqmp_firmware: zynqmp-firmware {
+                       compatible = "xlnx,zynqmp-firmware";
+                       method = "smc";
+
+                       nvmem_firmware {
+                               compatible = "xlnx,zynqmp-nvmem-fw";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               soc_revision: soc_revision@0 {
+                                       reg = <0x0 0x4>;
+                               };
+                       };
+
+                       zynqmp_pcap: pcap {
+                               compatible = "xlnx,zynqmp-pcap-fpga";
+                       };
+               };
+       };
+
        timer {
                compatible = "arm,armv8-timer";
                interrupt-parent = <&gic>;
                             <1 10 0xf08>;
        };
 
+       fpga_full: fpga-full {
+               compatible = "fpga-region";
+               fpga-mgr = <&zynqmp_pcap>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+       };
+
        amba_apu: amba-apu@0 {
                compatible = "simple-bus";
                #address-cells = <2>;
index c9a867a..47d1b8f 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_ACTIONS=y
 CONFIG_ARCH_AGILEX=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_ALPINE=y
@@ -48,6 +49,7 @@ CONFIG_ARCH_MXC=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_RENESAS=y
 CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_S32=y
 CONFIG_ARCH_SEATTLE=y
 CONFIG_ARCH_STRATIX10=y
 CONFIG_ARCH_SYNQUACER=y
@@ -71,6 +73,7 @@ CONFIG_COMPAT=y
 CONFIG_RANDOMIZE_BASE=y
 CONFIG_HIBERNATION=y
 CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+CONFIG_ENERGY_MODEL=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_ARM_PSCI_CPUIDLE=y
 CONFIG_CPU_FREQ=y
@@ -90,6 +93,7 @@ CONFIG_ARM_TEGRA186_CPUFREQ=y
 CONFIG_ARM_SCPI_PROTOCOL=y
 CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_INTEL_STRATIX10_SERVICE=y
+CONFIG_INTEL_STRATIX10_RSU=m
 CONFIG_TI_SCI_PROTOCOL=y
 CONFIG_EFI_CAPSULE_LOADER=y
 CONFIG_IMX_SCU=y
@@ -114,6 +118,8 @@ CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
 CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
 CONFIG_CRYPTO_CHACHA20_NEON=m
 CONFIG_CRYPTO_AES_ARM64_BS=m
+CONFIG_CRYPTO_DEV_ALLWINNER=y
+CONFIG_CRYPTO_DEV_SUN8I_CE=m
 CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -211,6 +217,7 @@ CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_CADENCE_QUADSPI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
 CONFIG_VIRTIO_BLK=y
@@ -285,7 +292,7 @@ CONFIG_SNI_AVE=y
 CONFIG_SNI_NETSEC=y
 CONFIG_STMMAC_ETH=m
 CONFIG_MDIO_BUS_MUX_MMIOREG=y
-CONFIG_AT803X_PHY=m
+CONFIG_AT803X_PHY=y
 CONFIG_MARVELL_PHY=m
 CONFIG_MARVELL_10G_PHY=m
 CONFIG_MESON_GXL_PHY=m
@@ -314,6 +321,7 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_ADC=m
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_SNVS_PWRKEY=m
+CONFIG_KEYBOARD_IMX_SC_KEY=m
 CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=m
@@ -352,6 +360,8 @@ CONFIG_SERIAL_XILINX_PS_UART=y
 CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
 CONFIG_SERIAL_FSL_LPUART=y
 CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+CONFIG_SERIAL_FSL_LINFLEXUART=y
+CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE=y
 CONFIG_SERIAL_MVEBU_UART=y
 CONFIG_SERIAL_DEV_BUS=y
 CONFIG_VIRTIO_CONSOLE=y
@@ -411,6 +421,7 @@ CONFIG_PINCTRL_QDF2XXX=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_SDM845=y
 CONFIG_PINCTRL_SM8150=y
+CONFIG_GPIO_ALTERA=m
 CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_MB86S7X=y
 CONFIG_GPIO_PL061=y
@@ -741,9 +752,11 @@ CONFIG_QCOM_SMD_RPM=y
 CONFIG_QCOM_SMP2P=y
 CONFIG_QCOM_SMSM=y
 CONFIG_ARCH_R8A774A1=y
+CONFIG_ARCH_R8A774B1=y
 CONFIG_ARCH_R8A774C0=y
 CONFIG_ARCH_R8A7795=y
 CONFIG_ARCH_R8A7796=y
+CONFIG_ARCH_R8A77961=y
 CONFIG_ARCH_R8A77965=y
 CONFIG_ARCH_R8A77970=y
 CONFIG_ARCH_R8A77980=y
@@ -801,6 +814,7 @@ CONFIG_PHY_ROCKCHIP_TYPEC=y
 CONFIG_PHY_UNIPHIER_USB2=y
 CONFIG_PHY_UNIPHIER_USB3=y
 CONFIG_PHY_TEGRA_XUSB=y
+CONFIG_ARM_SMMU_V3_PMU=m
 CONFIG_FSL_IMX8_DDR_PMU=m
 CONFIG_HISI_PMU=y
 CONFIG_QCOM_L2_PMU=y
@@ -848,6 +862,7 @@ CONFIG_NLS_ISO8859_1=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_ECHAINIV=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_HISI_ZIP=m
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_PRINTK_TIME=y
index b08029d..c1f9660 100644 (file)
@@ -211,12 +211,13 @@ static int __init chacha_simd_mod_init(void)
 
        static_branch_enable(&have_neon);
 
-       return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+       return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
+               crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
 }
 
 static void __exit chacha_simd_mod_fini(void)
 {
-       if (cpu_have_named_feature(ASIMD))
+       if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) && cpu_have_named_feature(ASIMD))
                crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
 }
 
index dd843d0..83a2338 100644 (file)
@@ -220,12 +220,13 @@ static int __init neon_poly1305_mod_init(void)
 
        static_branch_enable(&have_neon);
 
-       return crypto_register_shash(&neon_poly1305_alg);
+       return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
+               crypto_register_shash(&neon_poly1305_alg) : 0;
 }
 
 static void __exit neon_poly1305_mod_exit(void)
 {
-       if (cpu_have_named_feature(ASIMD))
+       if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && cpu_have_named_feature(ASIMD))
                crypto_unregister_shash(&neon_poly1305_alg);
 }
 
index 98a5405..bd23f87 100644 (file)
@@ -16,7 +16,6 @@ generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += mmiowb.h
-generic-y += msi.h
 generic-y += qrwlock.h
 generic-y += qspinlock.h
 generic-y += serial.h
index 0b6919c..197c473 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef _ASM_C6X_PGTABLE_H
 #define _ASM_C6X_PGTABLE_H
 
-#include <asm-generic/4level-fixup.h>
+#include <asm-generic/pgtable-nopud.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
diff --git a/arch/hexagon/include/uapi/asm/bitsperlong.h b/arch/hexagon/include/uapi/asm/bitsperlong.h
deleted file mode 100644 (file)
index 5adca0d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#ifndef __ASM_HEXAGON_BITSPERLONG_H
-#define __ASM_HEXAGON_BITSPERLONG_H
-
-#define __BITS_PER_LONG 32
-
-#include <asm-generic/bitsperlong.h>
-
-#endif
index 7904f59..eb0db20 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_IA64_IOMMU_H
 #define _ASM_IA64_IOMMU_H 1
 
+#include <linux/acpi.h>
+
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10)
 
@@ -9,6 +11,9 @@ extern void no_iommu_init(void);
 #ifdef CONFIG_INTEL_IOMMU
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
+
+static inline int __init
+arch_rmrr_sanity_check(struct acpi_dmar_reserved_memory *rmrr) { return 0; }
 #else
 #define no_iommu               (1)
 #define iommu_detected         (0)
index d97f843..1dc30f1 100644 (file)
@@ -36,11 +36,7 @@ static inline void arch_maybe_save_ip(unsigned long flags)
 static inline unsigned long arch_local_save_flags(void)
 {
        ia64_stop();
-#ifdef CONFIG_PARAVIRT
-       return ia64_get_psr_i();
-#else
        return ia64_getreg(_IA64_REG_PSR);
-#endif
 }
 
 static inline unsigned long arch_local_irq_save(void)
diff --git a/arch/ia64/include/uapi/asm/errno.h b/arch/ia64/include/uapi/asm/errno.h
deleted file mode 100644 (file)
index 9addba5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#include <asm-generic/errno.h>
index c60696f..ecfa3ea 100644 (file)
@@ -31,7 +31,7 @@ extern void ia64_bad_param_for_setreg (void);
 extern void ia64_bad_param_for_getreg (void);
 
 
-#define ia64_native_setreg(regnum, val)                                                \
+#define ia64_setreg(regnum, val)                                               \
 ({                                                                             \
        switch (regnum) {                                                       \
            case _IA64_REG_PSR_L:                                               \
@@ -60,7 +60,7 @@ extern void ia64_bad_param_for_getreg (void);
        }                                                                       \
 })
 
-#define ia64_native_getreg(regnum)                                             \
+#define ia64_getreg(regnum)                                                    \
 ({                                                                             \
        __u64 ia64_intri_res;                                                   \
                                                                                \
@@ -384,7 +384,7 @@ extern void ia64_bad_param_for_getreg (void);
 
 #define ia64_invala() asm volatile ("invala" ::: "memory")
 
-#define ia64_native_thash(addr)                                                        \
+#define ia64_thash(addr)                                                       \
 ({                                                                             \
        unsigned long ia64_intri_res;                                           \
        asm volatile ("thash %0=%1" : "=r"(ia64_intri_res) : "r" (addr));       \
@@ -437,10 +437,10 @@ extern void ia64_bad_param_for_getreg (void);
 #define ia64_set_pmd(index, val)                                               \
        asm volatile ("mov pmd[%0]=%1" :: "r"(index), "r"(val) : "memory")
 
-#define ia64_native_set_rr(index, val)                                                 \
+#define ia64_set_rr(index, val)                                                        \
        asm volatile ("mov rr[%0]=%1" :: "r"(index), "r"(val) : "memory");
 
-#define ia64_native_get_cpuid(index)                                                   \
+#define ia64_get_cpuid(index)                                                          \
 ({                                                                                     \
        unsigned long ia64_intri_res;                                                   \
        asm volatile ("mov %0=cpuid[%r1]" : "=r"(ia64_intri_res) : "rO"(index));        \
@@ -476,33 +476,33 @@ extern void ia64_bad_param_for_getreg (void);
 })
 
 
-#define ia64_native_get_pmd(index)                                             \
+#define ia64_get_pmd(index)                                                    \
 ({                                                                             \
        unsigned long ia64_intri_res;                                           \
        asm volatile ("mov %0=pmd[%1]" : "=r"(ia64_intri_res) : "r"(index));    \
        ia64_intri_res;                                                         \
 })
 
-#define ia64_native_get_rr(index)                                              \
+#define ia64_get_rr(index)                                                     \
 ({                                                                             \
        unsigned long ia64_intri_res;                                           \
        asm volatile ("mov %0=rr[%1]" : "=r"(ia64_intri_res) : "r" (index));    \
        ia64_intri_res;                                                         \
 })
 
-#define ia64_native_fc(addr)   asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_fc(addr)  asm volatile ("fc %0" :: "r"(addr) : "memory")
 
 
 #define ia64_sync_i()  asm volatile (";; sync.i" ::: "memory")
 
-#define ia64_native_ssm(mask)  asm volatile ("ssm %0":: "i"((mask)) : "memory")
-#define ia64_native_rsm(mask)  asm volatile ("rsm %0":: "i"((mask)) : "memory")
+#define ia64_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory")
+#define ia64_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory")
 #define ia64_sum(mask) asm volatile ("sum %0":: "i"((mask)) : "memory")
 #define ia64_rum(mask) asm volatile ("rum %0":: "i"((mask)) : "memory")
 
 #define ia64_ptce(addr)        asm volatile ("ptc.e %0" :: "r"(addr))
 
-#define ia64_native_ptcga(addr, size)                                          \
+#define ia64_ptcga(addr, size)                                                 \
 do {                                                                           \
        asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory");       \
        ia64_dv_serialize_data();                                               \
@@ -607,7 +607,7 @@ do {                                                                                \
         }                                                              \
 })
 
-#define ia64_native_intrin_local_irq_restore(x)                        \
+#define ia64_intrin_local_irq_restore(x)                       \
 do {                                                           \
        asm volatile (";;   cmp.ne p6,p7=%0,r0;;"               \
                      "(p6) ssm psr.i;"                         \
index ab64969..dc1884d 100644 (file)
@@ -17,8 +17,8 @@
                         * intrinsic
                         */
 
-#define ia64_native_getreg     __getReg
-#define ia64_native_setreg     __setReg
+#define ia64_getreg            __getReg
+#define ia64_setreg            __setReg
 
 #define ia64_hint              __hint
 #define ia64_hint_pause                __hint_pause
 #define ia64_invala_fr         __invala_fr
 #define ia64_nop               __nop
 #define ia64_sum               __sum
-#define ia64_native_ssm                __ssm
+#define ia64_ssm               __ssm
 #define ia64_rum               __rum
-#define ia64_native_rsm                __rsm
-#define ia64_native_fc                 __fc
+#define ia64_rsm               __rsm
+#define ia64_fc                        __fc
 
 #define ia64_ldfs              __ldfs
 #define ia64_ldfd              __ldfd
                __setIndReg(_IA64_REG_INDR_PMC, index, val)
 #define ia64_set_pmd(index, val)       \
                __setIndReg(_IA64_REG_INDR_PMD, index, val)
-#define ia64_native_set_rr(index, val) \
+#define ia64_set_rr(index, val)                \
                __setIndReg(_IA64_REG_INDR_RR, index, val)
 
-#define ia64_native_get_cpuid(index)   \
+#define ia64_get_cpuid(index)  \
                __getIndReg(_IA64_REG_INDR_CPUID, index)
 #define __ia64_get_dbr(index)          __getIndReg(_IA64_REG_INDR_DBR, index)
 #define ia64_get_ibr(index)            __getIndReg(_IA64_REG_INDR_IBR, index)
 #define ia64_get_pkr(index)            __getIndReg(_IA64_REG_INDR_PKR, index)
 #define ia64_get_pmc(index)            __getIndReg(_IA64_REG_INDR_PMC, index)
-#define ia64_native_get_pmd(index)     __getIndReg(_IA64_REG_INDR_PMD, index)
-#define ia64_native_get_rr(index)      __getIndReg(_IA64_REG_INDR_RR, index)
+#define ia64_get_pmd(index)            __getIndReg(_IA64_REG_INDR_PMD, index)
+#define ia64_get_rr(index)             __getIndReg(_IA64_REG_INDR_RR, index)
 
 #define ia64_srlz_d            __dsrlz
 #define ia64_srlz_i            __isrlz
 #define ia64_ld8_acq           __ld8_acq
 
 #define ia64_sync_i            __synci
-#define ia64_native_thash      __thash
-#define ia64_native_ttag       __ttag
+#define ia64_thash             __thash
+#define ia64_ttag              __ttag
 #define ia64_itcd              __itcd
 #define ia64_itci              __itci
 #define ia64_itrd              __itrd
 #define ia64_itri              __itri
 #define ia64_ptce              __ptce
 #define ia64_ptcl              __ptcl
-#define ia64_native_ptcg       __ptcg
-#define ia64_native_ptcga      __ptcga
+#define ia64_ptcg              __ptcg
+#define ia64_ptcga             __ptcga
 #define ia64_ptri              __ptri
 #define ia64_ptrd              __ptrd
 #define ia64_dep_mi            _m64_dep_mi
 #define ia64_lfetch_fault      __lfetch_fault
 #define ia64_lfetch_fault_excl __lfetch_fault_excl
 
-#define ia64_native_intrin_local_irq_restore(x)                \
+#define ia64_intrin_local_irq_restore(x)               \
 do {                                                   \
        if ((x) != 0) {                                 \
-               ia64_native_ssm(IA64_PSR_I);            \
+               ia64_ssm(IA64_PSR_I);                   \
                ia64_srlz_d();                          \
        } else {                                        \
-               ia64_native_rsm(IA64_PSR_I);            \
+               ia64_rsm(IA64_PSR_I);                   \
        }                                               \
 } while (0)
 
index aecc217..a0e0a06 100644 (file)
 #endif
 #include <asm/cmpxchg.h>
 
-#define ia64_native_get_psr_i()        (ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I)
-
-#define ia64_native_set_rr0_to_rr4(val0, val1, val2, val3, val4)       \
+#define ia64_set_rr0_to_rr4(val0, val1, val2, val3, val4)              \
 do {                                                                   \
-       ia64_native_set_rr(0x0000000000000000UL, (val0));               \
-       ia64_native_set_rr(0x2000000000000000UL, (val1));               \
-       ia64_native_set_rr(0x4000000000000000UL, (val2));               \
-       ia64_native_set_rr(0x6000000000000000UL, (val3));               \
-       ia64_native_set_rr(0x8000000000000000UL, (val4));               \
+       ia64_set_rr(0x0000000000000000UL, (val0));                      \
+       ia64_set_rr(0x2000000000000000UL, (val1));                      \
+       ia64_set_rr(0x4000000000000000UL, (val2));                      \
+       ia64_set_rr(0x6000000000000000UL, (val3));                      \
+       ia64_set_rr(0x8000000000000000UL, (val4));                      \
 } while (0)
 
 /*
@@ -85,41 +83,4 @@ extern unsigned long __bad_increment_for_ia64_fetch_and_add (void);
 
 #endif
 
-
-#ifndef __ASSEMBLY__
-
-#define IA64_INTRINSIC_API(name)       ia64_native_ ## name
-#define IA64_INTRINSIC_MACRO(name)     ia64_native_ ## name
-
-
-/************************************************/
-/* Instructions paravirtualized for correctness */
-/************************************************/
-/* fc, thash, get_cpuid, get_pmd, get_eflags, set_eflags */
-/* Note that "ttag" and "cover" are also privilege-sensitive; "ttag"
- * is not currently used (though it may be in a long-format VHPT system!)
- */
-#define ia64_fc                                IA64_INTRINSIC_API(fc)
-#define ia64_thash                     IA64_INTRINSIC_API(thash)
-#define ia64_get_cpuid                 IA64_INTRINSIC_API(get_cpuid)
-#define ia64_get_pmd                   IA64_INTRINSIC_API(get_pmd)
-
-
-/************************************************/
-/* Instructions paravirtualized for performance */
-/************************************************/
-#define ia64_ssm                       IA64_INTRINSIC_MACRO(ssm)
-#define ia64_rsm                       IA64_INTRINSIC_MACRO(rsm)
-#define ia64_getreg                    IA64_INTRINSIC_MACRO(getreg)
-#define ia64_setreg                    IA64_INTRINSIC_API(setreg)
-#define ia64_set_rr                    IA64_INTRINSIC_API(set_rr)
-#define ia64_get_rr                    IA64_INTRINSIC_API(get_rr)
-#define ia64_ptcga                     IA64_INTRINSIC_API(ptcga)
-#define ia64_get_psr_i                 IA64_INTRINSIC_API(get_psr_i)
-#define ia64_intrin_local_irq_restore  \
-       IA64_INTRINSIC_API(intrin_local_irq_restore)
-#define ia64_set_rr0_to_rr4            IA64_INTRINSIC_API(set_rr0_to_rr4)
-
-#endif /* !__ASSEMBLY__ */
-
 #endif /* _UAPI_ASM_IA64_INTRINSICS_H */
diff --git a/arch/ia64/include/uapi/asm/ioctl.h b/arch/ia64/include/uapi/asm/ioctl.h
deleted file mode 100644 (file)
index b809c45..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#include <asm-generic/ioctl.h>
diff --git a/arch/ia64/include/uapi/asm/ioctls.h b/arch/ia64/include/uapi/asm/ioctls.h
deleted file mode 100644 (file)
index b860019..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _ASM_IA64_IOCTLS_H
-#define _ASM_IA64_IOCTLS_H
-
-#include <asm-generic/ioctls.h>
-
-#endif /* _ASM_IA64_IOCTLS_H */
index 52d312d..d43a027 100644 (file)
@@ -108,7 +108,7 @@ ret_from_exception:
        btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel */
        jeq     Luser_return            /* if so, skip resched, signals */
 
-#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPTION
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
index b34d44d..82ec54c 100644 (file)
@@ -28,9 +28,6 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
        return (pmd_t *) pgd;
 }
 
-#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); })
-#define pmd_alloc_one(mm, address)      ({ BUG(); ((pmd_t *)2); })
-
 #define pmd_populate(mm, pmd, page) (pmd_val(*pmd) = \
        (unsigned long)(page_address(page)))
 
@@ -45,8 +42,6 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page,
        __free_page(page);
 }
 
-#define __pmd_free_tlb(tlb, pmd, address) do { } while (0)
-
 static inline struct page *pte_alloc_one(struct mm_struct *mm)
 {
        struct page *page = alloc_pages(GFP_DMA, 0);
@@ -100,6 +95,4 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return new_pgd;
 }
 
-#define pgd_populate(mm, pmd, pte) BUG()
-
 #endif /* M68K_MCF_PGALLOC_H */
index 5d5502c..b9f45ae 100644 (file)
@@ -198,17 +198,9 @@ static inline int pmd_bad2(pmd_t *pmd) { return 0; }
 #define pmd_present(pmd) (!pmd_none2(&(pmd)))
 static inline void pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; }
 
-static inline int pgd_none(pgd_t pgd) { return 0; }
-static inline int pgd_bad(pgd_t pgd) { return 0; }
-static inline int pgd_present(pgd_t pgd) { return 1; }
-static inline void pgd_clear(pgd_t *pgdp) {}
-
 #define pte_ERROR(e) \
        printk(KERN_ERR "%s:%d: bad pte %08lx.\n",      \
        __FILE__, __LINE__, pte_val(e))
-#define pmd_ERROR(e) \
-       printk(KERN_ERR "%s:%d: bad pmd %08lx.\n",      \
-       __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
        printk(KERN_ERR "%s:%d: bad pgd %08lx.\n",      \
        __FILE__, __LINE__, pgd_val(e))
@@ -339,14 +331,6 @@ extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
  */
 #define pgd_offset_k(address)  pgd_offset(&init_mm, address)
 
-/*
- * Find an entry in the second-level pagetable.
- */
-static inline pmd_t *pmd_offset(pgd_t *pgd, unsigned long address)
-{
-       return (pmd_t *) pgd;
-}
-
 /*
  * Find an entry in the third-level pagetable.
  */
@@ -360,12 +344,16 @@ static inline pmd_t *pmd_offset(pgd_t *pgd, unsigned long address)
 static inline void nocache_page(void *vaddr)
 {
        pgd_t *dir;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
        unsigned long addr = (unsigned long) vaddr;
 
        dir = pgd_offset_k(addr);
-       pmdp = pmd_offset(dir, addr);
+       p4dp = p4d_offset(dir, addr);
+       pudp = pud_offset(p4dp, addr);
+       pmdp = pmd_offset(pudp, addr);
        ptep = pte_offset_kernel(pmdp, addr);
        *ptep = pte_mknocache(*ptep);
 }
@@ -376,12 +364,16 @@ static inline void nocache_page(void *vaddr)
 static inline void cache_page(void *vaddr)
 {
        pgd_t *dir;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
        unsigned long addr = (unsigned long) vaddr;
 
        dir = pgd_offset_k(addr);
-       pmdp = pmd_offset(dir, addr);
+       p4dp = p4d_offset(dir, addr);
+       pudp = pud_offset(p4dp, addr);
+       pmdp = pmd_offset(pudp, addr);
        ptep = pte_offset_kernel(pmdp, addr);
        *ptep = pte_mkcache(*ptep);
 }
index f5b1852..cac9f28 100644 (file)
@@ -100,6 +100,8 @@ static inline void load_ksp_mmu(struct task_struct *task)
        struct mm_struct *mm;
        int asid;
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        unsigned long mmuar;
@@ -127,7 +129,15 @@ static inline void load_ksp_mmu(struct task_struct *task)
        if (pgd_none(*pgd))
                goto bug;
 
-       pmd = pmd_offset(pgd, mmuar);
+       p4d = p4d_offset(pgd, mmuar);
+       if (p4d_none(*p4d))
+               goto bug;
+
+       pud = pud_offset(p4d, mmuar);
+       if (pud_none(*pud))
+               goto bug;
+
+       pmd = pmd_offset(pud, mmuar);
        if (pmd_none(*pmd))
                goto bug;
 
index acab315..ff9cc40 100644 (file)
@@ -106,9 +106,9 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
-       pgd_set(pgd, pmd);
+       pud_set(pud, pmd);
 }
 
 #endif /* _MOTOROLA_PGALLOC_H */
index 7f66a7b..62bedc6 100644 (file)
@@ -117,14 +117,14 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
        }
 }
 
-static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp)
+static inline void pud_set(pud_t *pudp, pmd_t *pmdp)
 {
-       pgd_val(*pgdp) = _PAGE_TABLE | _PAGE_ACCESSED | __pa(pmdp);
+       pud_val(*pudp) = _PAGE_TABLE | _PAGE_ACCESSED | __pa(pmdp);
 }
 
 #define __pte_page(pte) ((unsigned long)__va(pte_val(pte) & PAGE_MASK))
 #define __pmd_page(pmd) ((unsigned long)__va(pmd_val(pmd) & _TABLE_MASK))
-#define __pgd_page(pgd) ((unsigned long)__va(pgd_val(pgd) & _TABLE_MASK))
+#define pud_page_vaddr(pud) ((unsigned long)__va(pud_val(pud) & _TABLE_MASK))
 
 
 #define pte_none(pte)          (!pte_val(pte))
@@ -147,11 +147,11 @@ static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp)
 #define pmd_page(pmd)          virt_to_page(__va(pmd_val(pmd)))
 
 
-#define pgd_none(pgd)          (!pgd_val(pgd))
-#define pgd_bad(pgd)           ((pgd_val(pgd) & _DESCTYPE_MASK) != _PAGE_TABLE)
-#define pgd_present(pgd)       (pgd_val(pgd) & _PAGE_TABLE)
-#define pgd_clear(pgdp)                ({ pgd_val(*pgdp) = 0; })
-#define pgd_page(pgd)          (mem_map + ((unsigned long)(__va(pgd_val(pgd)) - PAGE_OFFSET) >> PAGE_SHIFT))
+#define pud_none(pud)          (!pud_val(pud))
+#define pud_bad(pud)           ((pud_val(pud) & _DESCTYPE_MASK) != _PAGE_TABLE)
+#define pud_present(pud)       (pud_val(pud) & _PAGE_TABLE)
+#define pud_clear(pudp)                ({ pud_val(*pudp) = 0; })
+#define pud_page(pud)          (mem_map + ((unsigned long)(__va(pud_val(pud)) - PAGE_OFFSET) >> PAGE_SHIFT))
 
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
@@ -209,9 +209,9 @@ static inline pgd_t *pgd_offset_k(unsigned long address)
 
 
 /* Find an entry in the second-level page table.. */
-static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
+static inline pmd_t *pmd_offset(pud_t *dir, unsigned long address)
 {
-       return (pmd_t *)__pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1));
+       return (pmd_t *)pud_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1));
 }
 
 /* Find an entry in the third-level page table.. */
@@ -239,11 +239,15 @@ static inline void nocache_page(void *vaddr)
 
        if (CPU_IS_040_OR_060) {
                pgd_t *dir;
+               p4d_t *p4dp;
+               pud_t *pudp;
                pmd_t *pmdp;
                pte_t *ptep;
 
                dir = pgd_offset_k(addr);
-               pmdp = pmd_offset(dir, addr);
+               p4dp = p4d_offset(dir, addr);
+               pudp = pud_offset(p4dp, addr);
+               pmdp = pmd_offset(pudp, addr);
                ptep = pte_offset_kernel(pmdp, addr);
                *ptep = pte_mknocache(*ptep);
        }
@@ -255,11 +259,15 @@ static inline void cache_page(void *vaddr)
 
        if (CPU_IS_040_OR_060) {
                pgd_t *dir;
+               p4d_t *p4dp;
+               pud_t *pudp;
                pmd_t *pmdp;
                pte_t *ptep;
 
                dir = pgd_offset_k(addr);
-               pmdp = pmd_offset(dir, addr);
+               p4dp = p4d_offset(dir, addr);
+               pudp = pud_offset(p4dp, addr);
+               pmdp = pmd_offset(pudp, addr);
                ptep = pte_offset_kernel(pmdp, addr);
                *ptep = pte_mkcache(*ptep);
        }
index 700d819..05e1e1e 100644 (file)
 /*
  * These are used to make use of C type-checking..
  */
-typedef struct { unsigned long pte; } pte_t;
+#if !defined(CONFIG_MMU) || CONFIG_PGTABLE_LEVELS == 3
 typedef struct { unsigned long pmd[16]; } pmd_t;
+#define pmd_val(x)     ((&x)->pmd[0])
+#define __pmd(x)       ((pmd_t) { { (x) }, })
+#endif
+
+typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 typedef struct page *pgtable_t;
 
 #define pte_val(x)     ((x).pte)
-#define pmd_val(x)     ((&x)->pmd[0])
 #define pgd_val(x)     ((x).pgd)
 #define pgprot_val(x)  ((x).pgprot)
 
 #define __pte(x)       ((pte_t) { (x) } )
-#define __pmd(x)       ((pmd_t) { { (x) }, })
 #define __pgd(x)       ((pgd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
 
index 646c174..2bf5c35 100644 (file)
@@ -2,7 +2,12 @@
 #ifndef _M68K_PGTABLE_H
 #define _M68K_PGTABLE_H
 
-#include <asm-generic/4level-fixup.h>
+
+#if defined(CONFIG_SUN3) || defined(CONFIG_COLDFIRE)
+#include <asm-generic/pgtable-nopmd.h>
+#else
+#include <asm-generic/pgtable-nopud.h>
+#endif
 
 #include <asm/setup.h>
 
@@ -30,9 +35,7 @@
 
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
-#ifdef CONFIG_SUN3
-#define PMD_SHIFT       17
-#else
+#if CONFIG_PGTABLE_LEVELS == 3
 #define PMD_SHIFT      22
 #endif
 #define PMD_SIZE       (1UL << PMD_SHIFT)
index c18165b..ccc4568 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _M68KNOMMU_PGTABLE_H
 #define _M68KNOMMU_PGTABLE_H
 
-#include <asm-generic/4level-fixup.h>
+#include <asm-generic/pgtable-nopud.h>
 
 /*
  * (C) Copyright 2000-2002, Greg Ungerer <gerg@snapgear.com>
index 8561211..11b95da 100644 (file)
@@ -17,8 +17,6 @@
 
 extern const char bad_pmd_string[];
 
-#define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
-
 #define __pte_free_tlb(tlb,pte,addr)                   \
 do {                                                   \
        pgtable_pte_page_dtor(pte);                     \
@@ -41,7 +39,6 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page
  * inside the pgd, so has no extra memory associated with it.
  */
 #define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb, x, addr)   do { } while (0)
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
@@ -58,6 +55,4 @@ static inline pgd_t * pgd_alloc(struct mm_struct *mm)
      return new_pgd;
 }
 
-#define pgd_populate(mm, pmd, pte) BUG()
-
 #endif /* SUN3_PGALLOC_H */
index c987d50..bc41552 100644 (file)
@@ -110,11 +110,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 #define pmd_set(pmdp,ptep) do {} while (0)
 
-static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp)
-{
-       pgd_val(*pgdp) = virt_to_phys(pmdp);
-}
-
 #define __pte_page(pte) \
 ((unsigned long) __va ((pte_val (pte) & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT))
 #define __pmd_page(pmd) \
@@ -145,16 +140,9 @@ static inline int pmd_present2 (pmd_t *pmd) { return pmd_val (*pmd) & SUN3_PMD_V
 #define pmd_present(pmd) (!pmd_none2(&(pmd)))
 static inline void pmd_clear (pmd_t *pmdp) { pmd_val (*pmdp) = 0; }
 
-static inline int pgd_none (pgd_t pgd) { return 0; }
-static inline int pgd_bad (pgd_t pgd) { return 0; }
-static inline int pgd_present (pgd_t pgd) { return 1; }
-static inline void pgd_clear (pgd_t *pgdp) {}
-
 
 #define pte_ERROR(e) \
        pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
-#define pmd_ERROR(e) \
-       pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
        pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
@@ -194,12 +182,6 @@ extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
 /* Find an entry in a kernel pagetable directory. */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-/* Find an entry in the second-level pagetable. */
-static inline pmd_t *pmd_offset (pgd_t *pgd, unsigned long address)
-{
-       return (pmd_t *) pgd;
-}
-
 /* Find an entry in the third-level pagetable. */
 #define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
 #define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address))
index 6363ec8..18a4de7 100644 (file)
@@ -465,6 +465,8 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
        for (;;) {
                struct mm_struct *mm = current->mm;
                pgd_t *pgd;
+               p4d_t *p4d;
+               pud_t *pud;
                pmd_t *pmd;
                pte_t *pte;
                spinlock_t *ptl;
@@ -474,7 +476,13 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
                pgd = pgd_offset(mm, (unsigned long)mem);
                if (!pgd_present(*pgd))
                        goto bad_access;
-               pmd = pmd_offset(pgd, (unsigned long)mem);
+               p4d = p4d_offset(pgd, (unsigned long)mem);
+               if (!p4d_present(*p4d))
+                       goto bad_access;
+               pud = pud_offset(p4d, (unsigned long)mem);
+               if (!pud_present(*pud))
+                       goto bad_access;
+               pmd = pmd_offset(pud, (unsigned long)mem);
                if (!pmd_present(*pmd))
                        goto bad_access;
                pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
index 778cacb..27c453f 100644 (file)
@@ -130,8 +130,10 @@ static inline void init_pointer_tables(void)
        /* insert pointer tables allocated so far into the tablelist */
        init_pointer_table((unsigned long)kernel_pg_dir);
        for (i = 0; i < PTRS_PER_PGD; i++) {
-               if (pgd_present(kernel_pg_dir[i]))
-                       init_pointer_table(__pgd_page(kernel_pg_dir[i]));
+               pud_t *pud = (pud_t *)(&kernel_pg_dir[i]);
+
+               if (pud_present(*pud))
+                       init_pointer_table(pgd_page_vaddr(kernel_pg_dir[i]));
        }
 
        /* insert also pointer table that we used to unmap the zero page */
index 23f9466..120030a 100644 (file)
@@ -63,18 +63,23 @@ static void __free_io_area(void *addr, unsigned long size)
 {
        unsigned long virtaddr = (unsigned long)addr;
        pgd_t *pgd_dir;
+       p4d_t *p4d_dir;
+       pud_t *pud_dir;
        pmd_t *pmd_dir;
        pte_t *pte_dir;
 
        while ((long)size > 0) {
                pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
+               p4d_dir = p4d_offset(pgd_dir, virtaddr);
+               pud_dir = pud_offset(p4d_dir, virtaddr);
+               if (pud_bad(*pud_dir)) {
+                       printk("iounmap: bad pud(%08lx)\n", pud_val(*pud_dir));
+                       pud_clear(pud_dir);
                        return;
                }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+               pmd_dir = pmd_offset(pud_dir, virtaddr);
 
+#if CONFIG_PGTABLE_LEVELS == 3
                if (CPU_IS_020_OR_030) {
                        int pmd_off = (virtaddr/PTRTREESIZE) & 15;
                        int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
@@ -87,6 +92,7 @@ static void __free_io_area(void *addr, unsigned long size)
                        } else if (pmd_type == 0)
                                continue;
                }
+#endif
 
                if (pmd_bad(*pmd_dir)) {
                        printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
@@ -159,6 +165,8 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla
        unsigned long virtaddr, retaddr;
        long offset;
        pgd_t *pgd_dir;
+       p4d_t *p4d_dir;
+       pud_t *pud_dir;
        pmd_t *pmd_dir;
        pte_t *pte_dir;
 
@@ -245,18 +253,23 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla
                        printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
 #endif
                pgd_dir = pgd_offset_k(virtaddr);
-               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
+               p4d_dir = p4d_offset(pgd_dir, virtaddr);
+               pud_dir = pud_offset(p4d_dir, virtaddr);
+               pmd_dir = pmd_alloc(&init_mm, pud_dir, virtaddr);
                if (!pmd_dir) {
                        printk("ioremap: no mem for pmd_dir\n");
                        return NULL;
                }
 
+#if CONFIG_PGTABLE_LEVELS == 3
                if (CPU_IS_020_OR_030) {
                        pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
                        physaddr += PTRTREESIZE;
                        virtaddr += PTRTREESIZE;
                        size -= PTRTREESIZE;
-               } else {
+               } else
+#endif
+               {
                        pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
                        if (!pte_dir) {
                                printk("ioremap: no mem for pte_dir\n");
@@ -307,6 +320,8 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
 {
        unsigned long virtaddr = (unsigned long)addr;
        pgd_t *pgd_dir;
+       p4d_t *p4d_dir;
+       pud_t *pud_dir;
        pmd_t *pmd_dir;
        pte_t *pte_dir;
 
@@ -341,13 +356,16 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
 
        while ((long)size > 0) {
                pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
+               p4d_dir = p4d_offset(pgd_dir, virtaddr);
+               pud_dir = pud_offset(p4d_dir, virtaddr);
+               if (pud_bad(*pud_dir)) {
+                       printk("iocachemode: bad pud(%08lx)\n", pud_val(*pud_dir));
+                       pud_clear(pud_dir);
                        return;
                }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+               pmd_dir = pmd_offset(pud_dir, virtaddr);
 
+#if CONFIG_PGTABLE_LEVELS == 3
                if (CPU_IS_020_OR_030) {
                        int pmd_off = (virtaddr/PTRTREESIZE) & 15;
 
@@ -359,6 +377,7 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
                                continue;
                        }
                }
+#endif
 
                if (pmd_bad(*pmd_dir)) {
                        printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
index 6cb1e41..0ea3756 100644 (file)
@@ -92,6 +92,8 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word)
        unsigned long flags, mmuar, mmutr;
        struct mm_struct *mm;
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        int asid;
@@ -113,7 +115,19 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word)
                return -1;
        }
 
-       pmd = pmd_offset(pgd, mmuar);
+       p4d = p4d_offset(pgd, mmuar);
+       if (p4d_none(*p4d)) {
+               local_irq_restore(flags);
+               return -1;
+       }
+
+       pud = pud_offset(p4d, mmuar);
+       if (pud_none(*pud)) {
+               local_irq_restore(flags);
+               return -1;
+       }
+
+       pmd = pmd_offset(pud, mmuar);
        if (pmd_none(*pmd)) {
                local_irq_restore(flags);
                return -1;
index 356601b..4857985 100644 (file)
@@ -82,9 +82,11 @@ static pmd_t * __init kernel_ptr_table(void)
                 */
                last = (unsigned long)kernel_pg_dir;
                for (i = 0; i < PTRS_PER_PGD; i++) {
-                       if (!pgd_present(kernel_pg_dir[i]))
+                       pud_t *pud = (pud_t *)(&kernel_pg_dir[i]);
+
+                       if (!pud_present(*pud))
                                continue;
-                       pmd = __pgd_page(kernel_pg_dir[i]);
+                       pmd = pgd_page_vaddr(kernel_pg_dir[i]);
                        if (pmd > last)
                                last = pmd;
                }
@@ -118,6 +120,8 @@ static void __init map_node(int node)
 #define ROOTTREESIZE (32*1024*1024)
        unsigned long physaddr, virtaddr, size;
        pgd_t *pgd_dir;
+       p4d_t *p4d_dir;
+       pud_t *pud_dir;
        pmd_t *pmd_dir;
        pte_t *pte_dir;
 
@@ -149,14 +153,16 @@ static void __init map_node(int node)
                                continue;
                        }
                }
-               if (!pgd_present(*pgd_dir)) {
+               p4d_dir = p4d_offset(pgd_dir, virtaddr);
+               pud_dir = pud_offset(p4d_dir, virtaddr);
+               if (!pud_present(*pud_dir)) {
                        pmd_dir = kernel_ptr_table();
 #ifdef DEBUG
                        printk ("[new pointer %p]", pmd_dir);
 #endif
-                       pgd_set(pgd_dir, pmd_dir);
+                       pud_set(pud_dir, pmd_dir);
                } else
-                       pmd_dir = pmd_offset(pgd_dir, virtaddr);
+                       pmd_dir = pmd_offset(pud_dir, virtaddr);
 
                if (CPU_IS_020_OR_030) {
                        if (virtaddr) {
@@ -304,4 +310,3 @@ void __init paging_init(void)
                        node_set_state(i, N_NORMAL_MEMORY);
        }
 }
-
index 89e630e..c4b8aa1 100644 (file)
@@ -80,6 +80,8 @@ inline int dvma_map_cpu(unsigned long kaddr,
                               unsigned long vaddr, int len)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        unsigned long end;
        int ret = 0;
 
@@ -90,12 +92,14 @@ inline int dvma_map_cpu(unsigned long kaddr,
 
        pr_debug("dvma: mapping kern %08lx to virt %08lx\n", kaddr, vaddr);
        pgd = pgd_offset_k(vaddr);
+       p4d = p4d_offset(pgd, vaddr);
+       pud = pud_offset(p4d, vaddr);
 
        do {
                pmd_t *pmd;
                unsigned long end2;
 
-               if((pmd = pmd_alloc(&init_mm, pgd, vaddr)) == NULL) {
+               if((pmd = pmd_alloc(&init_mm, pud, vaddr)) == NULL) {
                        ret = -ENOMEM;
                        goto out;
                }
@@ -196,4 +200,3 @@ void dvma_unmap_iommu(unsigned long baddr, int len)
        }
 
 }
-
index d506bb0..f4b44b2 100644 (file)
@@ -90,7 +90,6 @@ typedef struct { unsigned long        pte; }          pte_t;
 typedef struct { unsigned long pgprot; }       pgprot_t;
 /* FIXME this can depend on linux kernel version */
 #   ifdef CONFIG_MMU
-typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 #   else /* CONFIG_MMU */
 typedef struct { unsigned long ste[64]; }      pmd_t;
@@ -103,7 +102,6 @@ typedef struct { p4d_t              pge[1]; }       pgd_t;
 # define pgprot_val(x) ((x).pgprot)
 
 #   ifdef CONFIG_MMU
-#   define pmd_val(x)      ((x).pmd)
 #   define pgd_val(x)      ((x).pgd)
 #   else  /* CONFIG_MMU */
 #   define pmd_val(x)  ((x).ste[0])
@@ -112,7 +110,6 @@ typedef struct { p4d_t              pge[1]; }       pgd_t;
 #   endif  /* CONFIG_MMU */
 
 # define __pte(x)      ((pte_t) { (x) })
-# define __pmd(x)      ((pmd_t) { (x) })
 # define __pgd(x)      ((pgd_t) { (x) })
 # define __pgprot(x)   ((pgprot_t) { (x) })
 
index 7ecb05b..fcf1e23 100644 (file)
@@ -41,13 +41,6 @@ static inline void free_pgd(pgd_t *pgd)
 
 #define pmd_pgtable(pmd)       pmd_page(pmd)
 
-/*
- * We don't have any real pmd's, and this code never triggers because
- * the pgd will always be present..
- */
-#define pmd_alloc_one_fast(mm, address)        ({ BUG(); ((pmd_t *)1); })
-#define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
-
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm);
 
 #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
@@ -58,15 +51,6 @@ extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm);
 #define pmd_populate_kernel(mm, pmd, pte) \
                (pmd_val(*(pmd)) = (unsigned long) (pte))
 
-/*
- * We don't have any real pmd's, and this code never triggers because
- * the pgd will always be present..
- */
-#define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb, x, addr)   pmd_free((tlb)->mm, x)
-#define pgd_populate(mm, pmd, pte)     BUG()
-
 #endif /* CONFIG_MMU */
 
 #endif /* _ASM_MICROBLAZE_PGALLOC_H */
index 954b69a..2def331 100644 (file)
@@ -59,9 +59,7 @@ extern int mem_init_done;
 
 #else /* CONFIG_MMU */
 
-#include <asm-generic/4level-fixup.h>
-
-#define __PAGETABLE_PMD_FOLDED 1
+#include <asm-generic/pgtable-nopmd.h>
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
@@ -138,13 +136,8 @@ static inline pte_t pte_mkspecial(pte_t pte)       { return pte; }
  *
  */
 
-/* PMD_SHIFT determines the size of the area mapped by the PTE pages */
-#define PMD_SHIFT      (PAGE_SHIFT + PTE_SHIFT)
-#define PMD_SIZE       (1UL << PMD_SHIFT)
-#define PMD_MASK       (~(PMD_SIZE-1))
-
 /* PGDIR_SHIFT determines what a top-level page table entry can map */
-#define PGDIR_SHIFT    PMD_SHIFT
+#define PGDIR_SHIFT    (PAGE_SHIFT + PTE_SHIFT)
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
@@ -165,9 +158,6 @@ static inline pte_t pte_mkspecial(pte_t pte)        { return pte; }
 #define pte_ERROR(e) \
        printk(KERN_ERR "%s:%d: bad pte "PTE_FMT".\n", \
                __FILE__, __LINE__, pte_val(e))
-#define pmd_ERROR(e) \
-       printk(KERN_ERR "%s:%d: bad pmd %08lx.\n", \
-               __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
        printk(KERN_ERR "%s:%d: bad pgd %08lx.\n", \
                __FILE__, __LINE__, pgd_val(e))
@@ -313,18 +303,6 @@ extern unsigned long empty_zero_page[1024];
        __pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) | pgprot_val(prot))
 
 #ifndef __ASSEMBLY__
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-static inline int pgd_none(pgd_t pgd)          { return 0; }
-static inline int pgd_bad(pgd_t pgd)           { return 0; }
-static inline int pgd_present(pgd_t pgd)       { return 1; }
-#define pgd_clear(xp)                          do { } while (0)
-#define pgd_page(pgd) \
-       ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
-
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -479,12 +457,6 @@ static inline void ptep_mkdirty(struct mm_struct *mm,
 #define pgd_index(address)      ((address) >> PGDIR_SHIFT)
 #define pgd_offset(mm, address)         ((mm)->pgd + pgd_index(address))
 
-/* Find an entry in the second-level page table.. */
-static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
-{
-       return (pmd_t *) dir;
-}
-
 /* Find an entry in the third-level page table.. */
 #define pte_index(address)             \
        (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
index cdd4feb..c9125c3 100644 (file)
@@ -160,6 +160,9 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
        int err = 0, sig = ksig->sig;
        unsigned long address = 0;
 #ifdef CONFIG_MMU
+       pgd_t *pgdp;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
 #endif
@@ -195,9 +198,10 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 
        address = ((unsigned long)frame->tramp);
 #ifdef CONFIG_MMU
-       pmdp = pmd_offset(pud_offset(
-                       pgd_offset(current->mm, address),
-                                       address), address);
+       pgdp = pgd_offset(current->mm, address);
+       p4dp = p4d_offset(pgdp, address);
+       pudp = pud_offset(p4dp, address);
+       pmdp = pmd_offset(pudp, address);
 
        preempt_disable();
        ptep = pte_offset_map(pmdp, address);
index a015a95..050fc62 100644 (file)
@@ -53,8 +53,11 @@ EXPORT_SYMBOL(kmap_prot);
 
 static inline pte_t *virt_to_kpte(unsigned long vaddr)
 {
-       return pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr),
-                       vaddr), vaddr);
+       pgd_t *pgd = pgd_offset_k(vaddr);
+       p4d_t *p4d = p4d_offset(pgd, vaddr);
+       pud_t *pud = pud_offset(p4d, vaddr);
+
+       return pte_offset_kernel(pmd_offset(pud, vaddr), vaddr);
 }
 
 static void __init highmem_init(void)
index 010bb9c..68c26ca 100644 (file)
@@ -134,11 +134,16 @@ EXPORT_SYMBOL(iounmap);
 
 int map_page(unsigned long va, phys_addr_t pa, int flags)
 {
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pd;
        pte_t *pg;
        int err = -ENOMEM;
+
        /* Use upper 10 bits of VA to index the first level map */
-       pd = pmd_offset(pgd_offset_k(va), va);
+       p4d = p4d_offset(pgd_offset_k(va), va);
+       pud = pud_offset(p4d, va);
+       pd = pmd_offset(pud, va);
        /* Use middle 10 bits of VA to index the second-level map */
        pg = pte_alloc_kernel(pd, va); /* from powerpc - pgtable.c */
        /* pg = pte_alloc_kernel(&init_mm, pd, va); */
@@ -188,13 +193,17 @@ void __init mapin_ram(void)
 static int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
 {
        pgd_t   *pgd;
+       p4d_t   *p4d;
+       pud_t   *pud;
        pmd_t   *pmd;
        pte_t   *pte;
        int     retval = 0;
 
        pgd = pgd_offset(mm, addr & PAGE_MASK);
        if (pgd) {
-               pmd = pmd_offset(pgd, addr & PAGE_MASK);
+               p4d = p4d_offset(pgd, addr & PAGE_MASK);
+               pud = pud_offset(p4d, addr & PAGE_MASK);
+               pmd = pmd_offset(pud, addr & PAGE_MASK);
                if (pmd_present(*pmd)) {
                        pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
                        if (pte) {
index 779e399..d1fd23e 100644 (file)
@@ -128,12 +128,14 @@ static struct skcipher_alg algs[] = {
 
 static int __init chacha_simd_mod_init(void)
 {
-       return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+       return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
+               crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
 }
 
 static void __exit chacha_simd_mod_fini(void)
 {
-       crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+       if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER))
+               crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
 }
 
 module_init(chacha_simd_mod_init);
index b759b6c..b37d29c 100644 (file)
@@ -187,12 +187,14 @@ static struct shash_alg mips_poly1305_alg = {
 
 static int __init mips_poly1305_mod_init(void)
 {
-       return crypto_register_shash(&mips_poly1305_alg);
+       return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
+               crypto_register_shash(&mips_poly1305_alg) : 0;
 }
 
 static void __exit mips_poly1305_mod_exit(void)
 {
-       crypto_unregister_shash(&mips_poly1305_alg);
+       if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
+               crypto_unregister_shash(&mips_poly1305_alg);
 }
 
 module_init(mips_poly1305_mod_init);
index c8b595c..61b0fc2 100644 (file)
@@ -13,7 +13,6 @@ generic-y += irq_work.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += msi.h
 generic-y += parport.h
 generic-y += percpu.h
 generic-y += preempt.h
index 9e0c2e2..128af72 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _ASM_MSGBUF_H
 #define _ASM_MSGBUF_H
 
+#include <asm/ipcbuf.h>
 
 /*
  * The msqid64_ds structure for the MIPS architecture.
index 43e1b4a..ba7fe0c 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_SEMBUF_H
 #define _ASM_SEMBUF_H
 
+#include <asm/ipcbuf.h>
+
 /*
  * The semid64_ds structure for the MIPS architecture.
  * Note extra padding because this structure is passed back and forth
index 5a2a821..c3909bd 100644 (file)
@@ -115,7 +115,7 @@ ip32_rtc_platform_data[] = {
                .bcd_mode = true,
                .no_irq = false,
                .uie_unsupported = false,
-               .alloc_io_resources = true,
+               .access_type = ds1685_reg_direct,
                .plat_prepare_poweroff = ip32_prepare_poweroff,
        },
 };
index 8feb1fa..86b3201 100644 (file)
@@ -41,17 +41,14 @@ void clear_page(void *page);
 void copy_page(void *to, void *from);
 
 typedef unsigned long pte_t;
-typedef unsigned long pmd_t;
 typedef unsigned long pgd_t;
 typedef unsigned long pgprot_t;
 
 #define pte_val(x)      (x)
-#define pmd_val(x)      (x)
 #define pgd_val(x)     (x)
 #define pgprot_val(x)   (x)
 
 #define __pte(x)        (x)
-#define __pmd(x)        (x)
 #define __pgd(x)        (x)
 #define __pgprot(x)     (x)
 
index 37125e6..85c1173 100644 (file)
@@ -15,9 +15,6 @@
 /*
  * Since we have only two-level page tables, these are trivial
  */
-#define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(mm, pmd)                      do { } while (0)
-#define pgd_populate(mm, pmd, pte)     BUG()
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
index 6fbf251..0214e41 100644 (file)
@@ -4,8 +4,7 @@
 #ifndef _ASMNDS32_PGTABLE_H
 #define _ASMNDS32_PGTABLE_H
 
-#define __PAGETABLE_PMD_FOLDED 1
-#include <asm-generic/4level-fixup.h>
+#include <asm-generic/pgtable-nopmd.h>
 #include <linux/sizes.h>
 
 #include <asm/memory.h>
 #ifdef CONFIG_ANDES_PAGE_SIZE_4KB
 #define PGDIR_SHIFT      22
 #define PTRS_PER_PGD     1024
-#define PMD_SHIFT        22
-#define PTRS_PER_PMD     1
 #define PTRS_PER_PTE     1024
 #endif
 
 #ifdef CONFIG_ANDES_PAGE_SIZE_8KB
 #define PGDIR_SHIFT      24
 #define PTRS_PER_PGD     256
-#define PMD_SHIFT        24
-#define PTRS_PER_PMD     1
 #define PTRS_PER_PTE     2048
 #endif
 
 #ifndef __ASSEMBLY__
 extern void __pte_error(const char *file, int line, unsigned long val);
-extern void __pmd_error(const char *file, int line, unsigned long val);
 extern void __pgd_error(const char *file, int line, unsigned long val);
 
 #define pte_ERROR(pte)         __pte_error(__FILE__, __LINE__, pte_val(pte))
-#define pmd_ERROR(pmd)         __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
 #define pgd_ERROR(pgd)         __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
 #endif /* !__ASSEMBLY__ */
 
@@ -368,9 +361,6 @@ static inline pmd_t __mk_pmd(pte_t * ptep, unsigned long prot)
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(addr)      pgd_offset(&init_mm, addr)
 
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, addr)  ((pmd_t *)(dir))
-
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const unsigned long mask = 0xfff;
index a8aff1c..6726038 100644 (file)
@@ -7,6 +7,5 @@
 #include <asm-generic/tlb.h>
 
 #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
-#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tln)->mm, pmd)
 
 #endif
index ffa8040..e25700e 100644 (file)
@@ -14,6 +14,7 @@ unsigned int *phy_addr_sp_tmp;
 static void nds32_suspend2ram(void)
 {
        pgd_t *pgdv;
+       p4d_t *p4dv;
        pud_t *pudv;
        pmd_t *pmdv;
        pte_t *ptev;
@@ -21,7 +22,8 @@ static void nds32_suspend2ram(void)
        pgdv = (pgd_t *)__va((__nds32__mfsr(NDS32_SR_L1_PPTB) &
                L1_PPTB_mskBASE)) + pgd_index((unsigned int)cpu_resume);
 
-       pudv = pud_offset(pgdv, (unsigned int)cpu_resume);
+       p4dv = p4d_offset(pgdv, (unsigned int)cpu_resume);
+       pudv = pud_offset(p4dv, (unsigned int)cpu_resume);
        pmdv = pmd_offset(pudv, (unsigned int)cpu_resume);
        ptev = pte_offset_map(pmdv, (unsigned int)cpu_resume);
 
index 064ae5d..906dfb2 100644 (file)
@@ -31,6 +31,8 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
        pr_alert("[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
 
        do {
+               p4d_t *p4d;
+               pud_t *pud;
                pmd_t *pmd;
 
                if (pgd_none(*pgd))
@@ -41,7 +43,9 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
                        break;
                }
 
-               pmd = pmd_offset(pgd, addr);
+               p4d = p4d_offset(pgd, addr);
+               pud = pud_offset(p4d, addr);
+               pmd = pmd_offset(pud, addr);
 #if PTRS_PER_PMD != 1
                pr_alert(", *pmd=%08lx", pmd_val(*pmd));
 #endif
@@ -359,6 +363,7 @@ vmalloc_fault:
 
                unsigned int index = pgd_index(addr);
                pgd_t *pgd, *pgd_k;
+               p4d_t *p4d, *p4d_k;
                pud_t *pud, *pud_k;
                pmd_t *pmd, *pmd_k;
                pte_t *pte_k;
@@ -369,8 +374,13 @@ vmalloc_fault:
                if (!pgd_present(*pgd_k))
                        goto no_context;
 
-               pud = pud_offset(pgd, addr);
-               pud_k = pud_offset(pgd_k, addr);
+               p4d = p4d_offset(pgd, addr);
+               p4d_k = p4d_offset(pgd_k, addr);
+               if (!p4d_present(*p4d_k))
+                       goto no_context;
+
+               pud = pud_offset(p4d, addr);
+               pud_k = pud_offset(p4d_k, addr);
                if (!pud_present(*pud_k))
                        goto no_context;
 
index 55703b0..0be3833 100644 (file)
@@ -54,6 +54,7 @@ static void __init map_ram(void)
 {
        unsigned long v, p, e;
        pgd_t *pge;
+       p4d_t *p4e;
        pud_t *pue;
        pmd_t *pme;
        pte_t *pte;
@@ -69,7 +70,8 @@ static void __init map_ram(void)
 
        while (p < e) {
                int j;
-               pue = pud_offset(pge, v);
+               p4e = p4d_offset(pge, v);
+               pue = pud_offset(p4e, v);
                pme = pmd_offset(pue, v);
 
                if ((u32) pue != (u32) pge || (u32) pme != (u32) pge) {
@@ -100,6 +102,7 @@ static void __init fixedrange_init(void)
 {
        unsigned long vaddr;
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
 #ifdef CONFIG_HIGHMEM
@@ -111,7 +114,8 @@ static void __init fixedrange_init(void)
         */
        vaddr = __fix_to_virt(__end_of_fixed_addresses - 1);
        pgd = swapper_pg_dir + pgd_index(vaddr);
-       pud = pud_offset(pgd, vaddr);
+       p4d = p4d_offset(pgd, vaddr);
+       pud = pud_offset(p4d, vaddr);
        pmd = pmd_offset(pud, vaddr);
        fixmap_pmd_p = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
        if (!fixmap_pmd_p)
@@ -126,7 +130,8 @@ static void __init fixedrange_init(void)
        vaddr = PKMAP_BASE;
 
        pgd = swapper_pg_dir + pgd_index(vaddr);
-       pud = pud_offset(pgd, vaddr);
+       p4d = p4d_offset(pgd, vaddr);
+       pud = pud_offset(p4d, vaddr);
        pmd = pmd_offset(pud, vaddr);
        pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
        if (!pte)
index 3b43798..8503bee 100644 (file)
@@ -74,6 +74,8 @@ void setup_mm_for_reboot(char mode)
 {
        unsigned long pmdval;
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        int i;
 
@@ -84,7 +86,9 @@ void setup_mm_for_reboot(char mode)
 
        for (i = 0; i < USER_PTRS_PER_PGD; i++) {
                pmdval = (i << PGDIR_SHIFT);
-               pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
+               p4d = p4d_offset(pgd, i << PGDIR_SHIFT);
+               pud = pud_offset(p4d, i << PGDIR_SHIFT);
+               pmd = pmd_offset(pud + i, i << PGDIR_SHIFT);
                set_pmd(pmd, __pmd(pmdval));
        }
 }
index ba80992..837ae77 100644 (file)
@@ -16,10 +16,14 @@ extern struct cache_info L1_cache_info[2];
 
 int va_kernel_present(unsigned long addr)
 {
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *ptep, pte;
 
-       pmd = pmd_offset(pgd_offset_k(addr), addr);
+       p4d = p4d_offset(pgd_offset_k(addr), addr);
+       pud = pud_offset(p4d, addr);
+       pmd = pmd_offset(pud, addr);
        if (!pmd_none(*pmd)) {
                ptep = pte_offset_map(pmd, addr);
                pte = *ptep;
@@ -32,20 +36,24 @@ int va_kernel_present(unsigned long addr)
 pte_t va_present(struct mm_struct * mm, unsigned long addr)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *ptep, pte;
 
        pgd = pgd_offset(mm, addr);
        if (!pgd_none(*pgd)) {
-               pud = pud_offset(pgd, addr);
-               if (!pud_none(*pud)) {
-                       pmd = pmd_offset(pud, addr);
-                       if (!pmd_none(*pmd)) {
-                               ptep = pte_offset_map(pmd, addr);
-                               pte = *ptep;
-                               if (pte_present(pte))
-                                       return pte;
+               p4d = p4d_offset(pgd, addr);
+               if (!p4d_none(*p4d)) {
+                       pud = pud_offset(p4d, addr);
+                       if (!pud_none(*pud)) {
+                               pmd = pmd_offset(pud, addr);
+                               if (!pmd_none(*pmd)) {
+                                       ptep = pte_offset_map(pmd, addr);
+                                       pte = *ptep;
+                                       if (pte_present(pte))
+                                               return pte;
+                               }
                        }
                }
        }
index bf326f0..1928e06 100644 (file)
@@ -13,7 +13,7 @@ config OPENRISC
        select IRQ_DOMAIN
        select HANDLE_DOMAIN_IRQ
        select GPIOLIB
-        select HAVE_ARCH_TRACEHOOK
+       select HAVE_ARCH_TRACEHOOK
        select SPARSE_IRQ
        select GENERIC_IRQ_CHIP
        select GENERIC_IRQ_PROBE
@@ -51,12 +51,12 @@ config NO_IOPORT_MAP
        def_bool y
 
 config TRACE_IRQFLAGS_SUPPORT
-        def_bool y
+       def_bool y
 
 # For now, use generic checksum functions
 #These can be reimplemented in assembly later if so inclined
 config GENERIC_CSUM
-        def_bool y
+       def_bool y
 
 config STACKTRACE_SUPPORT
        def_bool y
@@ -89,8 +89,8 @@ config DCACHE_WRITETHROUGH
          If unsure say N here
 
 config OPENRISC_BUILTIN_DTB
-        string "Builtin DTB"
-        default ""
+       string "Builtin DTB"
+       default ""
 
 menu "Class II Instructions"
 
@@ -161,13 +161,13 @@ config OPENRISC_HAVE_SHADOW_GPRS
          On a unicore system it's safe to say N here if you are unsure.
 
 config CMDLINE
-        string "Default kernel command string"
-        default ""
-        help
-          On some architectures there is currently no way for the boot loader
-          to pass arguments to the kernel. For these architectures, you should
-          supply some command-line options at build time by entering them
-          here.
+       string "Default kernel command string"
+       default ""
+       help
+         On some architectures there is currently no way for the boot loader
+         to pass arguments to the kernel. For these architectures, you should
+         supply some command-line options at build time by entering them
+         here.
 
 menu "Debugging options"
 
@@ -185,7 +185,7 @@ config OPENRISC_ESR_EXCEPTION_BUG_CHECK
        default n
        help
          This option enables some checks that might expose some problems
-          in kernel.
+         in kernel.
 
          Say N if you are unsure.
 
index 93caf17..796ae29 100644 (file)
@@ -42,48 +42,54 @@ typedef struct { unsigned long pte; } pte_t; /* either 32 or 64bit */
 
 /* NOTE: even on 64 bits, these entries are __u32 because we allocate
  * the pmd and pgd in ZONE_DMA (i.e. under 4GB) */
-typedef struct { __u32 pmd; } pmd_t;
 typedef struct { __u32 pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 
-#define pte_val(x)     ((x).pte)
-/* These do not work lvalues, so make sure we don't use them as such. */
+#if CONFIG_PGTABLE_LEVELS == 3
+typedef struct { __u32 pmd; } pmd_t;
+#define __pmd(x)       ((pmd_t) { (x) } )
+/* pXd_val() do not work as lvalues, so make sure we don't use them as such. */
 #define pmd_val(x)     ((x).pmd + 0)
+#endif
+
+#define pte_val(x)     ((x).pte)
 #define pgd_val(x)     ((x).pgd + 0)
 #define pgprot_val(x)  ((x).pgprot)
 
 #define __pte(x)       ((pte_t) { (x) } )
-#define __pmd(x)       ((pmd_t) { (x) } )
 #define __pgd(x)       ((pgd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
 
-#define __pmd_val_set(x,n) (x).pmd = (n)
-#define __pgd_val_set(x,n) (x).pgd = (n)
-
 #else
 /*
  * .. while these make it easier on the compiler
  */
 typedef unsigned long pte_t;
+
+#if CONFIG_PGTABLE_LEVELS == 3
 typedef         __u32 pmd_t;
+#define pmd_val(x)      (x)
+#define __pmd(x)       (x)
+#endif
+
 typedef         __u32 pgd_t;
 typedef unsigned long pgprot_t;
 
 #define pte_val(x)      (x)
-#define pmd_val(x)      (x)
 #define pgd_val(x)      (x)
 #define pgprot_val(x)   (x)
 
 #define __pte(x)        (x)
-#define __pmd(x)       (x)
 #define __pgd(x)        (x)
 #define __pgprot(x)     (x)
 
-#define __pmd_val_set(x,n) (x) = (n)
-#define __pgd_val_set(x,n) (x) = (n)
-
 #endif /* STRICT_MM_TYPECHECKS */
 
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#if CONFIG_PGTABLE_LEVELS == 3
+#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
+#endif
+
 typedef struct page *pgtable_t;
 
 typedef struct __physmem_range {
index d98647c..9ac74da 100644 (file)
@@ -34,13 +34,13 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
                /* Populate first pmd with allocated memory.  We mark it
                 * with PxD_FLAG_ATTACHED as a signal to the system that this
                 * pmd entry may not be cleared. */
-               __pgd_val_set(*actual_pgd, (PxD_FLAG_PRESENT | 
-                                       PxD_FLAG_VALID | 
-                                       PxD_FLAG_ATTACHED) 
-                       + (__u32)(__pa((unsigned long)pgd) >> PxD_VALUE_SHIFT));
+               set_pgd(actual_pgd, __pgd((PxD_FLAG_PRESENT |
+                                       PxD_FLAG_VALID |
+                                       PxD_FLAG_ATTACHED)
+                       + (__u32)(__pa((unsigned long)pgd) >> PxD_VALUE_SHIFT)));
                /* The first pmd entry also is marked with PxD_FLAG_ATTACHED as
                 * a signal that this pmd may not be freed */
-               __pgd_val_set(*pgd, PxD_FLAG_ATTACHED);
+               set_pgd(pgd, __pgd(PxD_FLAG_ATTACHED));
 #endif
        }
        spin_lock_init(pgd_spinlock(actual_pgd));
@@ -59,10 +59,10 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 
 /* Three Level Page Table Support for pmd's */
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
-       __pgd_val_set(*pgd, (PxD_FLAG_PRESENT | PxD_FLAG_VALID) +
-                       (__u32)(__pa((unsigned long)pmd) >> PxD_VALUE_SHIFT));
+       set_pud(pud, __pud((PxD_FLAG_PRESENT | PxD_FLAG_VALID) +
+                       (__u32)(__pa((unsigned long)pmd) >> PxD_VALUE_SHIFT)));
 }
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
@@ -88,19 +88,6 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
-#else
-
-/* Two Level Page Table Support for pmd's */
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-
-#define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(mm, x)                        do { } while (0)
-#define pgd_populate(mm, pmd, pte)     BUG()
-
 #endif
 
 static inline void
@@ -110,14 +97,14 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
        /* preserve the gateway marker if this is the beginning of
         * the permanent pmd */
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
-               __pmd_val_set(*pmd, (PxD_FLAG_PRESENT |
-                                PxD_FLAG_VALID |
-                                PxD_FLAG_ATTACHED) 
-                       + (__u32)(__pa((unsigned long)pte) >> PxD_VALUE_SHIFT));
+               set_pmd(pmd, __pmd((PxD_FLAG_PRESENT |
+                               PxD_FLAG_VALID |
+                               PxD_FLAG_ATTACHED)
+                       + (__u32)(__pa((unsigned long)pte) >> PxD_VALUE_SHIFT)));
        else
 #endif
-               __pmd_val_set(*pmd, (PxD_FLAG_PRESENT | PxD_FLAG_VALID) 
-                       + (__u32)(__pa((unsigned long)pte) >> PxD_VALUE_SHIFT));
+               set_pmd(pmd, __pmd((PxD_FLAG_PRESENT | PxD_FLAG_VALID)
+                       + (__u32)(__pa((unsigned long)pte) >> PxD_VALUE_SHIFT)));
 }
 
 #define pmd_populate(mm, pmd, pte_page) \
index 4ac374b..f0a3659 100644 (file)
@@ -3,7 +3,12 @@
 #define _PARISC_PGTABLE_H
 
 #include <asm/page.h>
-#include <asm-generic/4level-fixup.h>
+
+#if CONFIG_PGTABLE_LEVELS == 3
+#include <asm-generic/pgtable-nopud.h>
+#elif CONFIG_PGTABLE_LEVELS == 2
+#include <asm-generic/pgtable-nopmd.h>
+#endif
 
 #include <asm/fixmap.h>
 
@@ -101,8 +106,10 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#if CONFIG_PGTABLE_LEVELS == 3
 #define pmd_ERROR(e) \
        printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, (unsigned long)pmd_val(e))
+#endif
 #define pgd_ERROR(e) \
        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
 
@@ -132,19 +139,18 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 #define PTRS_PER_PTE    (1UL << BITS_PER_PTE)
 
 /* Definitions for 2nd level */
+#if CONFIG_PGTABLE_LEVELS == 3
 #define PMD_SHIFT       (PLD_SHIFT + BITS_PER_PTE)
 #define PMD_SIZE       (1UL << PMD_SHIFT)
 #define PMD_MASK       (~(PMD_SIZE-1))
-#if CONFIG_PGTABLE_LEVELS == 3
 #define BITS_PER_PMD   (PAGE_SHIFT + PMD_ORDER - BITS_PER_PMD_ENTRY)
+#define PTRS_PER_PMD    (1UL << BITS_PER_PMD)
 #else
-#define __PAGETABLE_PMD_FOLDED 1
 #define BITS_PER_PMD   0
 #endif
-#define PTRS_PER_PMD    (1UL << BITS_PER_PMD)
 
 /* Definitions for 1st level */
-#define PGDIR_SHIFT    (PMD_SHIFT + BITS_PER_PMD)
+#define PGDIR_SHIFT    (PLD_SHIFT + BITS_PER_PTE + BITS_PER_PMD)
 #if (PGDIR_SHIFT + PAGE_SHIFT + PGD_ORDER - BITS_PER_PGD_ENTRY) > BITS_PER_LONG
 #define BITS_PER_PGD   (BITS_PER_LONG - PGDIR_SHIFT)
 #else
@@ -317,6 +323,8 @@ extern unsigned long *empty_zero_page;
 
 #define pmd_flag(x)    (pmd_val(x) & PxD_FLAG_MASK)
 #define pmd_address(x) ((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
+#define pud_flag(x)    (pud_val(x) & PxD_FLAG_MASK)
+#define pud_address(x) ((unsigned long)(pud_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
 #define pgd_flag(x)    (pgd_val(x) & PxD_FLAG_MASK)
 #define pgd_address(x) ((unsigned long)(pgd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
 
@@ -334,42 +342,32 @@ static inline void pmd_clear(pmd_t *pmd) {
        if (pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
                /* This is the entry pointing to the permanent pmd
                 * attached to the pgd; cannot clear it */
-               __pmd_val_set(*pmd, PxD_FLAG_ATTACHED);
+               set_pmd(pmd, __pmd(PxD_FLAG_ATTACHED));
        else
 #endif
-               __pmd_val_set(*pmd,  0);
+               set_pmd(pmd,  __pmd(0));
 }
 
 
 
 #if CONFIG_PGTABLE_LEVELS == 3
-#define pgd_page_vaddr(pgd) ((unsigned long) __va(pgd_address(pgd)))
-#define pgd_page(pgd)  virt_to_page((void *)pgd_page_vaddr(pgd))
+#define pud_page_vaddr(pud) ((unsigned long) __va(pud_address(pud)))
+#define pud_page(pud)  virt_to_page((void *)pud_page_vaddr(pud))
 
 /* For 64 bit we have three level tables */
 
-#define pgd_none(x)     (!pgd_val(x))
-#define pgd_bad(x)      (!(pgd_flag(x) & PxD_FLAG_VALID))
-#define pgd_present(x)  (pgd_flag(x) & PxD_FLAG_PRESENT)
-static inline void pgd_clear(pgd_t *pgd) {
+#define pud_none(x)     (!pud_val(x))
+#define pud_bad(x)      (!(pud_flag(x) & PxD_FLAG_VALID))
+#define pud_present(x)  (pud_flag(x) & PxD_FLAG_PRESENT)
+static inline void pud_clear(pud_t *pud) {
 #if CONFIG_PGTABLE_LEVELS == 3
-       if(pgd_flag(*pgd) & PxD_FLAG_ATTACHED)
-               /* This is the permanent pmd attached to the pgd; cannot
+       if(pud_flag(*pud) & PxD_FLAG_ATTACHED)
+               /* This is the permanent pmd attached to the pud; cannot
                 * free it */
                return;
 #endif
-       __pgd_val_set(*pgd, 0);
+       set_pud(pud, __pud(0));
 }
-#else
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-static inline int pgd_none(pgd_t pgd)          { return 0; }
-static inline int pgd_bad(pgd_t pgd)           { return 0; }
-static inline int pgd_present(pgd_t pgd)       { return 1; }
-static inline void pgd_clear(pgd_t * pgdp)     { }
 #endif
 
 /*
@@ -452,7 +450,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #if CONFIG_PGTABLE_LEVELS == 3
 #define pmd_index(addr)         (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
 #define pmd_offset(dir,address) \
-((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(address))
+((pmd_t *) pud_page_vaddr(*(dir)) + pmd_index(address))
 #else
 #define pmd_offset(dir,addr) ((pmd_t *) dir)
 #endif
index 8c0446b..44235f3 100644 (file)
@@ -4,7 +4,9 @@
 
 #include <asm-generic/tlb.h>
 
+#if CONFIG_PGTABLE_LEVELS == 3
 #define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+#endif
 #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
 
 #endif
index 3b87733..3b4de5b 100644 (file)
@@ -3,6 +3,7 @@
 #define _PARISC_MSGBUF_H
 
 #include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
 
 /* 
  * The msqid64_ds structure for parisc architecture, copied from sparc.
index 8241cf1..e2ca430 100644 (file)
@@ -3,6 +3,7 @@
 #define _PARISC_SEMBUF_H
 
 #include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
 
 /* 
  * The semid64_ds structure for parisc architecture.
index 2407b0b..1eedfec 100644 (file)
@@ -534,11 +534,14 @@ static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
        pte_t *ptep = NULL;
 
        if (!pgd_none(*pgd)) {
-               pud_t *pud = pud_offset(pgd, addr);
-               if (!pud_none(*pud)) {
-                       pmd_t *pmd = pmd_offset(pud, addr);
-                       if (!pmd_none(*pmd))
-                               ptep = pte_offset_map(pmd, addr);
+               p4d_t *p4d = p4d_offset(pgd, addr);
+               if (!p4d_none(*p4d)) {
+                       pud_t *pud = pud_offset(p4d, addr);
+                       if (!pud_none(*pud)) {
+                               pmd_t *pmd = pmd_offset(pud, addr);
+                               if (!pmd_none(*pmd))
+                                       ptep = pte_offset_map(pmd, addr);
+                       }
                }
        }
        return ptep;
index a60d47f..0f1b460 100644 (file)
@@ -133,9 +133,14 @@ static inline int map_uncached_pages(unsigned long vaddr, unsigned long size,
 
        dir = pgd_offset_k(vaddr);
        do {
+               p4d_t *p4d;
+               pud_t *pud;
                pmd_t *pmd;
-               
-               pmd = pmd_alloc(NULL, dir, vaddr);
+
+               p4d = p4d_offset(dir, vaddr);
+               pud = pud_offset(p4d, vaddr);
+               pmd = pmd_alloc(NULL, pud, vaddr);
+
                if (!pmd)
                        return -ENOMEM;
                if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr))
index 474cd24..e2d8b0a 100644 (file)
@@ -14,11 +14,13 @@ void notrace set_fixmap(enum fixed_addresses idx, phys_addr_t phys)
 {
        unsigned long vaddr = __fix_to_virt(idx);
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = pmd_offset(pgd, vaddr);
+       p4d_t *p4d = p4d_offset(pgd, vaddr);
+       pud_t *pud = pud_offset(p4d, vaddr);
+       pmd_t *pmd = pmd_offset(pud, vaddr);
        pte_t *pte;
 
        if (pmd_none(*pmd))
-               pmd = pmd_alloc(NULL, pgd, vaddr);
+               pmd = pmd_alloc(NULL, pud, vaddr);
 
        pte = pte_offset_kernel(pmd, vaddr);
        if (pte_none(*pte))
@@ -32,7 +34,9 @@ void notrace clear_fixmap(enum fixed_addresses idx)
 {
        unsigned long vaddr = __fix_to_virt(idx);
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = pmd_offset(pgd, vaddr);
+       p4d_t *p4d = p4d_offset(pgd, vaddr);
+       pud_t *pud = pud_offset(p4d, vaddr);
+       pmd_t *pmd = pmd_offset(pud, vaddr);
        pte_t *pte = pte_offset_kernel(pmd, vaddr);
 
        if (WARN_ON(pte_none(*pte)))
index d578809..0e1e212 100644 (file)
@@ -49,6 +49,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
                        unsigned long addr, unsigned long sz)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte = NULL;
@@ -61,7 +62,8 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
        addr &= HPAGE_MASK;
 
        pgd = pgd_offset(mm, addr);
-       pud = pud_alloc(mm, pgd, addr);
+       p4d = p4d_offset(pgd, addr);
+       pud = pud_alloc(mm, p4d, addr);
        if (pud) {
                pmd = pmd_alloc(mm, pud, addr);
                if (pmd)
@@ -74,6 +76,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
                       unsigned long addr, unsigned long sz)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte = NULL;
@@ -82,11 +85,14 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
 
        pgd = pgd_offset(mm, addr);
        if (!pgd_none(*pgd)) {
-               pud = pud_offset(pgd, addr);
-               if (!pud_none(*pud)) {
-                       pmd = pmd_offset(pud, addr);
-                       if (!pmd_none(*pmd))
-                               pte = pte_offset_map(pmd, addr);
+               p4d = p4d_offset(pgd, addr);
+               if (!p4d_none(*p4d)) {
+                       pud = pud_offset(p4d, addr);
+                       if (!pud_none(*pud)) {
+                               pmd = pmd_offset(pud, addr);
+                               if (!pmd_none(*pmd))
+                                       pte = pte_offset_map(pmd, addr);
+                       }
                }
        }
        return pte;
index e446bb5..1ec34e1 100644 (file)
@@ -452,6 +452,23 @@ config PPC_TRANSACTIONAL_MEM
        help
          Support user-mode Transactional Memory on POWERPC.
 
+config PPC_UV
+       bool "Ultravisor support"
+       depends on KVM_BOOK3S_HV_POSSIBLE
+       select ZONE_DEVICE
+       select DEV_PAGEMAP_OPS
+       select DEVICE_PRIVATE
+       select MEMORY_HOTPLUG
+       select MEMORY_HOTREMOVE
+       default n
+       help
+         This option paravirtualizes the kernel to run in POWER platforms that
+         supports the Protected Execution Facility (PEF). On such platforms,
+         the ultravisor firmware runs at a privilege level above the
+         hypervisor.
+
+         If unsure, say "N".
+
 config LD_HEAD_STUB_CATCH
        bool "Reserve 256 bytes to cope with linker stubs in HEAD text" if EXPERT
        depends on PPC64
index 2abc8e8..9757d4f 100644 (file)
@@ -6,6 +6,8 @@
 #include <string.h>
 
 #define INT_MAX                        ((int)(~0U>>1))
+#define UINT32_MAX             ((u32)~0U)
+#define INT32_MAX              ((s32)(UINT32_MAX >> 1))
 
 #include "of.h"
 
index 148bee2..d0a23d0 100644 (file)
@@ -11,5 +11,4 @@ generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += vtime.h
-generic-y += msi.h
 generic-y += early_ioremap.h
index a069dfc..4e697bc 100644 (file)
@@ -70,9 +70,6 @@ static inline int get_hugepd_cache_index(int index)
        /* should not reach */
 }
 
-#else /* !CONFIG_HUGETLB_PAGE */
-static inline int pmd_huge(pmd_t pmd) { return 0; }
-static inline int pud_huge(pud_t pud) { return 0; }
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #endif /* __ASSEMBLY__ */
index e3d4dd4..34d1018 100644 (file)
@@ -59,9 +59,6 @@ static inline int get_hugepd_cache_index(int index)
        BUG();
 }
 
-#else /* !CONFIG_HUGETLB_PAGE */
-static inline int pmd_huge(pmd_t pmd) { return 0; }
-static inline int pud_huge(pud_t pud) { return 0; }
 #endif /* CONFIG_HUGETLB_PAGE */
 
 static inline int remap_4k_pfn(struct vm_area_struct *vma, unsigned long addr,
index 1111202..13bd870 100644 (file)
 #define H_TLB_INVALIDATE       0xF808
 #define H_COPY_TOFROM_GUEST    0xF80C
 
+/* Flags for H_SVM_PAGE_IN */
+#define H_PAGE_IN_SHARED        0x1
+
+/* Platform-specific hcalls used by the Ultravisor */
+#define H_SVM_PAGE_IN          0xEF00
+#define H_SVM_PAGE_OUT         0xEF04
+#define H_SVM_INIT_START       0xEF08
+#define H_SVM_INIT_DONE                0xEF0C
+
 /* Values for 2nd argument to H_SET_MODE */
 #define H_SET_MODE_RESOURCE_SET_CIABR          1
 #define H_SET_MODE_RESOURCE_SET_DAWR           2
diff --git a/arch/powerpc/include/asm/kvm_book3s_uvmem.h b/arch/powerpc/include/asm/kvm_book3s_uvmem.h
new file mode 100644 (file)
index 0000000..50204e2
--- /dev/null
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_KVM_BOOK3S_UVMEM_H__
+#define __ASM_KVM_BOOK3S_UVMEM_H__
+
+#ifdef CONFIG_PPC_UV
+int kvmppc_uvmem_init(void);
+void kvmppc_uvmem_free(void);
+int kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot);
+void kvmppc_uvmem_slot_free(struct kvm *kvm,
+                           const struct kvm_memory_slot *slot);
+unsigned long kvmppc_h_svm_page_in(struct kvm *kvm,
+                                  unsigned long gra,
+                                  unsigned long flags,
+                                  unsigned long page_shift);
+unsigned long kvmppc_h_svm_page_out(struct kvm *kvm,
+                                   unsigned long gra,
+                                   unsigned long flags,
+                                   unsigned long page_shift);
+unsigned long kvmppc_h_svm_init_start(struct kvm *kvm);
+unsigned long kvmppc_h_svm_init_done(struct kvm *kvm);
+int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn);
+void kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
+                            struct kvm *kvm);
+#else
+static inline int kvmppc_uvmem_init(void)
+{
+       return 0;
+}
+
+static inline void kvmppc_uvmem_free(void) { }
+
+static inline int
+kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot)
+{
+       return 0;
+}
+
+static inline void
+kvmppc_uvmem_slot_free(struct kvm *kvm, const struct kvm_memory_slot *slot) { }
+
+static inline unsigned long
+kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gra,
+                    unsigned long flags, unsigned long page_shift)
+{
+       return H_UNSUPPORTED;
+}
+
+static inline unsigned long
+kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gra,
+                     unsigned long flags, unsigned long page_shift)
+{
+       return H_UNSUPPORTED;
+}
+
+static inline unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
+{
+       return H_UNSUPPORTED;
+}
+
+static inline unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
+{
+       return H_UNSUPPORTED;
+}
+
+static inline int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn)
+{
+       return -EFAULT;
+}
+
+static inline void
+kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
+                       struct kvm *kvm) { }
+#endif /* CONFIG_PPC_UV */
+#endif /* __ASM_KVM_BOOK3S_UVMEM_H__ */
index 4273e79..0a398f2 100644 (file)
@@ -275,6 +275,10 @@ struct kvm_hpt_info {
 
 struct kvm_resize_hpt;
 
+/* Flag values for kvm_arch.secure_guest */
+#define KVMPPC_SECURE_INIT_START 0x1 /* H_SVM_INIT_START has been called */
+#define KVMPPC_SECURE_INIT_DONE  0x2 /* H_SVM_INIT_DONE completed */
+
 struct kvm_arch {
        unsigned int lpid;
        unsigned int smt_mode;          /* # vcpus per virtual core */
@@ -330,6 +334,8 @@ struct kvm_arch {
 #endif
        struct kvmppc_ops *kvm_ops;
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       struct mutex uvmem_lock;
+       struct list_head uvmem_pfns;
        struct mutex mmu_setup_lock;    /* nests inside vcpu mutexes */
        u64 l1_ptcr;
        int max_nested_lpid;
index d63f649..3d2f871 100644 (file)
@@ -322,6 +322,7 @@ struct kvmppc_ops {
                               int size);
        int (*store_to_eaddr)(struct kvm_vcpu *vcpu, ulong *eaddr, void *ptr,
                              int size);
+       int (*svm_off)(struct kvm *kvm);
 };
 
 extern struct kvmppc_ops *kvmppc_hv_ops;
index 4fcda1d..b66f6db 100644 (file)
 #define UV_WRITE_PATE                  0xF104
 #define UV_RETURN                      0xF11C
 #define UV_ESM                         0xF110
+#define UV_REGISTER_MEM_SLOT           0xF120
+#define UV_UNREGISTER_MEM_SLOT         0xF124
+#define UV_PAGE_IN                     0xF128
+#define UV_PAGE_OUT                    0xF12C
 #define UV_SHARE_PAGE                  0xF130
 #define UV_UNSHARE_PAGE                        0xF134
 #define UV_UNSHARE_ALL_PAGES           0xF140
+#define UV_PAGE_INVAL                  0xF138
+#define UV_SVM_TERMINATE               0xF13C
 
 #endif /* _ASM_POWERPC_ULTRAVISOR_API_H */
index b1bc2e0..790b0e6 100644 (file)
@@ -46,4 +46,40 @@ static inline int uv_unshare_all_pages(void)
        return ucall_norets(UV_UNSHARE_ALL_PAGES);
 }
 
+static inline int uv_page_in(u64 lpid, u64 src_ra, u64 dst_gpa, u64 flags,
+                            u64 page_shift)
+{
+       return ucall_norets(UV_PAGE_IN, lpid, src_ra, dst_gpa, flags,
+                           page_shift);
+}
+
+static inline int uv_page_out(u64 lpid, u64 dst_ra, u64 src_gpa, u64 flags,
+                             u64 page_shift)
+{
+       return ucall_norets(UV_PAGE_OUT, lpid, dst_ra, src_gpa, flags,
+                           page_shift);
+}
+
+static inline int uv_register_mem_slot(u64 lpid, u64 start_gpa, u64 size,
+                                      u64 flags, u64 slotid)
+{
+       return ucall_norets(UV_REGISTER_MEM_SLOT, lpid, start_gpa,
+                           size, flags, slotid);
+}
+
+static inline int uv_unregister_mem_slot(u64 lpid, u64 slotid)
+{
+       return ucall_norets(UV_UNREGISTER_MEM_SLOT, lpid, slotid);
+}
+
+static inline int uv_page_inval(u64 lpid, u64 gpa, u64 page_shift)
+{
+       return ucall_norets(UV_PAGE_INVAL, lpid, gpa, page_shift);
+}
+
+static inline int uv_svm_terminate(u64 lpid)
+{
+       return ucall_norets(UV_SVM_TERMINATE, lpid);
+}
+
 #endif /* _ASM_POWERPC_ULTRAVISOR_H */
index 969bd83..7919b2b 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_POWERPC_MSGBUF_H
 #define _ASM_POWERPC_MSGBUF_H
 
+#include <asm/ipcbuf.h>
+
 /*
  * The msqid64_ds structure for the PowerPC architecture.
  * Note extra padding because this structure is passed back and forth
index 008ae77..85e96cc 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_POWERPC_SEMBUF_H
 #define _ASM_POWERPC_SEMBUF_H
 
+#include <asm/ipcbuf.h>
+
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 4c67cc7..2bfeaa1 100644 (file)
@@ -71,6 +71,9 @@ kvm-hv-y += \
        book3s_64_mmu_radix.o \
        book3s_hv_nested.o
 
+kvm-hv-$(CONFIG_PPC_UV) += \
+       book3s_hv_uvmem.o
+
 kvm-hv-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
        book3s_hv_tm.o
 
index 2d415c3..da857c8 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/pte-walk.h>
+#include <asm/ultravisor.h>
+#include <asm/kvm_book3s_uvmem.h>
 
 /*
  * Supported radix tree geometry.
@@ -915,6 +917,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
        if (!(dsisr & DSISR_PRTABLE_FAULT))
                gpa |= ea & 0xfff;
 
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE)
+               return kvmppc_send_page_to_uv(kvm, gfn);
+
        /* Get the corresponding memslot */
        memslot = gfn_to_memslot(kvm, gfn);
 
@@ -972,6 +977,11 @@ int kvm_unmap_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
        unsigned long gpa = gfn << PAGE_SHIFT;
        unsigned int shift;
 
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE) {
+               uv_page_inval(kvm->arch.lpid, gpa, PAGE_SHIFT);
+               return 0;
+       }
+
        ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
        if (ptep && pte_present(*ptep))
                kvmppc_unmap_pte(kvm, ptep, gpa, shift, memslot,
@@ -989,6 +999,9 @@ int kvm_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
        int ref = 0;
        unsigned long old, *rmapp;
 
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE)
+               return ref;
+
        ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
        if (ptep && pte_present(*ptep) && pte_young(*ptep)) {
                old = kvmppc_radix_update_pte(kvm, ptep, _PAGE_ACCESSED, 0,
@@ -1013,6 +1026,9 @@ int kvm_test_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
        unsigned int shift;
        int ref = 0;
 
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE)
+               return ref;
+
        ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
        if (ptep && pte_present(*ptep) && pte_young(*ptep))
                ref = 1;
@@ -1030,6 +1046,9 @@ static int kvm_radix_test_clear_dirty(struct kvm *kvm,
        int ret = 0;
        unsigned long old, *rmapp;
 
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE)
+               return ret;
+
        ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
        if (ptep && pte_present(*ptep) && pte_dirty(*ptep)) {
                ret = 1;
@@ -1082,6 +1101,12 @@ void kvmppc_radix_flush_memslot(struct kvm *kvm,
        unsigned long gpa;
        unsigned int shift;
 
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START)
+               kvmppc_uvmem_drop_pages(memslot, kvm);
+
+       if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE)
+               return;
+
        gpa = memslot->base_gfn << PAGE_SHIFT;
        spin_lock(&kvm->mmu_lock);
        for (n = memslot->npages; n; --n) {
index ec5c037..dc53578 100644 (file)
@@ -72,6 +72,9 @@
 #include <asm/xics.h>
 #include <asm/xive.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_book3s_uvmem.h>
+#include <asm/ultravisor.h>
 
 #include "book3s.h"
 
@@ -1070,6 +1073,25 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                                         kvmppc_get_gpr(vcpu, 5),
                                         kvmppc_get_gpr(vcpu, 6));
                break;
+       case H_SVM_PAGE_IN:
+               ret = kvmppc_h_svm_page_in(vcpu->kvm,
+                                          kvmppc_get_gpr(vcpu, 4),
+                                          kvmppc_get_gpr(vcpu, 5),
+                                          kvmppc_get_gpr(vcpu, 6));
+               break;
+       case H_SVM_PAGE_OUT:
+               ret = kvmppc_h_svm_page_out(vcpu->kvm,
+                                           kvmppc_get_gpr(vcpu, 4),
+                                           kvmppc_get_gpr(vcpu, 5),
+                                           kvmppc_get_gpr(vcpu, 6));
+               break;
+       case H_SVM_INIT_START:
+               ret = kvmppc_h_svm_init_start(vcpu->kvm);
+               break;
+       case H_SVM_INIT_DONE:
+               ret = kvmppc_h_svm_init_done(vcpu->kvm);
+               break;
+
        default:
                return RESUME_HOST;
        }
@@ -4494,6 +4516,29 @@ static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
        if (change == KVM_MR_FLAGS_ONLY && kvm_is_radix(kvm) &&
            ((new->flags ^ old->flags) & KVM_MEM_LOG_DIRTY_PAGES))
                kvmppc_radix_flush_memslot(kvm, old);
+       /*
+        * If UV hasn't yet called H_SVM_INIT_START, don't register memslots.
+        */
+       if (!kvm->arch.secure_guest)
+               return;
+
+       switch (change) {
+       case KVM_MR_CREATE:
+               if (kvmppc_uvmem_slot_init(kvm, new))
+                       return;
+               uv_register_mem_slot(kvm->arch.lpid,
+                                    new->base_gfn << PAGE_SHIFT,
+                                    new->npages * PAGE_SIZE,
+                                    0, new->id);
+               break;
+       case KVM_MR_DELETE:
+               uv_unregister_mem_slot(kvm->arch.lpid, old->id);
+               kvmppc_uvmem_slot_free(kvm, old);
+               break;
+       default:
+               /* TODO: Handle KVM_MR_MOVE */
+               break;
+       }
 }
 
 /*
@@ -4767,6 +4812,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
        char buf[32];
        int ret;
 
+       mutex_init(&kvm->arch.uvmem_lock);
+       INIT_LIST_HEAD(&kvm->arch.uvmem_pfns);
        mutex_init(&kvm->arch.mmu_setup_lock);
 
        /* Allocate the guest's logical partition ID */
@@ -4936,8 +4983,10 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
                if (nesting_enabled(kvm))
                        kvmhv_release_all_nested(kvm);
                kvm->arch.process_table = 0;
+               uv_svm_terminate(kvm->arch.lpid);
                kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
        }
+
        kvmppc_free_lpid(kvm->arch.lpid);
 
        kvmppc_free_pimap(kvm);
@@ -5377,6 +5426,94 @@ static int kvmhv_store_to_eaddr(struct kvm_vcpu *vcpu, ulong *eaddr, void *ptr,
        return rc;
 }
 
+static void unpin_vpa_reset(struct kvm *kvm, struct kvmppc_vpa *vpa)
+{
+       unpin_vpa(kvm, vpa);
+       vpa->gpa = 0;
+       vpa->pinned_addr = NULL;
+       vpa->dirty = false;
+       vpa->update_pending = 0;
+}
+
+/*
+ *  IOCTL handler to turn off secure mode of guest
+ *
+ * - Release all device pages
+ * - Issue ucall to terminate the guest on the UV side
+ * - Unpin the VPA pages.
+ * - Reinit the partition scoped page tables
+ */
+static int kvmhv_svm_off(struct kvm *kvm)
+{
+       struct kvm_vcpu *vcpu;
+       int mmu_was_ready;
+       int srcu_idx;
+       int ret = 0;
+       int i;
+
+       if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
+               return ret;
+
+       mutex_lock(&kvm->arch.mmu_setup_lock);
+       mmu_was_ready = kvm->arch.mmu_ready;
+       if (kvm->arch.mmu_ready) {
+               kvm->arch.mmu_ready = 0;
+               /* order mmu_ready vs. vcpus_running */
+               smp_mb();
+               if (atomic_read(&kvm->arch.vcpus_running)) {
+                       kvm->arch.mmu_ready = 1;
+                       ret = -EBUSY;
+                       goto out;
+               }
+       }
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+               struct kvm_memory_slot *memslot;
+               struct kvm_memslots *slots = __kvm_memslots(kvm, i);
+
+               if (!slots)
+                       continue;
+
+               kvm_for_each_memslot(memslot, slots) {
+                       kvmppc_uvmem_drop_pages(memslot, kvm);
+                       uv_unregister_mem_slot(kvm->arch.lpid, memslot->id);
+               }
+       }
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+
+       ret = uv_svm_terminate(kvm->arch.lpid);
+       if (ret != U_SUCCESS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * When secure guest is reset, all the guest pages are sent
+        * to UV via UV_PAGE_IN before the non-boot vcpus get a
+        * chance to run and unpin their VPA pages. Unpinning of all
+        * VPA pages is done here explicitly so that VPA pages
+        * can be migrated to the secure side.
+        *
+        * This is required to for the secure SMP guest to reboot
+        * correctly.
+        */
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               spin_lock(&vcpu->arch.vpa_update_lock);
+               unpin_vpa_reset(kvm, &vcpu->arch.dtl);
+               unpin_vpa_reset(kvm, &vcpu->arch.slb_shadow);
+               unpin_vpa_reset(kvm, &vcpu->arch.vpa);
+               spin_unlock(&vcpu->arch.vpa_update_lock);
+       }
+
+       kvmppc_setup_partition_table(kvm);
+       kvm->arch.secure_guest = 0;
+       kvm->arch.mmu_ready = mmu_was_ready;
+out:
+       mutex_unlock(&kvm->arch.mmu_setup_lock);
+       return ret;
+}
+
 static struct kvmppc_ops kvm_ops_hv = {
        .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
        .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@@ -5420,6 +5557,7 @@ static struct kvmppc_ops kvm_ops_hv = {
        .enable_nested = kvmhv_enable_nested,
        .load_from_eaddr = kvmhv_load_from_eaddr,
        .store_to_eaddr = kvmhv_store_to_eaddr,
+       .svm_off = kvmhv_svm_off,
 };
 
 static int kvm_init_subcore_bitmap(void)
@@ -5528,11 +5666,16 @@ static int kvmppc_book3s_init_hv(void)
                        no_mixing_hpt_and_radix = true;
        }
 
+       r = kvmppc_uvmem_init();
+       if (r < 0)
+               pr_err("KVM-HV: kvmppc_uvmem_init failed %d\n", r);
+
        return r;
 }
 
 static void kvmppc_book3s_exit_hv(void)
 {
+       kvmppc_uvmem_free();
        kvmppc_free_host_rm_ops();
        if (kvmppc_radix_possible())
                kvmppc_radix_exit();
diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c
new file mode 100644 (file)
index 0000000..2de264f
--- /dev/null
@@ -0,0 +1,785 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Secure pages management: Migration of pages between normal and secure
+ * memory of KVM guests.
+ *
+ * Copyright 2018 Bharata B Rao, IBM Corp. <bharata@linux.ibm.com>
+ */
+
+/*
+ * A pseries guest can be run as secure guest on Ultravisor-enabled
+ * POWER platforms. On such platforms, this driver will be used to manage
+ * the movement of guest pages between the normal memory managed by
+ * hypervisor (HV) and secure memory managed by Ultravisor (UV).
+ *
+ * The page-in or page-out requests from UV will come to HV as hcalls and
+ * HV will call back into UV via ultracalls to satisfy these page requests.
+ *
+ * Private ZONE_DEVICE memory equal to the amount of secure memory
+ * available in the platform for running secure guests is hotplugged.
+ * Whenever a page belonging to the guest becomes secure, a page from this
+ * private device memory is used to represent and track that secure page
+ * on the HV side. Some pages (like virtio buffers, VPA pages etc) are
+ * shared between UV and HV. However such pages aren't represented by
+ * device private memory and mappings to shared memory exist in both
+ * UV and HV page tables.
+ */
+
+/*
+ * Notes on locking
+ *
+ * kvm->arch.uvmem_lock is a per-guest lock that prevents concurrent
+ * page-in and page-out requests for the same GPA. Concurrent accesses
+ * can either come via UV (guest vCPUs requesting for same page)
+ * or when HV and guest simultaneously access the same page.
+ * This mutex serializes the migration of page from HV(normal) to
+ * UV(secure) and vice versa. So the serialization points are around
+ * migrate_vma routines and page-in/out routines.
+ *
+ * Per-guest mutex comes with a cost though. Mainly it serializes the
+ * fault path as page-out can occur when HV faults on accessing secure
+ * guest pages. Currently UV issues page-in requests for all the guest
+ * PFNs one at a time during early boot (UV_ESM uvcall), so this is
+ * not a cause for concern. Also currently the number of page-outs caused
+ * by HV touching secure pages is very very low. If an when UV supports
+ * overcommitting, then we might see concurrent guest driven page-outs.
+ *
+ * Locking order
+ *
+ * 1. kvm->srcu - Protects KVM memslots
+ * 2. kvm->mm->mmap_sem - find_vma, migrate_vma_pages and helpers, ksm_madvise
+ * 3. kvm->arch.uvmem_lock - protects read/writes to uvmem slots thus acting
+ *                          as sync-points for page-in/out
+ */
+
+/*
+ * Notes on page size
+ *
+ * Currently UV uses 2MB mappings internally, but will issue H_SVM_PAGE_IN
+ * and H_SVM_PAGE_OUT hcalls in PAGE_SIZE(64K) granularity. HV tracks
+ * secure GPAs at 64K page size and maintains one device PFN for each
+ * 64K secure GPA. UV_PAGE_IN and UV_PAGE_OUT calls by HV are also issued
+ * for 64K page at a time.
+ *
+ * HV faulting on secure pages: When HV touches any secure page, it
+ * faults and issues a UV_PAGE_OUT request with 64K page size. Currently
+ * UV splits and remaps the 2MB page if necessary and copies out the
+ * required 64K page contents.
+ *
+ * Shared pages: Whenever guest shares a secure page, UV will split and
+ * remap the 2MB page if required and issue H_SVM_PAGE_IN with 64K page size.
+ *
+ * HV invalidating a page: When a regular page belonging to secure
+ * guest gets unmapped, HV informs UV with UV_PAGE_INVAL of 64K
+ * page size. Using 64K page size is correct here because any non-secure
+ * page will essentially be of 64K page size. Splitting by UV during sharing
+ * and page-out ensures this.
+ *
+ * Page fault handling: When HV handles page fault of a page belonging
+ * to secure guest, it sends that to UV with a 64K UV_PAGE_IN request.
+ * Using 64K size is correct here too as UV would have split the 2MB page
+ * into 64k mappings and would have done page-outs earlier.
+ *
+ * In summary, the current secure pages handling code in HV assumes
+ * 64K page size and in fact fails any page-in/page-out requests of
+ * non-64K size upfront. If and when UV starts supporting multiple
+ * page-sizes, we need to break this assumption.
+ */
+
+#include <linux/pagemap.h>
+#include <linux/migrate.h>
+#include <linux/kvm_host.h>
+#include <linux/ksm.h>
+#include <asm/ultravisor.h>
+#include <asm/mman.h>
+#include <asm/kvm_ppc.h>
+
+static struct dev_pagemap kvmppc_uvmem_pgmap;
+static unsigned long *kvmppc_uvmem_bitmap;
+static DEFINE_SPINLOCK(kvmppc_uvmem_bitmap_lock);
+
+#define KVMPPC_UVMEM_PFN       (1UL << 63)
+
+struct kvmppc_uvmem_slot {
+       struct list_head list;
+       unsigned long nr_pfns;
+       unsigned long base_pfn;
+       unsigned long *pfns;
+};
+
+struct kvmppc_uvmem_page_pvt {
+       struct kvm *kvm;
+       unsigned long gpa;
+       bool skip_page_out;
+};
+
+int kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot)
+{
+       struct kvmppc_uvmem_slot *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       p->pfns = vzalloc(array_size(slot->npages, sizeof(*p->pfns)));
+       if (!p->pfns) {
+               kfree(p);
+               return -ENOMEM;
+       }
+       p->nr_pfns = slot->npages;
+       p->base_pfn = slot->base_gfn;
+
+       mutex_lock(&kvm->arch.uvmem_lock);
+       list_add(&p->list, &kvm->arch.uvmem_pfns);
+       mutex_unlock(&kvm->arch.uvmem_lock);
+
+       return 0;
+}
+
+/*
+ * All device PFNs are already released by the time we come here.
+ */
+void kvmppc_uvmem_slot_free(struct kvm *kvm, const struct kvm_memory_slot *slot)
+{
+       struct kvmppc_uvmem_slot *p, *next;
+
+       mutex_lock(&kvm->arch.uvmem_lock);
+       list_for_each_entry_safe(p, next, &kvm->arch.uvmem_pfns, list) {
+               if (p->base_pfn == slot->base_gfn) {
+                       vfree(p->pfns);
+                       list_del(&p->list);
+                       kfree(p);
+                       break;
+               }
+       }
+       mutex_unlock(&kvm->arch.uvmem_lock);
+}
+
+static void kvmppc_uvmem_pfn_insert(unsigned long gfn, unsigned long uvmem_pfn,
+                                   struct kvm *kvm)
+{
+       struct kvmppc_uvmem_slot *p;
+
+       list_for_each_entry(p, &kvm->arch.uvmem_pfns, list) {
+               if (gfn >= p->base_pfn && gfn < p->base_pfn + p->nr_pfns) {
+                       unsigned long index = gfn - p->base_pfn;
+
+                       p->pfns[index] = uvmem_pfn | KVMPPC_UVMEM_PFN;
+                       return;
+               }
+       }
+}
+
+static void kvmppc_uvmem_pfn_remove(unsigned long gfn, struct kvm *kvm)
+{
+       struct kvmppc_uvmem_slot *p;
+
+       list_for_each_entry(p, &kvm->arch.uvmem_pfns, list) {
+               if (gfn >= p->base_pfn && gfn < p->base_pfn + p->nr_pfns) {
+                       p->pfns[gfn - p->base_pfn] = 0;
+                       return;
+               }
+       }
+}
+
+static bool kvmppc_gfn_is_uvmem_pfn(unsigned long gfn, struct kvm *kvm,
+                                   unsigned long *uvmem_pfn)
+{
+       struct kvmppc_uvmem_slot *p;
+
+       list_for_each_entry(p, &kvm->arch.uvmem_pfns, list) {
+               if (gfn >= p->base_pfn && gfn < p->base_pfn + p->nr_pfns) {
+                       unsigned long index = gfn - p->base_pfn;
+
+                       if (p->pfns[index] & KVMPPC_UVMEM_PFN) {
+                               if (uvmem_pfn)
+                                       *uvmem_pfn = p->pfns[index] &
+                                                    ~KVMPPC_UVMEM_PFN;
+                               return true;
+                       } else
+                               return false;
+               }
+       }
+       return false;
+}
+
+unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
+{
+       struct kvm_memslots *slots;
+       struct kvm_memory_slot *memslot;
+       int ret = H_SUCCESS;
+       int srcu_idx;
+
+       if (!kvmppc_uvmem_bitmap)
+               return H_UNSUPPORTED;
+
+       /* Only radix guests can be secure guests */
+       if (!kvm_is_radix(kvm))
+               return H_UNSUPPORTED;
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       slots = kvm_memslots(kvm);
+       kvm_for_each_memslot(memslot, slots) {
+               if (kvmppc_uvmem_slot_init(kvm, memslot)) {
+                       ret = H_PARAMETER;
+                       goto out;
+               }
+               ret = uv_register_mem_slot(kvm->arch.lpid,
+                                          memslot->base_gfn << PAGE_SHIFT,
+                                          memslot->npages * PAGE_SIZE,
+                                          0, memslot->id);
+               if (ret < 0) {
+                       kvmppc_uvmem_slot_free(kvm, memslot);
+                       ret = H_PARAMETER;
+                       goto out;
+               }
+       }
+       kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_START;
+out:
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+       return ret;
+}
+
+unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
+{
+       if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
+               return H_UNSUPPORTED;
+
+       kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_DONE;
+       pr_info("LPID %d went secure\n", kvm->arch.lpid);
+       return H_SUCCESS;
+}
+
+/*
+ * Drop device pages that we maintain for the secure guest
+ *
+ * We first mark the pages to be skipped from UV_PAGE_OUT when there
+ * is HV side fault on these pages. Next we *get* these pages, forcing
+ * fault on them, do fault time migration to replace the device PTEs in
+ * QEMU page table with normal PTEs from newly allocated pages.
+ */
+void kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
+                            struct kvm *kvm)
+{
+       int i;
+       struct kvmppc_uvmem_page_pvt *pvt;
+       unsigned long pfn, uvmem_pfn;
+       unsigned long gfn = free->base_gfn;
+
+       for (i = free->npages; i; --i, ++gfn) {
+               struct page *uvmem_page;
+
+               mutex_lock(&kvm->arch.uvmem_lock);
+               if (!kvmppc_gfn_is_uvmem_pfn(gfn, kvm, &uvmem_pfn)) {
+                       mutex_unlock(&kvm->arch.uvmem_lock);
+                       continue;
+               }
+
+               uvmem_page = pfn_to_page(uvmem_pfn);
+               pvt = uvmem_page->zone_device_data;
+               pvt->skip_page_out = true;
+               mutex_unlock(&kvm->arch.uvmem_lock);
+
+               pfn = gfn_to_pfn(kvm, gfn);
+               if (is_error_noslot_pfn(pfn))
+                       continue;
+               kvm_release_pfn_clean(pfn);
+       }
+}
+
+/*
+ * Get a free device PFN from the pool
+ *
+ * Called when a normal page is moved to secure memory (UV_PAGE_IN). Device
+ * PFN will be used to keep track of the secure page on HV side.
+ *
+ * Called with kvm->arch.uvmem_lock held
+ */
+static struct page *kvmppc_uvmem_get_page(unsigned long gpa, struct kvm *kvm)
+{
+       struct page *dpage = NULL;
+       unsigned long bit, uvmem_pfn;
+       struct kvmppc_uvmem_page_pvt *pvt;
+       unsigned long pfn_last, pfn_first;
+
+       pfn_first = kvmppc_uvmem_pgmap.res.start >> PAGE_SHIFT;
+       pfn_last = pfn_first +
+                  (resource_size(&kvmppc_uvmem_pgmap.res) >> PAGE_SHIFT);
+
+       spin_lock(&kvmppc_uvmem_bitmap_lock);
+       bit = find_first_zero_bit(kvmppc_uvmem_bitmap,
+                                 pfn_last - pfn_first);
+       if (bit >= (pfn_last - pfn_first))
+               goto out;
+       bitmap_set(kvmppc_uvmem_bitmap, bit, 1);
+       spin_unlock(&kvmppc_uvmem_bitmap_lock);
+
+       pvt = kzalloc(sizeof(*pvt), GFP_KERNEL);
+       if (!pvt)
+               goto out_clear;
+
+       uvmem_pfn = bit + pfn_first;
+       kvmppc_uvmem_pfn_insert(gpa >> PAGE_SHIFT, uvmem_pfn, kvm);
+
+       pvt->gpa = gpa;
+       pvt->kvm = kvm;
+
+       dpage = pfn_to_page(uvmem_pfn);
+       dpage->zone_device_data = pvt;
+       get_page(dpage);
+       lock_page(dpage);
+       return dpage;
+out_clear:
+       spin_lock(&kvmppc_uvmem_bitmap_lock);
+       bitmap_clear(kvmppc_uvmem_bitmap, bit, 1);
+out:
+       spin_unlock(&kvmppc_uvmem_bitmap_lock);
+       return NULL;
+}
+
+/*
+ * Alloc a PFN from private device memory pool and copy page from normal
+ * memory to secure memory using UV_PAGE_IN uvcall.
+ */
+static int
+kvmppc_svm_page_in(struct vm_area_struct *vma, unsigned long start,
+                  unsigned long end, unsigned long gpa, struct kvm *kvm,
+                  unsigned long page_shift, bool *downgrade)
+{
+       unsigned long src_pfn, dst_pfn = 0;
+       struct migrate_vma mig;
+       struct page *spage;
+       unsigned long pfn;
+       struct page *dpage;
+       int ret = 0;
+
+       memset(&mig, 0, sizeof(mig));
+       mig.vma = vma;
+       mig.start = start;
+       mig.end = end;
+       mig.src = &src_pfn;
+       mig.dst = &dst_pfn;
+
+       /*
+        * We come here with mmap_sem write lock held just for
+        * ksm_madvise(), otherwise we only need read mmap_sem.
+        * Hence downgrade to read lock once ksm_madvise() is done.
+        */
+       ret = ksm_madvise(vma, vma->vm_start, vma->vm_end,
+                         MADV_UNMERGEABLE, &vma->vm_flags);
+       downgrade_write(&kvm->mm->mmap_sem);
+       *downgrade = true;
+       if (ret)
+               return ret;
+
+       ret = migrate_vma_setup(&mig);
+       if (ret)
+               return ret;
+
+       if (!(*mig.src & MIGRATE_PFN_MIGRATE)) {
+               ret = -1;
+               goto out_finalize;
+       }
+
+       dpage = kvmppc_uvmem_get_page(gpa, kvm);
+       if (!dpage) {
+               ret = -1;
+               goto out_finalize;
+       }
+
+       pfn = *mig.src >> MIGRATE_PFN_SHIFT;
+       spage = migrate_pfn_to_page(*mig.src);
+       if (spage)
+               uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0,
+                          page_shift);
+
+       *mig.dst = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
+       migrate_vma_pages(&mig);
+out_finalize:
+       migrate_vma_finalize(&mig);
+       return ret;
+}
+
+/*
+ * Shares the page with HV, thus making it a normal page.
+ *
+ * - If the page is already secure, then provision a new page and share
+ * - If the page is a normal page, share the existing page
+ *
+ * In the former case, uses dev_pagemap_ops.migrate_to_ram handler
+ * to unmap the device page from QEMU's page tables.
+ */
+static unsigned long
+kvmppc_share_page(struct kvm *kvm, unsigned long gpa, unsigned long page_shift)
+{
+
+       int ret = H_PARAMETER;
+       struct page *uvmem_page;
+       struct kvmppc_uvmem_page_pvt *pvt;
+       unsigned long pfn;
+       unsigned long gfn = gpa >> page_shift;
+       int srcu_idx;
+       unsigned long uvmem_pfn;
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       mutex_lock(&kvm->arch.uvmem_lock);
+       if (kvmppc_gfn_is_uvmem_pfn(gfn, kvm, &uvmem_pfn)) {
+               uvmem_page = pfn_to_page(uvmem_pfn);
+               pvt = uvmem_page->zone_device_data;
+               pvt->skip_page_out = true;
+       }
+
+retry:
+       mutex_unlock(&kvm->arch.uvmem_lock);
+       pfn = gfn_to_pfn(kvm, gfn);
+       if (is_error_noslot_pfn(pfn))
+               goto out;
+
+       mutex_lock(&kvm->arch.uvmem_lock);
+       if (kvmppc_gfn_is_uvmem_pfn(gfn, kvm, &uvmem_pfn)) {
+               uvmem_page = pfn_to_page(uvmem_pfn);
+               pvt = uvmem_page->zone_device_data;
+               pvt->skip_page_out = true;
+               kvm_release_pfn_clean(pfn);
+               goto retry;
+       }
+
+       if (!uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, page_shift))
+               ret = H_SUCCESS;
+       kvm_release_pfn_clean(pfn);
+       mutex_unlock(&kvm->arch.uvmem_lock);
+out:
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+       return ret;
+}
+
+/*
+ * H_SVM_PAGE_IN: Move page from normal memory to secure memory.
+ *
+ * H_PAGE_IN_SHARED flag makes the page shared which means that the same
+ * memory in is visible from both UV and HV.
+ */
+unsigned long
+kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gpa,
+                    unsigned long flags, unsigned long page_shift)
+{
+       bool downgrade = false;
+       unsigned long start, end;
+       struct vm_area_struct *vma;
+       int srcu_idx;
+       unsigned long gfn = gpa >> page_shift;
+       int ret;
+
+       if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
+               return H_UNSUPPORTED;
+
+       if (page_shift != PAGE_SHIFT)
+               return H_P3;
+
+       if (flags & ~H_PAGE_IN_SHARED)
+               return H_P2;
+
+       if (flags & H_PAGE_IN_SHARED)
+               return kvmppc_share_page(kvm, gpa, page_shift);
+
+       ret = H_PARAMETER;
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       down_write(&kvm->mm->mmap_sem);
+
+       start = gfn_to_hva(kvm, gfn);
+       if (kvm_is_error_hva(start))
+               goto out;
+
+       mutex_lock(&kvm->arch.uvmem_lock);
+       /* Fail the page-in request of an already paged-in page */
+       if (kvmppc_gfn_is_uvmem_pfn(gfn, kvm, NULL))
+               goto out_unlock;
+
+       end = start + (1UL << page_shift);
+       vma = find_vma_intersection(kvm->mm, start, end);
+       if (!vma || vma->vm_start > start || vma->vm_end < end)
+               goto out_unlock;
+
+       if (!kvmppc_svm_page_in(vma, start, end, gpa, kvm, page_shift,
+                               &downgrade))
+               ret = H_SUCCESS;
+out_unlock:
+       mutex_unlock(&kvm->arch.uvmem_lock);
+out:
+       if (downgrade)
+               up_read(&kvm->mm->mmap_sem);
+       else
+               up_write(&kvm->mm->mmap_sem);
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+       return ret;
+}
+
+/*
+ * Provision a new page on HV side and copy over the contents
+ * from secure memory using UV_PAGE_OUT uvcall.
+ */
+static int
+kvmppc_svm_page_out(struct vm_area_struct *vma, unsigned long start,
+                   unsigned long end, unsigned long page_shift,
+                   struct kvm *kvm, unsigned long gpa)
+{
+       unsigned long src_pfn, dst_pfn = 0;
+       struct migrate_vma mig;
+       struct page *dpage, *spage;
+       struct kvmppc_uvmem_page_pvt *pvt;
+       unsigned long pfn;
+       int ret = U_SUCCESS;
+
+       memset(&mig, 0, sizeof(mig));
+       mig.vma = vma;
+       mig.start = start;
+       mig.end = end;
+       mig.src = &src_pfn;
+       mig.dst = &dst_pfn;
+
+       mutex_lock(&kvm->arch.uvmem_lock);
+       /* The requested page is already paged-out, nothing to do */
+       if (!kvmppc_gfn_is_uvmem_pfn(gpa >> page_shift, kvm, NULL))
+               goto out;
+
+       ret = migrate_vma_setup(&mig);
+       if (ret)
+               return ret;
+
+       spage = migrate_pfn_to_page(*mig.src);
+       if (!spage || !(*mig.src & MIGRATE_PFN_MIGRATE))
+               goto out_finalize;
+
+       if (!is_zone_device_page(spage))
+               goto out_finalize;
+
+       dpage = alloc_page_vma(GFP_HIGHUSER, vma, start);
+       if (!dpage) {
+               ret = -1;
+               goto out_finalize;
+       }
+
+       lock_page(dpage);
+       pvt = spage->zone_device_data;
+       pfn = page_to_pfn(dpage);
+
+       /*
+        * This function is used in two cases:
+        * - When HV touches a secure page, for which we do UV_PAGE_OUT
+        * - When a secure page is converted to shared page, we *get*
+        *   the page to essentially unmap the device page. In this
+        *   case we skip page-out.
+        */
+       if (!pvt->skip_page_out)
+               ret = uv_page_out(kvm->arch.lpid, pfn << page_shift,
+                                 gpa, 0, page_shift);
+
+       if (ret == U_SUCCESS)
+               *mig.dst = migrate_pfn(pfn) | MIGRATE_PFN_LOCKED;
+       else {
+               unlock_page(dpage);
+               __free_page(dpage);
+               goto out_finalize;
+       }
+
+       migrate_vma_pages(&mig);
+out_finalize:
+       migrate_vma_finalize(&mig);
+out:
+       mutex_unlock(&kvm->arch.uvmem_lock);
+       return ret;
+}
+
+/*
+ * Fault handler callback that gets called when HV touches any page that
+ * has been moved to secure memory, we ask UV to give back the page by
+ * issuing UV_PAGE_OUT uvcall.
+ *
+ * This eventually results in dropping of device PFN and the newly
+ * provisioned page/PFN gets populated in QEMU page tables.
+ */
+static vm_fault_t kvmppc_uvmem_migrate_to_ram(struct vm_fault *vmf)
+{
+       struct kvmppc_uvmem_page_pvt *pvt = vmf->page->zone_device_data;
+
+       if (kvmppc_svm_page_out(vmf->vma, vmf->address,
+                               vmf->address + PAGE_SIZE, PAGE_SHIFT,
+                               pvt->kvm, pvt->gpa))
+               return VM_FAULT_SIGBUS;
+       else
+               return 0;
+}
+
+/*
+ * Release the device PFN back to the pool
+ *
+ * Gets called when secure page becomes a normal page during H_SVM_PAGE_OUT.
+ * Gets called with kvm->arch.uvmem_lock held.
+ */
+static void kvmppc_uvmem_page_free(struct page *page)
+{
+       unsigned long pfn = page_to_pfn(page) -
+                       (kvmppc_uvmem_pgmap.res.start >> PAGE_SHIFT);
+       struct kvmppc_uvmem_page_pvt *pvt;
+
+       spin_lock(&kvmppc_uvmem_bitmap_lock);
+       bitmap_clear(kvmppc_uvmem_bitmap, pfn, 1);
+       spin_unlock(&kvmppc_uvmem_bitmap_lock);
+
+       pvt = page->zone_device_data;
+       page->zone_device_data = NULL;
+       kvmppc_uvmem_pfn_remove(pvt->gpa >> PAGE_SHIFT, pvt->kvm);
+       kfree(pvt);
+}
+
+static const struct dev_pagemap_ops kvmppc_uvmem_ops = {
+       .page_free = kvmppc_uvmem_page_free,
+       .migrate_to_ram = kvmppc_uvmem_migrate_to_ram,
+};
+
+/*
+ * H_SVM_PAGE_OUT: Move page from secure memory to normal memory.
+ */
+unsigned long
+kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gpa,
+                     unsigned long flags, unsigned long page_shift)
+{
+       unsigned long gfn = gpa >> page_shift;
+       unsigned long start, end;
+       struct vm_area_struct *vma;
+       int srcu_idx;
+       int ret;
+
+       if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
+               return H_UNSUPPORTED;
+
+       if (page_shift != PAGE_SHIFT)
+               return H_P3;
+
+       if (flags)
+               return H_P2;
+
+       ret = H_PARAMETER;
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       down_read(&kvm->mm->mmap_sem);
+       start = gfn_to_hva(kvm, gfn);
+       if (kvm_is_error_hva(start))
+               goto out;
+
+       end = start + (1UL << page_shift);
+       vma = find_vma_intersection(kvm->mm, start, end);
+       if (!vma || vma->vm_start > start || vma->vm_end < end)
+               goto out;
+
+       if (!kvmppc_svm_page_out(vma, start, end, page_shift, kvm, gpa))
+               ret = H_SUCCESS;
+out:
+       up_read(&kvm->mm->mmap_sem);
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+       return ret;
+}
+
+int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn)
+{
+       unsigned long pfn;
+       int ret = U_SUCCESS;
+
+       pfn = gfn_to_pfn(kvm, gfn);
+       if (is_error_noslot_pfn(pfn))
+               return -EFAULT;
+
+       mutex_lock(&kvm->arch.uvmem_lock);
+       if (kvmppc_gfn_is_uvmem_pfn(gfn, kvm, NULL))
+               goto out;
+
+       ret = uv_page_in(kvm->arch.lpid, pfn << PAGE_SHIFT, gfn << PAGE_SHIFT,
+                        0, PAGE_SHIFT);
+out:
+       kvm_release_pfn_clean(pfn);
+       mutex_unlock(&kvm->arch.uvmem_lock);
+       return (ret == U_SUCCESS) ? RESUME_GUEST : -EFAULT;
+}
+
+static u64 kvmppc_get_secmem_size(void)
+{
+       struct device_node *np;
+       int i, len;
+       const __be32 *prop;
+       u64 size = 0;
+
+       np = of_find_compatible_node(NULL, NULL, "ibm,uv-firmware");
+       if (!np)
+               goto out;
+
+       prop = of_get_property(np, "secure-memory-ranges", &len);
+       if (!prop)
+               goto out_put;
+
+       for (i = 0; i < len / (sizeof(*prop) * 4); i++)
+               size += of_read_number(prop + (i * 4) + 2, 2);
+
+out_put:
+       of_node_put(np);
+out:
+       return size;
+}
+
+int kvmppc_uvmem_init(void)
+{
+       int ret = 0;
+       unsigned long size;
+       struct resource *res;
+       void *addr;
+       unsigned long pfn_last, pfn_first;
+
+       size = kvmppc_get_secmem_size();
+       if (!size) {
+               /*
+                * Don't fail the initialization of kvm-hv module if
+                * the platform doesn't export ibm,uv-firmware node.
+                * Let normal guests run on such PEF-disabled platform.
+                */
+               pr_info("KVMPPC-UVMEM: No support for secure guests\n");
+               goto out;
+       }
+
+       res = request_free_mem_region(&iomem_resource, size, "kvmppc_uvmem");
+       if (IS_ERR(res)) {
+               ret = PTR_ERR(res);
+               goto out;
+       }
+
+       kvmppc_uvmem_pgmap.type = MEMORY_DEVICE_PRIVATE;
+       kvmppc_uvmem_pgmap.res = *res;
+       kvmppc_uvmem_pgmap.ops = &kvmppc_uvmem_ops;
+       addr = memremap_pages(&kvmppc_uvmem_pgmap, NUMA_NO_NODE);
+       if (IS_ERR(addr)) {
+               ret = PTR_ERR(addr);
+               goto out_free_region;
+       }
+
+       pfn_first = res->start >> PAGE_SHIFT;
+       pfn_last = pfn_first + (resource_size(res) >> PAGE_SHIFT);
+       kvmppc_uvmem_bitmap = kcalloc(BITS_TO_LONGS(pfn_last - pfn_first),
+                                     sizeof(unsigned long), GFP_KERNEL);
+       if (!kvmppc_uvmem_bitmap) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
+       pr_info("KVMPPC-UVMEM: Secure Memory size 0x%lx\n", size);
+       return ret;
+out_unmap:
+       memunmap_pages(&kvmppc_uvmem_pgmap);
+out_free_region:
+       release_mem_region(res->start, size);
+out:
+       return ret;
+}
+
+void kvmppc_uvmem_free(void)
+{
+       memunmap_pages(&kvmppc_uvmem_pgmap);
+       release_mem_region(kvmppc_uvmem_pgmap.res.start,
+                          resource_size(&kvmppc_uvmem_pgmap.res));
+       kfree(kvmppc_uvmem_bitmap);
+}
index 9e085e9..416fb3d 100644 (file)
@@ -31,6 +31,8 @@
 #include <asm/hvcall.h>
 #include <asm/plpar_wrappers.h>
 #endif
+#include <asm/ultravisor.h>
+#include <asm/kvm_host.h>
 
 #include "timing.h"
 #include "irq.h"
@@ -2413,6 +2415,16 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        r = -EFAULT;
                break;
        }
+       case KVM_PPC_SVM_OFF: {
+               struct kvm *kvm = filp->private_data;
+
+               r = 0;
+               if (!kvm->arch.kvm_ops->svm_off)
+                       goto out;
+
+               r = kvm->arch.kvm_ops->svm_off(kvm);
+               break;
+       }
        default: {
                struct kvm *kvm = filp->private_data;
                r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
index 6ee17d0..974109b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/mm.h>
+#include <linux/hugetlb.h>
 #include <linux/string_helpers.h>
 #include <linux/stop_machine.h>
 
index 536c0ef..634759a 100644 (file)
@@ -1,13 +1,13 @@
 menu "SoC selection"
 
 config SOC_SIFIVE
-       bool "SiFive SoCs"
-       select SERIAL_SIFIVE
-       select SERIAL_SIFIVE_CONSOLE
-       select CLK_SIFIVE
-       select CLK_SIFIVE_FU540_PRCI
-       select SIFIVE_PLIC
-       help
-         This enables support for SiFive SoC platform hardware.
+       bool "SiFive SoCs"
+       select SERIAL_SIFIVE
+       select SERIAL_SIFIVE_CONSOLE
+       select CLK_SIFIVE
+       select CLK_SIFIVE_FU540_PRCI
+       select SIFIVE_PLIC
+       help
+         This enables support for SiFive SoC platform hardware.
 
 endmenu
index 420a0db..e2ff95c 100644 (file)
@@ -100,4 +100,28 @@ CONFIG_9P_FS=y
 CONFIG_CRYPTO_USER_API_HASH=y
 CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_VM=y
+CONFIG_DEBUG_VM_PGFLAGS=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_PER_CPU_MAPS=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_TIMEKEEPING=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_PLIST=y
+CONFIG_DEBUG_SG=y
 # CONFIG_RCU_TRACE is not set
+CONFIG_RCU_EQS_DEBUG=y
+CONFIG_DEBUG_BLOCK_EXT_DEVT=y
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_MEMTEST=y
index 87ee6e6..eb51940 100644 (file)
@@ -97,4 +97,28 @@ CONFIG_9P_FS=y
 CONFIG_CRYPTO_USER_API_HASH=y
 CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_VM=y
+CONFIG_DEBUG_VM_PGFLAGS=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_PER_CPU_MAPS=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_TIMEKEEPING=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_PLIST=y
+CONFIG_DEBUG_SG=y
 # CONFIG_RCU_TRACE is not set
+CONFIG_RCU_EQS_DEBUG=y
+CONFIG_DEBUG_BLOCK_EXT_DEVT=y
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_MEMTEST=y
index 16970f2..1efaedd 100644 (file)
@@ -22,7 +22,6 @@ generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mm-arch-hooks.h
-generic-y += msi.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += sections.h
index b2fe9d1..69f6678 100644 (file)
@@ -46,6 +46,37 @@ static void setup_zero_page(void)
        memset((void *)empty_zero_page, 0, PAGE_SIZE);
 }
 
+#ifdef CONFIG_DEBUG_VM
+static inline void print_mlk(char *name, unsigned long b, unsigned long t)
+{
+       pr_notice("%12s : 0x%08lx - 0x%08lx   (%4ld kB)\n", name, b, t,
+                 (((t) - (b)) >> 10));
+}
+
+static inline void print_mlm(char *name, unsigned long b, unsigned long t)
+{
+       pr_notice("%12s : 0x%08lx - 0x%08lx   (%4ld MB)\n", name, b, t,
+                 (((t) - (b)) >> 20));
+}
+
+static void print_vm_layout(void)
+{
+       pr_notice("Virtual kernel memory layout:\n");
+       print_mlk("fixmap", (unsigned long)FIXADDR_START,
+                 (unsigned long)FIXADDR_TOP);
+       print_mlm("pci io", (unsigned long)PCI_IO_START,
+                 (unsigned long)PCI_IO_END);
+       print_mlm("vmemmap", (unsigned long)VMEMMAP_START,
+                 (unsigned long)VMEMMAP_END);
+       print_mlm("vmalloc", (unsigned long)VMALLOC_START,
+                 (unsigned long)VMALLOC_END);
+       print_mlm("lowmem", (unsigned long)PAGE_OFFSET,
+                 (unsigned long)high_memory);
+}
+#else
+static void print_vm_layout(void) { }
+#endif /* CONFIG_DEBUG_VM */
+
 void __init mem_init(void)
 {
 #ifdef CONFIG_FLATMEM
@@ -56,6 +87,7 @@ void __init mem_init(void)
        memblock_free_all();
 
        mem_init_print_info(NULL);
+       print_vm_layout();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
index f0df9e4..d4051e8 100644 (file)
@@ -170,6 +170,7 @@ config S390
        select HAVE_PERF_EVENTS
        select HAVE_RCU_TABLE_FREE
        select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_RELIABLE_STACKTRACE
        select HAVE_RSEQ
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_VIRT_CPU_ACCOUNTING
@@ -426,9 +427,6 @@ config COMPAT
          (and some other stuff like libraries and such) is needed for
          executing 31 bit applications.  It is safe to say "Y".
 
-config COMPAT_VDSO
-       def_bool COMPAT && !CC_IS_CLANG
-
 config SYSVIPC_COMPAT
        def_bool y if COMPAT && SYSVIPC
 
@@ -1018,3 +1016,17 @@ config S390_GUEST
          the KVM hypervisor.
 
 endmenu
+
+menu "Selftests"
+
+config S390_UNWIND_SELFTEST
+       def_tristate n
+       prompt "Test unwind functions"
+       help
+         This option enables s390 specific stack unwinder testing kernel
+         module. This option is not useful for distributions or general
+         kernels, but only for kernel developers working on architecture code.
+
+         Say N if you are unsure.
+
+endmenu
index 478b645..ba8556b 100644 (file)
@@ -157,7 +157,6 @@ zfcpdump:
 
 vdso_install:
        $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@
-       $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
index fbd341e..3b3a11f 100644 (file)
@@ -170,6 +170,11 @@ void startup_kernel(void)
                handle_relocs(__kaslr_offset);
 
        if (__kaslr_offset) {
+               /*
+                * Save KASLR offset for early dumps, before vmcore_info is set.
+                * Mark as uneven to distinguish from real vmcore_info pointer.
+                */
+               S390_lowcore.vmcore_info = __kaslr_offset | 0x1UL;
                /* Clear non-relocated kernel */
                if (IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED))
                        memset(img, 0, vmlinux.image_size);
index 819803a..0d90cbe 100644 (file)
@@ -313,7 +313,7 @@ static inline unsigned long *trailer_entry_ptr(unsigned long v)
        return (unsigned long *) ret;
 }
 
-/* Return if the entry in the sample data block table (sdbt)
+/* Return true if the entry in the sample data block table (sdbt)
  * is a link to the next sdbt */
 static inline int is_link_entry(unsigned long *s)
 {
index a2399ef..3a06c26 100644 (file)
@@ -2,9 +2,6 @@
 #ifndef __ASM_S390_PCI_H
 #define __ASM_S390_PCI_H
 
-/* must be set before including pci_clp.h */
-#define PCI_BAR_COUNT  6
-
 #include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/iommu.h>
@@ -138,7 +135,7 @@ struct zpci_dev {
 
        char res_name[16];
        bool mio_capable;
-       struct zpci_bar_struct bars[PCI_BAR_COUNT];
+       struct zpci_bar_struct bars[PCI_STD_NUM_BARS];
 
        u64             start_dma;      /* Start of available DMA addresses */
        u64             end_dma;        /* End of available DMA addresses */
index 5035917..bd2cb4e 100644 (file)
@@ -77,7 +77,7 @@ struct mio_info {
        struct {
                u64 wb;
                u64 wt;
-       } addr[PCI_BAR_COUNT];
+       } addr[PCI_STD_NUM_BARS];
        u32 reserved[6];
 } __packed;
 
@@ -98,9 +98,9 @@ struct clp_rsp_query_pci {
        u16 util_str_avail      :  1;   /* utility string available? */
        u16 pfgid               :  8;   /* pci function group id */
        u32 fid;                        /* pci function id */
-       u8 bar_size[PCI_BAR_COUNT];
+       u8 bar_size[PCI_STD_NUM_BARS];
        u16 pchid;
-       __le32 bar[PCI_BAR_COUNT];
+       __le32 bar[PCI_STD_NUM_BARS];
        u8 pfip[CLP_PFIP_NR_SEGMENTS];  /* pci function internal path */
        u32                     : 16;
        u8 fmb_len;
index 4652fff..b9da716 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/perf_event.h>
 #include <linux/device.h>
+#include <asm/stacktrace.h>
 
 /* Per-CPU flags for PMU states */
 #define PMU_F_RESERVED                 0x1000
@@ -73,4 +74,10 @@ struct perf_sf_sde_regs {
 #define SDB_FULL_BLOCKS(hwc)   (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FULL_BLOCKS)
 #define SAMPLE_FREQ_MODE(hwc)  (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FREQ_MODE)
 
+#define perf_arch_fetch_caller_regs(regs, __ip) do {                   \
+       (regs)->psw.addr = (__ip);                                      \
+       (regs)->gprs[15] = (unsigned long)__builtin_frame_address(0) -  \
+               offsetof(struct stack_frame, back_chain);               \
+} while (0)
+
 #endif /* _ASM_S390_PERF_EVENT_H */
index 881fc37..361ef5e 100644 (file)
@@ -310,7 +310,7 @@ void enabled_wait(void);
 /*
  * Function to drop a processor into disabled wait state
  */
-static inline void __noreturn disabled_wait(void)
+static __always_inline void __noreturn disabled_wait(void)
 {
        psw_t psw;
 
index fee4021..ee056f4 100644 (file)
@@ -33,12 +33,12 @@ static inline bool on_stack(struct stack_info *info,
        return addr >= info->begin && addr + len <= info->end;
 }
 
-static inline unsigned long get_stack_pointer(struct task_struct *task,
-                                             struct pt_regs *regs)
+static __always_inline unsigned long get_stack_pointer(struct task_struct *task,
+                                                      struct pt_regs *regs)
 {
        if (regs)
                return (unsigned long) kernel_stack_pointer(regs);
-       if (!task || task == current)
+       if (task == current)
                return current_stack_pointer();
        return (unsigned long) task->thread.ksp;
 }
@@ -62,6 +62,17 @@ struct stack_frame {
 };
 #endif
 
+/*
+ * Unlike current_stack_pointer() which simply returns current value of %r15
+ * current_frame_address() returns function stack frame address, which matches
+ * %r15 upon function invocation. It may differ from %r15 later if function
+ * allocates stack for local variables or new stack frame to call other
+ * functions.
+ */
+#define current_frame_address()                                                \
+       ((unsigned long)__builtin_frame_address(0) -                    \
+        offsetof(struct stack_frame, back_chain))
+
 #define CALL_ARGS_0()                                                  \
        register unsigned long r2 asm("2")
 #define CALL_ARGS_1(arg1)                                              \
@@ -95,20 +106,33 @@ struct stack_frame {
 
 #define CALL_ON_STACK(fn, stack, nr, args...)                          \
 ({                                                                     \
+       unsigned long frame = current_frame_address();                  \
        CALL_ARGS_##nr(args);                                           \
        unsigned long prev;                                             \
                                                                        \
        asm volatile(                                                   \
                "       la      %[_prev],0(15)\n"                       \
-               "       la      15,0(%[_stack])\n"                      \
-               "       stg     %[_prev],%[_bc](15)\n"                  \
+               "       lg      15,%[_stack]\n"                         \
+               "       stg     %[_frame],%[_bc](15)\n"                 \
                "       brasl   14,%[_fn]\n"                            \
                "       la      15,0(%[_prev])\n"                       \
                : [_prev] "=&a" (prev), CALL_FMT_##nr                   \
-                 [_stack] "a" (stack),                                 \
+                 [_stack] "R" (stack),                                 \
                  [_bc] "i" (offsetof(struct stack_frame, back_chain)), \
+                 [_frame] "d" (frame),                                 \
                  [_fn] "X" (fn) : CALL_CLOBBER_##nr);                  \
        r2;                                                             \
 })
 
+#define CALL_ON_STACK_NORETURN(fn, stack)                              \
+({                                                                     \
+       asm volatile(                                                   \
+               "       la      15,0(%[_stack])\n"                      \
+               "       xc      %[_bc](8,15),%[_bc](15)\n"              \
+               "       brasl   14,%[_fn]\n"                            \
+               ::[_bc] "i" (offsetof(struct stack_frame, back_chain)), \
+                 [_stack] "a" (stack), [_fn] "X" (fn));                \
+       BUG();                                                          \
+})
+
 #endif /* _ASM_S390_STACKTRACE_H */
index eaaefec..de9006b 100644 (file)
@@ -35,7 +35,6 @@ struct unwind_state {
        struct task_struct *task;
        struct pt_regs *regs;
        unsigned long sp, ip;
-       bool reuse_sp;
        int graph_idx;
        bool reliable;
        bool error;
@@ -59,10 +58,11 @@ static inline bool unwind_error(struct unwind_state *state)
 static inline void unwind_start(struct unwind_state *state,
                                struct task_struct *task,
                                struct pt_regs *regs,
-                               unsigned long sp)
+                               unsigned long first_frame)
 {
-       sp = sp ? : get_stack_pointer(task, regs);
-       __unwind_start(state, task, regs, sp);
+       task = task ?: current;
+       first_frame = first_frame ?: get_stack_pointer(task, regs);
+       __unwind_start(state, task, regs, first_frame);
 }
 
 static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
index 169d760..3bcfdeb 100644 (file)
@@ -41,8 +41,17 @@ struct vdso_data {
 struct vdso_per_cpu_data {
        __u64 ectg_timer_base;
        __u64 ectg_user_time;
-       __u32 cpu_nr;
-       __u32 node_id;
+       /*
+        * Note: node_id and cpu_nr must be at adjacent memory locations.
+        * VDSO userspace must read both values with a single instruction.
+        */
+       union {
+               __u64 getcpu_val;
+               struct {
+                       __u32 node_id;
+                       __u32 cpu_nr;
+               };
+       };
 };
 
 extern struct vdso_data *vdso_data;
index 5b1c4f4..1030cd1 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __S390_IPCBUF_H__
 #define __S390_IPCBUF_H__
 
+#include <linux/posix_types.h>
+
 /*
  * The user_ipc_perm structure for S/390 architecture.
  * Note extra padding because this structure is passed back and forth
index 7edbbcd..2b1203c 100644 (file)
@@ -81,4 +81,3 @@ obj-$(CONFIG_TRACEPOINTS)     += trace.o
 
 # vdso
 obj-y                          += vdso64/
-obj-$(CONFIG_COMPAT_VDSO)      += vdso32/
index 41ac4ad..ce33406 100644 (file)
@@ -78,8 +78,7 @@ int main(void)
        OFFSET(__VDSO_TS_END, vdso_data, ts_end);
        OFFSET(__VDSO_ECTG_BASE, vdso_per_cpu_data, ectg_timer_base);
        OFFSET(__VDSO_ECTG_USER, vdso_per_cpu_data, ectg_user_time);
-       OFFSET(__VDSO_CPU_NR, vdso_per_cpu_data, cpu_nr);
-       OFFSET(__VDSO_NODE_ID, vdso_per_cpu_data, node_id);
+       OFFSET(__VDSO_GETCPU_VAL, vdso_per_cpu_data, getcpu_val);
        BLANK();
        /* constants used by the vdso */
        DEFINE(__CLOCK_REALTIME, CLOCK_REALTIME);
index 34bdc60..d306fe0 100644 (file)
@@ -38,6 +38,7 @@ const char *stack_type_name(enum stack_type type)
                return "unknown";
        }
 }
+EXPORT_SYMBOL_GPL(stack_type_name);
 
 static inline bool in_stack(unsigned long sp, struct stack_info *info,
                            enum stack_type type, unsigned long low,
@@ -93,7 +94,9 @@ int get_stack_info(unsigned long sp, struct task_struct *task,
        if (!sp)
                goto unknown;
 
-       task = task ? : current;
+       /* Sanity check: ABI requires SP to be aligned 8 bytes. */
+       if (sp & 0x7)
+               goto unknown;
 
        /* Check per-task stack */
        if (in_task_stack(sp, task, info))
@@ -128,8 +131,6 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        struct unwind_state state;
 
        printk("Call Trace:\n");
-       if (!task)
-               task = current;
        unwind_for_each_frame(&state, task, NULL, (unsigned long) stack)
                printk(state.reliable ? " [<%016lx>] %pSR \n" :
                                        "([<%016lx>] %pSR)\n",
index b9e585f..8b88dbb 100644 (file)
@@ -31,7 +31,7 @@ ENTRY(startup_continue)
 #
        larl    %r14,init_task
        stg     %r14,__LC_CURRENT
-       larl    %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD
+       larl    %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD-__PT_SIZE
 #ifdef CONFIG_KASAN
        brasl   %r14,kasan_early_init
 #endif
index 444a191..cb8b1cc 100644 (file)
@@ -164,7 +164,9 @@ static bool kdump_csum_valid(struct kimage *image)
 #ifdef CONFIG_CRASH_DUMP
        int rc;
 
+       preempt_disable();
        rc = CALL_ON_STACK(do_start_kdump, S390_lowcore.nodat_stack, 1, image);
+       preempt_enable();
        return rc == 0;
 #else
        return false;
@@ -254,10 +256,10 @@ void arch_crash_save_vmcoreinfo(void)
        VMCOREINFO_SYMBOL(lowcore_ptr);
        VMCOREINFO_SYMBOL(high_memory);
        VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS);
-       mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
        vmcoreinfo_append_str("SDMA=%lx\n", __sdma);
        vmcoreinfo_append_str("EDMA=%lx\n", __edma);
        vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
+       mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
 }
 
 void machine_shutdown(void)
index 69506fd..c07fdcd 100644 (file)
@@ -156,8 +156,8 @@ static void free_sampling_buffer(struct sf_buffer *sfb)
                }
        }
 
-       debug_sprintf_event(sfdbg, 5, "%s freed sdbt %p\n", __func__,
-                           sfb->sdbt);
+       debug_sprintf_event(sfdbg, 5, "%s: freed sdbt %#lx\n", __func__,
+                           (unsigned long)sfb->sdbt);
        memset(sfb, 0, sizeof(*sfb));
 }
 
@@ -193,7 +193,7 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
                                   unsigned long num_sdb, gfp_t gfp_flags)
 {
        int i, rc;
-       unsigned long *new, *tail;
+       unsigned long *new, *tail, *tail_prev = NULL;
 
        if (!sfb->sdbt || !sfb->tail)
                return -EINVAL;
@@ -213,9 +213,10 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
         */
        if (sfb->sdbt != get_next_sdbt(tail)) {
                debug_sprintf_event(sfdbg, 3, "%s: "
-                                   "sampling buffer is not linked: origin %p"
-                                   " tail %p\n", __func__,
-                                   (void *)sfb->sdbt, (void *)tail);
+                                   "sampling buffer is not linked: origin %#lx"
+                                   " tail %#lx\n", __func__,
+                                   (unsigned long)sfb->sdbt,
+                                   (unsigned long)tail);
                return -EINVAL;
        }
 
@@ -232,6 +233,7 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
                        sfb->num_sdbt++;
                        /* Link current page to tail of chain */
                        *tail = (unsigned long)(void *) new + 1;
+                       tail_prev = tail;
                        tail = new;
                }
 
@@ -241,18 +243,30 @@ static int realloc_sampling_buffer(struct sf_buffer *sfb,
                 * issue, a new realloc call (if required) might succeed.
                 */
                rc = alloc_sample_data_block(tail, gfp_flags);
-               if (rc)
+               if (rc) {
+                       /* Undo last SDBT. An SDBT with no SDB at its first
+                        * entry but with an SDBT entry instead can not be
+                        * handled by the interrupt handler code.
+                        * Avoid this situation.
+                        */
+                       if (tail_prev) {
+                               sfb->num_sdbt--;
+                               free_page((unsigned long) new);
+                               tail = tail_prev;
+                       }
                        break;
+               }
                sfb->num_sdb++;
                tail++;
+               tail_prev = new = NULL; /* Allocated at least one SBD */
        }
 
        /* Link sampling buffer to its origin */
        *tail = (unsigned long) sfb->sdbt + 1;
        sfb->tail = tail;
 
-       debug_sprintf_event(sfdbg, 4, "realloc_sampling_buffer: new buffer"
-                           " settings: sdbt %lu sdb %lu\n",
+       debug_sprintf_event(sfdbg, 4, "%s: new buffer"
+                           " settings: sdbt %lu sdb %lu\n", __func__,
                            sfb->num_sdbt, sfb->num_sdb);
        return rc;
 }
@@ -292,12 +306,13 @@ static int alloc_sampling_buffer(struct sf_buffer *sfb, unsigned long num_sdb)
        rc = realloc_sampling_buffer(sfb, num_sdb, GFP_KERNEL);
        if (rc) {
                free_sampling_buffer(sfb);
-               debug_sprintf_event(sfdbg, 4, "alloc_sampling_buffer: "
-                       "realloc_sampling_buffer failed with rc %i\n", rc);
+               debug_sprintf_event(sfdbg, 4, "%s: "
+                       "realloc_sampling_buffer failed with rc %i\n",
+                       __func__, rc);
        } else
                debug_sprintf_event(sfdbg, 4,
-                       "alloc_sampling_buffer: tear %p dear %p\n",
-                       sfb->sdbt, (void *)*sfb->sdbt);
+                       "%s: tear %#lx dear %#lx\n", __func__,
+                       (unsigned long)sfb->sdbt, (unsigned long)*sfb->sdbt);
        return rc;
 }
 
@@ -465,8 +480,8 @@ static void sfb_account_overflows(struct cpu_hw_sf *cpuhw,
        if (num)
                sfb_account_allocs(num, hwc);
 
-       debug_sprintf_event(sfdbg, 5, "sfb: overflow: overflow %llu ratio %lu"
-                           " num %lu\n", OVERFLOW_REG(hwc), ratio, num);
+       debug_sprintf_event(sfdbg, 5, "%s: overflow %llu ratio %lu num %lu\n",
+                           __func__, OVERFLOW_REG(hwc), ratio, num);
        OVERFLOW_REG(hwc) = 0;
 }
 
@@ -504,13 +519,13 @@ static void extend_sampling_buffer(struct sf_buffer *sfb,
         */
        rc = realloc_sampling_buffer(sfb, num, GFP_ATOMIC);
        if (rc)
-               debug_sprintf_event(sfdbg, 5, "sfb: extend: realloc "
-                                   "failed with rc %i\n", rc);
+               debug_sprintf_event(sfdbg, 5, "%s: realloc failed with rc %i\n",
+                                   __func__, rc);
 
        if (sfb_has_pending_allocs(sfb, hwc))
-               debug_sprintf_event(sfdbg, 5, "sfb: extend: "
+               debug_sprintf_event(sfdbg, 5, "%s: "
                                    "req %lu alloc %lu remaining %lu\n",
-                                   num, sfb->num_sdb - num_old,
+                                   __func__, num, sfb->num_sdb - num_old,
                                    sfb_pending_allocs(sfb, hwc));
 }
 
@@ -600,13 +615,6 @@ static void hw_init_period(struct hw_perf_event *hwc, u64 period)
        local64_set(&hwc->period_left, hwc->sample_period);
 }
 
-static void hw_reset_registers(struct hw_perf_event *hwc,
-                              unsigned long *sdbt_origin)
-{
-       /* (Re)set to first sample-data-block-table */
-       TEAR_REG(hwc) = (unsigned long) sdbt_origin;
-}
-
 static unsigned long hw_limit_rate(const struct hws_qsi_info_block *si,
                                   unsigned long rate)
 {
@@ -698,9 +706,9 @@ static unsigned long getrate(bool freq, unsigned long sample,
                 */
                if (sample_rate_to_freq(si, rate) >
                    sysctl_perf_event_sample_rate) {
-                       debug_sprintf_event(sfdbg, 1,
+                       debug_sprintf_event(sfdbg, 1, "%s: "
                                            "Sampling rate exceeds maximum "
-                                           "perf sample rate\n");
+                                           "perf sample rate\n", __func__);
                        rate = 0;
                }
        }
@@ -745,10 +753,9 @@ static int __hw_perf_event_init_rate(struct perf_event *event,
        attr->sample_period = rate;
        SAMPL_RATE(hwc) = rate;
        hw_init_period(hwc, SAMPL_RATE(hwc));
-       debug_sprintf_event(sfdbg, 4, "__hw_perf_event_init_rate:"
-                           "cpu:%d period:%#llx freq:%d,%#lx\n", event->cpu,
-                           event->attr.sample_period, event->attr.freq,
-                           SAMPLE_FREQ_MODE(hwc));
+       debug_sprintf_event(sfdbg, 4, "%s: cpu %d period %#llx freq %d,%#lx\n",
+                           __func__, event->cpu, event->attr.sample_period,
+                           event->attr.freq, SAMPLE_FREQ_MODE(hwc));
        return 0;
 }
 
@@ -951,8 +958,7 @@ static void cpumsf_pmu_enable(struct pmu *pmu)
                         * buffer extents
                         */
                        sfb_account_overflows(cpuhw, hwc);
-                       if (sfb_has_pending_allocs(&cpuhw->sfb, hwc))
-                               extend_sampling_buffer(&cpuhw->sfb, hwc);
+                       extend_sampling_buffer(&cpuhw->sfb, hwc);
                }
                /* Rate may be adjusted with ioctl() */
                cpuhw->lsctl.interval = SAMPL_RATE(&cpuhw->event->hw);
@@ -973,12 +979,11 @@ static void cpumsf_pmu_enable(struct pmu *pmu)
        /* Load current program parameter */
        lpp(&S390_lowcore.lpp);
 
-       debug_sprintf_event(sfdbg, 6, "pmu_enable: es %i cs %i ed %i cd %i "
-                           "interval %#lx tear %p dear %p\n",
+       debug_sprintf_event(sfdbg, 6, "%s: es %i cs %i ed %i cd %i "
+                           "interval %#lx tear %#lx dear %#lx\n", __func__,
                            cpuhw->lsctl.es, cpuhw->lsctl.cs, cpuhw->lsctl.ed,
                            cpuhw->lsctl.cd, cpuhw->lsctl.interval,
-                           (void *) cpuhw->lsctl.tear,
-                           (void *) cpuhw->lsctl.dear);
+                           cpuhw->lsctl.tear, cpuhw->lsctl.dear);
 }
 
 static void cpumsf_pmu_disable(struct pmu *pmu)
@@ -1019,8 +1024,8 @@ static void cpumsf_pmu_disable(struct pmu *pmu)
                        cpuhw->lsctl.dear = si.dear;
                }
        } else
-               debug_sprintf_event(sfdbg, 3, "cpumsf_pmu_disable: "
-                                   "qsi() failed with err %i\n", err);
+               debug_sprintf_event(sfdbg, 3, "%s: qsi() failed with err %i\n",
+                                   __func__, err);
 
        cpuhw->flags &= ~PMU_F_ENABLED;
 }
@@ -1265,9 +1270,9 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
                        sampl_overflow += te->overflow;
 
                /* Timestamps are valid for full sample-data-blocks only */
-               debug_sprintf_event(sfdbg, 6, "%s: sdbt %p "
+               debug_sprintf_event(sfdbg, 6, "%s: sdbt %#lx "
                                    "overflow %llu timestamp %#llx\n",
-                                   __func__, sdbt, te->overflow,
+                                   __func__, (unsigned long)sdbt, te->overflow,
                                    (te->f) ? trailer_timestamp(te) : 0ULL);
 
                /* Collect all samples from a single sample-data-block and
@@ -1312,8 +1317,10 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
                                                 sampl_overflow, 1 + num_sdb);
        if (sampl_overflow || event_overflow)
                debug_sprintf_event(sfdbg, 4, "%s: "
-                                   "overflow stats: sample %llu event %llu\n",
-                                   __func__, sampl_overflow, event_overflow);
+                                   "overflows: sample %llu event %llu"
+                                   " total %llu num_sdb %llu\n",
+                                   __func__, sampl_overflow, event_overflow,
+                                   OVERFLOW_REG(hwc), num_sdb);
 }
 
 #define AUX_SDB_INDEX(aux, i) ((i) % aux->sfb.num_sdb)
@@ -1424,10 +1431,10 @@ static int aux_output_begin(struct perf_output_handle *handle,
        cpuhw->lsctl.tear = base + offset * sizeof(unsigned long);
        cpuhw->lsctl.dear = aux->sdb_index[head];
 
-       debug_sprintf_event(sfdbg, 6, "aux_output_begin: "
+       debug_sprintf_event(sfdbg, 6, "%s: "
                            "head->alert_mark->empty_mark (num_alert, range)"
                            "[%#lx -> %#lx -> %#lx] (%#lx, %#lx) "
-                           "tear index %#lx, tear %#lx dear %#lx\n",
+                           "tear index %#lx, tear %#lx dear %#lx\n", __func__,
                            aux->head, aux->alert_mark, aux->empty_mark,
                            AUX_SDB_NUM_ALERT(aux), range,
                            head / CPUM_SF_SDB_PER_TABLE,
@@ -1571,7 +1578,9 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
                        pr_err("The AUX buffer with %lu pages for the "
                               "diagnostic-sampling mode is full\n",
                                num_sdb);
-                       debug_sprintf_event(sfdbg, 1, "AUX buffer used up\n");
+                       debug_sprintf_event(sfdbg, 1,
+                                           "%s: AUX buffer used up\n",
+                                           __func__);
                        break;
                }
                if (WARN_ON_ONCE(!aux))
@@ -1594,23 +1603,25 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
                        perf_aux_output_end(&cpuhw->handle, size);
                        pr_err("Sample data caused the AUX buffer with %lu "
                               "pages to overflow\n", num_sdb);
-                       debug_sprintf_event(sfdbg, 1, "head %#lx range %#lx "
-                                           "overflow %#llx\n",
+                       debug_sprintf_event(sfdbg, 1, "%s: head %#lx range %#lx "
+                                           "overflow %#llx\n", __func__,
                                            aux->head, range, overflow);
                } else {
                        size = AUX_SDB_NUM_ALERT(aux) << PAGE_SHIFT;
                        perf_aux_output_end(&cpuhw->handle, size);
-                       debug_sprintf_event(sfdbg, 6, "head %#lx alert %#lx "
+                       debug_sprintf_event(sfdbg, 6, "%s: head %#lx alert %#lx "
                                            "already full, try another\n",
+                                           __func__,
                                            aux->head, aux->alert_mark);
                }
        }
 
        if (done)
-               debug_sprintf_event(sfdbg, 6, "aux_reset_buffer: "
+               debug_sprintf_event(sfdbg, 6, "%s: aux_reset_buffer "
                                    "[%#lx -> %#lx -> %#lx] (%#lx, %#lx)\n",
-                                   aux->head, aux->alert_mark, aux->empty_mark,
-                                   AUX_SDB_NUM_ALERT(aux), range);
+                                   __func__, aux->head, aux->alert_mark,
+                                   aux->empty_mark, AUX_SDB_NUM_ALERT(aux),
+                                   range);
 }
 
 /*
@@ -1633,8 +1644,8 @@ static void aux_buffer_free(void *data)
        kfree(aux->sdb_index);
        kfree(aux);
 
-       debug_sprintf_event(sfdbg, 4, "aux_buffer_free: free "
-                           "%lu SDBTs\n", num_sdbt);
+       debug_sprintf_event(sfdbg, 4, "%s: free "
+                           "%lu SDBTs\n", __func__, num_sdbt);
 }
 
 static void aux_sdb_init(unsigned long sdb)
@@ -1742,9 +1753,8 @@ static void *aux_buffer_setup(struct perf_event *event, void **pages,
         */
        aux->empty_mark = sfb->num_sdb - 1;
 
-       debug_sprintf_event(sfdbg, 4, "aux_buffer_setup: setup %lu SDBTs"
-                           " and %lu SDBs\n",
-                           sfb->num_sdbt, sfb->num_sdb);
+       debug_sprintf_event(sfdbg, 4, "%s: setup %lu SDBTs and %lu SDBs\n",
+                           __func__, sfb->num_sdbt, sfb->num_sdb);
 
        return aux;
 
@@ -1797,9 +1807,9 @@ static int cpumsf_pmu_check_period(struct perf_event *event, u64 value)
        event->attr.sample_period = rate;
        SAMPL_RATE(&event->hw) = rate;
        hw_init_period(&event->hw, SAMPL_RATE(&event->hw));
-       debug_sprintf_event(sfdbg, 4, "cpumsf_pmu_check_period:"
-                           "cpu:%d value:%#llx period:%#llx freq:%d\n",
-                           event->cpu, value,
+       debug_sprintf_event(sfdbg, 4, "%s:"
+                           " cpu %d value %#llx period %#llx freq %d\n",
+                           __func__, event->cpu, value,
                            event->attr.sample_period, do_freq);
        return 0;
 }
@@ -1875,7 +1885,7 @@ static int cpumsf_pmu_add(struct perf_event *event, int flags)
        if (!SAMPL_DIAG_MODE(&event->hw)) {
                cpuhw->lsctl.tear = (unsigned long) cpuhw->sfb.sdbt;
                cpuhw->lsctl.dear = *(unsigned long *) cpuhw->sfb.sdbt;
-               hw_reset_registers(&event->hw, cpuhw->sfb.sdbt);
+               TEAR_REG(&event->hw) = (unsigned long) cpuhw->sfb.sdbt;
        }
 
        /* Ensure sampling functions are in the disabled state.  If disabled,
@@ -2030,7 +2040,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code,
 
        /* Report measurement alerts only for non-PRA codes */
        if (alert != CPU_MF_INT_SF_PRA)
-               debug_sprintf_event(sfdbg, 6, "measurement alert: %#x\n",
+               debug_sprintf_event(sfdbg, 6, "%s: alert %#x\n", __func__,
                                    alert);
 
        /* Sampling authorization change request */
index 3ff291b..9cbf490 100644 (file)
@@ -355,7 +355,6 @@ early_initcall(async_stack_realloc);
 
 void __init arch_call_rest_init(void)
 {
-       struct stack_frame *frame;
        unsigned long stack;
 
        stack = stack_alloc();
@@ -368,13 +367,7 @@ void __init arch_call_rest_init(void)
        set_task_stack_end_magic(current);
        stack += STACK_INIT_OFFSET;
        S390_lowcore.kernel_stack = stack;
-       frame = (struct stack_frame *) stack;
-       memset(frame, 0, sizeof(*frame));
-       /* Branch to rest_init on the new stack, never returns */
-       asm volatile(
-               "       la      15,0(%[_frame])\n"
-               "       jg      rest_init\n"
-               : : [_frame] "a" (frame));
+       CALL_ON_STACK_NORETURN(rest_init, stack);
 }
 
 static void __init setup_lowcore_dat_off(void)
index 6acdcf1..2794cad 100644 (file)
@@ -262,10 +262,13 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
        lc->spinlock_index = 0;
        lc->percpu_offset = __per_cpu_offset[cpu];
        lc->kernel_asce = S390_lowcore.kernel_asce;
+       lc->user_asce = S390_lowcore.kernel_asce;
        lc->machine_flags = S390_lowcore.machine_flags;
        lc->user_timer = lc->system_timer =
                lc->steal_timer = lc->avg_steal_timer = 0;
        __ctl_store(lc->cregs_save_area, 0, 15);
+       lc->cregs_save_area[1] = lc->kernel_asce;
+       lc->cregs_save_area[7] = lc->vdso_asce;
        save_access_regs((unsigned int *) lc->access_regs_save_area);
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
               sizeof(lc->stfle_fac_list));
@@ -844,6 +847,8 @@ static void smp_init_secondary(void)
 
        S390_lowcore.last_update_clock = get_tod_clock();
        restore_access_regs(S390_lowcore.access_regs_save_area);
+       set_cpu_flag(CIF_ASCE_PRIMARY);
+       set_cpu_flag(CIF_ASCE_SECONDARY);
        cpu_init();
        preempt_disable();
        init_cpu_timer();
@@ -871,7 +876,7 @@ static void __no_sanitize_address smp_start_secondary(void *cpuvoid)
        S390_lowcore.restart_source = -1UL;
        __ctl_load(S390_lowcore.cregs_save_area, 0, 15);
        __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_DAT);
-       CALL_ON_STACK(smp_init_secondary, S390_lowcore.kernel_stack, 0);
+       CALL_ON_STACK_NORETURN(smp_init_secondary, S390_lowcore.kernel_stack);
 }
 
 /* Upping and downing of CPUs */
index f8fc4f8..fc5419a 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/stacktrace.h>
 #include <asm/stacktrace.h>
 #include <asm/unwind.h>
+#include <asm/kprobes.h>
 
 void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
                     struct task_struct *task, struct pt_regs *regs)
@@ -22,3 +23,45 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
                        break;
        }
 }
+
+/*
+ * This function returns an error if it detects any unreliable features of the
+ * stack.  Otherwise it guarantees that the stack trace is reliable.
+ *
+ * If the task is not 'current', the caller *must* ensure the task is inactive.
+ */
+int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
+                            void *cookie, struct task_struct *task)
+{
+       struct unwind_state state;
+       unsigned long addr;
+
+       unwind_for_each_frame(&state, task, NULL, 0) {
+               if (state.stack_info.type != STACK_TYPE_TASK)
+                       return -EINVAL;
+
+               if (state.regs)
+                       return -EINVAL;
+
+               addr = unwind_get_return_address(&state);
+               if (!addr)
+                       return -EINVAL;
+
+#ifdef CONFIG_KPROBES
+               /*
+                * Mark stacktraces with kretprobed functions on them
+                * as unreliable.
+                */
+               if (state.ip == (unsigned long)kretprobe_trampoline)
+                       return -EINVAL;
+#endif
+
+               if (!consume_entry(cookie, addr, false))
+                       return -EINVAL;
+       }
+
+       /* Check for stack corruption */
+       if (unwind_error(&state))
+               return -EINVAL;
+       return 0;
+}
index fa111d3..da2d4d4 100644 (file)
@@ -36,6 +36,12 @@ static bool update_stack_info(struct unwind_state *state, unsigned long sp)
        return true;
 }
 
+static inline bool is_task_pt_regs(struct unwind_state *state,
+                                  struct pt_regs *regs)
+{
+       return task_pt_regs(state->task) == regs;
+}
+
 bool unwind_next_frame(struct unwind_state *state)
 {
        struct stack_info *info = &state->stack_info;
@@ -46,20 +52,16 @@ bool unwind_next_frame(struct unwind_state *state)
 
        regs = state->regs;
        if (unlikely(regs)) {
-               if (state->reuse_sp) {
-                       sp = state->sp;
-                       state->reuse_sp = false;
-               } else {
-                       sp = READ_ONCE_NOCHECK(regs->gprs[15]);
-                       if (unlikely(outside_of_stack(state, sp))) {
-                               if (!update_stack_info(state, sp))
-                                       goto out_err;
-                       }
-               }
+               sp = state->sp;
                sf = (struct stack_frame *) sp;
                ip = READ_ONCE_NOCHECK(sf->gprs[8]);
                reliable = false;
                regs = NULL;
+               if (!__kernel_text_address(ip)) {
+                       /* skip bogus %r14 */
+                       state->regs = NULL;
+                       return unwind_next_frame(state);
+               }
        } else {
                sf = (struct stack_frame *) state->sp;
                sp = READ_ONCE_NOCHECK(sf->back_chain);
@@ -76,15 +78,24 @@ bool unwind_next_frame(struct unwind_state *state)
                        /* No back-chain, look for a pt_regs structure */
                        sp = state->sp + STACK_FRAME_OVERHEAD;
                        if (!on_stack(info, sp, sizeof(struct pt_regs)))
-                               goto out_stop;
+                               goto out_err;
                        regs = (struct pt_regs *) sp;
-                       if (READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE)
+                       if (is_task_pt_regs(state, regs))
                                goto out_stop;
                        ip = READ_ONCE_NOCHECK(regs->psw.addr);
+                       sp = READ_ONCE_NOCHECK(regs->gprs[15]);
+                       if (unlikely(outside_of_stack(state, sp))) {
+                               if (!update_stack_info(state, sp))
+                                       goto out_err;
+                       }
                        reliable = true;
                }
        }
 
+       /* Sanity check: ABI requires SP to be aligned 8 bytes. */
+       if (sp & 0x7)
+               goto out_err;
+
        ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, (void *) sp);
 
        /* Update unwind state */
@@ -103,13 +114,11 @@ out_stop:
 EXPORT_SYMBOL_GPL(unwind_next_frame);
 
 void __unwind_start(struct unwind_state *state, struct task_struct *task,
-                   struct pt_regs *regs, unsigned long sp)
+                   struct pt_regs *regs, unsigned long first_frame)
 {
        struct stack_info *info = &state->stack_info;
-       unsigned long *mask = &state->stack_mask;
-       bool reliable, reuse_sp;
        struct stack_frame *sf;
-       unsigned long ip;
+       unsigned long ip, sp;
 
        memset(state, 0, sizeof(*state));
        state->task = task;
@@ -121,25 +130,28 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
                return;
        }
 
+       /* Get the instruction pointer from pt_regs or the stack frame */
+       if (regs) {
+               ip = regs->psw.addr;
+               sp = regs->gprs[15];
+       } else if (task == current) {
+               sp = current_frame_address();
+       } else {
+               sp = task->thread.ksp;
+       }
+
        /* Get current stack pointer and initialize stack info */
-       if (get_stack_info(sp, task, info, mask) != 0 ||
-           !on_stack(info, sp, sizeof(struct stack_frame))) {
+       if (!update_stack_info(state, sp)) {
                /* Something is wrong with the stack pointer */
                info->type = STACK_TYPE_UNKNOWN;
                state->error = true;
                return;
        }
 
-       /* Get the instruction pointer from pt_regs or the stack frame */
-       if (regs) {
-               ip = READ_ONCE_NOCHECK(regs->psw.addr);
-               reliable = true;
-               reuse_sp = true;
-       } else {
-               sf = (struct stack_frame *) sp;
+       if (!regs) {
+               /* Stack frame is within valid stack */
+               sf = (struct stack_frame *)sp;
                ip = READ_ONCE_NOCHECK(sf->gprs[8]);
-               reliable = false;
-               reuse_sp = false;
        }
 
        ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
@@ -147,7 +159,17 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
        /* Update unwind state */
        state->sp = sp;
        state->ip = ip;
-       state->reliable = reliable;
-       state->reuse_sp = reuse_sp;
+       state->reliable = true;
+
+       if (!first_frame)
+               return;
+       /* Skip through the call chain to the specified starting frame */
+       while (!unwind_done(state)) {
+               if (on_stack(&state->stack_info, first_frame, sizeof(struct stack_frame))) {
+                       if (state->sp >= first_frame)
+                               break;
+               }
+               unwind_next_frame(state);
+       }
 }
 EXPORT_SYMBOL_GPL(__unwind_start);
index ed1fc08..bcc9bdb 100644 (file)
 #include <asm/vdso.h>
 #include <asm/facility.h>
 
-#ifdef CONFIG_COMPAT_VDSO
-extern char vdso32_start, vdso32_end;
-static void *vdso32_kbase = &vdso32_start;
-static unsigned int vdso32_pages;
-static struct page **vdso32_pagelist;
-#endif
-
 extern char vdso64_start, vdso64_end;
 static void *vdso64_kbase = &vdso64_start;
 static unsigned int vdso64_pages;
@@ -55,12 +48,6 @@ static vm_fault_t vdso_fault(const struct vm_special_mapping *sm,
 
        vdso_pagelist = vdso64_pagelist;
        vdso_pages = vdso64_pages;
-#ifdef CONFIG_COMPAT_VDSO
-       if (vma->vm_mm->context.compat_mm) {
-               vdso_pagelist = vdso32_pagelist;
-               vdso_pages = vdso32_pages;
-       }
-#endif
 
        if (vmf->pgoff >= vdso_pages)
                return VM_FAULT_SIGBUS;
@@ -76,10 +63,6 @@ static int vdso_mremap(const struct vm_special_mapping *sm,
        unsigned long vdso_pages;
 
        vdso_pages = vdso64_pages;
-#ifdef CONFIG_COMPAT_VDSO
-       if (vma->vm_mm->context.compat_mm)
-               vdso_pages = vdso32_pages;
-#endif
 
        if ((vdso_pages << PAGE_SHIFT) != vma->vm_end - vma->vm_start)
                return -EINVAL;
@@ -209,12 +192,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (!vdso_enabled)
                return 0;
 
+       if (is_compat_task())
+               return 0;
+
        vdso_pages = vdso64_pages;
-#ifdef CONFIG_COMPAT_VDSO
-       mm->context.compat_mm = is_compat_task();
-       if (mm->context.compat_mm)
-               vdso_pages = vdso32_pages;
-#endif
        /*
         * vDSO has a problem and was disabled, just don't "enable" it for
         * the process
@@ -267,23 +248,6 @@ static int __init vdso_init(void)
        int i;
 
        vdso_init_data(vdso_data);
-#ifdef CONFIG_COMPAT_VDSO
-       /* Calculate the size of the 32 bit vDSO */
-       vdso32_pages = ((&vdso32_end - &vdso32_start
-                        + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
-
-       /* Make sure pages are in the correct state */
-       vdso32_pagelist = kcalloc(vdso32_pages + 1, sizeof(struct page *),
-                                 GFP_KERNEL);
-       BUG_ON(vdso32_pagelist == NULL);
-       for (i = 0; i < vdso32_pages - 1; i++) {
-               struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
-               get_page(pg);
-               vdso32_pagelist[i] = pg;
-       }
-       vdso32_pagelist[vdso32_pages - 1] = virt_to_page(vdso_data);
-       vdso32_pagelist[vdso32_pages] = NULL;
-#endif
 
        /* Calculate the size of the 64 bit vDSO */
        vdso64_pages = ((&vdso64_end - &vdso64_start
diff --git a/arch/s390/kernel/vdso32/.gitignore b/arch/s390/kernel/vdso32/.gitignore
deleted file mode 100644 (file)
index e45fba9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-vdso32.lds
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile
deleted file mode 100644 (file)
index aee9ffb..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# List of files in the vdso, has to be asm only for now
-
-KCOV_INSTRUMENT := n
-
-obj-vdso32 = gettimeofday.o clock_getres.o clock_gettime.o note.o getcpu.o
-
-# Build rules
-
-targets := $(obj-vdso32) vdso32.so vdso32.so.dbg
-obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
-
-KBUILD_AFLAGS += -DBUILD_VDSO
-KBUILD_CFLAGS += -DBUILD_VDSO
-
-KBUILD_AFLAGS_31 := $(filter-out -m64,$(KBUILD_AFLAGS))
-KBUILD_AFLAGS_31 += -m31 -s
-
-KBUILD_CFLAGS_31 := $(filter-out -m64,$(KBUILD_CFLAGS))
-KBUILD_CFLAGS_31 += -m31 -fPIC -shared -fno-common -fno-builtin
-KBUILD_CFLAGS_31 += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
-                   -Wl,--hash-style=both
-
-$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_31)
-$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_31)
-
-obj-y += vdso32_wrapper.o
-extra-y += vdso32.lds
-CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
-
-# Disable gcov profiling, ubsan and kasan for VDSO code
-GCOV_PROFILE := n
-UBSAN_SANITIZE := n
-KASAN_SANITIZE := n
-
-# Force dependency (incbin is bad)
-$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
-
-# link rule for the .so file, .lds has to be first
-$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) FORCE
-       $(call if_changed,vdso32ld)
-
-# strip rule for the .so file
-$(obj)/%.so: OBJCOPYFLAGS := -S
-$(obj)/%.so: $(obj)/%.so.dbg FORCE
-       $(call if_changed,objcopy)
-
-# assembly rules for the .S files
-$(obj-vdso32): %.o: %.S FORCE
-       $(call if_changed_dep,vdso32as)
-
-# actual build commands
-quiet_cmd_vdso32ld = VDSO32L $@
-      cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $(filter %.lds %.o,$^) -o $@
-quiet_cmd_vdso32as = VDSO32A $@
-      cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $<
-
-# install commands for the unstripped file
-quiet_cmd_vdso_install = INSTALL $@
-      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
-
-vdso32.so: $(obj)/vdso32.so.dbg
-       @mkdir -p $(MODLIB)/vdso
-       $(call cmd,vdso_install)
-
-vdso_install: vdso32.so
diff --git a/arch/s390/kernel/vdso32/clock_getres.S b/arch/s390/kernel/vdso32/clock_getres.S
deleted file mode 100644 (file)
index eaf9cf1..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Userland implementation of clock_getres() for 32 bits processes in a
- * s390 kernel for use in the vDSO
- *
- *  Copyright IBM Corp. 2008
- *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- */
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-#include <asm/unistd.h>
-#include <asm/dwarf.h>
-
-       .text
-       .align 4
-       .globl __kernel_clock_getres
-       .type  __kernel_clock_getres,@function
-__kernel_clock_getres:
-       CFI_STARTPROC
-       basr    %r1,0
-       la      %r1,4f-.(%r1)
-       chi     %r2,__CLOCK_REALTIME
-       je      0f
-       chi     %r2,__CLOCK_MONOTONIC
-       je      0f
-       la      %r1,5f-4f(%r1)
-       chi     %r2,__CLOCK_REALTIME_COARSE
-       je      0f
-       chi     %r2,__CLOCK_MONOTONIC_COARSE
-       jne     3f
-0:     ltr     %r3,%r3
-       jz      2f                              /* res == NULL */
-1:     l       %r0,0(%r1)
-       xc      0(4,%r3),0(%r3)                 /* set tp->tv_sec to zero */
-       st      %r0,4(%r3)                      /* store tp->tv_usec */
-2:     lhi     %r2,0
-       br      %r14
-3:     lhi     %r1,__NR_clock_getres           /* fallback to svc */
-       svc     0
-       br      %r14
-       CFI_ENDPROC
-4:     .long   __CLOCK_REALTIME_RES
-5:     .long   __CLOCK_COARSE_RES
-       .size   __kernel_clock_getres,.-__kernel_clock_getres
diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S
deleted file mode 100644 (file)
index ada5c11..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Userland implementation of clock_gettime() for 32 bits processes in a
- * s390 kernel for use in the vDSO
- *
- *  Copyright IBM Corp. 2008
- *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- */
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-#include <asm/unistd.h>
-#include <asm/dwarf.h>
-#include <asm/ptrace.h>
-
-       .text
-       .align 4
-       .globl __kernel_clock_gettime
-       .type  __kernel_clock_gettime,@function
-__kernel_clock_gettime:
-       CFI_STARTPROC
-       ahi     %r15,-16
-       CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD+16
-       CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
-       basr    %r5,0
-0:     al      %r5,21f-0b(%r5)                 /* get &_vdso_data */
-       chi     %r2,__CLOCK_REALTIME_COARSE
-       je      10f
-       chi     %r2,__CLOCK_REALTIME
-       je      11f
-       chi     %r2,__CLOCK_MONOTONIC_COARSE
-       je      9f
-       chi     %r2,__CLOCK_MONOTONIC
-       jne     19f
-
-       /* CLOCK_MONOTONIC */
-1:     l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
-       tml     %r4,0x0001                      /* pending update ? loop */
-       jnz     1b
-       stcke   0(%r15)                         /* Store TOD clock */
-       lm      %r0,%r1,1(%r15)
-       s       %r0,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
-       sl      %r1,__VDSO_XTIME_STAMP+4(%r5)
-       brc     3,2f
-       ahi     %r0,-1
-2:     ms      %r0,__VDSO_TK_MULT(%r5)         /*  * tk->mult */
-       lr      %r2,%r0
-       l       %r0,__VDSO_TK_MULT(%r5)
-       ltr     %r1,%r1
-       mr      %r0,%r0
-       jnm     3f
-       a       %r0,__VDSO_TK_MULT(%r5)
-3:     alr     %r0,%r2
-       al      %r0,__VDSO_WTOM_NSEC(%r5)
-       al      %r1,__VDSO_WTOM_NSEC+4(%r5)
-       brc     12,5f
-       ahi     %r0,1
-5:     l       %r2,__VDSO_TK_SHIFT(%r5)        /* Timekeeper shift */
-       srdl    %r0,0(%r2)                      /*  >> tk->shift */
-       l       %r2,__VDSO_WTOM_SEC+4(%r5)
-       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
-       jne     1b
-       basr    %r5,0
-6:     ltr     %r0,%r0
-       jnz     7f
-       cl      %r1,20f-6b(%r5)
-       jl      8f
-7:     ahi     %r2,1
-       sl      %r1,20f-6b(%r5)
-       brc     3,6b
-       ahi     %r0,-1
-       j       6b
-8:     st      %r2,0(%r3)                      /* store tp->tv_sec */
-       st      %r1,4(%r3)                      /* store tp->tv_nsec */
-       lhi     %r2,0
-       ahi     %r15,16
-       CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
-       CFI_RESTORE 15
-       br      %r14
-
-       /* CLOCK_MONOTONIC_COARSE */
-       CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD+16
-       CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
-9:     l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
-       tml     %r4,0x0001                      /* pending update ? loop */
-       jnz     9b
-       l       %r2,__VDSO_WTOM_CRS_SEC+4(%r5)
-       l       %r1,__VDSO_WTOM_CRS_NSEC+4(%r5)
-       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
-       jne     9b
-       j       8b
-
-       /* CLOCK_REALTIME_COARSE */
-10:    l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
-       tml     %r4,0x0001                      /* pending update ? loop */
-       jnz     10b
-       l       %r2,__VDSO_XTIME_CRS_SEC+4(%r5)
-       l       %r1,__VDSO_XTIME_CRS_NSEC+4(%r5)
-       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
-       jne     10b
-       j       17f
-
-       /* CLOCK_REALTIME */
-11:    l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
-       tml     %r4,0x0001                      /* pending update ? loop */
-       jnz     11b
-       stcke   0(%r15)                         /* Store TOD clock */
-       lm      %r0,%r1,__VDSO_TS_END(%r5)      /* TOD steering end time */
-       s       %r0,1(%r15)                     /* no - ts_steering_end */
-       sl      %r1,5(%r15)
-       brc     3,22f
-       ahi     %r0,-1
-22:    ltr     %r0,%r0                         /* past end of steering? */
-       jm      24f
-       srdl    %r0,15                          /* 1 per 2^16 */
-       tm      __VDSO_TS_DIR+3(%r5),0x01       /* steering direction? */
-       jz      23f
-       lcr     %r0,%r0                         /* negative TOD offset */
-       lcr     %r1,%r1
-       je      23f
-       ahi     %r0,-1
-23:    a       %r0,1(%r15)                     /* add TOD timestamp */
-       al      %r1,5(%r15)
-       brc     12,25f
-       ahi     %r0,1
-       j       25f
-24:    lm      %r0,%r1,1(%r15)                 /* load TOD timestamp */
-25:    s       %r0,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
-       sl      %r1,__VDSO_XTIME_STAMP+4(%r5)
-       brc     3,12f
-       ahi     %r0,-1
-12:    ms      %r0,__VDSO_TK_MULT(%r5)         /*  * tk->mult */
-       lr      %r2,%r0
-       l       %r0,__VDSO_TK_MULT(%r5)
-       ltr     %r1,%r1
-       mr      %r0,%r0
-       jnm     13f
-       a       %r0,__VDSO_TK_MULT(%r5)
-13:    alr     %r0,%r2
-       al      %r0,__VDSO_XTIME_NSEC(%r5)      /*  + tk->xtime_nsec */
-       al      %r1,__VDSO_XTIME_NSEC+4(%r5)
-       brc     12,14f
-       ahi     %r0,1
-14:    l       %r2,__VDSO_TK_SHIFT(%r5)        /* Timekeeper shift */
-       srdl    %r0,0(%r2)                      /*  >> tk->shift */
-       l       %r2,__VDSO_XTIME_SEC+4(%r5)
-       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
-       jne     11b
-       basr    %r5,0
-15:    ltr     %r0,%r0
-       jnz     16f
-       cl      %r1,20f-15b(%r5)
-       jl      17f
-16:    ahi     %r2,1
-       sl      %r1,20f-15b(%r5)
-       brc     3,15b
-       ahi     %r0,-1
-       j       15b
-17:    st      %r2,0(%r3)                      /* store tp->tv_sec */
-       st      %r1,4(%r3)                      /* store tp->tv_nsec */
-       lhi     %r2,0
-       ahi     %r15,16
-       CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
-       CFI_RESTORE 15
-       br      %r14
-
-       /* Fallback to system call */
-       CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD+16
-       CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
-19:    lhi     %r1,__NR_clock_gettime
-       svc     0
-       ahi     %r15,16
-       CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
-       CFI_RESTORE 15
-       br      %r14
-       CFI_ENDPROC
-
-20:    .long   1000000000
-21:    .long   _vdso_data - 0b
-       .size   __kernel_clock_gettime,.-__kernel_clock_gettime
diff --git a/arch/s390/kernel/vdso32/getcpu.S b/arch/s390/kernel/vdso32/getcpu.S
deleted file mode 100644 (file)
index 25515f3..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Userland implementation of getcpu() for 32 bits processes in a
- * s390 kernel for use in the vDSO
- *
- *  Copyright IBM Corp. 2016
- *  Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-#include <asm/dwarf.h>
-
-       .text
-       .align 4
-       .globl __kernel_getcpu
-       .type  __kernel_getcpu,@function
-__kernel_getcpu:
-       CFI_STARTPROC
-       la      %r4,0
-       sacf    256
-       l       %r5,__VDSO_CPU_NR(%r4)
-       l       %r4,__VDSO_NODE_ID(%r4)
-       sacf    0
-       ltr     %r2,%r2
-       jz      2f
-       st      %r5,0(%r2)
-2:     ltr     %r3,%r3
-       jz      3f
-       st      %r4,0(%r3)
-3:     lhi     %r2,0
-       br      %r14
-       CFI_ENDPROC
-       .size   __kernel_getcpu,.-__kernel_getcpu
diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S
deleted file mode 100644 (file)
index b23063f..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Userland implementation of gettimeofday() for 32 bits processes in a
- * s390 kernel for use in the vDSO
- *
- *  Copyright IBM Corp. 2008
- *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- */
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-#include <asm/unistd.h>
-#include <asm/dwarf.h>
-#include <asm/ptrace.h>
-
-       .text
-       .align 4
-       .globl __kernel_gettimeofday
-       .type  __kernel_gettimeofday,@function
-__kernel_gettimeofday:
-       CFI_STARTPROC
-       ahi     %r15,-16
-       CFI_ADJUST_CFA_OFFSET 16
-       CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
-       basr    %r5,0
-0:     al      %r5,13f-0b(%r5)                 /* get &_vdso_data */
-1:     ltr     %r3,%r3                         /* check if tz is NULL */
-       je      2f
-       mvc     0(8,%r3),__VDSO_TIMEZONE(%r5)
-2:     ltr     %r2,%r2                         /* check if tv is NULL */
-       je      10f
-       l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
-       tml     %r4,0x0001                      /* pending update ? loop */
-       jnz     1b
-       stcke   0(%r15)                         /* Store TOD clock */
-       lm      %r0,%r1,__VDSO_TS_END(%r5)      /* TOD steering end time */
-       s       %r0,1(%r15)
-       sl      %r1,5(%r15)
-       brc     3,14f
-       ahi     %r0,-1
-14:    ltr     %r0,%r0                         /* past end of steering? */
-       jm      16f
-       srdl    %r0,15                          /* 1 per 2^16 */
-       tm      __VDSO_TS_DIR+3(%r5),0x01       /* steering direction? */
-       jz      15f
-       lcr     %r0,%r0                         /* negative TOD offset */
-       lcr     %r1,%r1
-       je      15f
-       ahi     %r0,-1
-15:    a       %r0,1(%r15)                     /* add TOD timestamp */
-       al      %r1,5(%r15)
-       brc     12,17f
-       ahi     %r0,1
-       j       17f
-16:    lm      %r0,%r1,1(%r15)                 /* load TOD timestamp */
-17:    s       %r0,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
-       sl      %r1,__VDSO_XTIME_STAMP+4(%r5)
-       brc     3,3f
-       ahi     %r0,-1
-3:     ms      %r0,__VDSO_TK_MULT(%r5)         /*  * tk->mult */
-       st      %r0,0(%r15)
-       l       %r0,__VDSO_TK_MULT(%r5)
-       ltr     %r1,%r1
-       mr      %r0,%r0
-       jnm     4f
-       a       %r0,__VDSO_TK_MULT(%r5)
-4:     al      %r0,0(%r15)
-       al      %r0,__VDSO_XTIME_NSEC(%r5)      /*  + xtime */
-       al      %r1,__VDSO_XTIME_NSEC+4(%r5)
-       brc     12,5f
-       ahi     %r0,1
-5:     mvc     0(4,%r15),__VDSO_XTIME_SEC+4(%r5)
-       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
-       jne     1b
-       l       %r4,__VDSO_TK_SHIFT(%r5)        /* Timekeeper shift */
-       srdl    %r0,0(%r4)                      /*  >> tk->shift */
-       l       %r4,0(%r15)                     /* get tv_sec from stack */
-       basr    %r5,0
-6:     ltr     %r0,%r0
-       jnz     7f
-       cl      %r1,11f-6b(%r5)
-       jl      8f
-7:     ahi     %r4,1
-       sl      %r1,11f-6b(%r5)
-       brc     3,6b
-       ahi     %r0,-1
-       j       6b
-8:     st      %r4,0(%r2)                      /* store tv->tv_sec */
-       ltr     %r1,%r1
-       m       %r0,12f-6b(%r5)
-       jnm     9f
-       al      %r0,12f-6b(%r5)
-9:     srl     %r0,6
-       st      %r0,4(%r2)                      /* store tv->tv_usec */
-10:    slr     %r2,%r2
-       ahi     %r15,16
-       CFI_ADJUST_CFA_OFFSET -16
-       CFI_RESTORE 15
-       br      %r14
-       CFI_ENDPROC
-11:    .long   1000000000
-12:    .long   274877907
-13:    .long   _vdso_data - 0b
-       .size   __kernel_gettimeofday,.-__kernel_gettimeofday
diff --git a/arch/s390/kernel/vdso32/note.S b/arch/s390/kernel/vdso32/note.S
deleted file mode 100644 (file)
index db19d06..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
- * Here we can supply some information useful to userland.
- */
-
-#include <linux/uts.h>
-#include <linux/version.h>
-#include <linux/elfnote.h>
-
-ELFNOTE_START(Linux, 0, "a")
-       .long LINUX_VERSION_CODE
-ELFNOTE_END
diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S
deleted file mode 100644 (file)
index 721c495..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * This is the infamous ld script for the 32 bits vdso
- * library
- */
-
-#include <asm/page.h>
-#include <asm/vdso.h>
-
-OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
-OUTPUT_ARCH(s390:31-bit)
-ENTRY(_start)
-
-SECTIONS
-{
-       . = VDSO32_LBASE + SIZEOF_HEADERS;
-
-       .hash           : { *(.hash) }                  :text
-       .gnu.hash       : { *(.gnu.hash) }
-       .dynsym         : { *(.dynsym) }
-       .dynstr         : { *(.dynstr) }
-       .gnu.version    : { *(.gnu.version) }
-       .gnu.version_d  : { *(.gnu.version_d) }
-       .gnu.version_r  : { *(.gnu.version_r) }
-
-       .note           : { *(.note.*) }                :text   :note
-
-       . = ALIGN(16);
-       .text           : {
-               *(.text .stub .text.* .gnu.linkonce.t.*)
-       } :text
-       PROVIDE(__etext = .);
-       PROVIDE(_etext = .);
-       PROVIDE(etext = .);
-
-       /*
-        * Other stuff is appended to the text segment:
-        */
-       .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
-       .rodata1        : { *(.rodata1) }
-
-       .dynamic        : { *(.dynamic) }               :text   :dynamic
-
-       .eh_frame_hdr   : { *(.eh_frame_hdr) }          :text   :eh_frame_hdr
-       .eh_frame       : { KEEP (*(.eh_frame)) }       :text
-       .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
-
-       .rela.dyn ALIGN(8) : { *(.rela.dyn) }
-       .got ALIGN(8)   : { *(.got .toc) }
-
-       _end = .;
-       PROVIDE(end = .);
-
-       /*
-        * Stabs debugging sections are here too.
-        */
-       .stab          0 : { *(.stab) }
-       .stabstr       0 : { *(.stabstr) }
-       .stab.excl     0 : { *(.stab.excl) }
-       .stab.exclstr  0 : { *(.stab.exclstr) }
-       .stab.index    0 : { *(.stab.index) }
-       .stab.indexstr 0 : { *(.stab.indexstr) }
-       .comment       0 : { *(.comment) }
-
-       /*
-        * DWARF debug sections.
-        * Symbols in the DWARF debugging sections are relative to the
-        * beginning of the section so we begin them at 0.
-        */
-       /* DWARF 1 */
-       .debug          0 : { *(.debug) }
-       .line           0 : { *(.line) }
-       /* GNU DWARF 1 extensions */
-       .debug_srcinfo  0 : { *(.debug_srcinfo) }
-       .debug_sfnames  0 : { *(.debug_sfnames) }
-       /* DWARF 1.1 and DWARF 2 */
-       .debug_aranges  0 : { *(.debug_aranges) }
-       .debug_pubnames 0 : { *(.debug_pubnames) }
-       /* DWARF 2 */
-       .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
-       .debug_abbrev   0 : { *(.debug_abbrev) }
-       .debug_line     0 : { *(.debug_line) }
-       .debug_frame    0 : { *(.debug_frame) }
-       .debug_str      0 : { *(.debug_str) }
-       .debug_loc      0 : { *(.debug_loc) }
-       .debug_macinfo  0 : { *(.debug_macinfo) }
-       /* SGI/MIPS DWARF 2 extensions */
-       .debug_weaknames 0 : { *(.debug_weaknames) }
-       .debug_funcnames 0 : { *(.debug_funcnames) }
-       .debug_typenames 0 : { *(.debug_typenames) }
-       .debug_varnames  0 : { *(.debug_varnames) }
-       /* DWARF 3 */
-       .debug_pubtypes 0 : { *(.debug_pubtypes) }
-       .debug_ranges   0 : { *(.debug_ranges) }
-       .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
-
-       . = ALIGN(PAGE_SIZE);
-       PROVIDE(_vdso_data = .);
-
-       /DISCARD/       : {
-               *(.note.GNU-stack)
-               *(.branch_lt)
-               *(.data .data.* .gnu.linkonce.d.* .sdata*)
-               *(.bss .sbss .dynbss .dynsbss)
-       }
-}
-
-/*
- * Very old versions of ld do not recognize this name token; use the constant.
- */
-#define PT_GNU_EH_FRAME        0x6474e550
-
-/*
- * We must supply the ELF program headers explicitly to get just one
- * PT_LOAD segment, and set the flags explicitly to make segments read-only.
- */
-PHDRS
-{
-       text            PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
-       dynamic         PT_DYNAMIC FLAGS(4);            /* PF_R */
-       note            PT_NOTE FLAGS(4);               /* PF_R */
-       eh_frame_hdr    PT_GNU_EH_FRAME;
-}
-
-/*
- * This controls what symbols we export from the DSO.
- */
-VERSION
-{
-       VDSO_VERSION_STRING {
-       global:
-               /*
-                * Has to be there for the kernel to find
-                */
-               __kernel_gettimeofday;
-               __kernel_clock_gettime;
-               __kernel_clock_getres;
-               __kernel_getcpu;
-
-       local: *;
-       };
-}
diff --git a/arch/s390/kernel/vdso32/vdso32_wrapper.S b/arch/s390/kernel/vdso32/vdso32_wrapper.S
deleted file mode 100644 (file)
index de2fb93..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/init.h>
-#include <linux/linkage.h>
-#include <asm/page.h>
-
-       __PAGE_ALIGNED_DATA
-
-       .globl vdso32_start, vdso32_end
-       .balign PAGE_SIZE
-vdso32_start:
-       .incbin "arch/s390/kernel/vdso32/vdso32.so"
-       .balign PAGE_SIZE
-vdso32_end:
-
-       .previous
index 2446e9d..3c04f73 100644 (file)
        .type  __kernel_getcpu,@function
 __kernel_getcpu:
        CFI_STARTPROC
-       la      %r4,0
        sacf    256
-       l       %r5,__VDSO_CPU_NR(%r4)
-       l       %r4,__VDSO_NODE_ID(%r4)
+       lm      %r4,%r5,__VDSO_GETCPU_VAL(%r0)
        sacf    0
        ltgr    %r2,%r2
        jz      2f
index d7c218e..28fd66d 100644 (file)
@@ -11,3 +11,6 @@ lib-$(CONFIG_UPROBES) += probes.o
 # Instrumenting memory accesses to __user data (in different address space)
 # produce false positives
 KASAN_SANITIZE_uaccess.o := n
+
+obj-$(CONFIG_S390_UNWIND_SELFTEST) += test_unwind.o
+CFLAGS_test_unwind.o += -fno-optimize-sibling-calls
diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c
new file mode 100644 (file)
index 0000000..bda7ac0
--- /dev/null
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test module for unwind_for_each_frame
+ */
+
+#define pr_fmt(fmt) "test_unwind: " fmt
+#include <asm/unwind.h>
+#include <linux/completion.h>
+#include <linux/kallsyms.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kprobes.h>
+#include <linux/wait.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+
+#define BT_BUF_SIZE (PAGE_SIZE * 4)
+
+/*
+ * To avoid printk line limit split backtrace by lines
+ */
+static void print_backtrace(char *bt)
+{
+       char *p;
+
+       while (true) {
+               p = strsep(&bt, "\n");
+               if (!p)
+                       break;
+               pr_err("%s\n", p);
+       }
+}
+
+/*
+ * Calls unwind_for_each_frame(task, regs, sp) and verifies that the result
+ * contains unwindme_func2 followed by unwindme_func1.
+ */
+static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
+                               unsigned long sp)
+{
+       int frame_count, prev_is_func2, seen_func2_func1;
+       const int max_frames = 128;
+       struct unwind_state state;
+       size_t bt_pos = 0;
+       int ret = 0;
+       char *bt;
+
+       bt = kmalloc(BT_BUF_SIZE, GFP_ATOMIC);
+       if (!bt) {
+               pr_err("failed to allocate backtrace buffer\n");
+               return -ENOMEM;
+       }
+       /* Unwind. */
+       frame_count = 0;
+       prev_is_func2 = 0;
+       seen_func2_func1 = 0;
+       unwind_for_each_frame(&state, task, regs, sp) {
+               unsigned long addr = unwind_get_return_address(&state);
+               char sym[KSYM_SYMBOL_LEN];
+
+               if (frame_count++ == max_frames)
+                       break;
+               if (state.reliable && !addr) {
+                       pr_err("unwind state reliable but addr is 0\n");
+                       return -EINVAL;
+               }
+               sprint_symbol(sym, addr);
+               if (bt_pos < BT_BUF_SIZE) {
+                       bt_pos += snprintf(bt + bt_pos, BT_BUF_SIZE - bt_pos,
+                                          state.reliable ? " [%-7s%px] %pSR\n" :
+                                                           "([%-7s%px] %pSR)\n",
+                                          stack_type_name(state.stack_info.type),
+                                          (void *)state.sp, (void *)state.ip);
+                       if (bt_pos >= BT_BUF_SIZE)
+                               pr_err("backtrace buffer is too small\n");
+               }
+               frame_count += 1;
+               if (prev_is_func2 && str_has_prefix(sym, "unwindme_func1"))
+                       seen_func2_func1 = 1;
+               prev_is_func2 = str_has_prefix(sym, "unwindme_func2");
+       }
+
+       /* Check the results. */
+       if (unwind_error(&state)) {
+               pr_err("unwind error\n");
+               ret = -EINVAL;
+       }
+       if (!seen_func2_func1) {
+               pr_err("unwindme_func2 and unwindme_func1 not found\n");
+               ret = -EINVAL;
+       }
+       if (frame_count == max_frames) {
+               pr_err("Maximum number of frames exceeded\n");
+               ret = -EINVAL;
+       }
+       if (ret)
+               print_backtrace(bt);
+       kfree(bt);
+       return ret;
+}
+
+/* State of the task being unwound. */
+struct unwindme {
+       int flags;
+       int ret;
+       struct task_struct *task;
+       struct completion task_ready;
+       wait_queue_head_t task_wq;
+       unsigned long sp;
+};
+
+static struct unwindme *unwindme;
+
+/* Values of unwindme.flags. */
+#define UWM_DEFAULT            0x0
+#define UWM_THREAD             0x1     /* Unwind a separate task. */
+#define UWM_REGS               0x2     /* Pass regs to test_unwind(). */
+#define UWM_SP                 0x4     /* Pass sp to test_unwind(). */
+#define UWM_CALLER             0x8     /* Unwind starting from caller. */
+#define UWM_SWITCH_STACK       0x10    /* Use CALL_ON_STACK. */
+#define UWM_IRQ                        0x20    /* Unwind from irq context. */
+#define UWM_PGM                        0x40    /* Unwind from program check handler. */
+
+static __always_inline unsigned long get_psw_addr(void)
+{
+       unsigned long psw_addr;
+
+       asm volatile(
+               "basr   %[psw_addr],0\n"
+               : [psw_addr] "=d" (psw_addr));
+       return psw_addr;
+}
+
+#ifdef CONFIG_KPROBES
+static int pgm_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct unwindme *u = unwindme;
+
+       u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? regs : NULL,
+                            (u->flags & UWM_SP) ? u->sp : 0);
+       return 0;
+}
+#endif
+
+/* This function may or may not appear in the backtrace. */
+static noinline int unwindme_func4(struct unwindme *u)
+{
+       if (!(u->flags & UWM_CALLER))
+               u->sp = current_frame_address();
+       if (u->flags & UWM_THREAD) {
+               complete(&u->task_ready);
+               wait_event(u->task_wq, kthread_should_park());
+               kthread_parkme();
+               return 0;
+#ifdef CONFIG_KPROBES
+       } else if (u->flags & UWM_PGM) {
+               struct kprobe kp;
+               int ret;
+
+               unwindme = u;
+               memset(&kp, 0, sizeof(kp));
+               kp.symbol_name = "do_report_trap";
+               kp.pre_handler = pgm_pre_handler;
+               ret = register_kprobe(&kp);
+               if (ret < 0) {
+                       pr_err("register_kprobe failed %d\n", ret);
+                       return -EINVAL;
+               }
+
+               /*
+                * trigger specification exception
+                */
+               asm volatile(
+                       "       mvcl    %%r1,%%r1\n"
+                       "0:     nopr    %%r7\n"
+                       EX_TABLE(0b, 0b)
+                       :);
+
+               unregister_kprobe(&kp);
+               unwindme = NULL;
+               return u->ret;
+#endif
+       } else {
+               struct pt_regs regs;
+
+               memset(&regs, 0, sizeof(regs));
+               regs.psw.addr = get_psw_addr();
+               regs.gprs[15] = current_stack_pointer();
+               return test_unwind(NULL,
+                                  (u->flags & UWM_REGS) ? &regs : NULL,
+                                  (u->flags & UWM_SP) ? u->sp : 0);
+       }
+}
+
+/* This function may or may not appear in the backtrace. */
+static noinline int unwindme_func3(struct unwindme *u)
+{
+       u->sp = current_frame_address();
+       return unwindme_func4(u);
+}
+
+/* This function must appear in the backtrace. */
+static noinline int unwindme_func2(struct unwindme *u)
+{
+       int rc;
+
+       if (u->flags & UWM_SWITCH_STACK) {
+               preempt_disable();
+               rc = CALL_ON_STACK(unwindme_func3, S390_lowcore.nodat_stack, 1, u);
+               preempt_enable();
+               return rc;
+       } else {
+               return unwindme_func3(u);
+       }
+}
+
+/* This function must follow unwindme_func2 in the backtrace. */
+static noinline int unwindme_func1(void *u)
+{
+       return unwindme_func2((struct unwindme *)u);
+}
+
+static void unwindme_irq_handler(struct ext_code ext_code,
+                                      unsigned int param32,
+                                      unsigned long param64)
+{
+       struct unwindme *u = READ_ONCE(unwindme);
+
+       if (u && u->task == current) {
+               unwindme = NULL;
+               u->task = NULL;
+               u->ret = unwindme_func1(u);
+       }
+}
+
+static int test_unwind_irq(struct unwindme *u)
+{
+       preempt_disable();
+       if (register_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler)) {
+               pr_info("Couldn't reqister external interrupt handler");
+               return -1;
+       }
+       u->task = current;
+       unwindme = u;
+       udelay(1);
+       unregister_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler);
+       preempt_enable();
+       return u->ret;
+}
+
+/* Spawns a task and passes it to test_unwind(). */
+static int test_unwind_task(struct unwindme *u)
+{
+       struct task_struct *task;
+       int ret;
+
+       /* Initialize thread-related fields. */
+       init_completion(&u->task_ready);
+       init_waitqueue_head(&u->task_wq);
+
+       /*
+        * Start the task and wait until it reaches unwindme_func4() and sleeps
+        * in (task_ready, unwind_done] range.
+        */
+       task = kthread_run(unwindme_func1, u, "%s", __func__);
+       if (IS_ERR(task)) {
+               pr_err("kthread_run() failed\n");
+               return PTR_ERR(task);
+       }
+       /*
+        * Make sure task reaches unwindme_func4 before parking it,
+        * we might park it before kthread function has been executed otherwise
+        */
+       wait_for_completion(&u->task_ready);
+       kthread_park(task);
+       /* Unwind. */
+       ret = test_unwind(task, NULL, (u->flags & UWM_SP) ? u->sp : 0);
+       kthread_stop(task);
+       return ret;
+}
+
+static int test_unwind_flags(int flags)
+{
+       struct unwindme u;
+
+       u.flags = flags;
+       if (u.flags & UWM_THREAD)
+               return test_unwind_task(&u);
+       else if (u.flags & UWM_IRQ)
+               return test_unwind_irq(&u);
+       else
+               return unwindme_func1(&u);
+}
+
+static int test_unwind_init(void)
+{
+       int ret = 0;
+
+#define TEST(flags)                                                    \
+do {                                                                   \
+       pr_info("[ RUN      ] " #flags "\n");                           \
+       if (!test_unwind_flags((flags))) {                              \
+               pr_info("[       OK ] " #flags "\n");                   \
+       } else {                                                        \
+               pr_err("[  FAILED  ] " #flags "\n");                    \
+               ret = -EINVAL;                                          \
+       }                                                               \
+} while (0)
+
+       TEST(UWM_DEFAULT);
+       TEST(UWM_SP);
+       TEST(UWM_REGS);
+       TEST(UWM_SWITCH_STACK);
+       TEST(UWM_SP | UWM_REGS);
+       TEST(UWM_CALLER | UWM_SP);
+       TEST(UWM_CALLER | UWM_SP | UWM_REGS);
+       TEST(UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
+       TEST(UWM_THREAD);
+       TEST(UWM_THREAD | UWM_SP);
+       TEST(UWM_THREAD | UWM_CALLER | UWM_SP);
+       TEST(UWM_IRQ);
+       TEST(UWM_IRQ | UWM_SWITCH_STACK);
+       TEST(UWM_IRQ | UWM_SP);
+       TEST(UWM_IRQ | UWM_REGS);
+       TEST(UWM_IRQ | UWM_SP | UWM_REGS);
+       TEST(UWM_IRQ | UWM_CALLER | UWM_SP);
+       TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS);
+       TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
+#ifdef CONFIG_KPROBES
+       TEST(UWM_PGM);
+       TEST(UWM_PGM | UWM_SP);
+       TEST(UWM_PGM | UWM_REGS);
+       TEST(UWM_PGM | UWM_SP | UWM_REGS);
+#endif
+#undef TEST
+
+       return ret;
+}
+
+static void test_unwind_exit(void)
+{
+}
+
+module_init(test_unwind_init);
+module_exit(test_unwind_exit);
+MODULE_LICENSE("GPL");
index 59ad799..de7ca4b 100644 (file)
@@ -119,9 +119,15 @@ static unsigned long __no_sanitize_address _memcpy_real(unsigned long dest,
  */
 int memcpy_real(void *dest, void *src, size_t count)
 {
-       if (S390_lowcore.nodat_stack != 0)
-               return CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack,
-                                    3, dest, src, count);
+       int rc;
+
+       if (S390_lowcore.nodat_stack != 0) {
+               preempt_disable();
+               rc = CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack, 3,
+                                  dest, src, count);
+               preempt_enable();
+               return rc;
+       }
        /*
         * This is a really early memcpy_real call, the stacks are
         * not set up yet. Just call _memcpy_real on the early boot
index c7fea9b..8e87295 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/seq_file.h>
 #include <linux/jump_label.h>
 #include <linux/pci.h>
+#include <linux/printk.h>
 
 #include <asm/isc.h>
 #include <asm/airq.h>
@@ -43,7 +44,7 @@ static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
 static DEFINE_SPINLOCK(zpci_domain_lock);
 
 #define ZPCI_IOMAP_ENTRIES                                             \
-       min(((unsigned long) ZPCI_NR_DEVICES * PCI_BAR_COUNT / 2),      \
+       min(((unsigned long) ZPCI_NR_DEVICES * PCI_STD_NUM_BARS / 2),   \
            ZPCI_IOMAP_MAX_ENTRIES)
 
 static DEFINE_SPINLOCK(zpci_iomap_lock);
@@ -294,7 +295,7 @@ static void __iomem *pci_iomap_range_mio(struct pci_dev *pdev, int bar,
 void __iomem *pci_iomap_range(struct pci_dev *pdev, int bar,
                              unsigned long offset, unsigned long max)
 {
-       if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT)
+       if (bar >= PCI_STD_NUM_BARS || !pci_resource_len(pdev, bar))
                return NULL;
 
        if (static_branch_likely(&have_mio))
@@ -324,7 +325,7 @@ static void __iomem *pci_iomap_wc_range_mio(struct pci_dev *pdev, int bar,
 void __iomem *pci_iomap_wc_range(struct pci_dev *pdev, int bar,
                                 unsigned long offset, unsigned long max)
 {
-       if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT)
+       if (bar >= PCI_STD_NUM_BARS || !pci_resource_len(pdev, bar))
                return NULL;
 
        if (static_branch_likely(&have_mio))
@@ -416,7 +417,7 @@ static void zpci_map_resources(struct pci_dev *pdev)
        resource_size_t len;
        int i;
 
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                len = pci_resource_len(pdev, i);
                if (!len)
                        continue;
@@ -451,7 +452,7 @@ static void zpci_unmap_resources(struct pci_dev *pdev)
        if (zpci_use_mio(zdev))
                return;
 
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                len = pci_resource_len(pdev, i);
                if (!len)
                        continue;
@@ -514,7 +515,7 @@ static int zpci_setup_bus_resources(struct zpci_dev *zdev,
        snprintf(zdev->res_name, sizeof(zdev->res_name),
                 "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR);
 
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (!zdev->bars[i].size)
                        continue;
                entry = zpci_alloc_iomap(zdev);
@@ -551,7 +552,7 @@ static void zpci_cleanup_bus_resources(struct zpci_dev *zdev)
 {
        int i;
 
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (!zdev->bars[i].size || !zdev->bars[i].res)
                        continue;
 
@@ -573,7 +574,7 @@ int pcibios_add_device(struct pci_dev *pdev)
        pdev->dev.dma_ops = &s390_pci_dma_ops;
        zpci_map_resources(pdev);
 
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                res = &pdev->resource[i];
                if (res->parent || !res->flags)
                        continue;
@@ -659,6 +660,8 @@ static int zpci_alloc_domain(struct zpci_dev *zdev)
                spin_lock(&zpci_domain_lock);
                if (test_bit(zdev->domain, zpci_domain)) {
                        spin_unlock(&zpci_domain_lock);
+                       pr_err("Adding PCI function %08x failed because domain %04x is already assigned\n",
+                               zdev->fid, zdev->domain);
                        return -EEXIST;
                }
                set_bit(zdev->domain, zpci_domain);
@@ -670,6 +673,8 @@ static int zpci_alloc_domain(struct zpci_dev *zdev)
        zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES);
        if (zdev->domain == ZPCI_NR_DEVICES) {
                spin_unlock(&zpci_domain_lock);
+               pr_err("Adding PCI function %08x failed because the configured limit of %d is reached\n",
+                       zdev->fid, ZPCI_NR_DEVICES);
                return -ENOSPC;
        }
        set_bit(zdev->domain, zpci_domain);
index e585a62..4c613e5 100644 (file)
@@ -145,7 +145,7 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev,
 {
        int i;
 
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                zdev->bars[i].val = le32_to_cpu(response->bar[i]);
                zdev->bars[i].size = response->bar_size[i];
        }
@@ -164,8 +164,8 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev,
                       sizeof(zdev->util_str));
        }
        zdev->mio_capable = response->mio_addr_avail;
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
-               if (!(response->mio.valid & (1 << (PCI_BAR_COUNT - i - 1))))
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+               if (!(response->mio.valid & (1 << (PCI_STD_NUM_BARS - i - 1))))
                        continue;
 
                zdev->bars[i].mio_wb = (void __iomem *) response->mio.addr[i].wb;
index dbd2cde..b0f9c8f 100644 (file)
@@ -67,7 +67,7 @@ static struct cpuidle_driver cpuidle_driver = {
                        .enter = cpuidle_sleep_enter,
                        .name = "C2",
                        .desc = "SuperH Sleep Mode [SF]",
-                       .disabled = true,
+                       .flags = CPUIDLE_FLAG_UNUSABLE,
                },
                {
                        .exit_latency = 2300,
@@ -76,7 +76,7 @@ static struct cpuidle_driver cpuidle_driver = {
                        .enter = cpuidle_sleep_enter,
                        .name = "C3",
                        .desc = "SuperH Mobile Standby Mode [SF]",
-                       .disabled = true,
+                       .flags = CPUIDLE_FLAG_UNUSABLE,
                },
        },
        .safe_state_index = 0,
@@ -86,10 +86,10 @@ static struct cpuidle_driver cpuidle_driver = {
 int __init sh_mobile_setup_cpuidle(void)
 {
        if (sh_mobile_sleep_supported & SUSP_SH_SF)
-               cpuidle_driver.states[1].disabled = false;
+               cpuidle_driver.states[1].flags = CPUIDLE_FLAG_NONE;
 
        if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
-               cpuidle_driver.states[2].disabled = false;
+               cpuidle_driver.states[2].flags = CPUIDLE_FLAG_NONE;
 
        return cpuidle_register(&cpuidle_driver, NULL);
 }
index b621216..62de2eb 100644 (file)
@@ -18,7 +18,6 @@ generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += mmiowb.h
 generic-y += module.h
-generic-y += msi.h
 generic-y += preempt.h
 generic-y += serial.h
 generic-y += trace_clock.h
index 10538a4..eae0c92 100644 (file)
@@ -26,14 +26,14 @@ static inline void free_pgd_fast(pgd_t *pgd)
 #define pgd_free(mm, pgd)      free_pgd_fast(pgd)
 #define pgd_alloc(mm)  get_pgd_fast()
 
-static inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+static inline void pud_set(pud_t * pudp, pmd_t * pmdp)
 {
        unsigned long pa = __nocache_pa(pmdp);
 
-       set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD | (pa >> 4))));
+       set_pte((pte_t *)pudp, __pte((SRMMU_ET_PTD | (pa >> 4))));
 }
 
-#define pgd_populate(MM, PGD, PMD)      pgd_set(PGD, PMD)
+#define pud_populate(MM, PGD, PMD)      pud_set(PGD, PMD)
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm,
                                   unsigned long address)
index 31da448..6d6f44c 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/const.h>
 
 #ifndef __ASSEMBLY__
-#include <asm-generic/4level-fixup.h>
+#include <asm-generic/pgtable-nopud.h>
 
 #include <linux/spinlock.h>
 #include <linux/mm_types.h>
@@ -132,12 +132,12 @@ static inline struct page *pmd_page(pmd_t pmd)
        return pfn_to_page((pmd_val(pmd) & SRMMU_PTD_PMASK) >> (PAGE_SHIFT-4));
 }
 
-static inline unsigned long pgd_page_vaddr(pgd_t pgd)
+static inline unsigned long pud_page_vaddr(pud_t pud)
 {
-       if (srmmu_device_memory(pgd_val(pgd))) {
+       if (srmmu_device_memory(pud_val(pud))) {
                return ~0;
        } else {
-               unsigned long v = pgd_val(pgd) & SRMMU_PTD_PMASK;
+               unsigned long v = pud_val(pud) & SRMMU_PTD_PMASK;
                return (unsigned long)__nocache_va(v << 4);
        }
 }
@@ -184,24 +184,24 @@ static inline void pmd_clear(pmd_t *pmdp)
                set_pte((pte_t *)&pmdp->pmdv[i], __pte(0));
 }
 
-static inline int pgd_none(pgd_t pgd)          
+static inline int pud_none(pud_t pud)
 {
-       return !(pgd_val(pgd) & 0xFFFFFFF);
+       return !(pud_val(pud) & 0xFFFFFFF);
 }
 
-static inline int pgd_bad(pgd_t pgd)
+static inline int pud_bad(pud_t pud)
 {
-       return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD;
+       return (pud_val(pud) & SRMMU_ET_MASK) != SRMMU_ET_PTD;
 }
 
-static inline int pgd_present(pgd_t pgd)
+static inline int pud_present(pud_t pud)
 {
-       return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD);
+       return ((pud_val(pud) & SRMMU_ET_MASK) == SRMMU_ET_PTD);
 }
 
-static inline void pgd_clear(pgd_t *pgdp)
+static inline void pud_clear(pud_t *pudp)
 {
-       set_pte((pte_t *)pgdp, __pte(0));
+       set_pte((pte_t *)pudp, __pte(0));
 }
 
 /*
@@ -319,9 +319,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
-static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t *pmd_offset(pud_t * dir, unsigned long address)
 {
-       return (pmd_t *) pgd_page_vaddr(*dir) +
+       return (pmd_t *) pud_page_vaddr(*dir) +
                ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
 }
 
index 9d0d125..5b933a5 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __SPARC_IPCBUF_H
 #define __SPARC_IPCBUF_H
 
+#include <linux/posix_types.h>
+
 /*
  * The ipc64_perm structure for sparc/sparc64 architecture.
  * Note extra padding because this structure is passed back and forth
index eeeb919..0954552 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _SPARC_MSGBUF_H
 #define _SPARC_MSGBUF_H
 
+#include <asm/ipcbuf.h>
+
 /*
  * The msqid64_ds structure for sparc64 architecture.
  * Note extra padding because this structure is passed back and forth
index cbcbaa4..10621d0 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _SPARC_SEMBUF_H
 #define _SPARC_SEMBUF_H
 
+#include <asm/ipcbuf.h>
+
 /*
  * The semid64_ds structure for sparc architecture.
  * Note extra padding because this structure is passed back and forth
index 8d69de1..89976c9 100644 (file)
@@ -351,6 +351,8 @@ vmalloc_fault:
                 */
                int offset = pgd_index(address);
                pgd_t *pgd, *pgd_k;
+               p4d_t *p4d, *p4d_k;
+               pud_t *pud, *pud_k;
                pmd_t *pmd, *pmd_k;
 
                pgd = tsk->active_mm->pgd + offset;
@@ -363,8 +365,13 @@ vmalloc_fault:
                        return;
                }
 
-               pmd = pmd_offset(pgd, address);
-               pmd_k = pmd_offset(pgd_k, address);
+               p4d = p4d_offset(pgd, address);
+               pud = pud_offset(p4d, address);
+               pmd = pmd_offset(pud, address);
+
+               p4d_k = p4d_offset(pgd_k, address);
+               pud_k = pud_offset(p4d_k, address);
+               pmd_k = pmd_offset(pud_k, address);
 
                if (pmd_present(*pmd) || !pmd_present(*pmd_k))
                        goto bad_area_nosemaphore;
index 86bc2a5..d4a80ad 100644 (file)
@@ -39,10 +39,14 @@ static pte_t *kmap_pte;
 void __init kmap_init(void)
 {
        unsigned long address;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *dir;
 
        address = __fix_to_virt(FIX_KMAP_BEGIN);
-       dir = pmd_offset(pgd_offset_k(address), address);
+       p4d = p4d_offset(pgd_offset_k(address), address);
+       pud = pud_offset(p4d, address);
+       dir = pmd_offset(pud, address);
 
         /* cache the first kmap pte */
         kmap_pte = pte_offset_kernel(dir, address);
index f770ee7..33a0fac 100644 (file)
@@ -239,12 +239,16 @@ static void *iounit_alloc(struct device *dev, size_t len,
                page = va;
                {
                        pgd_t *pgdp;
+                       p4d_t *p4dp;
+                       pud_t *pudp;
                        pmd_t *pmdp;
                        pte_t *ptep;
                        long i;
 
                        pgdp = pgd_offset(&init_mm, addr);
-                       pmdp = pmd_offset(pgdp, addr);
+                       p4dp = p4d_offset(pgdp, addr);
+                       pudp = pud_offset(p4dp, addr);
+                       pmdp = pmd_offset(pudp, addr);
                        ptep = pte_offset_map(pmdp, addr);
 
                        set_pte(ptep, mk_pte(virt_to_page(page), dvma_prot));
index 71ac353..4d3c699 100644 (file)
@@ -343,6 +343,8 @@ static void *sbus_iommu_alloc(struct device *dev, size_t len,
                page = va;
                {
                        pgd_t *pgdp;
+                       p4d_t *p4dp;
+                       pud_t *pudp;
                        pmd_t *pmdp;
                        pte_t *ptep;
 
@@ -354,7 +356,9 @@ static void *sbus_iommu_alloc(struct device *dev, size_t len,
                                __flush_page_to_ram(page);
 
                        pgdp = pgd_offset(&init_mm, addr);
-                       pmdp = pmd_offset(pgdp, addr);
+                       p4dp = p4d_offset(pgdp, addr);
+                       pudp = pud_offset(p4dp, addr);
+                       pmdp = pmd_offset(pudp, addr);
                        ptep = pte_offset_map(pmdp, addr);
 
                        set_pte(ptep, mk_pte(virt_to_page(page), dvma_prot));
index cc3ad64..f56c3c9 100644 (file)
@@ -296,6 +296,8 @@ static void __init srmmu_nocache_init(void)
        void *srmmu_nocache_bitmap;
        unsigned int bitmap_bits;
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        unsigned long paddr, vaddr;
@@ -329,6 +331,8 @@ static void __init srmmu_nocache_init(void)
 
        while (vaddr < srmmu_nocache_end) {
                pgd = pgd_offset_k(vaddr);
+               p4d = p4d_offset(__nocache_fix(pgd), vaddr);
+               pud = pud_offset(__nocache_fix(p4d), vaddr);
                pmd = pmd_offset(__nocache_fix(pgd), vaddr);
                pte = pte_offset_kernel(__nocache_fix(pmd), vaddr);
 
@@ -516,13 +520,17 @@ static inline void srmmu_mapioaddr(unsigned long physaddr,
                                   unsigned long virt_addr, int bus_type)
 {
        pgd_t *pgdp;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
        unsigned long tmp;
 
        physaddr &= PAGE_MASK;
        pgdp = pgd_offset_k(virt_addr);
-       pmdp = pmd_offset(pgdp, virt_addr);
+       p4dp = p4d_offset(pgdp, virt_addr);
+       pudp = pud_offset(p4dp, virt_addr);
+       pmdp = pmd_offset(pudp, virt_addr);
        ptep = pte_offset_kernel(pmdp, virt_addr);
        tmp = (physaddr >> 4) | SRMMU_ET_PTE;
 
@@ -551,11 +559,16 @@ void srmmu_mapiorange(unsigned int bus, unsigned long xpa,
 static inline void srmmu_unmapioaddr(unsigned long virt_addr)
 {
        pgd_t *pgdp;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
 
+
        pgdp = pgd_offset_k(virt_addr);
-       pmdp = pmd_offset(pgdp, virt_addr);
+       p4dp = p4d_offset(pgdp, virt_addr);
+       pudp = pud_offset(p4dp, virt_addr);
+       pmdp = pmd_offset(pudp, virt_addr);
        ptep = pte_offset_kernel(pmdp, virt_addr);
 
        /* No need to flush uncacheable page. */
@@ -693,20 +706,24 @@ static void __init srmmu_early_allocate_ptable_skeleton(unsigned long start,
                                                        unsigned long end)
 {
        pgd_t *pgdp;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
 
        while (start < end) {
                pgdp = pgd_offset_k(start);
-               if (pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
+               p4dp = p4d_offset(pgdp, start);
+               pudp = pud_offset(p4dp, start);
+               if (pud_none(*(pud_t *)__nocache_fix(pudp))) {
                        pmdp = __srmmu_get_nocache(
                            SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
                        if (pmdp == NULL)
                                early_pgtable_allocfail("pmd");
                        memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE);
-                       pgd_set(__nocache_fix(pgdp), pmdp);
+                       pud_set(__nocache_fix(pudp), pmdp);
                }
-               pmdp = pmd_offset(__nocache_fix(pgdp), start);
+               pmdp = pmd_offset(__nocache_fix(pudp), start);
                if (srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
                        ptep = __srmmu_get_nocache(PTE_SIZE, PTE_SIZE);
                        if (ptep == NULL)
@@ -724,19 +741,23 @@ static void __init srmmu_allocate_ptable_skeleton(unsigned long start,
                                                  unsigned long end)
 {
        pgd_t *pgdp;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
 
        while (start < end) {
                pgdp = pgd_offset_k(start);
-               if (pgd_none(*pgdp)) {
+               p4dp = p4d_offset(pgdp, start);
+               pudp = pud_offset(p4dp, start);
+               if (pud_none(*pudp)) {
                        pmdp = __srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
                        if (pmdp == NULL)
                                early_pgtable_allocfail("pmd");
                        memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE);
-                       pgd_set(pgdp, pmdp);
+                       pud_set((pud_t *)pgdp, pmdp);
                }
-               pmdp = pmd_offset(pgdp, start);
+               pmdp = pmd_offset(pudp, start);
                if (srmmu_pmd_none(*pmdp)) {
                        ptep = __srmmu_get_nocache(PTE_SIZE,
                                                             PTE_SIZE);
@@ -779,6 +800,8 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start,
        unsigned long probed;
        unsigned long addr;
        pgd_t *pgdp;
+       p4d_t *p4dp;
+       pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
        int what; /* 0 = normal-pte, 1 = pmd-level pte, 2 = pgd-level pte */
@@ -810,18 +833,20 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start,
                }
 
                pgdp = pgd_offset_k(start);
+               p4dp = p4d_offset(pgdp, start);
+               pudp = pud_offset(p4dp, start);
                if (what == 2) {
                        *(pgd_t *)__nocache_fix(pgdp) = __pgd(probed);
                        start += SRMMU_PGDIR_SIZE;
                        continue;
                }
-               if (pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
+               if (pud_none(*(pud_t *)__nocache_fix(pudp))) {
                        pmdp = __srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE,
                                                   SRMMU_PMD_TABLE_SIZE);
                        if (pmdp == NULL)
                                early_pgtable_allocfail("pmd");
                        memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE);
-                       pgd_set(__nocache_fix(pgdp), pmdp);
+                       pud_set(__nocache_fix(pudp), pmdp);
                }
                pmdp = pmd_offset(__nocache_fix(pgdp), start);
                if (srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
@@ -906,6 +931,8 @@ void __init srmmu_paging_init(void)
        phandle cpunode;
        char node_str[128];
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        unsigned long pages_avail;
@@ -967,7 +994,9 @@ void __init srmmu_paging_init(void)
        srmmu_allocate_ptable_skeleton(PKMAP_BASE, PKMAP_END);
 
        pgd = pgd_offset_k(PKMAP_BASE);
-       pmd = pmd_offset(pgd, PKMAP_BASE);
+       p4d = p4d_offset(pgd, PKMAP_BASE);
+       pud = pud_offset(p4d, PKMAP_BASE);
+       pmd = pmd_offset(pud, PKMAP_BASE);
        pte = pte_offset_kernel(pmd, PKMAP_BASE);
        pkmap_page_table = pte;
 
index fec6b4c..2a6d04f 100644 (file)
@@ -153,7 +153,7 @@ config KERNEL_STACK_ORDER
          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.
+         signals.
 
 config MMAPPER
        tristate "iomem emulation driver"
index fea5a0d..388096f 100644 (file)
@@ -337,7 +337,7 @@ config UML_NET_SLIRP
 endmenu
 
 config VIRTIO_UML
-       tristate "UML driver for virtio devices"
+       bool "UML driver for virtio devices"
        select VIRTIO
        help
          This driver provides support for virtio based paravirtual device
index 769ffbd..92617e1 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2017 - Cambridge Greys Limited
+ * Copyright (C) 2017 - 2019 Cambridge Greys Limited
  * Copyright (C) 2011 - 2014 Cisco Systems Inc
  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
@@ -21,6 +21,9 @@
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <uapi/linux/filter.h>
 #include <init.h>
 #include <irq_kern.h>
 #include <irq_user.h>
@@ -128,6 +131,23 @@ static int get_mtu(struct arglist *def)
        return ETH_MAX_PACKET;
 }
 
+static char *get_bpf_file(struct arglist *def)
+{
+       return uml_vector_fetch_arg(def, "bpffile");
+}
+
+static bool get_bpf_flash(struct arglist *def)
+{
+       char *allow = uml_vector_fetch_arg(def, "bpfflash");
+       long result;
+
+       if (allow != NULL) {
+               if (kstrtoul(allow, 10, &result) == 0)
+                       return (allow > 0);
+       }
+       return false;
+}
+
 static int get_depth(struct arglist *def)
 {
        char *mtu = uml_vector_fetch_arg(def, "depth");
@@ -176,6 +196,7 @@ static int get_transport_options(struct arglist *def)
        int vec_rx = VECTOR_RX;
        int vec_tx = VECTOR_TX;
        long parsed;
+       int result = 0;
 
        if (vector != NULL) {
                if (kstrtoul(vector, 10, &parsed) == 0) {
@@ -186,14 +207,16 @@ static int get_transport_options(struct arglist *def)
                }
        }
 
+       if (get_bpf_flash(def))
+               result = VECTOR_BPF_FLASH;
 
        if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
-               return 0;
+               return result;
        if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
-               return (vec_rx | VECTOR_BPF);
+               return (result | vec_rx | VECTOR_BPF);
        if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
-               return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS);
-       return (vec_rx | vec_tx);
+               return (result | vec_rx | vec_tx | VECTOR_QDISC_BYPASS);
+       return (result | vec_rx | vec_tx);
 }
 
 
@@ -1139,6 +1162,8 @@ static int vector_net_close(struct net_device *dev)
        }
        tasklet_kill(&vp->tx_poll);
        if (vp->fds->rx_fd > 0) {
+               if (vp->bpf)
+                       uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf);
                os_close_file(vp->fds->rx_fd);
                vp->fds->rx_fd = -1;
        }
@@ -1146,7 +1171,10 @@ static int vector_net_close(struct net_device *dev)
                os_close_file(vp->fds->tx_fd);
                vp->fds->tx_fd = -1;
        }
+       if (vp->bpf != NULL)
+               kfree(vp->bpf->filter);
        kfree(vp->bpf);
+       vp->bpf = NULL;
        kfree(vp->fds->remote_addr);
        kfree(vp->transport_data);
        kfree(vp->header_rxbuffer);
@@ -1181,6 +1209,7 @@ static void vector_reset_tx(struct work_struct *work)
        netif_start_queue(vp->dev);
        netif_wake_queue(vp->dev);
 }
+
 static int vector_net_open(struct net_device *dev)
 {
        struct vector_private *vp = netdev_priv(dev);
@@ -1196,6 +1225,8 @@ static int vector_net_open(struct net_device *dev)
        vp->opened = true;
        spin_unlock_irqrestore(&vp->lock, flags);
 
+       vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed));
+
        vp->fds = uml_vector_user_open(vp->unit, vp->parsed);
 
        if (vp->fds == NULL)
@@ -1267,8 +1298,11 @@ static int vector_net_open(struct net_device *dev)
                if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd))
                        vp->options |= VECTOR_BPF;
        }
-       if ((vp->options & VECTOR_BPF) != 0)
-               vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr);
+       if (((vp->options & VECTOR_BPF) != 0) && (vp->bpf == NULL))
+               vp->bpf = uml_vector_default_bpf(dev->dev_addr);
+
+       if (vp->bpf != NULL)
+               uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf);
 
        netif_start_queue(dev);
 
@@ -1347,6 +1381,65 @@ static void vector_net_get_drvinfo(struct net_device *dev,
        strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
 }
 
+static int vector_net_load_bpf_flash(struct net_device *dev,
+                               struct ethtool_flash *efl)
+{
+       struct vector_private *vp = netdev_priv(dev);
+       struct vector_device *vdevice;
+       const struct firmware *fw;
+       int result = 0;
+
+       if (!(vp->options & VECTOR_BPF_FLASH)) {
+               netdev_err(dev, "loading firmware not permitted: %s\n", efl->data);
+               return -1;
+       }
+
+       spin_lock(&vp->lock);
+
+       if (vp->bpf != NULL) {
+               if (vp->opened)
+                       uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf);
+               kfree(vp->bpf->filter);
+               vp->bpf->filter = NULL;
+       } else {
+               vp->bpf = kmalloc(sizeof(struct sock_fprog), GFP_KERNEL);
+               if (vp->bpf == NULL) {
+                       netdev_err(dev, "failed to allocate memory for firmware\n");
+                       goto flash_fail;
+               }
+       }
+
+       vdevice = find_device(vp->unit);
+
+       if (request_firmware(&fw, efl->data, &vdevice->pdev.dev))
+               goto flash_fail;
+
+       vp->bpf->filter = kmemdup(fw->data, fw->size, GFP_KERNEL);
+       if (!vp->bpf->filter)
+               goto free_buffer;
+
+       vp->bpf->len = fw->size / sizeof(struct sock_filter);
+       release_firmware(fw);
+
+       if (vp->opened)
+               result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf);
+
+       spin_unlock(&vp->lock);
+
+       return result;
+
+free_buffer:
+       release_firmware(fw);
+
+flash_fail:
+       spin_unlock(&vp->lock);
+       if (vp->bpf != NULL)
+               kfree(vp->bpf->filter);
+       kfree(vp->bpf);
+       vp->bpf = NULL;
+       return -1;
+}
+
 static void vector_get_ringparam(struct net_device *netdev,
                                struct ethtool_ringparam *ring)
 {
@@ -1424,6 +1517,7 @@ static const struct ethtool_ops vector_net_ethtool_ops = {
        .get_ethtool_stats = vector_get_ethtool_stats,
        .get_coalesce   = vector_get_coalesce,
        .set_coalesce   = vector_set_coalesce,
+       .flash_device   = vector_net_load_bpf_flash,
 };
 
 
@@ -1528,8 +1622,9 @@ static void vector_eth_configure(
                .in_write_poll          = false,
                .coalesce               = 2,
                .req_size               = get_req_size(def),
-               .in_error               = false
-               });
+               .in_error               = false,
+               .bpf                    = NULL
+       });
 
        dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST);
        tasklet_init(&vp->tx_poll, vector_tx_poll, (unsigned long)vp);
index 4d292e6..d015908 100644 (file)
 #define VECTOR_TX (1 << 1)
 #define VECTOR_BPF (1 << 2)
 #define VECTOR_QDISC_BYPASS (1 << 3)
+#define VECTOR_BPF_FLASH (1 << 4)
 
 #define ETH_MAX_PACKET 1500
 #define ETH_HEADER_OTHER 32 /* just in case someone decides to go mad on QnQ */
 
+#define MAX_FILTER_PROG (2 << 16)
+
 struct vector_queue {
        struct mmsghdr *mmsg_vector;
        void **skbuff_vector;
@@ -118,10 +121,13 @@ struct vector_private {
        bool in_write_poll;
        bool in_error;
 
+       /* guest allowed to use ethtool flash to load bpf */
+       bool bpf_via_flash;
+
        /* ethtool stats */
 
        struct vector_estats estats;
-       void *bpf;
+       struct sock_fprog *bpf;
 
        char user[0];
 };
index e2c969b..ddcd917 100644 (file)
@@ -46,7 +46,8 @@
 #define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
 #define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
 #define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i"
-#define BPF_ATTACH_FAIL "Failed to attach filter size %d to %d, err %d\n"
+#define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n"
+#define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n"
 
 #define MAX_UN_LEN 107
 
@@ -660,31 +661,44 @@ int uml_vector_recvmmsg(
        else
                return -errno;
 }
-int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len)
+int uml_vector_attach_bpf(int fd, void *bpf)
 {
-       int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, bpf_len);
+       struct sock_fprog *prog = bpf;
+
+       int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(struct sock_fprog));
 
        if (err < 0)
-               printk(KERN_ERR BPF_ATTACH_FAIL, bpf_len, fd, -errno);
+               printk(KERN_ERR BPF_ATTACH_FAIL, prog->len, prog->filter, fd, -errno);
        return err;
 }
 
-#define DEFAULT_BPF_LEN 6
+int uml_vector_detach_bpf(int fd, void *bpf)
+{
+       struct sock_fprog *prog = bpf;
 
-void *uml_vector_default_bpf(int fd, void *mac)
+       int err = setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, bpf, sizeof(struct sock_fprog));
+       if (err < 0)
+               printk(KERN_ERR BPF_DETACH_FAIL, prog->len, prog->filter, fd, -errno);
+       return err;
+}
+void *uml_vector_default_bpf(void *mac)
 {
        struct sock_filter *bpf;
        uint32_t *mac1 = (uint32_t *)(mac + 2);
        uint16_t *mac2 = (uint16_t *) mac;
-       struct sock_fprog bpf_prog = {
-               .len = 6,
-               .filter = NULL,
-       };
+       struct sock_fprog *bpf_prog;
 
+       bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
+       if (bpf_prog) {
+               bpf_prog->len = DEFAULT_BPF_LEN;
+               bpf_prog->filter = NULL;
+       } else {
+               return NULL;
+       }
        bpf = uml_kmalloc(
                sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL);
-       if (bpf != NULL) {
-               bpf_prog.filter = bpf;
+       if (bpf) {
+               bpf_prog->filter = bpf;
                /* ld   [8] */
                bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 };
                /* jeq  #0xMAC[2-6] jt 2 jf 5*/
@@ -697,12 +711,56 @@ void *uml_vector_default_bpf(int fd, void *mac)
                bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 };
                /* ret  #0x40000 */
                bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 };
-               if (uml_vector_attach_bpf(
-                       fd, &bpf_prog, sizeof(struct sock_fprog)) < 0) {
-                       kfree(bpf);
-                       bpf = NULL;
-               }
+       } else {
+               kfree(bpf_prog);
+               bpf_prog = NULL;
        }
-       return bpf;
+       return bpf_prog;
 }
 
+/* Note - this function requires a valid mac being passed as an arg */
+
+void *uml_vector_user_bpf(char *filename)
+{
+       struct sock_filter *bpf;
+       struct sock_fprog *bpf_prog;
+       struct stat statbuf;
+       int res, ffd = -1;
+
+       if (filename == NULL)
+               return NULL;
+
+       if (stat(filename, &statbuf) < 0) {
+               printk(KERN_ERR "Error %d reading bpf file", -errno);
+               return false;
+       }
+       bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
+       if (bpf_prog != NULL) {
+               bpf_prog->len = statbuf.st_size / sizeof(struct sock_filter);
+               bpf_prog->filter = NULL;
+       }
+       ffd = os_open_file(filename, of_read(OPENFLAGS()), 0);
+       if (ffd < 0) {
+               printk(KERN_ERR "Error %d opening bpf file", -errno);
+               goto bpf_failed;
+       }
+       bpf = uml_kmalloc(statbuf.st_size, UM_GFP_KERNEL);
+       if (bpf == NULL) {
+               printk(KERN_ERR "Failed to allocate bpf buffer");
+               goto bpf_failed;
+       }
+       bpf_prog->filter = bpf;
+       res = os_read_file(ffd, bpf, statbuf.st_size);
+       if (res < statbuf.st_size) {
+               printk(KERN_ERR "Failed to read bpf program %s, error %d", filename, res);
+               kfree(bpf);
+               goto bpf_failed;
+       }
+       os_close_file(ffd);
+       return bpf_prog;
+bpf_failed:
+       if (ffd > 0)
+               os_close_file(ffd);
+       kfree(bpf_prog);
+       return NULL;
+}
index 649ec25..91f35b2 100644 (file)
@@ -28,6 +28,8 @@
 #define TRANS_BESS "bess"
 #define TRANS_BESS_LEN strlen(TRANS_BESS)
 
+#define DEFAULT_BPF_LEN 6
+
 #ifndef IPPROTO_GRE
 #define IPPROTO_GRE 0x2F
 #endif
@@ -95,8 +97,10 @@ extern int uml_vector_recvmmsg(
        unsigned int vlen,
        unsigned int flags
 );
-extern void *uml_vector_default_bpf(int fd, void *mac);
-extern int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len);
+extern void *uml_vector_default_bpf(void *mac);
+extern void *uml_vector_user_bpf(char *filename);
+extern int uml_vector_attach_bpf(int fd, void *bpf);
+extern int uml_vector_detach_bpf(int fd, void *bpf);
 extern bool uml_raw_enable_qdisc_bypass(int fd);
 extern bool uml_raw_enable_vnet_headers(int fd);
 extern bool uml_tap_enable_vnet_headers(int fd);
index fc8c52c..023ced2 100644 (file)
@@ -4,12 +4,12 @@
  *
  * Copyright(c) 2019 Intel Corporation
  *
- * This module allows virtio devices to be used over a vhost-user socket.
+ * This driver allows virtio devices to be used over a vhost-user socket.
  *
  * Guest devices can be instantiated by kernel module or command line
  * parameters. One device will be created for each parameter. Syntax:
  *
- *             [virtio_uml.]device=<socket>:<virtio_id>[:<platform_id>]
+ *             virtio_uml.device=<socket>:<virtio_id>[:<platform_id>]
  * where:
  *             <socket>        := vhost-user socket path to connect
  *             <virtio_id>     := virtio device id (as in virtio_ids.h)
 #define to_virtio_uml_device(_vdev) \
        container_of(_vdev, struct virtio_uml_device, vdev)
 
+struct virtio_uml_platform_data {
+       u32 virtio_device_id;
+       const char *socket_path;
+       struct work_struct conn_broken_wk;
+       struct platform_device *pdev;
+};
+
 struct virtio_uml_device {
        struct virtio_device vdev;
        struct platform_device *pdev;
@@ -50,6 +57,7 @@ struct virtio_uml_device {
        u64 features;
        u64 protocol_features;
        u8 status;
+       u8 registered:1;
 };
 
 struct virtio_uml_vq_info {
@@ -83,7 +91,7 @@ static int full_sendmsg_fds(int fd, const void *buf, unsigned int len,
        return 0;
 }
 
-static int full_read(int fd, void *buf, int len)
+static int full_read(int fd, void *buf, int len, bool abortable)
 {
        int rc;
 
@@ -93,7 +101,7 @@ static int full_read(int fd, void *buf, int len)
                        buf += rc;
                        len -= rc;
                }
-       } while (len && (rc > 0 || rc == -EINTR));
+       } while (len && (rc > 0 || rc == -EINTR || (!abortable && rc == -EAGAIN)));
 
        if (rc < 0)
                return rc;
@@ -104,28 +112,37 @@ static int full_read(int fd, void *buf, int len)
 
 static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
 {
-       return full_read(fd, msg, sizeof(msg->header));
+       return full_read(fd, msg, sizeof(msg->header), true);
 }
 
-static int vhost_user_recv(int fd, struct vhost_user_msg *msg,
+static int vhost_user_recv(struct virtio_uml_device *vu_dev,
+                          int fd, struct vhost_user_msg *msg,
                           size_t max_payload_size)
 {
        size_t size;
        int rc = vhost_user_recv_header(fd, msg);
 
+       if (rc == -ECONNRESET && vu_dev->registered) {
+               struct virtio_uml_platform_data *pdata;
+
+               pdata = vu_dev->pdev->dev.platform_data;
+
+               virtio_break_device(&vu_dev->vdev);
+               schedule_work(&pdata->conn_broken_wk);
+       }
        if (rc)
                return rc;
        size = msg->header.size;
        if (size > max_payload_size)
                return -EPROTO;
-       return full_read(fd, &msg->payload, size);
+       return full_read(fd, &msg->payload, size, false);
 }
 
 static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
                                struct vhost_user_msg *msg,
                                size_t max_payload_size)
 {
-       int rc = vhost_user_recv(vu_dev->sock, msg, max_payload_size);
+       int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, max_payload_size);
 
        if (rc)
                return rc;
@@ -155,7 +172,7 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev,
                               struct vhost_user_msg *msg,
                               size_t max_payload_size)
 {
-       int rc = vhost_user_recv(vu_dev->req_fd, msg, max_payload_size);
+       int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg, max_payload_size);
 
        if (rc)
                return rc;
@@ -963,11 +980,6 @@ static void virtio_uml_release_dev(struct device *d)
 
 /* Platform device */
 
-struct virtio_uml_platform_data {
-       u32 virtio_device_id;
-       const char *socket_path;
-};
-
 static int virtio_uml_probe(struct platform_device *pdev)
 {
        struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
@@ -1005,6 +1017,7 @@ static int virtio_uml_probe(struct platform_device *pdev)
        rc = register_virtio_device(&vu_dev->vdev);
        if (rc)
                put_device(&vu_dev->vdev.dev);
+       vu_dev->registered = 1;
        return rc;
 
 error_init:
@@ -1034,13 +1047,31 @@ static struct device vu_cmdline_parent = {
 static bool vu_cmdline_parent_registered;
 static int vu_cmdline_id;
 
+static int vu_unregister_cmdline_device(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
+
+       kfree(pdata->socket_path);
+       platform_device_unregister(pdev);
+       return 0;
+}
+
+static void vu_conn_broken(struct work_struct *wk)
+{
+       struct virtio_uml_platform_data *pdata;
+
+       pdata = container_of(wk, struct virtio_uml_platform_data, conn_broken_wk);
+       vu_unregister_cmdline_device(&pdata->pdev->dev, NULL);
+}
+
 static int vu_cmdline_set(const char *device, const struct kernel_param *kp)
 {
        const char *ids = strchr(device, ':');
        unsigned int virtio_device_id;
        int processed, consumed, err;
        char *socket_path;
-       struct virtio_uml_platform_data pdata;
+       struct virtio_uml_platform_data pdata, *ppdata;
        struct platform_device *pdev;
 
        if (!ids || ids == device)
@@ -1079,6 +1110,11 @@ static int vu_cmdline_set(const char *device, const struct kernel_param *kp)
        err = PTR_ERR_OR_ZERO(pdev);
        if (err)
                goto free;
+
+       ppdata = pdev->dev.platform_data;
+       ppdata->pdev = pdev;
+       INIT_WORK(&ppdata->conn_broken_wk, vu_conn_broken);
+
        return 0;
 
 free:
@@ -1121,16 +1157,6 @@ __uml_help(vu_cmdline_param_ops,
 );
 
 
-static int vu_unregister_cmdline_device(struct device *dev, void *data)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
-
-       kfree(pdata->socket_path);
-       platform_device_unregister(pdev);
-       return 0;
-}
-
 static void vu_unregister_cmdline_devices(void)
 {
        if (vu_cmdline_parent_registered) {
index 32b3d26..32106d3 100644 (file)
@@ -8,7 +8,6 @@
 #ifndef __UM_PGTABLE_2LEVEL_H
 #define __UM_PGTABLE_2LEVEL_H
 
-#define __ARCH_USE_5LEVEL_HACK
 #include <asm-generic/pgtable-nopmd.h>
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
index 9812269..8a3b689 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef __UM_PGTABLE_3LEVEL_H
 #define __UM_PGTABLE_3LEVEL_H
 
-#define __ARCH_USE_5LEVEL_HACK
 #include <asm-generic/pgtable-nopud.h>
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
index 36a44d5..2daa58d 100644 (file)
@@ -106,6 +106,9 @@ extern unsigned long end_iomem;
 #define pud_newpage(x)  (pud_val(x) & _PAGE_NEWPAGE)
 #define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE)
 
+#define p4d_newpage(x)  (p4d_val(x) & _PAGE_NEWPAGE)
+#define p4d_mkuptodate(x) (p4d_val(x) &= ~_PAGE_NEWPAGE)
+
 #define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
 
 #define pte_page(x) pfn_to_page(pte_pfn(x))
index 417ff64..30885d0 100644 (file)
@@ -96,6 +96,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
                                 pgd_t *pgd_base)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        int i, j;
@@ -107,7 +108,8 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
        pgd = pgd_base + i;
 
        for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
-               pud = pud_offset(pgd, vaddr);
+               p4d = p4d_offset(pgd, vaddr);
+               pud = pud_offset(p4d, vaddr);
                if (pud_none(*pud))
                        one_md_table_init(pud);
                pmd = pmd_offset(pud, vaddr);
@@ -124,6 +126,7 @@ static void __init fixaddr_user_init( void)
 #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
        long size = FIXADDR_USER_END - FIXADDR_USER_START;
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
@@ -144,7 +147,8 @@ static void __init fixaddr_user_init( void)
        for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
                      p += PAGE_SIZE) {
                pgd = swapper_pg_dir + pgd_index(vaddr);
-               pud = pud_offset(pgd, vaddr);
+               p4d = p4d_offset(pgd, vaddr);
+               pud = pud_offset(p4d, vaddr);
                pmd = pmd_offset(pud, vaddr);
                pte = pte_offset_kernel(pmd, vaddr);
                pte_set_val(*pte, p, PAGE_READONLY);
index b5e3d91..3f0d9a5 100644 (file)
@@ -19,15 +19,21 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
                         unsigned long kernel)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
 
        pgd = pgd_offset(mm, proc);
-       pud = pud_alloc(mm, pgd, proc);
-       if (!pud)
+
+       p4d = p4d_alloc(mm, pgd, proc);
+       if (!p4d)
                goto out;
 
+       pud = pud_alloc(mm, p4d, proc);
+       if (!pud)
+               goto out_pud;
+
        pmd = pmd_alloc(mm, pud, proc);
        if (!pmd)
                goto out_pmd;
@@ -44,6 +50,8 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
        pmd_free(mm, pmd);
  out_pmd:
        pud_free(mm, pud);
+ out_pud:
+       p4d_free(mm, p4d);
  out:
        return -ENOMEM;
 }
index 3236052..d617f8d 100644 (file)
@@ -17,6 +17,7 @@
 pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
 
@@ -27,7 +28,11 @@ pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
        if (!pgd_present(*pgd))
                return NULL;
 
-       pud = pud_offset(pgd, addr);
+       p4d = p4d_offset(pgd, addr);
+       if (!p4d_present(*p4d))
+               return NULL;
+
+       pud = pud_offset(p4d, addr);
        if (!pud_present(*pud))
                return NULL;
 
index b7eaf65..80a358c 100644 (file)
@@ -277,7 +277,7 @@ static inline int update_pmd_range(pud_t *pud, unsigned long addr,
        return ret;
 }
 
-static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
+static inline int update_pud_range(p4d_t *p4d, unsigned long addr,
                                   unsigned long end,
                                   struct host_vm_change *hvc)
 {
@@ -285,7 +285,7 @@ static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
        unsigned long next;
        int ret = 0;
 
-       pud = pud_offset(pgd, addr);
+       pud = pud_offset(p4d, addr);
        do {
                next = pud_addr_end(addr, end);
                if (!pud_present(*pud)) {
@@ -299,6 +299,28 @@ static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
        return ret;
 }
 
+static inline int update_p4d_range(pgd_t *pgd, unsigned long addr,
+                                  unsigned long end,
+                                  struct host_vm_change *hvc)
+{
+       p4d_t *p4d;
+       unsigned long next;
+       int ret = 0;
+
+       p4d = p4d_offset(pgd, addr);
+       do {
+               next = p4d_addr_end(addr, end);
+               if (!p4d_present(*p4d)) {
+                       if (hvc->force || p4d_newpage(*p4d)) {
+                               ret = add_munmap(addr, next - addr, hvc);
+                               p4d_mkuptodate(*p4d);
+                       }
+               } else
+                       ret = update_pud_range(p4d, addr, next, hvc);
+       } while (p4d++, addr = next, ((addr < end) && !ret));
+       return ret;
+}
+
 void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                      unsigned long end_addr, int force)
 {
@@ -316,8 +338,8 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                                ret = add_munmap(addr, next - addr, &hvc);
                                pgd_mkuptodate(*pgd);
                        }
-               }
-               else ret = update_pud_range(pgd, addr, next, &hvc);
+               } else
+                       ret = update_p4d_range(pgd, addr, next, &hvc);
        } while (pgd++, addr = next, ((addr < end_addr) && !ret));
 
        if (!ret)
@@ -338,6 +360,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
 {
        struct mm_struct *mm;
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
@@ -364,7 +387,23 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
                        continue;
                }
 
-               pud = pud_offset(pgd, addr);
+               p4d = p4d_offset(pgd, addr);
+               if (!p4d_present(*p4d)) {
+                       last = ADD_ROUND(addr, P4D_SIZE);
+                       if (last > end)
+                               last = end;
+                       if (p4d_newpage(*p4d)) {
+                               updated = 1;
+                               err = add_munmap(addr, last - addr, &hvc);
+                               if (err < 0)
+                                       panic("munmap failed, errno = %d\n",
+                                             -err);
+                       }
+                       addr = last;
+                       continue;
+               }
+
+               pud = pud_offset(p4d, addr);
                if (!pud_present(*pud)) {
                        last = ADD_ROUND(addr, PUD_SIZE);
                        if (last > end)
@@ -424,6 +463,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
@@ -437,7 +477,11 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
        if (!pgd_present(*pgd))
                goto kill;
 
-       pud = pud_offset(pgd, address);
+       p4d = p4d_offset(pgd, address);
+       if (!p4d_present(*p4d))
+               goto kill;
+
+       pud = pud_offset(p4d, address);
        if (!pud_present(*pud))
                goto kill;
 
@@ -490,35 +534,6 @@ kill:
        force_sig(SIGKILL);
 }
 
-pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
-{
-       return pgd_offset(mm, address);
-}
-
-pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
-{
-       return pud_offset(pgd, address);
-}
-
-pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
-{
-       return pmd_offset(pud, address);
-}
-
-pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
-{
-       return pte_offset_kernel(pmd, address);
-}
-
-pte_t *addr_pte(struct task_struct *task, unsigned long addr)
-{
-       pgd_t *pgd = pgd_offset(task->mm, addr);
-       pud_t *pud = pud_offset(pgd, addr);
-       pmd_t *pmd = pmd_offset(pud, addr);
-
-       return pte_offset_map(pmd, addr);
-}
-
 void flush_tlb_all(void)
 {
        /*
index e62296c..8185530 100644 (file)
@@ -28,6 +28,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
@@ -104,7 +105,8 @@ good_area:
                }
 
                pgd = pgd_offset(mm, address);
-               pud = pud_offset(pgd, address);
+               p4d = p4d_offset(pgd, address);
+               pud = pud_offset(p4d, address);
                pmd = pmd_offset(pud, address);
                pte = pte_offset_kernel(pmd, address);
        } while (!pte_present(*pte));
index 8014dfa..c8a42ec 100644 (file)
@@ -170,7 +170,7 @@ int __init main(int argc, char **argv, char **envp)
         * that they won't be delivered after the exec, when
         * they are definitely not expected.
         */
-       unblock_signals_trace();
+       unblock_signals();
 
        os_info("\n");
        /* Reboot */
index 0cb1756..5e89499 100644 (file)
@@ -134,6 +134,7 @@ config X86
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_JUMP_LABEL_RELATIVE
        select HAVE_ARCH_KASAN                  if X86_64
+       select HAVE_ARCH_KASAN_VMALLOC          if X86_64
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_MMAP_RND_BITS          if MMU
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS   if MMU && COMPAT
index 409c00f..c4eab8e 100644 (file)
@@ -117,7 +117,7 @@ config DEBUG_WX
 
 config DOUBLEFAULT
        default y
-       bool "Enable doublefault exception handler" if EXPERT
+       bool "Enable doublefault exception handler" if EXPERT && X86_32
        ---help---
          This option allows trapping of rare doublefault exceptions that
          would otherwise cause a system to silently reboot. Disabling this
index 4a37ba7..1d9ff8a 100644 (file)
@@ -210,12 +210,14 @@ static int __init blake2s_mod_init(void)
                              XFEATURE_MASK_AVX512, NULL))
                static_branch_enable(&blake2s_use_avx512);
 
-       return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
+       return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
+               crypto_register_shashes(blake2s_algs,
+                                       ARRAY_SIZE(blake2s_algs)) : 0;
 }
 
 static void __exit blake2s_mod_exit(void)
 {
-       if (boot_cpu_has(X86_FEATURE_SSSE3))
+       if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3))
                crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
 }
 
index a94e30b..68a7495 100644 (file)
@@ -299,12 +299,13 @@ static int __init chacha_simd_mod_init(void)
                    boot_cpu_has(X86_FEATURE_AVX512BW)) /* kmovq */
                        static_branch_enable(&chacha_use_avx512vl);
        }
-       return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+       return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
+               crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
 }
 
 static void __exit chacha_simd_mod_fini(void)
 {
-       if (boot_cpu_has(X86_FEATURE_SSSE3))
+       if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) && boot_cpu_has(X86_FEATURE_SSSE3))
                crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
 }
 
index a52a3fb..eec7d2d 100644 (file)
@@ -2457,13 +2457,14 @@ static int __init curve25519_mod_init(void)
                static_branch_enable(&curve25519_use_adx);
        else
                return 0;
-       return crypto_register_kpp(&curve25519_alg);
+       return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
+               crypto_register_kpp(&curve25519_alg) : 0;
 }
 
 static void __exit curve25519_mod_exit(void)
 {
-       if (boot_cpu_has(X86_FEATURE_BMI2) ||
-           boot_cpu_has(X86_FEATURE_ADX))
+       if (IS_REACHABLE(CONFIG_CRYPTO_KPP) &&
+           (boot_cpu_has(X86_FEATURE_BMI2) || boot_cpu_has(X86_FEATURE_ADX)))
                crypto_unregister_kpp(&curve25519_alg);
 }
 
index 370cd88..0cc4537 100644 (file)
@@ -224,12 +224,13 @@ static int __init poly1305_simd_mod_init(void)
            cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
                static_branch_enable(&poly1305_use_avx2);
 
-       return crypto_register_shash(&alg);
+       return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? crypto_register_shash(&alg) : 0;
 }
 
 static void __exit poly1305_simd_mod_exit(void)
 {
-       crypto_unregister_shash(&alg);
+       if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
+               crypto_unregister_shash(&alg);
 }
 
 module_init(poly1305_simd_mod_init);
index 5832b11..7e05604 100644 (file)
@@ -1090,7 +1090,6 @@ SYM_FUNC_START(entry_INT80_32)
 restore_all:
        TRACE_IRQS_IRET
        SWITCH_TO_ENTRY_STACK
-.Lrestore_all_notrace:
        CHECK_AND_APPLY_ESPFIX
 .Lrestore_nocheck:
        /* Switch back to user CR3 */
@@ -1537,6 +1536,48 @@ SYM_CODE_START(debug)
        jmp     common_exception
 SYM_CODE_END(debug)
 
+#ifdef CONFIG_DOUBLEFAULT
+SYM_CODE_START(double_fault)
+1:
+       /*
+        * This is a task gate handler, not an interrupt gate handler.
+        * The error code is on the stack, but the stack is otherwise
+        * empty.  Interrupts are off.  Our state is sane with the following
+        * exceptions:
+        *
+        *  - CR0.TS is set.  "TS" literally means "task switched".
+        *  - EFLAGS.NT is set because we're a "nested task".
+        *  - The doublefault TSS has back_link set and has been marked busy.
+        *  - TR points to the doublefault TSS and the normal TSS is busy.
+        *  - CR3 is the normal kernel PGD.  This would be delightful, except
+        *    that the CPU didn't bother to save the old CR3 anywhere.  This
+        *    would make it very awkward to return back to the context we came
+        *    from.
+        *
+        * The rest of EFLAGS is sanitized for us, so we don't need to
+        * worry about AC or DF.
+        *
+        * Don't even bother popping the error code.  It's always zero,
+        * and ignoring it makes us a bit more robust against buggy
+        * hypervisor task gate implementations.
+        *
+        * We will manually undo the task switch instead of doing a
+        * task-switching IRET.
+        */
+
+       clts                            /* clear CR0.TS */
+       pushl   $X86_EFLAGS_FIXED
+       popfl                           /* clear EFLAGS.NT */
+
+       call    doublefault_shim
+
+       /* We don't support returning, so we have no IRET here. */
+1:
+       hlt
+       jmp 1b
+SYM_CODE_END(double_fault)
+#endif
+
 /*
  * NMI is doubly nasty.  It can happen on the first instruction of
  * entry_SYSENTER_32 (just like #DB), but it can also interrupt the beginning
index 6e3f0c1..9a89d98 100644 (file)
@@ -49,6 +49,7 @@ DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
        .enabled = 1,
 };
 
+DEFINE_STATIC_KEY_FALSE(rdpmc_never_available_key);
 DEFINE_STATIC_KEY_FALSE(rdpmc_always_available_key);
 
 u64 __read_mostly hw_cache_event_ids
@@ -2181,21 +2182,26 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
        if (x86_pmu.attr_rdpmc_broken)
                return -ENOTSUPP;
 
-       if ((val == 2) != (x86_pmu.attr_rdpmc == 2)) {
+       if (val != x86_pmu.attr_rdpmc) {
                /*
-                * Changing into or out of always available, aka
-                * perf-event-bypassing mode.  This path is extremely slow,
+                * Changing into or out of never available or always available,
+                * aka perf-event-bypassing mode. This path is extremely slow,
                 * but only root can trigger it, so it's okay.
                 */
+               if (val == 0)
+                       static_branch_inc(&rdpmc_never_available_key);
+               else if (x86_pmu.attr_rdpmc == 0)
+                       static_branch_dec(&rdpmc_never_available_key);
+
                if (val == 2)
                        static_branch_inc(&rdpmc_always_available_key);
-               else
+               else if (x86_pmu.attr_rdpmc == 2)
                        static_branch_dec(&rdpmc_always_available_key);
+
                on_each_cpu(refresh_pce, NULL, 1);
+               x86_pmu.attr_rdpmc = val;
        }
 
-       x86_pmu.attr_rdpmc = val;
-
        return count;
 }
 
index ea866c7..8047340 100644 (file)
@@ -65,6 +65,13 @@ enum exception_stack_ordering {
 
 #endif
 
+#ifdef CONFIG_X86_32
+struct doublefault_stack {
+       unsigned long stack[(PAGE_SIZE - sizeof(struct x86_hw_tss)) / sizeof(unsigned long)];
+       struct x86_hw_tss tss;
+} __aligned(PAGE_SIZE);
+#endif
+
 /*
  * cpu_entry_area is a percpu region that contains things needed by the CPU
  * and early entry/exit code.  Real types aren't used for all fields here
@@ -86,6 +93,11 @@ struct cpu_entry_area {
 #endif
        struct entry_stack_page entry_stack_page;
 
+#ifdef CONFIG_X86_32
+       char guard_doublefault_stack[PAGE_SIZE];
+       struct doublefault_stack doublefault_stack;
+#endif
+
        /*
         * On x86_64, the TSS is mapped RO.  On x86_32, it's mapped RW because
         * we need task switches to work, and task switches write to the TSS.
diff --git a/arch/x86/include/asm/doublefault.h b/arch/x86/include/asm/doublefault.h
new file mode 100644 (file)
index 0000000..af9a14a
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_DOUBLEFAULT_H
+#define _ASM_X86_DOUBLEFAULT_H
+
+#if defined(CONFIG_X86_32) && defined(CONFIG_DOUBLEFAULT)
+extern void doublefault_init_cpu_tss(void);
+#else
+static inline void doublefault_init_cpu_tss(void)
+{
+}
+#endif
+
+#endif /* _ASM_X86_DOUBLEFAULT_H */
index 4c95c36..44c48e3 100644 (file)
@@ -509,7 +509,7 @@ static inline void __fpu_invalidate_fpregs_state(struct fpu *fpu)
 
 static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
 {
-       return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
+       return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
 }
 
 /*
index b91623d..bf1ed2d 100644 (file)
@@ -2,10 +2,28 @@
 #ifndef _ASM_X86_IOMMU_H
 #define _ASM_X86_IOMMU_H
 
+#include <linux/acpi.h>
+
+#include <asm/e820/api.h>
+
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
 
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
 
+static inline int __init
+arch_rmrr_sanity_check(struct acpi_dmar_reserved_memory *rmrr)
+{
+       u64 start = rmrr->base_address;
+       u64 end = rmrr->end_address + 1;
+
+       if (e820__mapped_all(start, end, E820_TYPE_RESERVED))
+               return 0;
+
+       pr_err(FW_BUG "No firmware reserved region can cover this RMRR [%#018Lx-%#018Lx], contact BIOS vendor for fixes\n",
+              start, end - 1);
+       return -EINVAL;
+}
+
 #endif /* _ASM_X86_IOMMU_H */
index 16ae821..5f33924 100644 (file)
@@ -26,12 +26,14 @@ static inline void paravirt_activate_mm(struct mm_struct *prev,
 
 #ifdef CONFIG_PERF_EVENTS
 
+DECLARE_STATIC_KEY_FALSE(rdpmc_never_available_key);
 DECLARE_STATIC_KEY_FALSE(rdpmc_always_available_key);
 
 static inline void load_mm_cr4_irqsoff(struct mm_struct *mm)
 {
        if (static_branch_unlikely(&rdpmc_always_available_key) ||
-           atomic_read(&mm->context.perf_rdpmc_allowed))
+           (!static_branch_unlikely(&rdpmc_never_available_key) &&
+            atomic_read(&mm->context.perf_rdpmc_allowed)))
                cr4_set_bits_irqsoff(X86_CR4_PCE);
        else
                cr4_clear_bits_irqsoff(X86_CR4_PCE);
index 19f5807..0416d42 100644 (file)
@@ -41,10 +41,11 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
 #endif
 
 /*
- * Define this here and validate with BUILD_BUG_ON() in pgtable_32.c
- * to avoid include recursion hell
+ * This is an upper bound on sizeof(struct cpu_entry_area) / PAGE_SIZE.
+ * Define this here and validate with BUILD_BUG_ON() in cpu_entry_area.c
+ * to avoid include recursion hell.
  */
-#define CPU_ENTRY_AREA_PAGES   (NR_CPUS * 41)
+#define CPU_ENTRY_AREA_PAGES   (NR_CPUS * 43)
 
 /* The +1 is for the readonly IDT page: */
 #define CPU_ENTRY_AREA_BASE    \
index e51afbb..0340aad 100644 (file)
@@ -166,7 +166,6 @@ enum cpuid_regs_idx {
 extern struct cpuinfo_x86      boot_cpu_data;
 extern struct cpuinfo_x86      new_cpu_data;
 
-extern struct x86_hw_tss       doublefault_tss;
 extern __u32                   cpu_caps_cleared[NCAPINTS + NBUGINTS];
 extern __u32                   cpu_caps_set[NCAPINTS + NBUGINTS];
 
@@ -997,7 +996,6 @@ bool xen_set_default_idle(void);
 #endif
 
 void stop_this_cpu(void *dummy);
-void df_debug(struct pt_regs *regs, long error_code);
 void microcode_check(void);
 
 enum l1tf_mitigations {
index b25e633..ffa0dc8 100644 (file)
@@ -69,6 +69,9 @@ dotraplinkage void do_overflow(struct pt_regs *regs, long error_code);
 dotraplinkage void do_bounds(struct pt_regs *regs, long error_code);
 dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code);
 dotraplinkage void do_device_not_available(struct pt_regs *regs, long error_code);
+#if defined(CONFIG_X86_64) || defined(CONFIG_DOUBLEFAULT)
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2);
+#endif
 dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *regs, long error_code);
 dotraplinkage void do_invalid_TSS(struct pt_regs *regs, long error_code);
 dotraplinkage void do_segment_not_present(struct pt_regs *regs, long error_code);
index 7c5bb43..b3d0664 100644 (file)
@@ -5,6 +5,9 @@
 #if !defined(__x86_64__) || !defined(__ILP32__)
 #include <asm-generic/msgbuf.h>
 #else
+
+#include <asm/ipcbuf.h>
+
 /*
  * The msqid64_ds structure for x86 architecture with x32 ABI.
  *
index 93030e9..71205b0 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_SEMBUF_H
 #define _ASM_X86_SEMBUF_H
 
+#include <asm/ipcbuf.h>
+
 /*
  * The semid64_ds structure for x86 architecture.
  * Note extra padding because this structure is passed back and forth
index 32acb97..6175e37 100644 (file)
@@ -100,7 +100,9 @@ obj-$(CONFIG_KEXEC_FILE)    += kexec-bzimage64.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
 obj-y                          += kprobes/
 obj-$(CONFIG_MODULES)          += module.o
-obj-$(CONFIG_DOUBLEFAULT)      += doublefault.o
+ifeq ($(CONFIG_X86_32),y)
+obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
+endif
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_VM86)             += vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
index baa2fed..2e4d902 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/stackprotector.h>
 #include <asm/perf_event.h>
 #include <asm/mmu_context.h>
+#include <asm/doublefault.h>
 #include <asm/archrandom.h>
 #include <asm/hypervisor.h>
 #include <asm/processor.h>
@@ -1814,8 +1815,6 @@ static inline void tss_setup_ist(struct tss_struct *tss)
        tss->x86_tss.ist[IST_INDEX_MCE] = __this_cpu_ist_top_va(MCE);
 }
 
-static inline void gdt_setup_doublefault_tss(int cpu) { }
-
 #else /* CONFIG_X86_64 */
 
 static inline void setup_getcpu(int cpu) { }
@@ -1827,13 +1826,6 @@ static inline void ucode_cpu_init(int cpu)
 
 static inline void tss_setup_ist(struct tss_struct *tss) { }
 
-static inline void gdt_setup_doublefault_tss(int cpu)
-{
-#ifdef CONFIG_DOUBLEFAULT
-       /* Set up the doublefault TSS pointer in the GDT */
-       __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
-#endif
-}
 #endif /* !CONFIG_X86_64 */
 
 static inline void tss_setup_io_bitmap(struct tss_struct *tss)
@@ -1923,7 +1915,7 @@ void cpu_init(void)
        clear_all_debug_regs();
        dbg_restore_debug_regs();
 
-       gdt_setup_doublefault_tss(cpu);
+       doublefault_init_cpu_tss();
 
        fpu__init_cpu();
 
diff --git a/arch/x86/kernel/doublefault.c b/arch/x86/kernel/doublefault.c
deleted file mode 100644 (file)
index 0d6c657..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/sched/debug.h>
-#include <linux/init_task.h>
-#include <linux/fs.h>
-
-#include <linux/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/desc.h>
-
-#ifdef CONFIG_X86_32
-
-#define DOUBLEFAULT_STACKSIZE (1024)
-static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
-#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
-
-#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM)
-
-static void doublefault_fn(void)
-{
-       struct desc_ptr gdt_desc = {0, 0};
-       unsigned long gdt, tss;
-
-       native_store_gdt(&gdt_desc);
-       gdt = gdt_desc.address;
-
-       printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
-
-       if (ptr_ok(gdt)) {
-               gdt += GDT_ENTRY_TSS << 3;
-               tss = get_desc_base((struct desc_struct *)gdt);
-               printk(KERN_EMERG "double fault, tss at %08lx\n", tss);
-
-               if (ptr_ok(tss)) {
-                       struct x86_hw_tss *t = (struct x86_hw_tss *)tss;
-
-                       printk(KERN_EMERG "eip = %08lx, esp = %08lx\n",
-                              t->ip, t->sp);
-
-                       printk(KERN_EMERG "eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
-                               t->ax, t->bx, t->cx, t->dx);
-                       printk(KERN_EMERG "esi = %08lx, edi = %08lx\n",
-                               t->si, t->di);
-               }
-       }
-
-       for (;;)
-               cpu_relax();
-}
-
-struct x86_hw_tss doublefault_tss __cacheline_aligned = {
-       .sp0            = STACK_START,
-       .ss0            = __KERNEL_DS,
-       .ldt            = 0,
-       .io_bitmap_base = IO_BITMAP_OFFSET_INVALID,
-
-       .ip             = (unsigned long) doublefault_fn,
-       /* 0x2 bit is always set */
-       .flags          = X86_EFLAGS_SF | 0x2,
-       .sp             = STACK_START,
-       .es             = __USER_DS,
-       .cs             = __KERNEL_CS,
-       .ss             = __KERNEL_DS,
-       .ds             = __USER_DS,
-       .fs             = __KERNEL_PERCPU,
-#ifndef CONFIG_X86_32_LAZY_GS
-       .gs             = __KERNEL_STACK_CANARY,
-#endif
-
-       .__cr3          = __pa_nodebug(swapper_pg_dir),
-};
-
-/* dummy for do_double_fault() call */
-void df_debug(struct pt_regs *regs, long error_code) {}
-
-#else /* !CONFIG_X86_32 */
-
-void df_debug(struct pt_regs *regs, long error_code)
-{
-       pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code);
-       show_regs(regs);
-       panic("Machine halted.");
-}
-#endif
diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c
new file mode 100644 (file)
index 0000000..3793646
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+
+#include <linux/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/traps.h>
+
+extern void double_fault(void);
+#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM)
+
+#define TSS(x) this_cpu_read(cpu_tss_rw.x86_tss.x)
+
+static void set_df_gdt_entry(unsigned int cpu);
+
+/*
+ * Called by double_fault with CR0.TS and EFLAGS.NT cleared.  The CPU thinks
+ * we're running the doublefault task.  Cannot return.
+ */
+asmlinkage notrace void __noreturn doublefault_shim(void)
+{
+       unsigned long cr2;
+       struct pt_regs regs;
+
+       BUILD_BUG_ON(sizeof(struct doublefault_stack) != PAGE_SIZE);
+
+       cr2 = native_read_cr2();
+
+       /* Reset back to the normal kernel task. */
+       force_reload_TR();
+       set_df_gdt_entry(smp_processor_id());
+
+       trace_hardirqs_off();
+
+       /*
+        * Fill in pt_regs.  A downside of doing this in C is that the unwinder
+        * won't see it (no ENCODE_FRAME_POINTER), so a nested stack dump
+        * won't successfully unwind to the source of the double fault.
+        * The main dump from do_double_fault() is fine, though, since it
+        * uses these regs directly.
+        *
+        * If anyone ever cares, this could be moved to asm.
+        */
+       regs.ss         = TSS(ss);
+       regs.__ssh      = 0;
+       regs.sp         = TSS(sp);
+       regs.flags      = TSS(flags);
+       regs.cs         = TSS(cs);
+       /* We won't go through the entry asm, so we can leave __csh as 0. */
+       regs.__csh      = 0;
+       regs.ip         = TSS(ip);
+       regs.orig_ax    = 0;
+       regs.gs         = TSS(gs);
+       regs.__gsh      = 0;
+       regs.fs         = TSS(fs);
+       regs.__fsh      = 0;
+       regs.es         = TSS(es);
+       regs.__esh      = 0;
+       regs.ds         = TSS(ds);
+       regs.__dsh      = 0;
+       regs.ax         = TSS(ax);
+       regs.bp         = TSS(bp);
+       regs.di         = TSS(di);
+       regs.si         = TSS(si);
+       regs.dx         = TSS(dx);
+       regs.cx         = TSS(cx);
+       regs.bx         = TSS(bx);
+
+       do_double_fault(&regs, 0, cr2);
+
+       /*
+        * x86_32 does not save the original CR3 anywhere on a task switch.
+        * This means that, even if we wanted to return, we would need to find
+        * some way to reconstruct CR3.  We could make a credible guess based
+        * on cpu_tlbstate, but that would be racy and would not account for
+        * PTI.
+        *
+        * Instead, don't bother.  We can return through
+        * rewind_stack_do_exit() instead.
+        */
+       panic("cannot return from double fault\n");
+}
+NOKPROBE_SYMBOL(doublefault_shim);
+
+DEFINE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack) = {
+       .tss = {
+                /*
+                 * No sp0 or ss0 -- we never run CPL != 0 with this TSS
+                 * active.  sp is filled in later.
+                 */
+               .ldt            = 0,
+       .io_bitmap_base = IO_BITMAP_OFFSET_INVALID,
+
+               .ip             = (unsigned long) double_fault,
+               .flags          = X86_EFLAGS_FIXED,
+               .es             = __USER_DS,
+               .cs             = __KERNEL_CS,
+               .ss             = __KERNEL_DS,
+               .ds             = __USER_DS,
+               .fs             = __KERNEL_PERCPU,
+#ifndef CONFIG_X86_32_LAZY_GS
+               .gs             = __KERNEL_STACK_CANARY,
+#endif
+
+               .__cr3          = __pa_nodebug(swapper_pg_dir),
+       },
+};
+
+static void set_df_gdt_entry(unsigned int cpu)
+{
+       /* Set up doublefault TSS pointer in the GDT */
+       __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS,
+                      &get_cpu_entry_area(cpu)->doublefault_stack.tss);
+
+}
+
+void doublefault_init_cpu_tss(void)
+{
+       unsigned int cpu = smp_processor_id();
+       struct cpu_entry_area *cea = get_cpu_entry_area(cpu);
+
+       /*
+        * The linker isn't smart enough to initialize percpu variables that
+        * point to other places in percpu space.
+        */
+        this_cpu_write(doublefault_stack.tss.sp,
+                       (unsigned long)&cea->doublefault_stack.stack +
+                       sizeof(doublefault_stack.stack));
+
+       set_df_gdt_entry(cpu);
+}
index 64a59d7..8e3a8fe 100644 (file)
@@ -29,6 +29,9 @@ const char *stack_type_name(enum stack_type type)
        if (type == STACK_TYPE_ENTRY)
                return "ENTRY_TRAMPOLINE";
 
+       if (type == STACK_TYPE_EXCEPTION)
+               return "#DF";
+
        return NULL;
 }
 
@@ -82,6 +85,30 @@ static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
        return true;
 }
 
+static bool in_doublefault_stack(unsigned long *stack, struct stack_info *info)
+{
+#ifdef CONFIG_DOUBLEFAULT
+       struct cpu_entry_area *cea = get_cpu_entry_area(raw_smp_processor_id());
+       struct doublefault_stack *ss = &cea->doublefault_stack;
+
+       void *begin = ss->stack;
+       void *end = begin + sizeof(ss->stack);
+
+       if ((void *)stack < begin || (void *)stack >= end)
+               return false;
+
+       info->type      = STACK_TYPE_EXCEPTION;
+       info->begin     = begin;
+       info->end       = end;
+       info->next_sp   = (unsigned long *)this_cpu_read(cpu_tss_rw.x86_tss.sp);
+
+       return true;
+#else
+       return false;
+#endif
+}
+
+
 int get_stack_info(unsigned long *stack, struct task_struct *task,
                   struct stack_info *info, unsigned long *visit_mask)
 {
@@ -105,6 +132,9 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
        if (in_softirq_stack(stack, info))
                goto recursion_check;
 
+       if (in_doublefault_stack(stack, info))
+               goto recursion_check;
+
        goto unknown;
 
 recursion_check:
index bd2a11c..61e93a3 100644 (file)
@@ -377,37 +377,37 @@ static void tss_copy_io_bitmap(struct tss_struct *tss, struct io_bitmap *iobm)
 void tss_update_io_bitmap(void)
 {
        struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
+       struct thread_struct *t = &current->thread;
        u16 *base = &tss->x86_tss.io_bitmap_base;
 
-       if (test_thread_flag(TIF_IO_BITMAP)) {
-               struct thread_struct *t = &current->thread;
-
-               if (IS_ENABLED(CONFIG_X86_IOPL_IOPERM) && t->iopl_emul == 3) {
-                       *base = IO_BITMAP_OFFSET_VALID_ALL;
-               } else {
-                       struct io_bitmap *iobm = t->io_bitmap;
-                       /*
-                        * Only copy bitmap data when the sequence number
-                        * differs. The update time is accounted to the
-                        * incoming task.
-                        */
-                       if (tss->io_bitmap.prev_sequence != iobm->sequence)
-                               tss_copy_io_bitmap(tss, iobm);
-
-                       /* Enable the bitmap */
-                       *base = IO_BITMAP_OFFSET_VALID_MAP;
-               }
+       if (!test_thread_flag(TIF_IO_BITMAP)) {
+               tss_invalidate_io_bitmap(tss);
+               return;
+       }
+
+       if (IS_ENABLED(CONFIG_X86_IOPL_IOPERM) && t->iopl_emul == 3) {
+               *base = IO_BITMAP_OFFSET_VALID_ALL;
+       } else {
+               struct io_bitmap *iobm = t->io_bitmap;
+
                /*
-                * Make sure that the TSS limit is covering the io bitmap.
-                * It might have been cut down by a VMEXIT to 0x67 which
-                * would cause a subsequent I/O access from user space to
-                * trigger a #GP because tbe bitmap is outside the TSS
-                * limit.
+                * Only copy bitmap data when the sequence number differs. The
+                * update time is accounted to the incoming task.
                 */
-               refresh_tss_limit();
-       } else {
-               tss_invalidate_io_bitmap(tss);
+               if (tss->io_bitmap.prev_sequence != iobm->sequence)
+                       tss_copy_io_bitmap(tss, iobm);
+
+               /* Enable the bitmap */
+               *base = IO_BITMAP_OFFSET_VALID_MAP;
        }
+
+       /*
+        * Make sure that the TSS limit is covering the IO bitmap. It might have
+        * been cut down by a VMEXIT to 0x67 which would cause a subsequent I/O
+        * access from user space to trigger a #GP because tbe bitmap is outside
+        * the TSS limit.
+        */
+       refresh_tss_limit();
 }
 #else /* CONFIG_X86_IOPL_IOPERM */
 static inline void switch_to_bitmap(unsigned long tifp) { }
index 066e5b0..f0e1ddb 100644 (file)
@@ -182,6 +182,9 @@ static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
 static int set_segment_reg(struct task_struct *task,
                           unsigned long offset, u16 value)
 {
+       if (WARN_ON_ONCE(task == current))
+               return -EIO;
+
        /*
         * The value argument was already truncated to 16 bits.
         */
@@ -209,10 +212,7 @@ static int set_segment_reg(struct task_struct *task,
                break;
 
        case offsetof(struct user_regs_struct, gs):
-               if (task == current)
-                       set_user_gs(task_pt_regs(task), value);
-               else
-                       task_user_gs(task) = value;
+               task_user_gs(task) = value;
        }
 
        return 0;
@@ -272,32 +272,41 @@ static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
 static int set_segment_reg(struct task_struct *task,
                           unsigned long offset, u16 value)
 {
+       if (WARN_ON_ONCE(task == current))
+               return -EIO;
+
        /*
         * The value argument was already truncated to 16 bits.
         */
        if (invalid_selector(value))
                return -EIO;
 
+       /*
+        * This function has some ABI oddities.
+        *
+        * A 32-bit ptracer probably expects that writing FS or GS will change
+        * FSBASE or GSBASE respectively.  In the absence of FSGSBASE support,
+        * this code indeed has that effect.  When FSGSBASE is added, this
+        * will require a special case.
+        *
+        * For existing 64-bit ptracers, writing FS or GS *also* currently
+        * changes the base if the selector is nonzero the next time the task
+        * is run.  This behavior may not be needed, and trying to preserve it
+        * when FSGSBASE is added would be complicated at best.
+        */
+
        switch (offset) {
        case offsetof(struct user_regs_struct,fs):
                task->thread.fsindex = value;
-               if (task == current)
-                       loadsegment(fs, task->thread.fsindex);
                break;
        case offsetof(struct user_regs_struct,gs):
                task->thread.gsindex = value;
-               if (task == current)
-                       load_gs_index(task->thread.gsindex);
                break;
        case offsetof(struct user_regs_struct,ds):
                task->thread.ds = value;
-               if (task == current)
-                       loadsegment(ds, task->thread.ds);
                break;
        case offsetof(struct user_regs_struct,es):
                task->thread.es = value;
-               if (task == current)
-                       loadsegment(es, task->thread.es);
                break;
 
                /*
@@ -375,6 +384,9 @@ static int putreg(struct task_struct *child,
                 * When changing the FS base, use do_arch_prctl_64()
                 * to set the index to zero and to set the base
                 * as requested.
+                *
+                * NB: This behavior is nonsensical and likely needs to
+                * change when FSGSBASE support is added.
                 */
                if (child->thread.fsbase != value)
                        return do_arch_prctl_64(child, ARCH_SET_FS, value);
index c903121..05da6b5 100644 (file)
@@ -306,8 +306,23 @@ __visible void __noreturn handle_stack_overflow(const char *message,
 }
 #endif
 
-#ifdef CONFIG_X86_64
-/* Runs on IST stack */
+#if defined(CONFIG_X86_64) || defined(CONFIG_DOUBLEFAULT)
+/*
+ * Runs on an IST stack for x86_64 and on a special task stack for x86_32.
+ *
+ * On x86_64, this is more or less a normal kernel entry.  Notwithstanding the
+ * SDM's warnings about double faults being unrecoverable, returning works as
+ * expected.  Presumably what the SDM actually means is that the CPU may get
+ * the register state wrong on entry, so returning could be a bad idea.
+ *
+ * Various CPU engineers have promised that double faults due to an IRET fault
+ * while the stack is read-only are, in fact, recoverable.
+ *
+ * On x86_32, this is entered through a task gate, and regs are synthesized
+ * from the TSS.  Returning is, in principle, okay, but changes to regs will
+ * be lost.  If, for some reason, we need to return to a context with modified
+ * regs, the shim code could be adjusted to synchronize the registers.
+ */
 dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2)
 {
        static const char str[] = "double fault";
@@ -411,15 +426,9 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsign
                handle_stack_overflow("kernel stack overflow (double-fault)", regs, cr2);
 #endif
 
-#ifdef CONFIG_DOUBLEFAULT
-       df_debug(regs, error_code);
-#endif
-       /*
-        * This is always a kernel trap and never fixable (and thus must
-        * never return).
-        */
-       for (;;)
-               die(str, regs, error_code);
+       pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code);
+       die("double fault", regs, error_code);
+       panic("Machine halted.");
 }
 #endif
 
index c0aa074..cfafa32 100644 (file)
@@ -504,7 +504,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 function,
 
        r = -E2BIG;
 
-       if (*nent >= maxnent)
+       if (WARN_ON(*nent >= maxnent))
                goto out;
 
        do_host_cpuid(entry, function, 0);
@@ -778,6 +778,11 @@ static inline int __do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 function,
        case 0x8000001a:
        case 0x8000001e:
                break;
+       /* Support memory encryption cpuid if host supports it */
+       case 0x8000001F:
+               if (!boot_cpu_has(X86_FEATURE_SEV))
+                       entry->eax = entry->ebx = entry->ecx = entry->edx = 0;
+               break;
        /*Add support for Centaur's CPUID instruction*/
        case 0xC0000000:
                /*Just support up to 0xC0000004 now*/
@@ -810,6 +815,9 @@ out:
 static int do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 func,
                         int *nent, int maxnent, unsigned int type)
 {
+       if (*nent >= maxnent)
+               return -E2BIG;
+
        if (type == KVM_GET_EMULATED_CPUID)
                return __do_cpuid_func_emulated(entry, func, nent, maxnent);
 
index 362e874..122d4ce 100644 (file)
@@ -5958,13 +5958,6 @@ static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
                if (npt_enabled)
                        entry->edx |= F(NPT);
 
-               break;
-       case 0x8000001F:
-               /* Support memory encryption cpuid if host supports it */
-               if (boot_cpu_has(X86_FEATURE_SEV))
-                       cpuid(0x8000001f, &entry->eax, &entry->ebx,
-                               &entry->ecx, &entry->edx);
-
        }
 }
 
index 1b9ab41..e3394c8 100644 (file)
@@ -6666,7 +6666,6 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
        free_vpid(vmx->vpid);
        nested_vmx_free_vcpu(vcpu);
        free_loaded_vmcs(vmx->loaded_vmcs);
-       kfree(vmx->guest_msrs);
        kvm_vcpu_uninit(vcpu);
        kmem_cache_free(x86_fpu_cache, vmx->vcpu.arch.user_fpu);
        kmem_cache_free(x86_fpu_cache, vmx->vcpu.arch.guest_fpu);
@@ -6723,12 +6722,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
                        goto uninit_vcpu;
        }
 
-       vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT);
-       BUILD_BUG_ON(ARRAY_SIZE(vmx_msr_index) * sizeof(vmx->guest_msrs[0])
-                    > PAGE_SIZE);
-
-       if (!vmx->guest_msrs)
-               goto free_pml;
+       BUILD_BUG_ON(ARRAY_SIZE(vmx_msr_index) != NR_SHARED_MSRS);
 
        for (i = 0; i < ARRAY_SIZE(vmx_msr_index); ++i) {
                u32 index = vmx_msr_index[i];
@@ -6760,7 +6754,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 
        err = alloc_loaded_vmcs(&vmx->vmcs01);
        if (err < 0)
-               goto free_msrs;
+               goto free_pml;
 
        msr_bitmap = vmx->vmcs01.msr_bitmap;
        vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_TSC, MSR_TYPE_R);
@@ -6822,8 +6816,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 
 free_vmcs:
        free_loaded_vmcs(vmx->loaded_vmcs);
-free_msrs:
-       kfree(vmx->guest_msrs);
 free_pml:
        vmx_destroy_pml_buffer(vmx);
 uninit_vcpu:
index 7c1b978..a4f7f73 100644 (file)
@@ -22,6 +22,12 @@ extern u32 get_umwait_control_msr(void);
 
 #define X2APIC_MSR(r) (APIC_BASE_MSR + ((r) >> 4))
 
+#ifdef CONFIG_X86_64
+#define NR_SHARED_MSRS 7
+#else
+#define NR_SHARED_MSRS 4
+#endif
+
 #define NR_LOADSTORE_MSRS 8
 
 struct vmx_msrs {
@@ -206,7 +212,7 @@ struct vcpu_vmx {
        u32                   idt_vectoring_info;
        ulong                 rflags;
 
-       struct shared_msr_entry *guest_msrs;
+       struct shared_msr_entry guest_msrs[NR_SHARED_MSRS];
        int                   nmsrs;
        int                   save_nmsrs;
        bool                  guest_msrs_ready;
index 0a0e911..8908c58 100644 (file)
@@ -695,16 +695,28 @@ AVXcode: 2
 4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev)
 4e: vrsqrt14ps/d Vpd,Wpd (66),(ev)
 4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev)
-# Skip 0x50-0x57
+50: vpdpbusd Vx,Hx,Wx (66),(ev)
+51: vpdpbusds Vx,Hx,Wx (66),(ev)
+52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66),(ev) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev)
+53: vpdpwssds Vx,Hx,Wx (66),(ev) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev)
+54: vpopcntb/w Vx,Wx (66),(ev)
+55: vpopcntd/q Vx,Wx (66),(ev)
 58: vpbroadcastd Vx,Wx (66),(v)
 59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo)
 5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo)
 5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev)
-# Skip 0x5c-0x63
+# Skip 0x5c-0x61
+62: vpexpandb/w Vx,Wx (66),(ev)
+63: vpcompressb/w Wx,Vx (66),(ev)
 64: vpblendmd/q Vx,Hx,Wx (66),(ev)
 65: vblendmps/d Vx,Hx,Wx (66),(ev)
 66: vpblendmb/w Vx,Hx,Wx (66),(ev)
-# Skip 0x67-0x74
+68: vp2intersectd/q Kx,Hx,Wx (F2),(ev)
+# Skip 0x69-0x6f
+70: vpshldvw Vx,Hx,Wx (66),(ev)
+71: vpshldvd/q Vx,Hx,Wx (66),(ev)
+72: vcvtne2ps2bf16 Vx,Hx,Wx (F2),(ev) | vcvtneps2bf16 Vx,Wx (F3),(ev) | vpshrdvw Vx,Hx,Wx (66),(ev)
+73: vpshrdvd/q Vx,Hx,Wx (66),(ev)
 75: vpermi2b/w Vx,Hx,Wx (66),(ev)
 76: vpermi2d/q Vx,Hx,Wx (66),(ev)
 77: vpermi2ps/d Vx,Hx,Wx (66),(ev)
@@ -727,6 +739,7 @@ AVXcode: 2
 8c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
 8d: vpermb/w Vx,Hx,Wx (66),(ev)
 8e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
+8f: vpshufbitqmb Kx,Hx,Wx (66),(ev)
 # 0x0f 0x38 0x90-0xbf (FMA)
 90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo)
 91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo)
@@ -738,8 +751,8 @@ AVXcode: 2
 97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v)
 98: vfmadd132ps/d Vx,Hx,Wx (66),(v)
 99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
-9a: vfmsub132ps/d Vx,Hx,Wx (66),(v)
-9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
+9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) | v4fmaddps Vdqq,Hdqq,Wdq (F2),(ev)
+9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) | v4fmaddss Vdq,Hdq,Wdq (F2),(ev)
 9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v)
 9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
 9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
@@ -752,8 +765,8 @@ a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
 a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
 a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
 a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
-aa: vfmsub213ps/d Vx,Hx,Wx (66),(v)
-ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
+aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) | v4fnmaddps Vdqq,Hdqq,Wdq (F2),(ev)
+ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) | v4fnmaddss Vdq,Hdq,Wdq (F2),(ev)
 ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v)
 ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
 ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
@@ -780,11 +793,12 @@ ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev)
 cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev)
 cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev)
 cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev)
+cf: vgf2p8mulb Vx,Wx (66)
 db: VAESIMC Vdq,Wdq (66),(v1)
-dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
-dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
-de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
-df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
+dc: vaesenc Vx,Hx,Wx (66)
+dd: vaesenclast Vx,Hx,Wx (66)
+de: vaesdec Vx,Hx,Wx (66)
+df: vaesdeclast Vx,Hx,Wx (66)
 f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2)
 f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2)
 f2: ANDN Gy,By,Ey (v)
@@ -848,7 +862,7 @@ AVXcode: 3
 41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
 42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo)
 43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev)
-44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
+44: vpclmulqdq Vx,Hx,Wx,Ib (66)
 46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
 4a: vblendvps Vx,Hx,Wx,Lx (66),(v)
 4b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
@@ -865,7 +879,13 @@ AVXcode: 3
 63: vpcmpistri Vdq,Wdq,Ib (66),(v1)
 66: vfpclassps/d Vk,Wx,Ib (66),(ev)
 67: vfpclassss/d Vk,Wx,Ib (66),(ev)
+70: vpshldw Vx,Hx,Wx,Ib (66),(ev)
+71: vpshldd/q Vx,Hx,Wx,Ib (66),(ev)
+72: vpshrdw Vx,Hx,Wx,Ib (66),(ev)
+73: vpshrdd/q Vx,Hx,Wx,Ib (66),(ev)
 cc: sha1rnds4 Vdq,Wdq,Ib
+ce: vgf2p8affineqb Vx,Wx,Ib (66)
+cf: vgf2p8affineinvqb Vx,Wx,Ib (66)
 df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
 f0: RORX Gy,Ey,Ib (F2),(v)
 EndTable
index 82ead8e..56f9189 100644 (file)
@@ -17,6 +17,10 @@ static DEFINE_PER_CPU_PAGE_ALIGNED(struct exception_stacks, exception_stacks);
 DEFINE_PER_CPU(struct cea_exception_stacks*, cea_exception_stacks);
 #endif
 
+#if defined(CONFIG_X86_32) && defined(CONFIG_DOUBLEFAULT)
+DECLARE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack);
+#endif
+
 struct cpu_entry_area *get_cpu_entry_area(int cpu)
 {
        unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE;
@@ -108,7 +112,15 @@ static void __init percpu_setup_exception_stacks(unsigned int cpu)
        cea_map_stack(MCE);
 }
 #else
-static inline void percpu_setup_exception_stacks(unsigned int cpu) {}
+static inline void percpu_setup_exception_stacks(unsigned int cpu)
+{
+#ifdef CONFIG_DOUBLEFAULT
+       struct cpu_entry_area *cea = get_cpu_entry_area(cpu);
+
+       cea_map_percpu_pages(&cea->doublefault_stack,
+                            &per_cpu(doublefault_stack, cpu), 1, PAGE_KERNEL);
+#endif
+}
 #endif
 
 /* Setup the fixmap mappings only once per-processor */
index 9ceacd1..304d31d 100644 (file)
@@ -197,7 +197,7 @@ void vmalloc_sync_all(void)
                return;
 
        for (address = VMALLOC_START & PMD_MASK;
-            address >= TASK_SIZE_MAX && address < FIXADDR_TOP;
+            address >= TASK_SIZE_MAX && address < VMALLOC_END;
             address += PMD_SIZE) {
                struct page *page;
 
index 296da58..cf5bc37 100644 (file)
@@ -245,6 +245,49 @@ static void __init kasan_map_early_shadow(pgd_t *pgd)
        } while (pgd++, addr = next, addr != end);
 }
 
+static void __init kasan_shallow_populate_p4ds(pgd_t *pgd,
+                                              unsigned long addr,
+                                              unsigned long end)
+{
+       p4d_t *p4d;
+       unsigned long next;
+       void *p;
+
+       p4d = p4d_offset(pgd, addr);
+       do {
+               next = p4d_addr_end(addr, end);
+
+               if (p4d_none(*p4d)) {
+                       p = early_alloc(PAGE_SIZE, NUMA_NO_NODE, true);
+                       p4d_populate(&init_mm, p4d, p);
+               }
+       } while (p4d++, addr = next, addr != end);
+}
+
+static void __init kasan_shallow_populate_pgds(void *start, void *end)
+{
+       unsigned long addr, next;
+       pgd_t *pgd;
+       void *p;
+
+       addr = (unsigned long)start;
+       pgd = pgd_offset_k(addr);
+       do {
+               next = pgd_addr_end(addr, (unsigned long)end);
+
+               if (pgd_none(*pgd)) {
+                       p = early_alloc(PAGE_SIZE, NUMA_NO_NODE, true);
+                       pgd_populate(&init_mm, pgd, p);
+               }
+
+               /*
+                * we need to populate p4ds to be synced when running in
+                * four level mode - see sync_global_pgds_l4()
+                */
+               kasan_shallow_populate_p4ds(pgd, addr, next);
+       } while (pgd++, addr = next, addr != (unsigned long)end);
+}
+
 #ifdef CONFIG_KASAN_INLINE
 static int kasan_die_handler(struct notifier_block *self,
                             unsigned long val,
@@ -354,6 +397,24 @@ void __init kasan_init(void)
 
        kasan_populate_early_shadow(
                kasan_mem_to_shadow((void *)PAGE_OFFSET + MAXMEM),
+               kasan_mem_to_shadow((void *)VMALLOC_START));
+
+       /*
+        * If we're in full vmalloc mode, don't back vmalloc space with early
+        * shadow pages. Instead, prepopulate pgds/p4ds so they are synced to
+        * the global table and we can populate the lower levels on demand.
+        */
+       if (IS_ENABLED(CONFIG_KASAN_VMALLOC))
+               kasan_shallow_populate_pgds(
+                       kasan_mem_to_shadow((void *)VMALLOC_START),
+                       kasan_mem_to_shadow((void *)VMALLOC_END));
+       else
+               kasan_populate_early_shadow(
+                       kasan_mem_to_shadow((void *)VMALLOC_START),
+                       kasan_mem_to_shadow((void *)VMALLOC_END));
+
+       kasan_populate_early_shadow(
+               kasan_mem_to_shadow((void *)VMALLOC_END + 1),
                shadow_cpu_entry_begin);
 
        kasan_populate_shadow((unsigned long)shadow_cpu_entry_begin,
index 47a1bf3..6855362 100644 (file)
@@ -56,7 +56,7 @@ static struct memtype *memtype_match(u64 start, u64 end, int match_type)
 {
        struct memtype *match;
 
-       match = memtype_interval_iter_first(&memtype_rbroot, start, end);
+       match = memtype_interval_iter_first(&memtype_rbroot, start, end-1);
        while (match != NULL && match->start < end) {
                if ((match_type == MEMTYPE_EXACT_MATCH) &&
                    (match->start == start) && (match->end == end))
@@ -66,7 +66,7 @@ static struct memtype *memtype_match(u64 start, u64 end, int match_type)
                    (match->start < start) && (match->end == end))
                        return match;
 
-               match = memtype_interval_iter_next(match, start, end);
+               match = memtype_interval_iter_next(match, start, end-1);
        }
 
        return NULL; /* Returns NULL if there is no match */
@@ -79,7 +79,7 @@ static int memtype_check_conflict(u64 start, u64 end,
        struct memtype *match;
        enum page_cache_mode found_type = reqtype;
 
-       match = memtype_interval_iter_first(&memtype_rbroot, start, end);
+       match = memtype_interval_iter_first(&memtype_rbroot, start, end-1);
        if (match == NULL)
                goto success;
 
@@ -89,12 +89,12 @@ static int memtype_check_conflict(u64 start, u64 end,
        dprintk("Overlap at 0x%Lx-0x%Lx\n", match->start, match->end);
        found_type = match->type;
 
-       match = memtype_interval_iter_next(match, start, end);
+       match = memtype_interval_iter_next(match, start, end-1);
        while (match) {
                if (match->type != found_type)
                        goto failure;
 
-               match = memtype_interval_iter_next(match, start, end);
+               match = memtype_interval_iter_next(match, start, end-1);
        }
 success:
        if (newtype)
@@ -160,7 +160,7 @@ struct memtype *memtype_erase(u64 start, u64 end)
 struct memtype *memtype_lookup(u64 addr)
 {
        return memtype_interval_iter_first(&memtype_rbroot, addr,
-                                          addr + PAGE_SIZE);
+                                          addr + PAGE_SIZE-1);
 }
 
 #if defined(CONFIG_DEBUG_FS)
index c806b57..48bcada 100644 (file)
@@ -24,6 +24,4 @@ obj-y                         += bus_numa.o
 obj-$(CONFIG_AMD_NB)           += amd_bus.o
 obj-$(CONFIG_PCI_CNB20LE_QUIRK)        += broadcom_bus.o
 
-ifeq ($(CONFIG_PCI_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_PCI_DEBUG)    += -DDEBUG
index 9acab6a..1e59df0 100644 (file)
@@ -135,7 +135,7 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev)
                * resource so the kernel doesn't attempt to assign
                * it later on in pci_assign_unassigned_resources
                */
-               for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) {
+               for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                        bar_r = &dev->resource[bar];
                        if (bar_r->start == 0 && bar_r->end != 0) {
                                bar_r->flags = 0;
index 527e69b..e723559 100644 (file)
@@ -588,6 +588,17 @@ static void pci_fixup_amd_ehci_pme(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7808, pci_fixup_amd_ehci_pme);
 
+/*
+ * Device [1022:7914]
+ * When in D0, PME# doesn't get asserted when plugging USB 2.0 device.
+ */
+static void pci_fixup_amd_fch_xhci_pme(struct pci_dev *dev)
+{
+       dev_info(&dev->dev, "PME# does not work under D0, disabling it\n");
+       dev->pme_support &= ~(PCI_PM_CAP_PME_D0 >> PCI_PM_CAP_PME_SHIFT);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7914, pci_fixup_amd_fch_xhci_pme);
+
 /*
  * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff]
  *
index 43867bc..00c6211 100644 (file)
@@ -382,7 +382,7 @@ static void pci_fixed_bar_fixup(struct pci_dev *dev)
            PCI_DEVFN(2, 2) == dev->devfn)
                return;
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                pci_read_config_dword(dev, offset + 8 + (i * 4), &size);
                dev->resource[i].end = dev->resource[i].start + size - 1;
                dev->resource[i].flags |= IORESOURCE_PCI_FIXED;
index 2e565e6..01a085d 100644 (file)
@@ -1,8 +1,5 @@
+// SPDX-License-Identifier: GPL-2.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.
- *
  * Numascale NumaConnect-specific PCI code
  *
  * Copyright (C) 2012 Numascale AS. All rights reserved.
index c95a347..4a3fa29 100644 (file)
@@ -21,8 +21,8 @@ config XTENSA
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
        select GENERIC_STRNCPY_FROM_USER if KASAN
-       select HAVE_ARCH_JUMP_LABEL
-       select HAVE_ARCH_KASAN if MMU
+       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
+       select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
@@ -215,151 +215,6 @@ config HOTPLUG_CPU
 
          Say N if you want to disable CPU hotplug.
 
-config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
-       bool "Initialize Xtensa MMU inside the Linux kernel code"
-       depends on !XTENSA_VARIANT_FSF && !XTENSA_VARIANT_DC232B
-       default y if XTENSA_VARIANT_DC233C || XTENSA_VARIANT_CUSTOM
-       help
-         Earlier version initialized the MMU in the exception vector
-         before jumping to _startup in head.S and had an advantage that
-         it was possible to place a software breakpoint at 'reset' and
-         then enter your normal kernel breakpoints once the MMU was mapped
-         to the kernel mappings (0XC0000000).
-
-         This unfortunately won't work for U-Boot and likely also wont
-         work for using KEXEC to have a hot kernel ready for doing a
-         KDUMP.
-
-         So now the MMU is initialized in head.S but it's necessary to
-         use hardware breakpoints (gdb 'hbreak' cmd) to break at _startup.
-         xt-gdb can't place a Software Breakpoint in the  0XD region prior
-         to mapping the MMU and after mapping even if the area of low memory
-         was mapped gdb wouldn't remove the breakpoint on hitting it as the
-         PC wouldn't match. Since Hardware Breakpoints are recommended for
-         Linux configurations it seems reasonable to just assume they exist
-         and leave this older mechanism for unfortunate souls that choose
-         not to follow Tensilica's recommendation.
-
-         Selecting this will cause U-Boot to set the KERNEL Load and Entry
-         address at 0x00003000 instead of the mapped std of 0xD0003000.
-
-         If in doubt, say Y.
-
-config MEMMAP_CACHEATTR
-       hex "Cache attributes for the memory address space"
-       depends on !MMU
-       default 0x22222222
-       help
-         These cache attributes are set up for noMMU systems. Each hex digit
-         specifies cache attributes for the corresponding 512MB memory
-         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.
-         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"
-       depends on INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX && MMU
-       default 0x00000000
-       help
-         This is the physical address where KSEG is mapped. Please refer to
-         the chosen KSEG layout help for the required address alignment.
-         Unpacked kernel image (including vectors) must be located completely
-         within KSEG.
-         Physical memory below this address is not available to linux.
-
-         If unsure, leave the default value here.
-
-config KERNEL_LOAD_ADDRESS
-       hex "Kernel load address"
-       default 0x60003000 if !MMU
-       default 0x00003000 if MMU && INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
-       default 0xd0003000 if MMU && !INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
-       help
-         This is the address where the kernel is loaded.
-         It is virtual address for MMUv2 configurations and physical address
-         for all other configurations.
-
-         If unsure, leave the default value here.
-
-config VECTORS_OFFSET
-       hex "Kernel vectors offset"
-       default 0x00003000
-       help
-         This is the offset of the kernel image from the relocatable vectors
-         base.
-
-         If unsure, leave the default value here.
-
-choice
-       prompt "KSEG layout"
-       depends on MMU
-       default XTENSA_KSEG_MMU_V2
-
-config XTENSA_KSEG_MMU_V2
-       bool "MMUv2: 128MB cached + 128MB uncached"
-       help
-         MMUv2 compatible kernel memory map: TLB way 5 maps 128MB starting
-         at KSEG_PADDR to 0xd0000000 with cache and to 0xd8000000
-         without cache.
-         KSEG_PADDR must be aligned to 128MB.
-
-config XTENSA_KSEG_256M
-       bool "256MB cached + 256MB uncached"
-       depends on INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
-       help
-         TLB way 6 maps 256MB starting at KSEG_PADDR to 0xb0000000
-         with cache and to 0xc0000000 without cache.
-         KSEG_PADDR must be aligned to 256MB.
-
-config XTENSA_KSEG_512M
-       bool "512MB cached + 512MB uncached"
-       depends on INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
-       help
-         TLB way 6 maps 512MB starting at KSEG_PADDR to 0xa0000000
-         with cache and to 0xc0000000 without cache.
-         KSEG_PADDR must be aligned to 256MB.
-
-endchoice
-
-config HIGHMEM
-       bool "High Memory Support"
-       depends on MMU
-       help
-         Linux can use the full amount of RAM in the system by
-         default. However, the default MMUv2 setup only maps the
-         lowermost 128 MB of memory linearly to the areas starting
-         at 0xd0000000 (cached) and 0xd8000000 (uncached).
-         When there are more than 128 MB memory in the system not
-         all of it can be "permanently mapped" by the kernel.
-         The physical memory that's not permanently mapped is called
-         "high memory".
-
-         If you are compiling a kernel which will never run on a
-         machine with more than 128 MB total physical RAM, answer
-         N here.
-
-         If unsure, say Y.
-
 config FAST_SYSCALL_XTENSA
        bool "Enable fast atomic syscalls"
        default n
@@ -446,6 +301,9 @@ config XTENSA_CALIBRATE_CCOUNT
 config SERIAL_CONSOLE
        def_bool n
 
+config PLATFORM_HAVE_XIP
+       def_bool n
+
 menu "Platform options"
 
 choice
@@ -472,6 +330,7 @@ config XTENSA_PLATFORM_XTFPGA
        select PLATFORM_WANT_DEFAULT_MEM if !MMU
        select SERIAL_CONSOLE
        select XTENSA_CALIBRATE_CCOUNT
+       select PLATFORM_HAVE_XIP
        help
          XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605).
          This hardware is capable of running a full Linux distribution.
@@ -563,34 +422,6 @@ config SIMDISK1_FILENAME
          Another simulated disk in a host file for a buildroot-independent
          storage.
 
-config FORCE_MAX_ZONEORDER
-       int "Maximum zone order"
-       default "11"
-       help
-         The kernel memory allocator divides physically contiguous memory
-         blocks into "zones", where each zone is a power of two number of
-         pages.  This option selects the largest power of two that the kernel
-         keeps in the memory allocator.  If you need to allocate very large
-         blocks of physically contiguous memory, then you may need to
-         increase this value.
-
-         This config option is actually maximum order plus one. For example,
-         a value of 11 means that the largest free memory block is 2^10 pages.
-
-config PLATFORM_WANT_DEFAULT_MEM
-       def_bool n
-
-config DEFAULT_MEM_START
-       hex
-       prompt "PAGE_OFFSET/PHYS_OFFSET" if !MMU && PLATFORM_WANT_DEFAULT_MEM
-       default 0x60000000 if PLATFORM_WANT_DEFAULT_MEM
-       default 0x00000000
-       help
-         This is the base address used for both PAGE_OFFSET and PHYS_OFFSET
-         in noMMU configurations.
-
-         If unsure, leave the default value here.
-
 config XTFPGA_LCD
        bool "Enable XTFPGA LCD driver"
        depends on XTENSA_PLATFORM_XTFPGA
@@ -621,6 +452,221 @@ config XTFPGA_LCD_8BIT_ACCESS
          only be used with 8-bit interface. Please consult prototyping user
          guide for your board for the correct interface width.
 
+comment "Kernel memory layout"
+
+config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
+       bool "Initialize Xtensa MMU inside the Linux kernel code"
+       depends on !XTENSA_VARIANT_FSF && !XTENSA_VARIANT_DC232B
+       default y if XTENSA_VARIANT_DC233C || XTENSA_VARIANT_CUSTOM
+       help
+         Earlier version initialized the MMU in the exception vector
+         before jumping to _startup in head.S and had an advantage that
+         it was possible to place a software breakpoint at 'reset' and
+         then enter your normal kernel breakpoints once the MMU was mapped
+         to the kernel mappings (0XC0000000).
+
+         This unfortunately won't work for U-Boot and likely also wont
+         work for using KEXEC to have a hot kernel ready for doing a
+         KDUMP.
+
+         So now the MMU is initialized in head.S but it's necessary to
+         use hardware breakpoints (gdb 'hbreak' cmd) to break at _startup.
+         xt-gdb can't place a Software Breakpoint in the  0XD region prior
+         to mapping the MMU and after mapping even if the area of low memory
+         was mapped gdb wouldn't remove the breakpoint on hitting it as the
+         PC wouldn't match. Since Hardware Breakpoints are recommended for
+         Linux configurations it seems reasonable to just assume they exist
+         and leave this older mechanism for unfortunate souls that choose
+         not to follow Tensilica's recommendation.
+
+         Selecting this will cause U-Boot to set the KERNEL Load and Entry
+         address at 0x00003000 instead of the mapped std of 0xD0003000.
+
+         If in doubt, say Y.
+
+config XIP_KERNEL
+       bool "Kernel Execute-In-Place from ROM"
+       depends on PLATFORM_HAVE_XIP
+       help
+         Execute-In-Place allows the kernel to run from non-volatile storage
+         directly addressable by the CPU, such as NOR flash. This saves RAM
+         space since the text section of the kernel is not loaded from flash
+         to RAM. Read-write sections, such as the data section and stack,
+         are still copied to RAM. The XIP kernel is not compressed since
+         it has to run directly from flash, so it will take more space to
+         store it. The flash address used to link the kernel object files,
+         and for storing it, is configuration dependent. Therefore, if you
+         say Y here, you must know the proper physical address where to
+         store the kernel image depending on your own flash memory usage.
+
+         Also note that the make target becomes "make xipImage" rather than
+         "make Image" or "make uImage". The final kernel binary to put in
+         ROM memory will be arch/xtensa/boot/xipImage.
+
+         If unsure, say N.
+
+config MEMMAP_CACHEATTR
+       hex "Cache attributes for the memory address space"
+       depends on !MMU
+       default 0x22222222
+       help
+         These cache attributes are set up for noMMU systems. Each hex digit
+         specifies cache attributes for the corresponding 512MB memory
+         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.
+         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"
+       depends on INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX && MMU
+       default 0x00000000
+       help
+         This is the physical address where KSEG is mapped. Please refer to
+         the chosen KSEG layout help for the required address alignment.
+         Unpacked kernel image (including vectors) must be located completely
+         within KSEG.
+         Physical memory below this address is not available to linux.
+
+         If unsure, leave the default value here.
+
+config KERNEL_VIRTUAL_ADDRESS
+       hex "Kernel virtual address"
+       depends on MMU && XIP_KERNEL
+       default 0xd0003000
+       help
+         This is the virtual address where the XIP kernel is mapped.
+         XIP kernel may be mapped into KSEG or KIO region, virtual address
+         provided here must match kernel load address provided in
+         KERNEL_LOAD_ADDRESS.
+
+config KERNEL_LOAD_ADDRESS
+       hex "Kernel load address"
+       default 0x60003000 if !MMU
+       default 0x00003000 if MMU && INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
+       default 0xd0003000 if MMU && !INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
+       help
+         This is the address where the kernel is loaded.
+         It is virtual address for MMUv2 configurations and physical address
+         for all other configurations.
+
+         If unsure, leave the default value here.
+
+config VECTORS_OFFSET
+       hex "Kernel vectors offset"
+       default 0x00003000
+       depends on !XIP_KERNEL
+       help
+         This is the offset of the kernel image from the relocatable vectors
+         base.
+
+         If unsure, leave the default value here.
+
+config XIP_DATA_ADDR
+       hex "XIP kernel data virtual address"
+       depends on XIP_KERNEL
+       default 0x00000000
+       help
+         This is the virtual address where XIP kernel data is copied.
+         It must be within KSEG if MMU is used.
+
+config PLATFORM_WANT_DEFAULT_MEM
+       def_bool n
+
+config DEFAULT_MEM_START
+       hex
+       prompt "PAGE_OFFSET/PHYS_OFFSET" if !MMU && PLATFORM_WANT_DEFAULT_MEM
+       default 0x60000000 if PLATFORM_WANT_DEFAULT_MEM
+       default 0x00000000
+       help
+         This is the base address used for both PAGE_OFFSET and PHYS_OFFSET
+         in noMMU configurations.
+
+         If unsure, leave the default value here.
+
+choice
+       prompt "KSEG layout"
+       depends on MMU
+       default XTENSA_KSEG_MMU_V2
+
+config XTENSA_KSEG_MMU_V2
+       bool "MMUv2: 128MB cached + 128MB uncached"
+       help
+         MMUv2 compatible kernel memory map: TLB way 5 maps 128MB starting
+         at KSEG_PADDR to 0xd0000000 with cache and to 0xd8000000
+         without cache.
+         KSEG_PADDR must be aligned to 128MB.
+
+config XTENSA_KSEG_256M
+       bool "256MB cached + 256MB uncached"
+       depends on INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
+       help
+         TLB way 6 maps 256MB starting at KSEG_PADDR to 0xb0000000
+         with cache and to 0xc0000000 without cache.
+         KSEG_PADDR must be aligned to 256MB.
+
+config XTENSA_KSEG_512M
+       bool "512MB cached + 512MB uncached"
+       depends on INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
+       help
+         TLB way 6 maps 512MB starting at KSEG_PADDR to 0xa0000000
+         with cache and to 0xc0000000 without cache.
+         KSEG_PADDR must be aligned to 256MB.
+
+endchoice
+
+config HIGHMEM
+       bool "High Memory Support"
+       depends on MMU
+       help
+         Linux can use the full amount of RAM in the system by
+         default. However, the default MMUv2 setup only maps the
+         lowermost 128 MB of memory linearly to the areas starting
+         at 0xd0000000 (cached) and 0xd8000000 (uncached).
+         When there are more than 128 MB memory in the system not
+         all of it can be "permanently mapped" by the kernel.
+         The physical memory that's not permanently mapped is called
+         "high memory".
+
+         If you are compiling a kernel which will never run on a
+         machine with more than 128 MB total physical RAM, answer
+         N here.
+
+         If unsure, say Y.
+
+config FORCE_MAX_ZONEORDER
+       int "Maximum zone order"
+       default "11"
+       help
+         The kernel memory allocator divides physically contiguous memory
+         blocks into "zones", where each zone is a power of two number of
+         pages.  This option selects the largest power of two that the kernel
+         keeps in the memory allocator.  If you need to allocate very large
+         blocks of physically contiguous memory, then you may need to
+         increase this value.
+
+         This config option is actually maximum order plus one. For example,
+         a value of 11 means that the largest free memory block is 2^10 pages.
+
 endmenu
 
 menu "Power management options"
index 39de98e..83cc8d1 100644 (file)
@@ -31,3 +31,10 @@ config S32C1I_SELFTEST
          It is easy to make wrong hardware configuration, this test should catch it early.
 
          Say 'N' on stable hardware.
+
+config PRINT_STACK_DEPTH
+       int "Stack depth to print" if DEBUG_KERNEL
+       default 64
+       help
+         This option allows you to set the stack depth that the kernel
+         prints in stack traces.
index 1542018..67a7d15 100644 (file)
@@ -87,7 +87,7 @@ drivers-$(CONFIG_OPROFILE)    += arch/xtensa/oprofile/
 
 boot           := arch/xtensa/boot
 
-all Image zImage uImage: vmlinux
+all Image zImage uImage xipImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $@
 
 archheaders:
@@ -97,4 +97,5 @@ define archhelp
   @echo '* Image       - Kernel ELF image with reset vector'
   @echo '* zImage      - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
   @echo '* uImage      - U-Boot wrapped image'
+  @echo '  xipImage    - XIP image'
 endef
index 2948461..efb91bf 100644 (file)
@@ -29,6 +29,7 @@ all: $(boot-y)
 Image: boot-elf
 zImage: boot-redboot
 uImage: $(obj)/uImage
+xipImage: $(obj)/xipImage
 
 boot-elf boot-redboot: $(addprefix $(obj)/,$(subdir-y))
        $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
@@ -50,3 +51,7 @@ UIMAGE_COMPRESSION = gzip
 $(obj)/uImage: vmlinux.bin.gz FORCE
        $(call if_changed,uimage)
        $(Q)$(kecho) '  Kernel: $@ is ready'
+
+$(obj)/xipImage: vmlinux FORCE
+       $(call if_changed,objcopy)
+       $(Q)$(kecho) '  Kernel: $@ is ready'
diff --git a/arch/xtensa/configs/xip_kc705_defconfig b/arch/xtensa/configs/xip_kc705_defconfig
new file mode 100644 (file)
index 0000000..f9e85c0
--- /dev/null
@@ -0,0 +1,119 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_MEMCG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PROFILING=y
+CONFIG_XTENSA_VARIANT_DC233C=y
+CONFIG_XTENSA_UNALIGNED_USER=y
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_DATA_ADDR=0xd0000000
+CONFIG_KERNEL_VIRTUAL_ADDRESS=0xe6000000
+CONFIG_KERNEL_LOAD_ADDRESS=0xf6000000
+CONFIG_XTENSA_KSEG_512M=y
+CONFIG_HIGHMEM=y
+CONFIG_XTENSA_PLATFORM_XTFPGA=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon=uart8250,mmio32native,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x38000000@0"
+CONFIG_USE_OF=y
+CONFIG_BUILTIN_DTB_SOURCE="kc705"
+# CONFIG_PARSE_BOOTPARAM is not set
+CONFIG_OPROFILE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPACTION is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_AURORA is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_MARVELL_PHY=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_DEVKMEM=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT3_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_ROOT_NFS=y
+CONFIG_SUNRPC_DEBUG=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_STACKTRACE=y
+CONFIG_RCU_TRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_S32C1I_SELFTEST is not set
index ffa0cf7..3acc31e 100644 (file)
@@ -11,6 +11,7 @@ generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
 generic-y += hardirq.h
+generic-y += hw_irq.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
@@ -30,6 +31,7 @@ generic-y += qspinlock.h
 generic-y += sections.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
index 7b00d26..3e7c613 100644 (file)
@@ -64,13 +64,13 @@ static inline void atomic_##op(int i, atomic_t *v)                  \
        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)                              \
+                       "1:     l32ex   %[tmp], %[addr]\n"              \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       "       s32ex   %[result], %[addr]\n"           \
+                       "       getex   %[result]\n"                    \
+                       "       beqz    %[result], 1b\n"                \
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp)    \
+                       : [i] "a" (i), [addr] "a" (v)                   \
                        : "memory"                                      \
                        );                                              \
 }                                                                      \
@@ -82,14 +82,14 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
        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)                              \
+                       "1:     l32ex   %[tmp], %[addr]\n"              \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       "       s32ex   %[result], %[addr]\n"           \
+                       "       getex   %[result]\n"                    \
+                       "       beqz    %[result], 1b\n"                \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp)    \
+                       : [i] "a" (i), [addr] "a" (v)                   \
                        : "memory"                                      \
                        );                                              \
                                                                        \
@@ -103,13 +103,13 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                   \
        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)                              \
+                       "1:     l32ex   %[tmp], %[addr]\n"              \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       "       s32ex   %[result], %[addr]\n"           \
+                       "       getex   %[result]\n"                    \
+                       "       beqz    %[result], 1b\n"                \
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp)    \
+                       : [i] "a" (i), [addr] "a" (v)                   \
                        : "memory"                                      \
                        );                                              \
                                                                        \
@@ -124,13 +124,14 @@ static inline void atomic_##op(int i, atomic_t * v)                       \
        int result;                                                     \
                                                                        \
        __asm__ __volatile__(                                           \
-                       "1:     l32i    %1, %3, 0\n"                    \
-                       "       wsr     %1, scompare1\n"                \
-                       "       " #op " %0, %1, %2\n"                   \
-                       "       s32c1i  %0, %3, 0\n"                    \
-                       "       bne     %0, %1, 1b\n"                   \
-                       : "=&a" (result), "=&a" (tmp)                   \
-                       : "a" (i), "a" (v)                              \
+                       "1:     l32i    %[tmp], %[mem]\n"               \
+                       "       wsr     %[tmp], scompare1\n"            \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       "       s32c1i  %[result], %[mem]\n"            \
+                       "       bne     %[result], %[tmp], 1b\n"        \
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp),   \
+                         [mem] "+m" (*v)                               \
+                       : [i] "a" (i)                                   \
                        : "memory"                                      \
                        );                                              \
 }                                                                      \
@@ -142,14 +143,15 @@ static inline int atomic_##op##_return(int i, atomic_t * v)               \
        int result;                                                     \
                                                                        \
        __asm__ __volatile__(                                           \
-                       "1:     l32i    %1, %3, 0\n"                    \
-                       "       wsr     %1, scompare1\n"                \
-                       "       " #op " %0, %1, %2\n"                   \
-                       "       s32c1i  %0, %3, 0\n"                    \
-                       "       bne     %0, %1, 1b\n"                   \
-                       "       " #op " %0, %0, %2\n"                   \
-                       : "=&a" (result), "=&a" (tmp)                   \
-                       : "a" (i), "a" (v)                              \
+                       "1:     l32i    %[tmp], %[mem]\n"               \
+                       "       wsr     %[tmp], scompare1\n"            \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       "       s32c1i  %[result], %[mem]\n"            \
+                       "       bne     %[result], %[tmp], 1b\n"        \
+                       "       " #op " %[result], %[result], %[i]\n"   \
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp),   \
+                         [mem] "+m" (*v)                               \
+                       : [i] "a" (i)                                   \
                        : "memory"                                      \
                        );                                              \
                                                                        \
@@ -163,13 +165,14 @@ static inline int atomic_fetch_##op(int i, atomic_t * v)          \
        int result;                                                     \
                                                                        \
        __asm__ __volatile__(                                           \
-                       "1:     l32i    %1, %3, 0\n"                    \
-                       "       wsr     %1, scompare1\n"                \
-                       "       " #op " %0, %1, %2\n"                   \
-                       "       s32c1i  %0, %3, 0\n"                    \
-                       "       bne     %0, %1, 1b\n"                   \
-                       : "=&a" (result), "=&a" (tmp)                   \
-                       : "a" (i), "a" (v)                              \
+                       "1:     l32i    %[tmp], %[mem]\n"               \
+                       "       wsr     %[tmp], scompare1\n"            \
+                       "       " #op " %[result], %[tmp], %[i]\n"      \
+                       "       s32c1i  %[result], %[mem]\n"            \
+                       "       bne     %[result], %[tmp], 1b\n"        \
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp),   \
+                         [mem] "+m" (*v)                               \
+                       : [i] "a" (i)                                   \
                        : "memory"                                      \
                        );                                              \
                                                                        \
@@ -184,14 +187,14 @@ static inline void atomic_##op(int i, atomic_t * v)                       \
        unsigned int vval;                                              \
                                                                        \
        __asm__ __volatile__(                                           \
-                       "       rsil    a15, "__stringify(TOPLEVEL)"\n"\
-                       "       l32i    %0, %2, 0\n"                    \
-                       "       " #op " %0, %0, %1\n"                   \
-                       "       s32i    %0, %2, 0\n"                    \
+                       "       rsil    a15, "__stringify(TOPLEVEL)"\n" \
+                       "       l32i    %[result], %[mem]\n"            \
+                       "       " #op " %[result], %[result], %[i]\n"   \
+                       "       s32i    %[result], %[mem]\n"            \
                        "       wsr     a15, ps\n"                      \
                        "       rsync\n"                                \
-                       : "=&a" (vval)                                  \
-                       : "a" (i), "a" (v)                              \
+                       : [result] "=&a" (vval), [mem] "+m" (*v)        \
+                       : [i] "a" (i)                                   \
                        : "a15", "memory"                               \
                        );                                              \
 }                                                                      \
@@ -203,13 +206,13 @@ static inline int atomic_##op##_return(int i, atomic_t * v)               \
                                                                        \
        __asm__ __volatile__(                                           \
                        "       rsil    a15,"__stringify(TOPLEVEL)"\n"  \
-                       "       l32i    %0, %2, 0\n"                    \
-                       "       " #op " %0, %0, %1\n"                   \
-                       "       s32i    %0, %2, 0\n"                    \
+                       "       l32i    %[result], %[mem]\n"            \
+                       "       " #op " %[result], %[result], %[i]\n"   \
+                       "       s32i    %[result], %[mem]\n"            \
                        "       wsr     a15, ps\n"                      \
                        "       rsync\n"                                \
-                       : "=&a" (vval)                                  \
-                       : "a" (i), "a" (v)                              \
+                       : [result] "=&a" (vval), [mem] "+m" (*v)        \
+                       : [i] "a" (i)                                   \
                        : "a15", "memory"                               \
                        );                                              \
                                                                        \
@@ -223,13 +226,14 @@ static inline int atomic_fetch_##op(int i, atomic_t * v)          \
                                                                        \
        __asm__ __volatile__(                                           \
                        "       rsil    a15,"__stringify(TOPLEVEL)"\n"  \
-                       "       l32i    %0, %3, 0\n"                    \
-                       "       " #op " %1, %0, %2\n"                   \
-                       "       s32i    %1, %3, 0\n"                    \
+                       "       l32i    %[result], %[mem]\n"            \
+                       "       " #op " %[tmp], %[result], %[i]\n"      \
+                       "       s32i    %[tmp], %[mem]\n"               \
                        "       wsr     a15, ps\n"                      \
                        "       rsync\n"                                \
-                       : "=&a" (vval), "=&a" (tmp)                     \
-                       : "a" (i), "a" (v)                              \
+                       : [result] "=&a" (vval), [tmp] "=&a" (tmp),     \
+                         [mem] "+m" (*v)                               \
+                       : [i] "a" (i)                                   \
                        : "a15", "memory"                               \
                        );                                              \
                                                                        \
index be8b2be..3f71d36 100644 (file)
@@ -98,247 +98,112 @@ static inline unsigned long __fls(unsigned long word)
 
 #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;
+#define BIT_OP(op, insn, inv)                                          \
+static inline void op##_bit(unsigned int bit, volatile unsigned long *p)\
+{                                                                      \
+       unsigned long tmp;                                              \
+       unsigned long mask = 1UL << (bit & 31);                         \
+                                                                       \
+       p += bit >> 5;                                                  \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32ex   %[tmp], %[addr]\n"              \
+                       "      "insn"   %[tmp], %[tmp], %[mask]\n"      \
+                       "       s32ex   %[tmp], %[addr]\n"              \
+                       "       getex   %[tmp]\n"                       \
+                       "       beqz    %[tmp], 1b\n"                   \
+                       : [tmp] "=&a" (tmp)                             \
+                       : [mask] "a" (inv mask), [addr] "a" (p)         \
+                       : "memory");                                    \
+}
+
+#define TEST_AND_BIT_OP(op, insn, inv)                                 \
+static inline int                                                      \
+test_and_##op##_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   %[value], %[addr]\n"            \
+                       "      "insn"   %[tmp], %[value], %[mask]\n"    \
+                       "       s32ex   %[tmp], %[addr]\n"              \
+                       "       getex   %[tmp]\n"                       \
+                       "       beqz    %[tmp], 1b\n"                   \
+                       : [tmp] "=&a" (tmp), [value] "=&a" (value)      \
+                       : [mask] "a" (inv mask), [addr] "a" (p)         \
+                       : "memory");                                    \
+                                                                       \
+       return value & mask;                                            \
 }
 
 #elif XCHAL_HAVE_S32C1I
 
-static inline void 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:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       or      %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (tmp), "=&a" (value)
-                       : "a" (mask), "a" (p)
-                       : "memory");
-}
-
-static inline void 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:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       and     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (tmp), "=&a" (value)
-                       : "a" (~mask), "a" (p)
-                       : "memory");
+#define BIT_OP(op, insn, inv)                                          \
+static inline void op##_bit(unsigned int bit, volatile unsigned long *p)\
+{                                                                      \
+       unsigned long tmp, value;                                       \
+       unsigned long mask = 1UL << (bit & 31);                         \
+                                                                       \
+       p += bit >> 5;                                                  \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32i    %[value], %[mem]\n"             \
+                       "       wsr     %[value], scompare1\n"          \
+                       "      "insn"   %[tmp], %[value], %[mask]\n"    \
+                       "       s32c1i  %[tmp], %[mem]\n"               \
+                       "       bne     %[tmp], %[value], 1b\n"         \
+                       : [tmp] "=&a" (tmp), [value] "=&a" (value),     \
+                         [mem] "+m" (*p)                               \
+                       : [mask] "a" (inv mask)                         \
+                       : "memory");                                    \
+}
+
+#define TEST_AND_BIT_OP(op, insn, inv)                                 \
+static inline int                                                      \
+test_and_##op##_bit(unsigned int bit, volatile unsigned long *p)       \
+{                                                                      \
+       unsigned long tmp, value;                                       \
+       unsigned long mask = 1UL << (bit & 31);                         \
+                                                                       \
+       p += bit >> 5;                                                  \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32i    %[value], %[mem]\n"             \
+                       "       wsr     %[value], scompare1\n"          \
+                       "      "insn"   %[tmp], %[value], %[mask]\n"    \
+                       "       s32c1i  %[tmp], %[mem]\n"               \
+                       "       bne     %[tmp], %[value], 1b\n"         \
+                       : [tmp] "=&a" (tmp), [value] "=&a" (value),     \
+                         [mem] "+m" (*p)                               \
+                       : [mask] "a" (inv mask)                         \
+                       : "memory");                                    \
+                                                                       \
+       return tmp & mask;                                              \
 }
 
-static inline void 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:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       xor     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (tmp), "=&a" (value)
-                       : "a" (mask), "a" (p)
-                       : "memory");
-}
+#else
 
-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:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       or      %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (tmp), "=&a" (value)
-                       : "a" (mask), "a" (p)
-                       : "memory");
-
-       return tmp & mask;
-}
+#define BIT_OP(op, insn, inv)
+#define TEST_AND_BIT_OP(op, insn, inv)
 
-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:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       and     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (tmp), "=&a" (value)
-                       : "a" (~mask), "a" (p)
-                       : "memory");
-
-       return tmp & mask;
-}
+#include <asm-generic/bitops/atomic.h>
 
-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:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       xor     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (tmp), "=&a" (value)
-                       : "a" (mask), "a" (p)
-                       : "memory");
-
-       return tmp & mask;
-}
+#endif /* XCHAL_HAVE_S32C1I */
 
-#else
+#define BIT_OPS(op, insn, inv)         \
+       BIT_OP(op, insn, inv)           \
+       TEST_AND_BIT_OP(op, insn, inv)
 
-#include <asm-generic/bitops/atomic.h>
+BIT_OPS(set, "or", )
+BIT_OPS(clear, "and", ~)
+BIT_OPS(change, "xor", )
 
-#endif /* XCHAL_HAVE_S32C1I */
+#undef BIT_OPS
+#undef BIT_OP
+#undef TEST_AND_BIT_OP
 
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/le.h>
index b21fd13..54e147a 100644 (file)
 
 #define ARCH_DMA_MINALIGN      L1_CACHE_BYTES
 
+/*
+ * R/O after init is actually writable, it cannot go to .rodata
+ * according to vmlinux linker script.
+ */
+#define __ro_after_init __read_mostly
+
 #endif /* _XTENSA_CACHE_H */
index 7ccc5cb..a175f8a 100644 (file)
@@ -27,25 +27,25 @@ __cmpxchg_u32(volatile int *p, int old, int new)
        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"
+                       "1:     l32ex   %[result], %[addr]\n"
+                       "       bne     %[result], %[cmp], 2f\n"
+                       "       mov     %[tmp], %[new]\n"
+                       "       s32ex   %[tmp], %[addr]\n"
+                       "       getex   %[tmp]\n"
+                       "       beqz    %[tmp], 1b\n"
                        "2:\n"
-                       : "=&a" (result), "=&a" (tmp)
-                       : "a" (new), "a" (p), "a" (old)
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp)
+                       : [new] "a" (new), [addr] "a" (p), [cmp] "a" (old)
                        : "memory"
                        );
 
        return result;
 #elif XCHAL_HAVE_S32C1I
        __asm__ __volatile__(
-                       "       wsr     %2, scompare1\n"
-                       "       s32c1i  %0, %1, 0\n"
-                       : "+a" (new)
-                       : "a" (p), "a" (old)
+                       "       wsr     %[cmp], scompare1\n"
+                       "       s32c1i  %[new], %[mem]\n"
+                       : [new] "+a" (new), [mem] "+m" (*p)
+                       : [cmp] "a" (old)
                        : "memory"
                        );
 
@@ -53,14 +53,14 @@ __cmpxchg_u32(volatile int *p, int old, int new)
 #else
        __asm__ __volatile__(
                        "       rsil    a15, "__stringify(TOPLEVEL)"\n"
-                       "       l32i    %0, %1, 0\n"
-                       "       bne     %0, %2, 1f\n"
-                       "       s32i    %3, %1, 0\n"
+                       "       l32i    %[old], %[mem]\n"
+                       "       bne     %[old], %[cmp], 1f\n"
+                       "       s32i    %[new], %[mem]\n"
                        "1:\n"
                        "       wsr     a15, ps\n"
                        "       rsync\n"
-                       : "=&a" (old)
-                       : "a" (p), "a" (old), "r" (new)
+                       : [old] "=&a" (old), [mem] "+m" (*p)
+                       : [cmp] "a" (old), [new] "r" (new)
                        : "a15", "memory");
        return old;
 #endif
@@ -129,13 +129,13 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
        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)
+                       "1:     l32ex   %[result], %[addr]\n"
+                       "       mov     %[tmp], %[val]\n"
+                       "       s32ex   %[tmp], %[addr]\n"
+                       "       getex   %[tmp]\n"
+                       "       beqz    %[tmp], 1b\n"
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp)
+                       : [val] "a" (val), [addr] "a" (m)
                        : "memory"
                        );
 
@@ -143,13 +143,14 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 #elif XCHAL_HAVE_S32C1I
        unsigned long tmp, result;
        __asm__ __volatile__(
-                       "1:     l32i    %1, %2, 0\n"
-                       "       mov     %0, %3\n"
-                       "       wsr     %1, scompare1\n"
-                       "       s32c1i  %0, %2, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (result), "=&a" (tmp)
-                       : "a" (m), "a" (val)
+                       "1:     l32i    %[tmp], %[mem]\n"
+                       "       mov     %[result], %[val]\n"
+                       "       wsr     %[tmp], scompare1\n"
+                       "       s32c1i  %[result], %[mem]\n"
+                       "       bne     %[result], %[tmp], 1b\n"
+                       : [result] "=&a" (result), [tmp] "=&a" (tmp),
+                         [mem] "+m" (*m)
+                       : [val] "a" (val)
                        : "memory"
                        );
        return result;
@@ -157,12 +158,12 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
        unsigned long tmp;
        __asm__ __volatile__(
                        "       rsil    a15, "__stringify(TOPLEVEL)"\n"
-                       "       l32i    %0, %1, 0\n"
-                       "       s32i    %2, %1, 0\n"
+                       "       l32i    %[tmp], %[mem]\n"
+                       "       s32i    %[val], %[mem]\n"
                        "       wsr     a15, ps\n"
                        "       rsync\n"
-                       : "=&a" (tmp)
-                       : "a" (m), "a" (val)
+                       : [tmp] "=&a" (tmp), [mem] "+m" (*m)
+                       : [val] "a" (val)
                        : "a15", "memory");
        return tmp;
 #endif
index 7e25c1b..cfb8696 100644 (file)
@@ -78,8 +78,10 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
 
 #define kmap_get_fixmap_pte(vaddr) \
        pte_offset_kernel( \
-               pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), \
-               (vaddr) \
-       )
+               pmd_offset(pud_offset(p4d_offset(pgd_offset_k(vaddr), \
+                                                (vaddr)), \
+                                     (vaddr)), \
+                          (vaddr)), \
+               (vaddr))
 
 #endif
index 0c4457c..9646110 100644 (file)
 #elif XCHAL_HAVE_S32C1I
 #define __futex_atomic_op(insn, ret, old, uaddr, arg)  \
        __asm__ __volatile(                             \
-       "1:     l32i    %[oldval], %[addr], 0\n"        \
+       "1:     l32i    %[oldval], %[mem]\n"            \
                insn "\n"                               \
        "       wsr     %[oldval], scompare1\n"         \
-       "2:     s32c1i  %[newval], %[addr], 0\n"        \
+       "2:     s32c1i  %[newval], %[mem]\n"            \
        "       bne     %[newval], %[oldval], 1b\n"     \
        "       movi    %[newval], 0\n"                 \
        "3:\n"                                          \
@@ -60,9 +60,9 @@
        "       .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)                         \
+       : [oldval] "=&r" (old), [newval] "=&r" (ret),   \
+         [mem] "+m" (*(uaddr))                         \
+       : [oparg] "r" (arg), [fault] "I" (-EFAULT)      \
        : "memory")
 #endif
 
diff --git a/arch/xtensa/include/asm/hw_irq.h b/arch/xtensa/include/asm/hw_irq.h
deleted file mode 100644 (file)
index 3ddbea7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * include/asm-xtensa/hw_irq.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) 2002 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_HW_IRQ_H
-#define _XTENSA_HW_IRQ_H
-
-#endif
index 3b054d2..e3e1d9a 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef _XTENSA_INITIALIZE_MMU_H
 #define _XTENSA_INITIALIZE_MMU_H
 
+#include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/vectors.h>
 
 #endif
 
 #if XCHAL_HAVE_MPU
-       .data
+       __REFCONST
        .align  4
 .Lattribute_table:
        .long 0x000000, 0x1fff00, 0x1ddf00, 0x1eef00
index 9c12bab..7cbf68c 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef _XTENSA_KMEM_LAYOUT_H
 #define _XTENSA_KMEM_LAYOUT_H
 
+#include <asm/core.h>
 #include <asm/types.h>
 
 #ifdef CONFIG_MMU
 
 #endif
 
+/* KIO definition */
+
+#if XCHAL_HAVE_PTP_MMU
+#define XCHAL_KIO_CACHED_VADDR         0xe0000000
+#define XCHAL_KIO_BYPASS_VADDR         0xf0000000
+#define XCHAL_KIO_DEFAULT_PADDR                0xf0000000
+#else
+#define XCHAL_KIO_BYPASS_VADDR         XCHAL_KIO_PADDR
+#define XCHAL_KIO_DEFAULT_PADDR                0x90000000
+#endif
+#define XCHAL_KIO_SIZE                 0x10000000
+
+#if (!XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY) && defined(CONFIG_OF)
+#define XCHAL_KIO_PADDR                        xtensa_get_kio_paddr()
+#ifndef __ASSEMBLY__
+extern unsigned long xtensa_kio_paddr;
+
+static inline unsigned long xtensa_get_kio_paddr(void)
+{
+       return xtensa_kio_paddr;
+}
+#endif
+#else
+#define XCHAL_KIO_PADDR                        XCHAL_KIO_DEFAULT_PADDR
+#endif
+
+/* KERNEL_STACK definition */
+
 #ifndef CONFIG_KASAN
 #define KERNEL_STACK_SHIFT     13
 #else
index 09c56cb..f4771c2 100644 (file)
@@ -169,7 +169,18 @@ static inline unsigned long ___pa(unsigned long va)
        if (off >= XCHAL_KSEG_SIZE)
                off -= XCHAL_KSEG_SIZE;
 
+#ifndef CONFIG_XIP_KERNEL
        return off + PHYS_OFFSET;
+#else
+       if (off < XCHAL_KSEG_SIZE)
+               return off + PHYS_OFFSET;
+
+       off -= XCHAL_KSEG_SIZE;
+       if (off >= XCHAL_KIO_SIZE)
+               off -= XCHAL_KIO_SIZE;
+
+       return off + XCHAL_KIO_PADDR;
+#endif
 }
 #define __pa(x)        ___pa((unsigned long)(x))
 #else
index 3f7fe5a..27ac17c 100644 (file)
@@ -8,7 +8,6 @@
 #ifndef _XTENSA_PGTABLE_H
 #define _XTENSA_PGTABLE_H
 
-#define __ARCH_USE_5LEVEL_HACK
 #include <asm/page.h>
 #include <asm/kmem_layout.h>
 #include <asm-generic/pgtable-nopmd.h>
@@ -371,9 +370,6 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 
 #define pgd_index(address)     ((address) >> PGDIR_SHIFT)
 
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir,address) ((pmd_t*)(dir))
-
 /* Find an entry in the third-level page table.. */
 #define pte_index(address)     (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset_kernel(dir,addr)                                    \
index 7495520..6fa903d 100644 (file)
@@ -195,6 +195,7 @@ struct thread_struct {
 /* Clearing a0 terminates the backtrace. */
 #define start_thread(regs, new_pc, new_sp) \
        do { \
+               unsigned long syscall = (regs)->syscall; \
                memset((regs), 0, sizeof(*(regs))); \
                (regs)->pc = (new_pc); \
                (regs)->ps = USER_PS_VALUE; \
@@ -204,7 +205,7 @@ struct thread_struct {
                (regs)->depc = 0; \
                (regs)->windowbase = 0; \
                (regs)->windowstart = 1; \
-               (regs)->syscall = NO_SYSCALL; \
+               (regs)->syscall = syscall; \
        } while (0)
 
 /* Forward declaration */
index 359ab40..f9a671c 100644 (file)
@@ -51,7 +51,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
                                            struct pt_regs *regs,
                                            int error, long val)
 {
-       regs->areg[0] = (long) error ? error : val;
+       regs->areg[2] = (long) error ? error : val;
 }
 
 #define SYSCALL_MAX_ARGS 6
@@ -79,7 +79,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
                regs->areg[reg[i]] = args[i];
 }
 
-asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
+asmlinkage long xtensa_rt_sigreturn(void);
 asmlinkage long xtensa_shmat(int, char __user *, int);
 asmlinkage long xtensa_fadvise64_64(int, int,
                                    unsigned long long, unsigned long long);
index 3f80386..47b7702 100644 (file)
@@ -132,13 +132,13 @@ do {                                                                      \
 #define __check_align_1  ""
 
 #define __check_align_2                                \
-       "   _bbci.l %[addr], 0, 1f      \n"     \
+       "   _bbci.l %[mem] * 0, 1f      \n"     \
        "   movi    %[err], %[efault]   \n"     \
        "   _j      2f                  \n"
 
 #define __check_align_4                                \
-       "   _bbsi.l %[addr], 0, 0f      \n"     \
-       "   _bbci.l %[addr], 1, 1f      \n"     \
+       "   _bbsi.l %[mem] * 0, 0f      \n"     \
+       "   _bbci.l %[mem] * 0 + 1, 1f  \n"     \
        "0: movi    %[err], %[efault]   \n"     \
        "   _j      2f                  \n"
 
@@ -154,7 +154,7 @@ do {                                                                        \
 #define __put_user_asm(x_, addr_, err_, align, insn, cb)\
 __asm__ __volatile__(                                  \
        __check_align_##align                           \
-       "1: "insn"  %[x], %[addr], 0    \n"             \
+       "1: "insn"  %[x], %[mem]        \n"             \
        "2:                             \n"             \
        "   .section  .fixup,\"ax\"     \n"             \
        "   .align 4                    \n"             \
@@ -167,8 +167,8 @@ __asm__ __volatile__(                                       \
        "   .section  __ex_table,\"a\"  \n"             \
        "   .long       1b, 5b          \n"             \
        "   .previous"                                  \
-       :[err] "+r"(err_), [tmp] "=r"(cb)               \
-       :[x] "r"(x_), [addr] "r"(addr_), [efault] "i"(-EFAULT))
+       :[err] "+r"(err_), [tmp] "=r"(cb), [mem] "=m"(*(addr_))         \
+       :[x] "r"(x_), [efault] "i"(-EFAULT))
 
 #define __get_user_nocheck(x, ptr, size)                       \
 ({                                                             \
@@ -222,7 +222,7 @@ do {                                                        \
        u32 __x = 0;                                    \
        __asm__ __volatile__(                           \
                __check_align_##align                   \
-               "1: "insn"  %[x], %[addr], 0    \n"     \
+               "1: "insn"  %[x], %[mem]        \n"     \
                "2:                             \n"     \
                "   .section  .fixup,\"ax\"     \n"     \
                "   .align 4                    \n"     \
@@ -236,7 +236,7 @@ do {                                                        \
                "   .long       1b, 5b          \n"     \
                "   .previous"                          \
                :[err] "+r"(err_), [tmp] "=r"(cb), [x] "+r"(__x) \
-               :[addr] "r"(addr_), [efault] "i"(-EFAULT)); \
+               :[mem] "m"(*(addr_)), [efault] "i"(-EFAULT)); \
        (x_) = (__force __typeof__(*(addr_)))__x;       \
 } while (0)
 
diff --git a/arch/xtensa/include/asm/user.h b/arch/xtensa/include/asm/user.h
deleted file mode 100644 (file)
index 2c3ed23..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * include/asm-xtensa/user.h
- *
- * Xtensa Processor version.
- *
- * 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_USER_H
-#define _XTENSA_USER_H
-
-/* This file usually defines a 'struct user' structure. However, it it only
- * used for a.out file, which are not supported on Xtensa.
- */
-
-#endif /* _XTENSA_USER_H */
index 79fe300..fd99b25 100644 (file)
 #include <asm/core.h>
 #include <asm/kmem_layout.h>
 
-#if XCHAL_HAVE_PTP_MMU
-#define XCHAL_KIO_CACHED_VADDR         0xe0000000
-#define XCHAL_KIO_BYPASS_VADDR         0xf0000000
-#define XCHAL_KIO_DEFAULT_PADDR                0xf0000000
+#if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
+#ifdef CONFIG_KERNEL_VIRTUAL_ADDRESS
+#define KERNELOFFSET                   CONFIG_KERNEL_VIRTUAL_ADDRESS
 #else
-#define XCHAL_KIO_BYPASS_VADDR         XCHAL_KIO_PADDR
-#define XCHAL_KIO_DEFAULT_PADDR                0x90000000
-#endif
-#define XCHAL_KIO_SIZE                 0x10000000
-
-#if (!XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY) && defined(CONFIG_OF)
-#define XCHAL_KIO_PADDR                        xtensa_get_kio_paddr()
-#ifndef __ASSEMBLY__
-extern unsigned long xtensa_kio_paddr;
-
-static inline unsigned long xtensa_get_kio_paddr(void)
-{
-       return xtensa_kio_paddr;
-}
-#endif
-#else
-#define XCHAL_KIO_PADDR                        XCHAL_KIO_DEFAULT_PADDR
-#endif
-
-#if defined(CONFIG_MMU)
-
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
-/* Image Virtual Start Address */
-#define KERNELOFFSET                   (XCHAL_KSEG_CACHED_VADDR + \
-                                        CONFIG_KERNEL_LOAD_ADDRESS - \
+#define KERNELOFFSET                   (CONFIG_KERNEL_LOAD_ADDRESS + \
+                                        XCHAL_KSEG_CACHED_VADDR - \
                                         XCHAL_KSEG_PADDR)
+#endif
 #else
 #define KERNELOFFSET                   CONFIG_KERNEL_LOAD_ADDRESS
 #endif
 
-#else /* !defined(CONFIG_MMU) */
-  /* MMU Not being used - Virtual == Physical */
-
-/* Location of the start of the kernel text, _start */
-#define KERNELOFFSET                   CONFIG_KERNEL_LOAD_ADDRESS
-
-
-#endif /* CONFIG_MMU */
-
 #define RESET_VECTOR1_VADDR            (XCHAL_RESET_VECTOR1_VADDR)
 #ifdef CONFIG_VECTORS_OFFSET
 #define VECBASE_VADDR                  (KERNELOFFSET - CONFIG_VECTORS_OFFSET)
index a57afa0..3bd0642 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _XTENSA_IPCBUF_H
 #define _XTENSA_IPCBUF_H
 
+#include <linux/posix_types.h>
+
 /*
  * Pad space is left for:
  * - 32-bit mode_t and seq
index d6915e9..1ed2c85 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _XTENSA_MSGBUF_H
 #define _XTENSA_MSGBUF_H
 
+#include <asm/ipcbuf.h>
+
 struct msqid64_ds {
        struct ipc64_perm msg_perm;
 #ifdef __XTENSA_EB__
index 09f348d..3b9cdd4 100644 (file)
@@ -22,6 +22,7 @@
 #define _XTENSA_SEMBUF_H
 
 #include <asm/byteorder.h>
+#include <asm/ipcbuf.h>
 
 struct semid64_ds {
        struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
index 80828b9..bb8e499 100644 (file)
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/asmmacro.h>
-#include <asm/processor.h>
 #include <asm/coprocessor.h>
-#include <asm/thread_info.h>
-#include <asm/asm-uaccess.h>
-#include <asm/unistd.h>
-#include <asm/ptrace.h>
 #include <asm/current.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/signal.h>
-#include <asm/tlbflush.h>
+#include <asm/regs.h>
 
 #if XTENSA_HAVE_COPROCESSORS
 
index 9e36768..be89780 100644 (file)
@@ -529,7 +529,7 @@ common_exception_return:
        l32i    a4, a2, TI_PRE_COUNT
        bnez    a4, 4f
        call4   preempt_schedule_irq
-       j       1b
+       j       4f
 #endif
 
 #if XTENSA_FAKE_NMI
@@ -1876,8 +1876,7 @@ ENDPROC(fast_store_prohibited)
 
 ENTRY(system_call)
 
-       /* reserve 4 bytes on stack for function parameter */
-       abi_entry(4)
+       abi_entry_default
 
        /* regs->syscall = regs->areg[2] */
 
@@ -1892,11 +1891,10 @@ ENTRY(system_call)
 
        mov     a6, a2
        call4   do_syscall_trace_enter
+       beqz    a6, .Lsyscall_exit
        l32i    a7, a2, PT_SYSCALL
 
 1:
-       s32i    a7, a1, 4
-
        /* syscall = sys_call_table[syscall_nr] */
 
        movi    a4, sys_call_table
@@ -1906,8 +1904,6 @@ ENTRY(system_call)
 
        addx4   a4, a7, a4
        l32i    a4, a4, 0
-       movi    a5, sys_ni_syscall;
-       beq     a4, a5, 1f
 
        /* Load args: arg0 - arg5 are passed via regs. */
 
@@ -1918,25 +1914,19 @@ ENTRY(system_call)
        l32i    a10, a2, PT_AREG8
        l32i    a11, a2, PT_AREG9
 
-       /* Pass one additional argument to the syscall: pt_regs (on stack) */
-       s32i    a2, a1, 0
-
        callx4  a4
 
 1:     /* regs->areg[2] = return_value */
 
        s32i    a6, a2, PT_AREG2
        bnez    a3, 1f
-       abi_ret(4)
+.Lsyscall_exit:
+       abi_ret_default
 
 1:
-       l32i    a4, a1, 4
-       l32i    a3, a2, PT_SYSCALL
-       s32i    a4, a2, PT_SYSCALL
        mov     a6, a2
        call4   do_syscall_trace_leave
-       s32i    a3, a2, PT_SYSCALL
-       abi_ret(4)
+       abi_ret_default
 
 ENDPROC(system_call)
 
index 4ae998b..e0c1fac 100644 (file)
@@ -260,6 +260,13 @@ ENTRY(_startup)
        ___invalidate_icache_all a2 a3
        isync
 
+#ifdef CONFIG_XIP_KERNEL
+       /* Setup bootstrap CPU stack in XIP kernel */
+
+       movi    a1, start_info
+       l32i    a1, a1, 0
+#endif
+
        movi    a6, 0
        xsr     a6, excsave1
 
@@ -355,10 +362,10 @@ ENDPROC(cpu_restart)
  * DATA section
  */
 
-        .section ".data.init.refok"
-        .align  4
+       __REFDATA
+       .align  4
 ENTRY(start_info)
-        .long   init_thread_union + KERNEL_STACK_SIZE
+       .long   init_thread_union + KERNEL_STACK_SIZE
 
 /*
  * BSS section
index db278a9..9e1c491 100644 (file)
@@ -264,6 +264,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
                               &regs->areg[XCHAL_NUM_AREGS - len/4], len);
                }
 
+               childregs->syscall = regs->syscall;
+
                /* The thread pointer is passed in the '4th argument' (= a5) */
                if (clone_flags & CLONE_SETTLS)
                        childregs->threadptr = childregs->areg[5];
index b964f0b..145742d 100644 (file)
@@ -542,14 +542,28 @@ long arch_ptrace(struct task_struct *child, long request,
        return ret;
 }
 
-void do_syscall_trace_enter(struct pt_regs *regs)
+void do_syscall_trace_leave(struct pt_regs *regs);
+int do_syscall_trace_enter(struct pt_regs *regs)
 {
+       if (regs->syscall == NO_SYSCALL)
+               regs->areg[2] = -ENOSYS;
+
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-           tracehook_report_syscall_entry(regs))
+           tracehook_report_syscall_entry(regs)) {
+               regs->areg[2] = -ENOSYS;
                regs->syscall = NO_SYSCALL;
+               return 0;
+       }
+
+       if (regs->syscall == NO_SYSCALL) {
+               do_syscall_trace_leave(regs);
+               return 0;
+       }
 
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, syscall_get_nr(current, regs));
+
+       return 1;
 }
 
 void do_syscall_trace_leave(struct pt_regs *regs)
index e0e1e18..0f93b67 100644 (file)
@@ -308,6 +308,10 @@ extern char _Level6InterruptVector_text_end;
 extern char _SecondaryResetVector_text_start;
 extern char _SecondaryResetVector_text_end;
 #endif
+#ifdef CONFIG_XIP_KERNEL
+extern char _xip_start[];
+extern char _xip_end[];
+#endif
 
 static inline int __init_memblock mem_reserve(unsigned long start,
                                              unsigned long end)
@@ -339,6 +343,9 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        mem_reserve(__pa(_stext), __pa(_end));
+#ifdef CONFIG_XIP_KERNEL
+       mem_reserve(__pa(_xip_start), __pa(_xip_end));
+#endif
 
 #ifdef CONFIG_VECTORS_OFFSET
        mem_reserve(__pa(&_WindowVectors_text_start),
index dae83cd..76cee34 100644 (file)
@@ -236,9 +236,9 @@ restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame)
  * Do a signal return; undo the signal stack.
  */
 
-asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3,
-                                   long a4, long a5, struct pt_regs *regs)
+asmlinkage long xtensa_rt_sigreturn(void)
 {
+       struct pt_regs *regs = current_pt_regs();
        struct rt_sigframe __user *frame;
        sigset_t set;
        int ret;
index 4a6c495..87bd68d 100644 (file)
@@ -491,32 +491,27 @@ void show_trace(struct task_struct *task, unsigned long *sp)
 
        pr_info("Call Trace:\n");
        walk_stackframe(sp, show_trace_cb, NULL);
-#ifndef CONFIG_KALLSYMS
-       pr_cont("\n");
-#endif
 }
 
-static int kstack_depth_to_print = 24;
+#define STACK_DUMP_ENTRY_SIZE 4
+#define STACK_DUMP_LINE_SIZE 32
+static size_t kstack_depth_to_print = CONFIG_PRINT_STACK_DEPTH;
 
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
-       int i = 0;
-       unsigned long *stack;
+       size_t len;
 
        if (!sp)
                sp = stack_pointer(task);
-       stack = sp;
 
-       pr_info("Stack:\n");
+       len = min((-(size_t)sp) & (THREAD_SIZE - STACK_DUMP_ENTRY_SIZE),
+                 kstack_depth_to_print * STACK_DUMP_ENTRY_SIZE);
 
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (kstack_end(sp))
-                       break;
-               pr_cont(" %08lx", *sp++);
-               if (i % 8 == 7)
-                       pr_cont("\n");
-       }
-       show_trace(task, stack);
+       pr_info("Stack:\n");
+       print_hex_dump(KERN_INFO, " ", DUMP_PREFIX_NONE,
+                      STACK_DUMP_LINE_SIZE, STACK_DUMP_ENTRY_SIZE,
+                      sp, len, false);
+       show_trace(task, sp);
 }
 
 DEFINE_SPINLOCK(die_lock);
index 0043d58..409c05c 100644 (file)
@@ -119,7 +119,7 @@ SECTIONS
     SCHED_TEXT
     CPUIDLE_TEXT
     LOCK_TEXT
-
+    *(.fixup)
   }
   _etext = .;
   PROVIDE (etext = .);
@@ -128,12 +128,11 @@ SECTIONS
 
   RO_DATA(4096)
 
-  /*  Relocation table */
-
-  .fixup   : { *(.fixup) }
-
   /* Data section */
 
+#ifdef CONFIG_XIP_KERNEL
+  INIT_TEXT_SECTION(PAGE_SIZE)
+#else
   _sdata = .;
   RW_DATA(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE)
   _edata = .;
@@ -147,6 +146,11 @@ SECTIONS
   .init.data :
   {
     INIT_DATA
+  }
+#endif
+
+  .init.rodata :
+  {
     . = ALIGN(0x4);
     __tagtable_begin = .;
     *(.taglist)
@@ -187,12 +191,16 @@ SECTIONS
     RELOCATE_ENTRY(_DebugInterruptVector_text,
                   .DebugInterruptVector.text);
 #endif
+#ifdef CONFIG_XIP_KERNEL
+    RELOCATE_ENTRY(_xip_data, .data);
+    RELOCATE_ENTRY(_xip_init_data, .init.data);
+#else
 #if defined(CONFIG_SMP)
     RELOCATE_ENTRY(_SecondaryResetVector_text,
                   .SecondaryResetVector.text);
+#endif
 #endif
 
-  
     __boot_reloc_table_end = ABSOLUTE(.) ;
 
     INIT_SETUP(XCHAL_ICACHE_LINESIZE)
@@ -278,7 +286,7 @@ SECTIONS
   . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
 
 #endif
-#if defined(CONFIG_SMP)
+#if !defined(CONFIG_XIP_KERNEL) && defined(CONFIG_SMP)
 
   SECTION_VECTOR (_SecondaryResetVector_text,
                  .SecondaryResetVector.text,
@@ -291,12 +299,48 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
 
+#ifndef CONFIG_XIP_KERNEL
   __init_end = .;
 
   BSS_SECTION(0, 8192, 0)
+#endif
 
   _end = .;
 
+#ifdef CONFIG_XIP_KERNEL
+  . = CONFIG_XIP_DATA_ADDR;
+
+  _xip_start = .;
+
+#undef LOAD_OFFSET
+#define LOAD_OFFSET \
+  (CONFIG_XIP_DATA_ADDR - (LOADADDR(.dummy) + SIZEOF(.dummy) + 3) & ~ 3)
+
+  _xip_data_start = .;
+  _sdata = .;
+  RW_DATA(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE)
+  _edata = .;
+  _xip_data_end = .;
+
+  /* Initialization data: */
+
+  STRUCT_ALIGN();
+
+  _xip_init_data_start = .;
+  __init_begin = .;
+  .init.data :
+  {
+    INIT_DATA
+  }
+  _xip_init_data_end = .;
+  __init_end = .;
+  BSS_SECTION(0, 8192, 0)
+
+  _xip_end = .;
+
+#undef LOAD_OFFSET
+#endif
+
   DWARF_DEBUG
 
   .xt.prop 0 : { KEEP(*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) }
index f81b147..bee30a7 100644 (file)
@@ -197,6 +197,8 @@ vmalloc_fault:
                struct mm_struct *act_mm = current->active_mm;
                int index = pgd_index(address);
                pgd_t *pgd, *pgd_k;
+               p4d_t *p4d, *p4d_k;
+               pud_t *pud, *pud_k;
                pmd_t *pmd, *pmd_k;
                pte_t *pte_k;
 
@@ -211,8 +213,18 @@ vmalloc_fault:
 
                pgd_val(*pgd) = pgd_val(*pgd_k);
 
-               pmd = pmd_offset(pgd, address);
-               pmd_k = pmd_offset(pgd_k, address);
+               p4d = p4d_offset(pgd, address);
+               p4d_k = p4d_offset(pgd_k, address);
+               if (!p4d_present(*p4d) || !p4d_present(*p4d_k))
+                       goto bad_page_fault;
+
+               pud = pud_offset(p4d, address);
+               pud_k = pud_offset(p4d_k, address);
+               if (!pud_present(*pud) || !pud_present(*pud_k))
+                       goto bad_page_fault;
+
+               pmd = pmd_offset(pud, address);
+               pmd_k = pmd_offset(pud_k, address);
                if (!pmd_present(*pmd) || !pmd_present(*pmd_k))
                        goto bad_page_fault;
 
index d898ed6..19c625e 100644 (file)
@@ -193,8 +193,8 @@ void __init mem_init(void)
                ((max_low_pfn - min_low_pfn) * PAGE_SIZE) >> 20,
                (unsigned long)_text, (unsigned long)_etext,
                (unsigned long)(_etext - _text) >> 10,
-               (unsigned long)__start_rodata, (unsigned long)_sdata,
-               (unsigned long)(_sdata - __start_rodata) >> 10,
+               (unsigned long)__start_rodata, (unsigned long)__end_rodata,
+               (unsigned long)(__end_rodata - __start_rodata) >> 10,
                (unsigned long)_sdata, (unsigned long)_edata,
                (unsigned long)(_edata - _sdata) >> 10,
                (unsigned long)__init_begin, (unsigned long)__init_end,
index af71525..e3baa21 100644 (file)
@@ -20,7 +20,9 @@ void __init kasan_early_init(void)
 {
        unsigned long vaddr = KASAN_SHADOW_START;
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = pmd_offset(pgd, vaddr);
+       p4d_t *p4d = p4d_offset(pgd, vaddr);
+       pud_t *pud = pud_offset(p4d, vaddr);
+       pmd_t *pmd = pmd_offset(pud, vaddr);
        int i;
 
        for (i = 0; i < PTRS_PER_PTE; ++i)
@@ -42,7 +44,9 @@ static void __init populate(void *start, void *end)
        unsigned long i, j;
        unsigned long vaddr = (unsigned long)start;
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = pmd_offset(pgd, vaddr);
+       p4d_t *p4d = p4d_offset(pgd, vaddr);
+       pud_t *pud = pud_offset(p4d, vaddr);
+       pmd_t *pmd = pmd_offset(pud, vaddr);
        pte_t *pte = memblock_alloc(n_pages * sizeof(pte_t), PAGE_SIZE);
 
        if (!pte)
@@ -56,7 +60,9 @@ static void __init populate(void *start, void *end)
 
                for (k = 0; k < PTRS_PER_PTE; ++k, ++j) {
                        phys_addr_t phys =
-                               memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
+                               memblock_phys_alloc_range(PAGE_SIZE, PAGE_SIZE,
+                                                         0,
+                                                         MEMBLOCK_ALLOC_ANYWHERE);
 
                        if (!phys)
                                panic("Failed to allocate page table page\n");
index 03678c4..37e478a 100644 (file)
@@ -22,7 +22,9 @@
 static void * __init init_pmd(unsigned long vaddr, unsigned long n_pages)
 {
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = pmd_offset(pgd, vaddr);
+       p4d_t *p4d = p4d_offset(pgd, vaddr);
+       pud_t *pud = pud_offset(p4d, vaddr);
+       pmd_t *pmd = pmd_offset(pud, vaddr);
        pte_t *pte;
        unsigned long i;
 
index 59153d0..f436cf2 100644 (file)
@@ -169,6 +169,8 @@ static unsigned get_pte_for_vaddr(unsigned vaddr)
        struct task_struct *task = get_current();
        struct mm_struct *mm = task->mm;
        pgd_t *pgd;
+       p4d_t *p4d;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
 
@@ -177,7 +179,13 @@ static unsigned get_pte_for_vaddr(unsigned vaddr)
        pgd = pgd_offset(mm, vaddr);
        if (pgd_none_or_clear_bad(pgd))
                return 0;
-       pmd = pmd_offset(pgd, vaddr);
+       p4d = p4d_offset(pgd, vaddr);
+       if (p4d_none_or_clear_bad(p4d))
+               return 0;
+       pud = pud_offset(p4d, vaddr);
+       if (pud_none_or_clear_bad(pud))
+               return 0;
+       pmd = pmd_offset(pud, vaddr);
        if (pmd_none_or_clear_bad(pmd))
                return 0;
        pte = pte_offset_map(pmd, vaddr);
@@ -216,6 +224,8 @@ static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
        unsigned tlbidx = w | (e << PAGE_SHIFT);
        unsigned r0 = dtlb ?
                read_dtlb_virtual(tlbidx) : read_itlb_virtual(tlbidx);
+       unsigned r1 = dtlb ?
+               read_dtlb_translation(tlbidx) : read_itlb_translation(tlbidx);
        unsigned vpn = (r0 & PAGE_MASK) | (e << PAGE_SHIFT);
        unsigned pte = get_pte_for_vaddr(vpn);
        unsigned mm_asid = (get_rasid_register() >> 8) & ASID_MASK;
@@ -231,8 +241,6 @@ static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
        }
 
        if (tlb_asid == mm_asid) {
-               unsigned r1 = dtlb ? read_dtlb_translation(tlbidx) :
-                       read_itlb_translation(tlbidx);
                if ((pte ^ r1) & PAGE_MASK) {
                        pr_err("%cTLB: way: %u, entry: %u, mapping: %08x->%08x, PTE: %08x\n",
                                        dtlb ? 'D' : 'I', w, e, r0, r1, pte);
index 4fb9751..002838d 100644 (file)
@@ -104,9 +104,9 @@ config ACPI_PROCFS_POWER
        depends on X86 && PROC_FS
        help
          For backwards compatibility, this option allows
-          deprecated power /proc/acpi/ directories to exist, even when
-          they have been replaced by functions in /sys.
-          The deprecated directories (and their replacements) include:
+         deprecated power /proc/acpi/ directories to exist, even when
+         they have been replaced by functions in /sys.
+         The deprecated directories (and their replacements) include:
          /proc/acpi/battery/* (/sys/class/power_supply/*) and
          /proc/acpi/ac_adapter/* (sys/class/power_supply/*).
          This option has no effect on /proc/acpi/ directories
@@ -448,7 +448,7 @@ config ACPI_CUSTOM_METHOD
 config ACPI_BGRT
        bool "Boottime Graphics Resource Table support"
        depends on EFI && (X86 || ARM64)
-        help
+       help
          This driver adds support for exposing the ACPI Boottime Graphics
          Resource Table, which allows the operating system to obtain
          data from the firmware boot splash. It will appear under
index 48bc96d..5400267 100644 (file)
@@ -153,7 +153,7 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
 {
        acpi_status status;
 
-       if (!*data)
+       if (!data)
                return -EINVAL;
 
        status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
index d27b01c..b758b45 100644 (file)
@@ -77,6 +77,19 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids);
 
 /* Please keep this list sorted alphabetically by vendor and model */
 static const struct dmi_system_id dmi_lid_quirks[] = {
+       {
+               /*
+                * Acer Switch 10 SW5-012. _LID method messes with home and
+                * power button GPIO IRQ settings causing an interrupt storm on
+                * both GPIOs. This is unfixable without a DSDT override, so we
+                * have to disable the lid-switch functionality altogether :|
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+               },
+               .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
+       },
        {
                /*
                 * Asus T200TA, _LID keeps reporting closed after every second
index 4fd84fb..d05be13 100644 (file)
@@ -533,26 +533,10 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static bool acpi_ec_query_flushed(struct acpi_ec *ec)
+static void __acpi_ec_flush_work(void)
 {
-       bool flushed;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
-       flushed = !ec->nr_pending_queries;
-       spin_unlock_irqrestore(&ec->lock, flags);
-       return flushed;
-}
-
-static void __acpi_ec_flush_event(struct acpi_ec *ec)
-{
-       /*
-        * When ec_freeze_events is true, we need to flush events in
-        * the proper position before entering the noirq stage.
-        */
-       wait_event(ec->wait, acpi_ec_query_flushed(ec));
-       if (ec_query_wq)
-               flush_workqueue(ec_query_wq);
+       flush_scheduled_work(); /* flush ec->work */
+       flush_workqueue(ec_query_wq); /* flush queries */
 }
 
 static void acpi_ec_disable_event(struct acpi_ec *ec)
@@ -562,15 +546,21 @@ static void acpi_ec_disable_event(struct acpi_ec *ec)
        spin_lock_irqsave(&ec->lock, flags);
        __acpi_ec_disable_event(ec);
        spin_unlock_irqrestore(&ec->lock, flags);
-       __acpi_ec_flush_event(ec);
+
+       /*
+        * When ec_freeze_events is true, we need to flush events in
+        * the proper position before entering the noirq stage.
+        */
+       __acpi_ec_flush_work();
 }
 
 void acpi_ec_flush_work(void)
 {
-       if (first_ec)
-               __acpi_ec_flush_event(first_ec);
+       /* Without ec_query_wq there is nothing to flush. */
+       if (!ec_query_wq)
+               return;
 
-       flush_scheduled_work();
+       __acpi_ec_flush_work();
 }
 #endif /* CONFIG_PM_SLEEP */
 
index a2e844a..41168c0 100644 (file)
@@ -374,19 +374,21 @@ void *__ref acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
-static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
+/* Must be called with mutex_lock(&acpi_ioremap_lock) */
+static unsigned long acpi_os_drop_map_ref(struct acpi_ioremap *map)
 {
-       if (!--map->refcount)
+       unsigned long refcount = --map->refcount;
+
+       if (!refcount)
                list_del_rcu(&map->list);
+       return refcount;
 }
 
 static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
-       if (!map->refcount) {
-               synchronize_rcu_expedited();
-               acpi_unmap(map->phys, map->virt);
-               kfree(map);
-       }
+       synchronize_rcu_expedited();
+       acpi_unmap(map->phys, map->virt);
+       kfree(map);
 }
 
 /**
@@ -406,6 +408,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
 {
        struct acpi_ioremap *map;
+       unsigned long refcount;
 
        if (!acpi_permanent_mmap) {
                __acpi_unmap_table(virt, size);
@@ -419,10 +422,11 @@ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
                WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
                return;
        }
-       acpi_os_drop_map_ref(map);
+       refcount = acpi_os_drop_map_ref(map);
        mutex_unlock(&acpi_ioremap_lock);
 
-       acpi_os_map_cleanup(map);
+       if (!refcount)
+               acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
 
@@ -457,6 +461,7 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)
 {
        u64 addr;
        struct acpi_ioremap *map;
+       unsigned long refcount;
 
        if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
                return;
@@ -472,10 +477,11 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)
                mutex_unlock(&acpi_ioremap_lock);
                return;
        }
-       acpi_os_drop_map_ref(map);
+       refcount = acpi_os_drop_map_ref(map);
        mutex_unlock(&acpi_ioremap_lock);
 
-       acpi_os_map_cleanup(map);
+       if (!refcount)
+               acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL(acpi_os_unmap_generic_address);
 
index 2af937a..6747a27 100644 (file)
@@ -977,6 +977,16 @@ static int acpi_s2idle_prepare_late(void)
        return 0;
 }
 
+static void acpi_s2idle_sync(void)
+{
+       /*
+        * The EC driver uses the system workqueue and an additional special
+        * one, so those need to be flushed too.
+        */
+       acpi_ec_flush_work();
+       acpi_os_wait_events_complete(); /* synchronize Notify handling */
+}
+
 static void acpi_s2idle_wake(void)
 {
        /*
@@ -1001,13 +1011,8 @@ static void acpi_s2idle_wake(void)
                 * should be missed by canceling the wakeup here.
                 */
                pm_system_cancel_wakeup();
-               /*
-                * The EC driver uses the system workqueue and an additional
-                * special one, so those need to be flushed too.
-                */
-               acpi_os_wait_events_complete(); /* synchronize EC GPE processing */
-               acpi_ec_flush_work();
-               acpi_os_wait_events_complete(); /* synchronize Notify handling */
+
+               acpi_s2idle_sync();
 
                rearm_wake_irq(acpi_sci_irq);
        }
@@ -1024,6 +1029,13 @@ static void acpi_s2idle_restore_early(void)
 
 static void acpi_s2idle_restore(void)
 {
+       /*
+        * Drain pending events before restoring the working-state configuration
+        * of GPEs.
+        */
+       acpi_os_wait_events_complete(); /* synchronize GPE processing */
+       acpi_s2idle_sync();
+
        s2idle_wakeup = false;
 
        acpi_enable_all_runtime_gpes();
index 75948a3..c60d2c6 100644 (file)
@@ -819,14 +819,14 @@ end:
  * interface:
  *   echo unmask > /sys/firmware/acpi/interrupts/gpe00
  */
-#define ACPI_MASKABLE_GPE_MAX  0xFF
+#define ACPI_MASKABLE_GPE_MAX  0x100
 static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
 
 static int __init acpi_gpe_set_masked_gpes(char *val)
 {
        u8 gpe;
 
-       if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX)
+       if (kstrtou8(val, 0, &gpe))
                return -EINVAL;
        set_bit(gpe, acpi_masked_gpes_map);
 
@@ -838,7 +838,7 @@ void __init acpi_gpe_apply_masked_gpes(void)
 {
        acpi_handle handle;
        acpi_status status;
-       u8 gpe;
+       u16 gpe;
 
        for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) {
                status = acpi_get_gpe_device(gpe, &handle);
index ebecab8..135173c 100644 (file)
@@ -219,7 +219,6 @@ struct arasan_cf_dev {
 
 static struct scsi_host_template arasan_cf_sht = {
        ATA_BASE_SHT(DRIVER_NAME),
-       .sg_tablesize = SG_NONE,
        .dma_boundary = 0xFFFFFFFFUL,
 };
 
index cfd0cf2..e01a3a6 100644 (file)
@@ -422,7 +422,7 @@ static int atp867x_ata_pci_sff_init_host(struct ata_host *host)
 #ifdef ATP867X_DEBUG
        atp867x_check_res(pdev);
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+       for (i = 0; i < PCI_STD_NUM_BARS; i++)
                printk(KERN_DEBUG "ATP867X: iomap[%d]=0x%llx\n", i,
                        (unsigned long long)(host->iomap[i]));
 #endif
index 65ec8df..f3e62f5 100644 (file)
@@ -2329,7 +2329,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
         // Make sure this is a SATA controller by counting the number of bars
         // (NVIDIA SATA controllers will always have six bars).  Otherwise,
         // it's an IDE controller and we ignore it.
-       for (bar = 0; bar < 6; bar++)
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                if (pci_resource_start(pdev, bar) == 0)
                        return -ENODEV;
 
index bef6b85..874c259 100644 (file)
@@ -287,31 +287,6 @@ static int charlcd_init_display(struct charlcd *lcd)
        return 0;
 }
 
-/*
- * Parses an unsigned integer from a string, until a non-digit character
- * is found. The empty string is not accepted. No overflow checks are done.
- *
- * Returns whether the parsing was successful. Only in that case
- * the output parameters are written to.
- *
- * TODO: If the kernel adds an inplace version of kstrtoul(), this function
- * could be easily replaced by that.
- */
-static bool parse_n(const char *s, unsigned long *res, const char **next_s)
-{
-       if (!isdigit(*s))
-               return false;
-
-       *res = 0;
-       while (isdigit(*s)) {
-               *res = *res * 10 + (*s - '0');
-               ++s;
-       }
-
-       *next_s = s;
-       return true;
-}
-
 /*
  * Parses a movement command of the form "(.*);", where the group can be
  * any number of subcommands of the form "(x|y)[0-9]+".
@@ -336,6 +311,7 @@ static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
 {
        unsigned long new_x = *x;
        unsigned long new_y = *y;
+       char *p;
 
        for (;;) {
                if (!*s)
@@ -345,11 +321,15 @@ static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
                        break;
 
                if (*s == 'x') {
-                       if (!parse_n(s + 1, &new_x, &s))
+                       new_x = simple_strtoul(s + 1, &p, 10);
+                       if (p == s + 1)
                                return false;
+                       s = p;
                } else if (*s == 'y') {
-                       if (!parse_n(s + 1, &new_y, &s))
+                       new_y = simple_strtoul(s + 1, &p, 10);
+                       if (p == s + 1)
                                return false;
+                       s = p;
                } else {
                        return false;
                }
index 28b92e3..c3b3b5c 100644 (file)
@@ -148,6 +148,10 @@ config DEBUG_TEST_DRIVER_REMOVE
          unusable. You should say N here unless you are explicitly looking to
          test this functionality.
 
+config PM_QOS_KUNIT_TEST
+       bool "KUnit Test for PM QoS features"
+       depends on KUNIT
+
 config HMEM_REPORTING
        bool
        default n
index 84c4e1f..799b431 100644 (file)
 #include <linux/memory.h>
 #include <linux/memory_hotplug.h>
 #include <linux/mm.h>
-#include <linux/mutex.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
 
 #include <linux/atomic.h>
 #include <linux/uaccess.h>
 
-static DEFINE_MUTEX(mem_sysfs_mutex);
-
 #define MEMORY_CLASS_NAME      "memory"
 
 #define to_memory_block(dev) container_of(dev, struct memory_block, dev)
@@ -538,12 +535,7 @@ static ssize_t soft_offline_page_store(struct device *dev,
        if (kstrtoull(buf, 0, &pfn) < 0)
                return -EINVAL;
        pfn >>= PAGE_SHIFT;
-       if (!pfn_valid(pfn))
-               return -ENXIO;
-       /* Only online pages can be soft-offlined (esp., not ZONE_DEVICE). */
-       if (!pfn_to_online_page(pfn))
-               return -EIO;
-       ret = soft_offline_page(pfn_to_page(pfn), 0);
+       ret = soft_offline_page(pfn, 0);
        return ret == 0 ? count : ret;
 }
 
@@ -705,6 +697,8 @@ static void unregister_memory(struct memory_block *memory)
  * Create memory block devices for the given memory area. Start and size
  * have to be aligned to memory block granularity. Memory block devices
  * will be initialized as offline.
+ *
+ * Called under device_hotplug_lock.
  */
 int create_memory_block_devices(unsigned long start, unsigned long size)
 {
@@ -718,7 +712,6 @@ int create_memory_block_devices(unsigned long start, unsigned long size)
                         !IS_ALIGNED(size, memory_block_size_bytes())))
                return -EINVAL;
 
-       mutex_lock(&mem_sysfs_mutex);
        for (block_id = start_block_id; block_id != end_block_id; block_id++) {
                ret = init_memory_block(&mem, block_id, MEM_OFFLINE);
                if (ret)
@@ -730,11 +723,12 @@ int create_memory_block_devices(unsigned long start, unsigned long size)
                for (block_id = start_block_id; block_id != end_block_id;
                     block_id++) {
                        mem = find_memory_block_by_id(block_id);
+                       if (WARN_ON_ONCE(!mem))
+                               continue;
                        mem->section_count = 0;
                        unregister_memory(mem);
                }
        }
-       mutex_unlock(&mem_sysfs_mutex);
        return ret;
 }
 
@@ -742,6 +736,8 @@ int create_memory_block_devices(unsigned long start, unsigned long size)
  * Remove memory block devices for the given memory area. Start and size
  * have to be aligned to memory block granularity. Memory block devices
  * have to be offline.
+ *
+ * Called under device_hotplug_lock.
  */
 void remove_memory_block_devices(unsigned long start, unsigned long size)
 {
@@ -754,7 +750,6 @@ void remove_memory_block_devices(unsigned long start, unsigned long size)
                         !IS_ALIGNED(size, memory_block_size_bytes())))
                return;
 
-       mutex_lock(&mem_sysfs_mutex);
        for (block_id = start_block_id; block_id != end_block_id; block_id++) {
                mem = find_memory_block_by_id(block_id);
                if (WARN_ON_ONCE(!mem))
@@ -763,7 +758,6 @@ void remove_memory_block_devices(unsigned long start, unsigned long size)
                unregister_memory_block_under_nodes(mem);
                unregister_memory(mem);
        }
-       mutex_unlock(&mem_sysfs_mutex);
 }
 
 /* return true if the memory block is offlined, otherwise, return false */
@@ -797,12 +791,13 @@ static const struct attribute_group *memory_root_attr_groups[] = {
 };
 
 /*
- * Initialize the sysfs support for memory devices...
+ * Initialize the sysfs support for memory devices. At the time this function
+ * is called, we cannot have concurrent creation/deletion of memory block
+ * devices, the device_hotplug_lock is not needed.
  */
 void __init memory_dev_init(void)
 {
        int ret;
-       int err;
        unsigned long block_sz, nr;
 
        /* Validate the configured memory block size */
@@ -813,24 +808,19 @@ void __init memory_dev_init(void)
 
        ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
        if (ret)
-               goto out;
+               panic("%s() failed to register subsystem: %d\n", __func__, ret);
 
        /*
         * Create entries for memory sections that were found
         * during boot and have been initialized
         */
-       mutex_lock(&mem_sysfs_mutex);
        for (nr = 0; nr <= __highest_present_section_nr;
             nr += sections_per_block) {
-               err = add_memory_block(nr);
-               if (!ret)
-                       ret = err;
+               ret = add_memory_block(nr);
+               if (ret)
+                       panic("%s() failed to add memory block: %d\n", __func__,
+                             ret);
        }
-       mutex_unlock(&mem_sysfs_mutex);
-
-out:
-       if (ret)
-               panic("%s() failed: %d\n", __func__, ret);
 }
 
 /**
index 296546f..98a31ba 100644 (file)
@@ -496,20 +496,17 @@ static ssize_t node_read_vmstat(struct device *dev,
        int n = 0;
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
+               n += sprintf(buf+n, "%s %lu\n", zone_stat_name(i),
                             sum_zone_node_page_state(nid, i));
 
 #ifdef CONFIG_NUMA
        for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
-               n += sprintf(buf+n, "%s %lu\n",
-                            vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
+               n += sprintf(buf+n, "%s %lu\n", numa_stat_name(i),
                             sum_zone_numa_state(nid, i));
 #endif
 
        for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
-               n += sprintf(buf+n, "%s %lu\n",
-                            vmstat_text[i + NR_VM_ZONE_STAT_ITEMS +
-                            NR_VM_NUMA_STAT_ITEMS],
+               n += sprintf(buf+n, "%s %lu\n", node_stat_name(i),
                             node_page_state(pgdat, i));
 
        return n;
index ec5bb19..8fdd007 100644 (file)
@@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP)  += main.o wakeup.o wakeup_stats.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS)       +=  domain.o domain_governor.o
 obj-$(CONFIG_HAVE_CLK) += clock_ops.o
+obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/qos-test.c b/drivers/base/power/qos-test.c
new file mode 100644 (file)
index 0000000..3115db0
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+#include <kunit/test.h>
+#include <linux/pm_qos.h>
+
+/* Basic test for aggregating two "min" requests */
+static void freq_qos_test_min(struct kunit *test)
+{
+       struct freq_constraints qos;
+       struct freq_qos_request req1, req2;
+       int ret;
+
+       freq_constraints_init(&qos);
+       memset(&req1, 0, sizeof(req1));
+       memset(&req2, 0, sizeof(req2));
+
+       ret = freq_qos_add_request(&qos, &req1, FREQ_QOS_MIN, 1000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       ret = freq_qos_add_request(&qos, &req2, FREQ_QOS_MIN, 2000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 2000);
+
+       ret = freq_qos_remove_request(&req2);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 1000);
+
+       ret = freq_qos_remove_request(&req1);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
+                       FREQ_QOS_MIN_DEFAULT_VALUE);
+}
+
+/* Test that requests for MAX_DEFAULT_VALUE have no effect */
+static void freq_qos_test_maxdef(struct kunit *test)
+{
+       struct freq_constraints qos;
+       struct freq_qos_request req1, req2;
+       int ret;
+
+       freq_constraints_init(&qos);
+       memset(&req1, 0, sizeof(req1));
+       memset(&req2, 0, sizeof(req2));
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX),
+                       FREQ_QOS_MAX_DEFAULT_VALUE);
+
+       ret = freq_qos_add_request(&qos, &req1, FREQ_QOS_MAX,
+                       FREQ_QOS_MAX_DEFAULT_VALUE);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+       ret = freq_qos_add_request(&qos, &req2, FREQ_QOS_MAX,
+                       FREQ_QOS_MAX_DEFAULT_VALUE);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+
+       /* Add max 1000 */
+       ret = freq_qos_update_request(&req1, 1000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 1000);
+
+       /* Add max 2000, no impact */
+       ret = freq_qos_update_request(&req2, 2000);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 1000);
+
+       /* Remove max 1000, new max 2000 */
+       ret = freq_qos_remove_request(&req1);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 2000);
+}
+
+/*
+ * Test that a freq_qos_request can be added again after removal
+ *
+ * This issue was solved by commit 05ff1ba412fd ("PM: QoS: Invalidate frequency
+ * QoS requests after removal")
+ */
+static void freq_qos_test_readd(struct kunit *test)
+{
+       struct freq_constraints qos;
+       struct freq_qos_request req;
+       int ret;
+
+       freq_constraints_init(&qos);
+       memset(&req, 0, sizeof(req));
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
+                       FREQ_QOS_MIN_DEFAULT_VALUE);
+
+       /* Add */
+       ret = freq_qos_add_request(&qos, &req, FREQ_QOS_MIN, 1000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 1000);
+
+       /* Remove */
+       ret = freq_qos_remove_request(&req);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
+                       FREQ_QOS_MIN_DEFAULT_VALUE);
+
+       /* Add again */
+       ret = freq_qos_add_request(&qos, &req, FREQ_QOS_MIN, 2000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 2000);
+}
+
+static struct kunit_case pm_qos_test_cases[] = {
+       KUNIT_CASE(freq_qos_test_min),
+       KUNIT_CASE(freq_qos_test_maxdef),
+       KUNIT_CASE(freq_qos_test_readd),
+       {},
+};
+
+static struct kunit_suite pm_qos_test_module = {
+       .name = "qos-kunit-test",
+       .test_cases = pm_qos_test_cases,
+};
+kunit_test_suite(pm_qos_test_module);
index 350dcaf..8e93167 100644 (file)
@@ -115,10 +115,20 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
 
        spin_lock_irqsave(&dev->power.lock, flags);
 
-       if (type == DEV_PM_QOS_RESUME_LATENCY) {
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
                ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
                        : pm_qos_read_value(&qos->resume_latency);
-       } else {
+               break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
+                       : freq_qos_read_value(&qos->freq, FREQ_QOS_MIN);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
+                       : freq_qos_read_value(&qos->freq, FREQ_QOS_MAX);
+               break;
+       default:
                WARN_ON(1);
                ret = 0;
        }
@@ -159,6 +169,10 @@ static int apply_constraint(struct dev_pm_qos_request *req,
                        req->dev->power.set_latency_tolerance(req->dev, value);
                }
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_apply(&req->data.freq, action, value);
+               break;
        case DEV_PM_QOS_FLAGS:
                ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
                                          action, value);
@@ -209,6 +223,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
        c->type = PM_QOS_MIN;
 
+       freq_constraints_init(&qos->freq);
+
        INIT_LIST_HEAD(&qos->flags.list);
 
        spin_lock_irq(&dev->power.lock);
@@ -269,6 +285,20 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
                memset(req, 0, sizeof(*req));
        }
 
+       c = &qos->freq.min_freq;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
+       c = &qos->freq.max_freq;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
        f = &qos->flags;
        list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -314,11 +344,22 @@ static int __dev_pm_qos_add_request(struct device *dev,
                ret = dev_pm_qos_constraints_allocate(dev);
 
        trace_dev_pm_qos_add_request(dev_name(dev), type, value);
-       if (!ret) {
-               req->dev = dev;
-               req->type = type;
+       if (ret)
+               return ret;
+
+       req->dev = dev;
+       req->type = type;
+       if (req->type == DEV_PM_QOS_MIN_FREQUENCY)
+               ret = freq_qos_add_request(&dev->power.qos->freq,
+                                          &req->data.freq,
+                                          FREQ_QOS_MIN, value);
+       else if (req->type == DEV_PM_QOS_MAX_FREQUENCY)
+               ret = freq_qos_add_request(&dev->power.qos->freq,
+                                          &req->data.freq,
+                                          FREQ_QOS_MAX, value);
+       else
                ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
-       }
+
        return ret;
 }
 
@@ -382,6 +423,10 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
        case DEV_PM_QOS_LATENCY_TOLERANCE:
                curr_value = req->data.pnode.prio;
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               curr_value = req->data.freq.pnode.prio;
+               break;
        case DEV_PM_QOS_FLAGS:
                curr_value = req->data.flr.flags;
                break;
@@ -507,6 +552,14 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
                ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
                                                       notifier);
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = freq_qos_add_notifier(&dev->power.qos->freq,
+                                           FREQ_QOS_MIN, notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_add_notifier(&dev->power.qos->freq,
+                                           FREQ_QOS_MAX, notifier);
+               break;
        default:
                WARN_ON(1);
                ret = -EINVAL;
@@ -546,6 +599,14 @@ int dev_pm_qos_remove_notifier(struct device *dev,
                ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
                                                         notifier);
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = freq_qos_remove_notifier(&dev->power.qos->freq,
+                                              FREQ_QOS_MIN, notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_remove_notifier(&dev->power.qos->freq,
+                                              FREQ_QOS_MAX, notifier);
+               break;
        default:
                WARN_ON(1);
                ret = -EINVAL;
index 5817b51..70a9edb 100644 (file)
@@ -247,6 +247,60 @@ void wakeup_source_unregister(struct wakeup_source *ws)
 }
 EXPORT_SYMBOL_GPL(wakeup_source_unregister);
 
+/**
+ * wakeup_sources_read_lock - Lock wakeup source list for read.
+ *
+ * Returns an index of srcu lock for struct wakeup_srcu.
+ * This index must be passed to the matching wakeup_sources_read_unlock().
+ */
+int wakeup_sources_read_lock(void)
+{
+       return srcu_read_lock(&wakeup_srcu);
+}
+EXPORT_SYMBOL_GPL(wakeup_sources_read_lock);
+
+/**
+ * wakeup_sources_read_unlock - Unlock wakeup source list.
+ * @idx: return value from corresponding wakeup_sources_read_lock()
+ */
+void wakeup_sources_read_unlock(int idx)
+{
+       srcu_read_unlock(&wakeup_srcu, idx);
+}
+EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock);
+
+/**
+ * wakeup_sources_walk_start - Begin a walk on wakeup source list
+ *
+ * Returns first object of the list of wakeup sources.
+ *
+ * Note that to be safe, wakeup sources list needs to be locked by calling
+ * wakeup_source_read_lock() for this.
+ */
+struct wakeup_source *wakeup_sources_walk_start(void)
+{
+       struct list_head *ws_head = &wakeup_sources;
+
+       return list_entry_rcu(ws_head->next, struct wakeup_source, entry);
+}
+EXPORT_SYMBOL_GPL(wakeup_sources_walk_start);
+
+/**
+ * wakeup_sources_walk_next - Get next wakeup source from the list
+ * @ws: Previous wakeup source object
+ *
+ * Note that to be safe, wakeup sources list needs to be locked by calling
+ * wakeup_source_read_lock() for this.
+ */
+struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws)
+{
+       struct list_head *ws_head = &wakeup_sources;
+
+       return list_next_or_null_rcu(ws_head, &ws->entry,
+                               struct wakeup_source, entry);
+}
+EXPORT_SYMBOL_GPL(wakeup_sources_walk_next);
+
 /**
  * device_wakeup_attach - Attach a wakeup source object to a device object.
  * @dev: Device to handle.
index 13527a0..2b18456 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/ceph/cls_lock_client.h>
 #include <linux/ceph/striper.h>
 #include <linux/ceph/decode.h>
-#include <linux/parser.h>
+#include <linux/fs_parser.h>
 #include <linux/bsearch.h>
 
 #include <linux/kernel.h>
@@ -377,7 +377,6 @@ struct rbd_client_id {
 
 struct rbd_mapping {
        u64                     size;
-       u64                     features;
 };
 
 /*
@@ -462,8 +461,9 @@ struct rbd_device {
  *   by rbd_dev->lock
  */
 enum rbd_dev_flags {
-       RBD_DEV_FLAG_EXISTS,    /* mapped snapshot has not been deleted */
+       RBD_DEV_FLAG_EXISTS,    /* rbd_dev_device_setup() ran */
        RBD_DEV_FLAG_REMOVING,  /* this mapping is being removed */
+       RBD_DEV_FLAG_READONLY,  /* -o ro or snapshot */
 };
 
 static DEFINE_MUTEX(client_mutex);     /* Serialize client creation */
@@ -514,6 +514,16 @@ static int minor_to_rbd_dev_id(int minor)
        return minor >> RBD_SINGLE_MAJOR_PART_SHIFT;
 }
 
+static bool rbd_is_ro(struct rbd_device *rbd_dev)
+{
+       return test_bit(RBD_DEV_FLAG_READONLY, &rbd_dev->flags);
+}
+
+static bool rbd_is_snap(struct rbd_device *rbd_dev)
+{
+       return rbd_dev->spec->snap_id != CEPH_NOSNAP;
+}
+
 static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev)
 {
        lockdep_assert_held(&rbd_dev->lock_rwsem);
@@ -633,8 +643,6 @@ static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
                                        u64 snap_id);
 static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
                                u8 *order, u64 *snap_size);
-static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
-               u64 *snap_features);
 static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev);
 
 static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result);
@@ -695,9 +703,16 @@ static int rbd_ioctl_set_ro(struct rbd_device *rbd_dev, unsigned long arg)
        if (get_user(ro, (int __user *)arg))
                return -EFAULT;
 
-       /* Snapshots can't be marked read-write */
-       if (rbd_dev->spec->snap_id != CEPH_NOSNAP && !ro)
-               return -EROFS;
+       /*
+        * Both images mapped read-only and snapshots can't be marked
+        * read-write.
+        */
+       if (!ro) {
+               if (rbd_is_ro(rbd_dev))
+                       return -EROFS;
+
+               rbd_assert(!rbd_is_snap(rbd_dev));
+       }
 
        /* Let blkdev_roset() handle it */
        return -ENOTTY;
@@ -823,34 +838,34 @@ enum {
        Opt_queue_depth,
        Opt_alloc_size,
        Opt_lock_timeout,
-       Opt_last_int,
        /* int args above */
        Opt_pool_ns,
-       Opt_last_string,
        /* string args above */
        Opt_read_only,
        Opt_read_write,
        Opt_lock_on_read,
        Opt_exclusive,
        Opt_notrim,
-       Opt_err
 };
 
-static match_table_t rbd_opts_tokens = {
-       {Opt_queue_depth, "queue_depth=%d"},
-       {Opt_alloc_size, "alloc_size=%d"},
-       {Opt_lock_timeout, "lock_timeout=%d"},
-       /* int args above */
-       {Opt_pool_ns, "_pool_ns=%s"},
-       /* string args above */
-       {Opt_read_only, "read_only"},
-       {Opt_read_only, "ro"},          /* Alternate spelling */
-       {Opt_read_write, "read_write"},
-       {Opt_read_write, "rw"},         /* Alternate spelling */
-       {Opt_lock_on_read, "lock_on_read"},
-       {Opt_exclusive, "exclusive"},
-       {Opt_notrim, "notrim"},
-       {Opt_err, NULL}
+static const struct fs_parameter_spec rbd_param_specs[] = {
+       fsparam_u32     ("alloc_size",                  Opt_alloc_size),
+       fsparam_flag    ("exclusive",                   Opt_exclusive),
+       fsparam_flag    ("lock_on_read",                Opt_lock_on_read),
+       fsparam_u32     ("lock_timeout",                Opt_lock_timeout),
+       fsparam_flag    ("notrim",                      Opt_notrim),
+       fsparam_string  ("_pool_ns",                    Opt_pool_ns),
+       fsparam_u32     ("queue_depth",                 Opt_queue_depth),
+       fsparam_flag    ("read_only",                   Opt_read_only),
+       fsparam_flag    ("read_write",                  Opt_read_write),
+       fsparam_flag    ("ro",                          Opt_read_only),
+       fsparam_flag    ("rw",                          Opt_read_write),
+       {}
+};
+
+static const struct fs_parameter_description rbd_parameters = {
+       .name           = "rbd",
+       .specs          = rbd_param_specs,
 };
 
 struct rbd_options {
@@ -871,87 +886,12 @@ struct rbd_options {
 #define RBD_EXCLUSIVE_DEFAULT  false
 #define RBD_TRIM_DEFAULT       true
 
-struct parse_rbd_opts_ctx {
+struct rbd_parse_opts_ctx {
        struct rbd_spec         *spec;
+       struct ceph_options     *copts;
        struct rbd_options      *opts;
 };
 
-static int parse_rbd_opts_token(char *c, void *private)
-{
-       struct parse_rbd_opts_ctx *pctx = private;
-       substring_t argstr[MAX_OPT_ARGS];
-       int token, intval, ret;
-
-       token = match_token(c, rbd_opts_tokens, argstr);
-       if (token < Opt_last_int) {
-               ret = match_int(&argstr[0], &intval);
-               if (ret < 0) {
-                       pr_err("bad option arg (not int) at '%s'\n", c);
-                       return ret;
-               }
-               dout("got int token %d val %d\n", token, intval);
-       } else if (token > Opt_last_int && token < Opt_last_string) {
-               dout("got string token %d val %s\n", token, argstr[0].from);
-       } else {
-               dout("got token %d\n", token);
-       }
-
-       switch (token) {
-       case Opt_queue_depth:
-               if (intval < 1) {
-                       pr_err("queue_depth out of range\n");
-                       return -EINVAL;
-               }
-               pctx->opts->queue_depth = intval;
-               break;
-       case Opt_alloc_size:
-               if (intval < SECTOR_SIZE) {
-                       pr_err("alloc_size out of range\n");
-                       return -EINVAL;
-               }
-               if (!is_power_of_2(intval)) {
-                       pr_err("alloc_size must be a power of 2\n");
-                       return -EINVAL;
-               }
-               pctx->opts->alloc_size = intval;
-               break;
-       case Opt_lock_timeout:
-               /* 0 is "wait forever" (i.e. infinite timeout) */
-               if (intval < 0 || intval > INT_MAX / 1000) {
-                       pr_err("lock_timeout out of range\n");
-                       return -EINVAL;
-               }
-               pctx->opts->lock_timeout = msecs_to_jiffies(intval * 1000);
-               break;
-       case Opt_pool_ns:
-               kfree(pctx->spec->pool_ns);
-               pctx->spec->pool_ns = match_strdup(argstr);
-               if (!pctx->spec->pool_ns)
-                       return -ENOMEM;
-               break;
-       case Opt_read_only:
-               pctx->opts->read_only = true;
-               break;
-       case Opt_read_write:
-               pctx->opts->read_only = false;
-               break;
-       case Opt_lock_on_read:
-               pctx->opts->lock_on_read = true;
-               break;
-       case Opt_exclusive:
-               pctx->opts->exclusive = true;
-               break;
-       case Opt_notrim:
-               pctx->opts->trim = false;
-               break;
-       default:
-               /* libceph prints "bad option" msg */
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static char* obj_op_name(enum obj_operation_type op_type)
 {
        switch (op_type) {
@@ -1302,51 +1242,23 @@ static int rbd_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
        return 0;
 }
 
-static int rbd_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
-                       u64 *snap_features)
-{
-       rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
-       if (snap_id == CEPH_NOSNAP) {
-               *snap_features = rbd_dev->header.features;
-       } else if (rbd_dev->image_format == 1) {
-               *snap_features = 0;     /* No features for format 1 */
-       } else {
-               u64 features = 0;
-               int ret;
-
-               ret = _rbd_dev_v2_snap_features(rbd_dev, snap_id, &features);
-               if (ret)
-                       return ret;
-
-               *snap_features = features;
-       }
-       return 0;
-}
-
 static int rbd_dev_mapping_set(struct rbd_device *rbd_dev)
 {
        u64 snap_id = rbd_dev->spec->snap_id;
        u64 size = 0;
-       u64 features = 0;
        int ret;
 
        ret = rbd_snap_size(rbd_dev, snap_id, &size);
-       if (ret)
-               return ret;
-       ret = rbd_snap_features(rbd_dev, snap_id, &features);
        if (ret)
                return ret;
 
        rbd_dev->mapping.size = size;
-       rbd_dev->mapping.features = features;
-
        return 0;
 }
 
 static void rbd_dev_mapping_clear(struct rbd_device *rbd_dev)
 {
        rbd_dev->mapping.size = 0;
-       rbd_dev->mapping.features = 0;
 }
 
 static void zero_bvec(struct bio_vec *bv)
@@ -1832,6 +1744,17 @@ static u8 rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
 
 static bool use_object_map(struct rbd_device *rbd_dev)
 {
+       /*
+        * An image mapped read-only can't use the object map -- it isn't
+        * loaded because the header lock isn't acquired.  Someone else can
+        * write to the image and update the object map behind our back.
+        *
+        * A snapshot can't be written to, so using the object map is always
+        * safe.
+        */
+       if (!rbd_is_snap(rbd_dev) && rbd_is_ro(rbd_dev))
+               return false;
+
        return ((rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) &&
                !(rbd_dev->object_map_flags & RBD_FLAG_OBJECT_MAP_INVALID));
 }
@@ -3555,7 +3478,7 @@ static bool need_exclusive_lock(struct rbd_img_request *img_req)
        if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK))
                return false;
 
-       if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+       if (rbd_is_ro(rbd_dev))
                return false;
 
        rbd_assert(!test_bit(IMG_REQ_CHILD, &img_req->flags));
@@ -4230,7 +4153,7 @@ again:
                 * lock owner acked, but resend if we don't see them
                 * release the lock
                 */
-               dout("%s rbd_dev %p requeueing lock_dwork\n", __func__,
+               dout("%s rbd_dev %p requeuing lock_dwork\n", __func__,
                     rbd_dev);
                mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork,
                    msecs_to_jiffies(2 * RBD_NOTIFY_TIMEOUT * MSEC_PER_SEC));
@@ -4826,24 +4749,14 @@ static void rbd_queue_workfn(struct work_struct *work)
                goto err_rq;
        }
 
-       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
-        * still possible the snapshot will have disappeared by the
-        * time our request arrives at the osd, but there's no sense in
-        * sending it if we already know.
-        */
-       if (!test_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags)) {
-               dout("request for non-existent snapshot");
-               rbd_assert(rbd_dev->spec->snap_id != CEPH_NOSNAP);
-               result = -ENXIO;
-               goto err_rq;
+       if (op_type != OBJ_OP_READ) {
+               if (rbd_is_ro(rbd_dev)) {
+                       rbd_warn(rbd_dev, "%s on read-only mapping",
+                                obj_op_name(op_type));
+                       result = -EIO;
+                       goto err;
+               }
+               rbd_assert(!rbd_is_snap(rbd_dev));
        }
 
        if (offset && length > U64_MAX - offset + 1) {
@@ -5025,25 +4938,6 @@ out:
        return ret;
 }
 
-/*
- * Clear the rbd device's EXISTS flag if the snapshot it's mapped to
- * has disappeared from the (just updated) snapshot context.
- */
-static void rbd_exists_validate(struct rbd_device *rbd_dev)
-{
-       u64 snap_id;
-
-       if (!test_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags))
-               return;
-
-       snap_id = rbd_dev->spec->snap_id;
-       if (snap_id == CEPH_NOSNAP)
-               return;
-
-       if (rbd_dev_snap_index(rbd_dev, snap_id) == BAD_SNAP_INDEX)
-               clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
-}
-
 static void rbd_dev_update_size(struct rbd_device *rbd_dev)
 {
        sector_t size;
@@ -5084,12 +4978,8 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
                        goto out;
        }
 
-       if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
-               rbd_dev->mapping.size = rbd_dev->header.image_size;
-       } else {
-               /* validate mapped snapshot's EXISTS flag */
-               rbd_exists_validate(rbd_dev);
-       }
+       rbd_assert(!rbd_is_snap(rbd_dev));
+       rbd_dev->mapping.size = rbd_dev->header.image_size;
 
 out:
        up_write(&rbd_dev->header_rwsem);
@@ -5211,17 +5101,12 @@ static ssize_t rbd_size_show(struct device *dev,
                (unsigned long long)rbd_dev->mapping.size);
 }
 
-/*
- * Note this shows the features for whatever's mapped, which is not
- * necessarily the base image.
- */
 static ssize_t rbd_features_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "0x%016llx\n",
-                       (unsigned long long)rbd_dev->mapping.features);
+       return sprintf(buf, "0x%016llx\n", rbd_dev->header.features);
 }
 
 static ssize_t rbd_major_show(struct device *dev,
@@ -5709,9 +5594,12 @@ out:
 }
 
 static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
-               u64 *snap_features)
+                                    bool read_only, u64 *snap_features)
 {
-       __le64 snapid = cpu_to_le64(snap_id);
+       struct {
+               __le64 snap_id;
+               u8 read_only;
+       } features_in;
        struct {
                __le64 features;
                __le64 incompat;
@@ -5719,9 +5607,12 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
        u64 unsup;
        int ret;
 
+       features_in.snap_id = cpu_to_le64(snap_id);
+       features_in.read_only = read_only;
+
        ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
                                  &rbd_dev->header_oloc, "get_features",
-                                 &snapid, sizeof(snapid),
+                                 &features_in, sizeof(features_in),
                                  &features_buf, sizeof(features_buf));
        dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
        if (ret < 0)
@@ -5749,7 +5640,8 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
 static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
 {
        return _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
-                                               &rbd_dev->header.features);
+                                        rbd_is_ro(rbd_dev),
+                                        &rbd_dev->header.features);
 }
 
 /*
@@ -6456,6 +6348,122 @@ static inline char *dup_token(const char **buf, size_t *lenp)
        return dup;
 }
 
+static int rbd_parse_param(struct fs_parameter *param,
+                           struct rbd_parse_opts_ctx *pctx)
+{
+       struct rbd_options *opt = pctx->opts;
+       struct fs_parse_result result;
+       int token, ret;
+
+       ret = ceph_parse_param(param, pctx->copts, NULL);
+       if (ret != -ENOPARAM)
+               return ret;
+
+       token = fs_parse(NULL, &rbd_parameters, param, &result);
+       dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
+       if (token < 0) {
+               if (token == -ENOPARAM) {
+                       return invalf(NULL, "rbd: Unknown parameter '%s'",
+                                     param->key);
+               }
+               return token;
+       }
+
+       switch (token) {
+       case Opt_queue_depth:
+               if (result.uint_32 < 1)
+                       goto out_of_range;
+               opt->queue_depth = result.uint_32;
+               break;
+       case Opt_alloc_size:
+               if (result.uint_32 < SECTOR_SIZE)
+                       goto out_of_range;
+               if (!is_power_of_2(result.uint_32)) {
+                       return invalf(NULL, "rbd: alloc_size must be a power of 2");
+               }
+               opt->alloc_size = result.uint_32;
+               break;
+       case Opt_lock_timeout:
+               /* 0 is "wait forever" (i.e. infinite timeout) */
+               if (result.uint_32 > INT_MAX / 1000)
+                       goto out_of_range;
+               opt->lock_timeout = msecs_to_jiffies(result.uint_32 * 1000);
+               break;
+       case Opt_pool_ns:
+               kfree(pctx->spec->pool_ns);
+               pctx->spec->pool_ns = param->string;
+               param->string = NULL;
+               break;
+       case Opt_read_only:
+               opt->read_only = true;
+               break;
+       case Opt_read_write:
+               opt->read_only = false;
+               break;
+       case Opt_lock_on_read:
+               opt->lock_on_read = true;
+               break;
+       case Opt_exclusive:
+               opt->exclusive = true;
+               break;
+       case Opt_notrim:
+               opt->trim = false;
+               break;
+       default:
+               BUG();
+       }
+
+       return 0;
+
+out_of_range:
+       return invalf(NULL, "rbd: %s out of range", param->key);
+}
+
+/*
+ * This duplicates most of generic_parse_monolithic(), untying it from
+ * fs_context and skipping standard superblock and security options.
+ */
+static int rbd_parse_options(char *options, struct rbd_parse_opts_ctx *pctx)
+{
+       char *key;
+       int ret = 0;
+
+       dout("%s '%s'\n", __func__, options);
+       while ((key = strsep(&options, ",")) != NULL) {
+               if (*key) {
+                       struct fs_parameter param = {
+                               .key    = key,
+                               .type   = fs_value_is_string,
+                       };
+                       char *value = strchr(key, '=');
+                       size_t v_len = 0;
+
+                       if (value) {
+                               if (value == key)
+                                       continue;
+                               *value++ = 0;
+                               v_len = strlen(value);
+                       }
+
+
+                       if (v_len > 0) {
+                               param.string = kmemdup_nul(value, v_len,
+                                                          GFP_KERNEL);
+                               if (!param.string)
+                                       return -ENOMEM;
+                       }
+                       param.size = v_len;
+
+                       ret = rbd_parse_param(&param, pctx);
+                       kfree(param.string);
+                       if (ret)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
 /*
  * Parse the options provided for an "rbd add" (i.e., rbd image
  * mapping) request.  These arrive via a write to /sys/bus/rbd/add,
@@ -6507,8 +6515,7 @@ static int rbd_add_parse_args(const char *buf,
        const char *mon_addrs;
        char *snap_name;
        size_t mon_addrs_size;
-       struct parse_rbd_opts_ctx pctx = { 0 };
-       struct ceph_options *copts;
+       struct rbd_parse_opts_ctx pctx = { 0 };
        int ret;
 
        /* The first four tokens are required */
@@ -6519,7 +6526,7 @@ static int rbd_add_parse_args(const char *buf,
                return -EINVAL;
        }
        mon_addrs = buf;
-       mon_addrs_size = len + 1;
+       mon_addrs_size = len;
        buf += len;
 
        ret = -EINVAL;
@@ -6569,6 +6576,10 @@ static int rbd_add_parse_args(const char *buf,
        *(snap_name + len) = '\0';
        pctx.spec->snap_name = snap_name;
 
+       pctx.copts = ceph_alloc_options();
+       if (!pctx.copts)
+               goto out_mem;
+
        /* Initialize all rbd options to the defaults */
 
        pctx.opts = kzalloc(sizeof(*pctx.opts), GFP_KERNEL);
@@ -6583,27 +6594,27 @@ static int rbd_add_parse_args(const char *buf,
        pctx.opts->exclusive = RBD_EXCLUSIVE_DEFAULT;
        pctx.opts->trim = RBD_TRIM_DEFAULT;
 
-       copts = ceph_parse_options(options, mon_addrs,
-                                  mon_addrs + mon_addrs_size - 1,
-                                  parse_rbd_opts_token, &pctx);
-       if (IS_ERR(copts)) {
-               ret = PTR_ERR(copts);
+       ret = ceph_parse_mon_ips(mon_addrs, mon_addrs_size, pctx.copts, NULL);
+       if (ret)
+               goto out_err;
+
+       ret = rbd_parse_options(options, &pctx);
+       if (ret)
                goto out_err;
-       }
-       kfree(options);
 
-       *ceph_opts = copts;
+       *ceph_opts = pctx.copts;
        *opts = pctx.opts;
        *rbd_spec = pctx.spec;
-
+       kfree(options);
        return 0;
+
 out_mem:
        ret = -ENOMEM;
 out_err:
        kfree(pctx.opts);
+       ceph_destroy_options(pctx.copts);
        rbd_spec_put(pctx.spec);
        kfree(options);
-
        return ret;
 }
 
@@ -6632,7 +6643,7 @@ static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
                return -EINVAL;
        }
 
-       if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+       if (rbd_is_ro(rbd_dev))
                return 0;
 
        rbd_assert(!rbd_is_lock_owner(rbd_dev));
@@ -6838,6 +6849,8 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
        __rbd_get_client(rbd_dev->rbd_client);
        rbd_spec_get(rbd_dev->parent_spec);
 
+       __set_bit(RBD_DEV_FLAG_READONLY, &parent->flags);
+
        ret = rbd_dev_image_probe(parent, depth);
        if (ret < 0)
                goto out_err;
@@ -6889,7 +6902,7 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
                goto err_out_blkdev;
 
        set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
-       set_disk_ro(rbd_dev->disk, rbd_dev->opts->read_only);
+       set_disk_ro(rbd_dev->disk, rbd_is_ro(rbd_dev));
 
        ret = dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id);
        if (ret)
@@ -6927,6 +6940,24 @@ static int rbd_dev_header_name(struct rbd_device *rbd_dev)
        return ret;
 }
 
+static void rbd_print_dne(struct rbd_device *rbd_dev, bool is_snap)
+{
+       if (!is_snap) {
+               pr_info("image %s/%s%s%s does not exist\n",
+                       rbd_dev->spec->pool_name,
+                       rbd_dev->spec->pool_ns ?: "",
+                       rbd_dev->spec->pool_ns ? "/" : "",
+                       rbd_dev->spec->image_name);
+       } else {
+               pr_info("snap %s/%s%s%s@%s does not exist\n",
+                       rbd_dev->spec->pool_name,
+                       rbd_dev->spec->pool_ns ?: "",
+                       rbd_dev->spec->pool_ns ? "/" : "",
+                       rbd_dev->spec->image_name,
+                       rbd_dev->spec->snap_name);
+       }
+}
+
 static void rbd_dev_image_release(struct rbd_device *rbd_dev)
 {
        rbd_dev_unprobe(rbd_dev);
@@ -6945,6 +6976,7 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
  */
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
 {
+       bool need_watch = !rbd_is_ro(rbd_dev);
        int ret;
 
        /*
@@ -6961,22 +6993,21 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        if (ret)
                goto err_out_format;
 
-       if (!depth) {
+       if (need_watch) {
                ret = rbd_register_watch(rbd_dev);
                if (ret) {
                        if (ret == -ENOENT)
-                               pr_info("image %s/%s%s%s does not exist\n",
-                                       rbd_dev->spec->pool_name,
-                                       rbd_dev->spec->pool_ns ?: "",
-                                       rbd_dev->spec->pool_ns ? "/" : "",
-                                       rbd_dev->spec->image_name);
+                               rbd_print_dne(rbd_dev, false);
                        goto err_out_format;
                }
        }
 
        ret = rbd_dev_header_info(rbd_dev);
-       if (ret)
+       if (ret) {
+               if (ret == -ENOENT && !need_watch)
+                       rbd_print_dne(rbd_dev, false);
                goto err_out_watch;
+       }
 
        /*
         * If this image is the one being mapped, we have pool name and
@@ -6990,12 +7021,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
                ret = rbd_spec_fill_names(rbd_dev);
        if (ret) {
                if (ret == -ENOENT)
-                       pr_info("snap %s/%s%s%s@%s does not exist\n",
-                               rbd_dev->spec->pool_name,
-                               rbd_dev->spec->pool_ns ?: "",
-                               rbd_dev->spec->pool_ns ? "/" : "",
-                               rbd_dev->spec->image_name,
-                               rbd_dev->spec->snap_name);
+                       rbd_print_dne(rbd_dev, true);
                goto err_out_probe;
        }
 
@@ -7003,7 +7029,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        if (ret)
                goto err_out_probe;
 
-       if (rbd_dev->spec->snap_id != CEPH_NOSNAP &&
+       if (rbd_is_snap(rbd_dev) &&
            (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP)) {
                ret = rbd_object_map_load(rbd_dev);
                if (ret)
@@ -7027,7 +7053,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
 err_out_probe:
        rbd_dev_unprobe(rbd_dev);
 err_out_watch:
-       if (!depth)
+       if (need_watch)
                rbd_unregister_watch(rbd_dev);
 err_out_format:
        rbd_dev->image_format = 0;
@@ -7079,6 +7105,11 @@ static ssize_t do_rbd_add(struct bus_type *bus,
        spec = NULL;            /* rbd_dev now owns this */
        rbd_opts = NULL;        /* rbd_dev now owns this */
 
+       /* if we are mapping a snapshot it will be a read-only mapping */
+       if (rbd_dev->opts->read_only ||
+           strcmp(rbd_dev->spec->snap_name, RBD_SNAP_HEAD_NAME))
+               __set_bit(RBD_DEV_FLAG_READONLY, &rbd_dev->flags);
+
        rbd_dev->config_info = kstrdup(buf, GFP_KERNEL);
        if (!rbd_dev->config_info) {
                rc = -ENOMEM;
@@ -7092,10 +7123,6 @@ static ssize_t do_rbd_add(struct bus_type *bus,
                goto err_out_rbd_dev;
        }
 
-       /* If we are mapping a snapshot it must be marked read-only */
-       if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
-               rbd_dev->opts->read_only = true;
-
        if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
                rbd_warn(rbd_dev, "alloc_size adjusted to %u",
                         rbd_dev->layout.object_size);
index 97ab5ad..50200d1 100644 (file)
@@ -41,8 +41,9 @@ config MOXTET
 
 config HISILICON_LPC
        bool "Support for ISA I/O space on HiSilicon Hip06/7"
-       depends on ARM64 && (ARCH_HISI || COMPILE_TEST)
-       select INDIRECT_PIO
+       depends on (ARM64 && ARCH_HISI) || (COMPILE_TEST && !ALPHA && !HEXAGON && !PARISC && !C6X)
+       depends on HAS_IOMEM
+       select INDIRECT_PIO if ARM64
        help
          Driver to enable I/O access to devices attached to the Low Pin
          Count bus on the HiSilicon Hip06/7 SoC.
index 20c9571..8101df9 100644 (file)
@@ -74,7 +74,7 @@ struct hisi_lpc_dev {
 /* About 10us. This is specific for single IO operations, such as inb */
 #define LPC_PEROP_WAITCNT      100
 
-static int wait_lpc_idle(unsigned char *mbase, unsigned int waitcnt)
+static int wait_lpc_idle(void __iomem *mbase, unsigned int waitcnt)
 {
        u32 status;
 
@@ -209,7 +209,7 @@ static u32 hisi_lpc_comm_in(void *hostdata, unsigned long pio, size_t dwidth)
        struct hisi_lpc_dev *lpcdev = hostdata;
        struct lpc_cycle_para iopara;
        unsigned long addr;
-       u32 rd_data = 0;
+       __le32 rd_data = 0;
        int ret;
 
        if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH)
@@ -244,13 +244,12 @@ static void hisi_lpc_comm_out(void *hostdata, unsigned long pio,
        struct lpc_cycle_para iopara;
        const unsigned char *buf;
        unsigned long addr;
+       __le32 _val = cpu_to_le32(val);
 
        if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH)
                return;
 
-       val = cpu_to_le32(val);
-
-       buf = (const unsigned char *)&val;
+       buf = (const unsigned char *)&_val;
        addr = hisi_lpc_pio_to_addr(lpcdev, pio);
 
        iopara.opflags = FG_INCRADDR_LPC;
index 2b6670d..97b8549 100644 (file)
@@ -917,6 +917,9 @@ set_midle:
                return -EINVAL;
        }
 
+       if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
+               best_mode = SYSC_IDLE_NO;
+
        reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
        reg |= best_mode << regbits->midle_shift;
        sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
@@ -978,6 +981,9 @@ static int sysc_disable_module(struct device *dev)
                return ret;
        }
 
+       if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
+               best_mode = SYSC_IDLE_FORCE;
+
        reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
        reg |= best_mode << regbits->midle_shift;
        sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
@@ -1037,8 +1043,6 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
        struct ti_sysc_platform_data *pdata;
        int error;
 
-       reset_control_deassert(ddata->rsts);
-
        pdata = dev_get_platdata(ddata->dev);
        if (!pdata)
                return 0;
@@ -1051,6 +1055,8 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
                dev_err(dev, "%s: could not enable: %i\n",
                        __func__, error);
 
+       reset_control_deassert(ddata->rsts);
+
        return 0;
 }
 
@@ -1104,8 +1110,6 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
 
        sysc_clkdm_deny_idle(ddata);
 
-       reset_control_deassert(ddata->rsts);
-
        if (sysc_opt_clks_needed(ddata)) {
                error = sysc_enable_opt_clocks(ddata);
                if (error)
@@ -1116,6 +1120,8 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
        if (error)
                goto err_opt_clocks;
 
+       reset_control_deassert(ddata->rsts);
+
        if (ddata->legacy_mode) {
                error = sysc_runtime_resume_legacy(dev, ddata);
                if (error)
@@ -1251,6 +1257,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0),
        SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff,
                   SYSC_MODULE_QUIRK_SGX),
+       SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
+                  0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+       SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -1, 0x4ea2080d, 0xffffffff,
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
                   SYSC_MODULE_QUIRK_WDT),
        /* Watchdog on am3 and am4 */
@@ -1309,8 +1319,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
        SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
        SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
-       SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
-                  0xffffffff, 0),
        SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
 #endif
 };
@@ -1532,37 +1540,6 @@ static int sysc_legacy_init(struct sysc *ddata)
        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;
-       }
-
-       reset_control_deassert(ddata->rsts);
-
-       return 0;
-}
-
 /*
  * Note that the caller must ensure the interconnect target module is enabled
  * before calling reset. Otherwise reset will not complete.
@@ -1625,15 +1602,6 @@ static int sysc_reset(struct sysc *ddata)
 static int sysc_init_module(struct sysc *ddata)
 {
        int error = 0;
-       bool manage_clocks = true;
-
-       error = sysc_rstctrl_reset_deassert(ddata, false);
-       if (error)
-               return error;
-
-       if (ddata->cfg.quirks &
-           (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))
-               manage_clocks = false;
 
        error = sysc_clockdomain_init(ddata);
        if (error)
@@ -1654,7 +1622,7 @@ static int sysc_init_module(struct sysc *ddata)
                goto err_opt_clocks;
 
        if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
-               error = sysc_rstctrl_reset_deassert(ddata, true);
+               error = reset_control_deassert(ddata->rsts);
                if (error)
                        goto err_main_clocks;
        }
@@ -1666,28 +1634,32 @@ static int sysc_init_module(struct sysc *ddata)
        if (ddata->legacy_mode) {
                error = sysc_legacy_init(ddata);
                if (error)
-                       goto err_main_clocks;
+                       goto err_reset;
        }
 
        if (!ddata->legacy_mode) {
                error = sysc_enable_module(ddata->dev);
                if (error)
-                       goto err_main_clocks;
+                       goto err_reset;
        }
 
        error = sysc_reset(ddata);
        if (error)
                dev_err(ddata->dev, "Reset failed with %d\n", error);
 
-       if (!ddata->legacy_mode && manage_clocks)
+       if (error && !ddata->legacy_mode)
                sysc_disable_module(ddata->dev);
 
+err_reset:
+       if (error && !(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
+               reset_control_assert(ddata->rsts);
+
 err_main_clocks:
-       if (manage_clocks)
+       if (error)
                sysc_disable_main_clocks(ddata);
 err_opt_clocks:
        /* No re-enable of clockdomain autoidle to prevent module autoidle */
-       if (manage_clocks) {
+       if (error) {
                sysc_disable_opt_clocks(ddata);
                sysc_clkdm_allow_idle(ddata);
        }
@@ -2460,10 +2432,17 @@ static int sysc_probe(struct platform_device *pdev)
                goto unprepare;
        }
 
-       /* Balance reset counts */
-       if (ddata->rsts)
+       /* Balance use counts as PM runtime should have enabled these all */
+       if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
                reset_control_assert(ddata->rsts);
 
+       if (!(ddata->cfg.quirks &
+             (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))) {
+               sysc_disable_main_clocks(ddata);
+               sysc_disable_opt_clocks(ddata);
+               sysc_clkdm_allow_idle(ddata);
+       }
+
        sysc_show_registers(ddata);
 
        ddata->dev->type = &sysc_device_type;
index dc920da..45653a0 100644 (file)
@@ -299,6 +299,11 @@ config COMMON_CLK_STM32H7
        help
          Support for stm32h7 SoC family clocks
 
+config COMMON_CLK_MMP2
+       def_bool COMMON_CLK && (MACH_MMP2_DT || MACH_MMP3_DT)
+       help
+         Support for Marvell MMP2 and MMP3 SoC clocks
+
 config COMMON_CLK_BD718XX
        tristate "Clock driver for ROHM BD718x7 PMIC"
        depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528
index 7bc7ac6..acc141a 100644 (file)
@@ -8,7 +8,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
 obj-$(CONFIG_RESET_CONTROLLER) += reset.o
 
 obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
-obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o
+obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o
 
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
 obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
index 2dbbe47..7ed313a 100644 (file)
@@ -500,7 +500,7 @@ static int __init clk_rpmh_init(void)
 {
        return platform_driver_register(&clk_rpmh_driver);
 }
-subsys_initcall(clk_rpmh_init);
+core_initcall(clk_rpmh_init);
 
 static void __exit clk_rpmh_exit(void)
 {
index bd32212..9b0c4ce 100644 (file)
@@ -2855,7 +2855,7 @@ static int __init gcc_qcs404_init(void)
 {
        return platform_driver_register(&gcc_qcs404_driver);
 }
-subsys_initcall(gcc_qcs404_init);
+core_initcall(gcc_qcs404_init);
 
 static void __exit gcc_qcs404_exit(void)
 {
index d2142fe..f7b370f 100644 (file)
@@ -3628,7 +3628,7 @@ static int __init gcc_sdm845_init(void)
 {
        return platform_driver_register(&gcc_sdm845_driver);
 }
-subsys_initcall(gcc_sdm845_init);
+core_initcall(gcc_sdm845_init);
 
 static void __exit gcc_sdm845_exit(void)
 {
index f35a53c..5fdd76c 100644 (file)
@@ -528,6 +528,7 @@ config SH_TIMER_MTU2
 config RENESAS_OSTM
        bool "Renesas OSTM timer driver" if COMPILE_TEST
        select CLKSRC_MMIO
+       select TIMER_OF
        help
          Enables the support for the Renesas OSTM.
 
index 9f09a59..5b39d37 100644 (file)
@@ -194,6 +194,10 @@ static int __init asm9260_timer_init(struct device_node *np)
        }
 
        clk = of_clk_get(np, 0);
+       if (IS_ERR(clk)) {
+               pr_err("Failed to get clk!\n");
+               return PTR_ERR(clk);
+       }
 
        ret = clk_prepare_enable(clk);
        if (ret) {
index 37c39b9..3d06ba6 100644 (file)
@@ -6,14 +6,14 @@
  * Copyright (C) 2017 Chris Brandt
  */
 
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/sched_clock.h>
 #include <linux/slab.h>
 
+#include "timer-of.h"
+
 /*
  * The OSTM contains independent channels.
  * The first OSTM channel probed will be set up as a free running
  * driven clock event.
  */
 
-struct ostm_device {
-       void __iomem *base;
-       unsigned long ticks_per_jiffy;
-       struct clock_event_device ced;
-};
-
 static void __iomem *system_clock;     /* For sched_clock() */
 
 /* OSTM REGISTERS */
@@ -47,41 +41,32 @@ static void __iomem *system_clock;  /* For sched_clock() */
 #define        CTL_ONESHOT             0x02
 #define        CTL_FREERUN             0x02
 
-static struct ostm_device *ced_to_ostm(struct clock_event_device *ced)
-{
-       return container_of(ced, struct ostm_device, ced);
-}
-
-static void ostm_timer_stop(struct ostm_device *ostm)
+static void ostm_timer_stop(struct timer_of *to)
 {
-       if (readb(ostm->base + OSTM_TE) & TE) {
-               writeb(TT, ostm->base + OSTM_TT);
+       if (readb(timer_of_base(to) + OSTM_TE) & TE) {
+               writeb(TT, timer_of_base(to) + OSTM_TT);
 
                /*
                 * Read back the register simply to confirm the write operation
                 * has completed since I/O writes can sometimes get queued by
                 * the bus architecture.
                 */
-               while (readb(ostm->base + OSTM_TE) & TE)
+               while (readb(timer_of_base(to) + OSTM_TE) & TE)
                        ;
        }
 }
 
-static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate)
+static int __init ostm_init_clksrc(struct timer_of *to)
 {
-       /*
-        * irq not used (clock sources don't use interrupts)
-        */
-
-       ostm_timer_stop(ostm);
+       ostm_timer_stop(to);
 
-       writel(0, ostm->base + OSTM_CMP);
-       writeb(CTL_FREERUN, ostm->base + OSTM_CTL);
-       writeb(TS, ostm->base + OSTM_TS);
+       writel(0, timer_of_base(to) + OSTM_CMP);
+       writeb(CTL_FREERUN, timer_of_base(to) + OSTM_CTL);
+       writeb(TS, timer_of_base(to) + OSTM_TS);
 
-       return clocksource_mmio_init(ostm->base + OSTM_CNT,
-                       "ostm", rate,
-                       300, 32, clocksource_mmio_readl_up);
+       return clocksource_mmio_init(timer_of_base(to) + OSTM_CNT,
+                                    to->np->full_name, timer_of_rate(to), 300,
+                                    32, clocksource_mmio_readl_up);
 }
 
 static u64 notrace ostm_read_sched_clock(void)
@@ -89,87 +74,75 @@ static u64 notrace ostm_read_sched_clock(void)
        return readl(system_clock);
 }
 
-static void __init ostm_init_sched_clock(struct ostm_device *ostm,
-                       unsigned long rate)
+static void __init ostm_init_sched_clock(struct timer_of *to)
 {
-       system_clock = ostm->base + OSTM_CNT;
-       sched_clock_register(ostm_read_sched_clock, 32, rate);
+       system_clock = timer_of_base(to) + OSTM_CNT;
+       sched_clock_register(ostm_read_sched_clock, 32, timer_of_rate(to));
 }
 
 static int ostm_clock_event_next(unsigned long delta,
-                                    struct clock_event_device *ced)
+                                struct clock_event_device *ced)
 {
-       struct ostm_device *ostm = ced_to_ostm(ced);
+       struct timer_of *to = to_timer_of(ced);
 
-       ostm_timer_stop(ostm);
+       ostm_timer_stop(to);
 
-       writel(delta, ostm->base + OSTM_CMP);
-       writeb(CTL_ONESHOT, ostm->base + OSTM_CTL);
-       writeb(TS, ostm->base + OSTM_TS);
+       writel(delta, timer_of_base(to) + OSTM_CMP);
+       writeb(CTL_ONESHOT, timer_of_base(to) + OSTM_CTL);
+       writeb(TS, timer_of_base(to) + OSTM_TS);
 
        return 0;
 }
 
 static int ostm_shutdown(struct clock_event_device *ced)
 {
-       struct ostm_device *ostm = ced_to_ostm(ced);
+       struct timer_of *to = to_timer_of(ced);
 
-       ostm_timer_stop(ostm);
+       ostm_timer_stop(to);
 
        return 0;
 }
 static int ostm_set_periodic(struct clock_event_device *ced)
 {
-       struct ostm_device *ostm = ced_to_ostm(ced);
+       struct timer_of *to = to_timer_of(ced);
 
        if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
-               ostm_timer_stop(ostm);
+               ostm_timer_stop(to);
 
-       writel(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP);
-       writeb(CTL_PERIODIC, ostm->base + OSTM_CTL);
-       writeb(TS, ostm->base + OSTM_TS);
+       writel(timer_of_period(to) - 1, timer_of_base(to) + OSTM_CMP);
+       writeb(CTL_PERIODIC, timer_of_base(to) + OSTM_CTL);
+       writeb(TS, timer_of_base(to) + OSTM_TS);
 
        return 0;
 }
 
 static int ostm_set_oneshot(struct clock_event_device *ced)
 {
-       struct ostm_device *ostm = ced_to_ostm(ced);
+       struct timer_of *to = to_timer_of(ced);
 
-       ostm_timer_stop(ostm);
+       ostm_timer_stop(to);
 
        return 0;
 }
 
 static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id)
 {
-       struct ostm_device *ostm = dev_id;
+       struct clock_event_device *ced = dev_id;
 
-       if (clockevent_state_oneshot(&ostm->ced))
-               ostm_timer_stop(ostm);
+       if (clockevent_state_oneshot(ced))
+               ostm_timer_stop(to_timer_of(ced));
 
        /* notify clockevent layer */
-       if (ostm->ced.event_handler)
-               ostm->ced.event_handler(&ostm->ced);
+       if (ced->event_handler)
+               ced->event_handler(ced);
 
        return IRQ_HANDLED;
 }
 
-static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq,
-                       unsigned long rate)
+static int __init ostm_init_clkevt(struct timer_of *to)
 {
-       struct clock_event_device *ced = &ostm->ced;
-       int ret = -ENXIO;
-
-       ret = request_irq(irq, ostm_timer_interrupt,
-                         IRQF_TIMER | IRQF_IRQPOLL,
-                         "ostm", ostm);
-       if (ret) {
-               pr_err("ostm: failed to request irq\n");
-               return ret;
-       }
+       struct clock_event_device *ced = &to->clkevt;
 
-       ced->name = "ostm";
        ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
        ced->set_state_shutdown = ostm_shutdown;
        ced->set_state_periodic = ostm_set_periodic;
@@ -178,79 +151,61 @@ static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq,
        ced->shift = 32;
        ced->rating = 300;
        ced->cpumask = cpumask_of(0);
-       clockevents_config_and_register(ced, rate, 0xf, 0xffffffff);
+       clockevents_config_and_register(ced, timer_of_rate(to), 0xf,
+                                       0xffffffff);
 
        return 0;
 }
 
 static int __init ostm_init(struct device_node *np)
 {
-       struct ostm_device *ostm;
-       int ret = -EFAULT;
-       struct clk *ostm_clk = NULL;
-       int irq;
-       unsigned long rate;
-
-       ostm = kzalloc(sizeof(*ostm), GFP_KERNEL);
-       if (!ostm)
-               return -ENOMEM;
-
-       ostm->base = of_iomap(np, 0);
-       if (!ostm->base) {
-               pr_err("ostm: failed to remap I/O memory\n");
-               goto err;
-       }
-
-       irq = irq_of_parse_and_map(np, 0);
-       if (irq < 0) {
-               pr_err("ostm: Failed to get irq\n");
-               goto err;
-       }
+       struct timer_of *to;
+       int ret;
 
-       ostm_clk = of_clk_get(np, 0);
-       if (IS_ERR(ostm_clk)) {
-               pr_err("ostm: Failed to get clock\n");
-               ostm_clk = NULL;
-               goto err;
-       }
+       to = kzalloc(sizeof(*to), GFP_KERNEL);
+       if (!to)
+               return -ENOMEM;
 
-       ret = clk_prepare_enable(ostm_clk);
-       if (ret) {
-               pr_err("ostm: Failed to enable clock\n");
-               goto err;
+       to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK;
+       if (system_clock) {
+               /*
+                * clock sources don't use interrupts, clock events do
+                */
+               to->flags |= TIMER_OF_IRQ;
+               to->of_irq.flags = IRQF_TIMER | IRQF_IRQPOLL;
+               to->of_irq.handler = ostm_timer_interrupt;
        }
 
-       rate = clk_get_rate(ostm_clk);
-       ostm->ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
+       ret = timer_of_init(np, to);
+       if (ret)
+               goto err_free;
 
        /*
         * First probed device will be used as system clocksource. Any
         * additional devices will be used as clock events.
         */
        if (!system_clock) {
-               ret = ostm_init_clksrc(ostm, rate);
-
-               if (!ret) {
-                       ostm_init_sched_clock(ostm, rate);
-                       pr_info("ostm: used for clocksource\n");
-               }
+               ret = ostm_init_clksrc(to);
+               if (ret)
+                       goto err_cleanup;
 
+               ostm_init_sched_clock(to);
+               pr_info("%pOF: used for clocksource\n", np);
        } else {
-               ret = ostm_init_clkevt(ostm, irq, rate);
+               ret = ostm_init_clkevt(to);
+               if (ret)
+                       goto err_cleanup;
 
-               if (!ret)
-                       pr_info("ostm: used for clock events\n");
-       }
-
-err:
-       if (ret) {
-               clk_disable_unprepare(ostm_clk);
-               iounmap(ostm->base);
-               kfree(ostm);
-               return ret;
+               pr_info("%pOF: used for clock events\n", np);
        }
 
        return 0;
+
+err_cleanup:
+       timer_of_cleanup(to);
+err_free:
+       kfree(to);
+       return ret;
 }
 
 TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init);
index 11ff701..572da47 100644 (file)
@@ -57,8 +57,8 @@ static __init int timer_of_irq_init(struct device_node *np,
        if (of_irq->name) {
                of_irq->irq = ret = of_irq_get_byname(np, of_irq->name);
                if (ret < 0) {
-                       pr_err("Failed to get interrupt %s for %s\n",
-                              of_irq->name, np->full_name);
+                       pr_err("Failed to get interrupt %s for %pOF\n",
+                              of_irq->name, np);
                        return ret;
                }
        } else  {
@@ -192,7 +192,7 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)
        }
 
        if (!to->clkevt.name)
-               to->clkevt.name = np->name;
+               to->clkevt.name = np->full_name;
 
        to->np = np;
 
index 35b4f70..58151ca 100644 (file)
@@ -48,9 +48,9 @@ config PPC_PASEMI_CPUFREQ
          PWRficient processors.
 
 config POWERNV_CPUFREQ
-       tristate "CPU frequency scaling for IBM POWERNV platform"
-       depends on PPC_POWERNV
-       default y
-       help
+       tristate "CPU frequency scaling for IBM POWERNV platform"
+       depends on PPC_POWERNV
+       default y
+       help
         This adds support for CPU frequency switching on IBM POWERNV
         platform
index dfa6457..a652838 100644 (file)
@@ -4,17 +4,17 @@
 #
 
 config X86_INTEL_PSTATE
-       bool "Intel P state control"
-       depends on X86
-       select ACPI_PROCESSOR if ACPI
-       select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
-       help
-          This driver provides a P state for Intel core processors.
+       bool "Intel P state control"
+       depends on X86
+       select ACPI_PROCESSOR if ACPI
+       select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
+       help
+         This driver provides a P state for Intel core processors.
          The driver implements an internal governor and will become
-          the scaling driver and governor for Sandy bridge processors.
+         the scaling driver and governor for Sandy bridge processors.
 
          When this driver is enabled it will become the preferred
-          scaling driver for Sandy bridge processors.
+         scaling driver for Sandy bridge processors.
 
          If in doubt, say N.
 
index 54bc767..f1d170d 100644 (file)
@@ -180,4 +180,4 @@ create_pdev:
                               -1, data,
                               sizeof(struct cpufreq_dt_platform_data)));
 }
-device_initcall(cpufreq_dt_platdev_init);
+core_initcall(cpufreq_dt_platdev_init);
index b66e81c..737ff3b 100644 (file)
@@ -346,7 +346,7 @@ struct cpufreq_governor *cpufreq_default_governor(void)
        return CPU_FREQ_GOV_CONSERVATIVE;
 }
 
-fs_initcall(cpufreq_gov_dbs_init);
+core_initcall(cpufreq_gov_dbs_init);
 #else
 module_init(cpufreq_gov_dbs_init);
 #endif
index dced033..82a4d37 100644 (file)
@@ -483,7 +483,7 @@ struct cpufreq_governor *cpufreq_default_governor(void)
        return CPU_FREQ_GOV_ONDEMAND;
 }
 
-fs_initcall(cpufreq_gov_dbs_init);
+core_initcall(cpufreq_gov_dbs_init);
 #else
 module_init(cpufreq_gov_dbs_init);
 #endif
index aaa04df..def9afe 100644 (file)
@@ -50,5 +50,5 @@ MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
 MODULE_DESCRIPTION("CPUfreq policy governor 'performance'");
 MODULE_LICENSE("GPL");
 
-fs_initcall(cpufreq_gov_performance_init);
+core_initcall(cpufreq_gov_performance_init);
 module_exit(cpufreq_gov_performance_exit);
index c143dc2..1ae6601 100644 (file)
@@ -43,7 +43,7 @@ struct cpufreq_governor *cpufreq_default_governor(void)
        return &cpufreq_gov_powersave;
 }
 
-fs_initcall(cpufreq_gov_powersave_init);
+core_initcall(cpufreq_gov_powersave_init);
 #else
 module_init(cpufreq_gov_powersave_init);
 #endif
index cbd81c5..b43e7cd 100644 (file)
@@ -147,7 +147,7 @@ struct cpufreq_governor *cpufreq_default_governor(void)
        return &cpufreq_gov_userspace;
 }
 
-fs_initcall(cpufreq_gov_userspace_init);
+core_initcall(cpufreq_gov_userspace_init);
 #else
 module_init(cpufreq_gov_userspace_init);
 #endif
index a9ae2f8..fc92a88 100644 (file)
@@ -334,7 +334,7 @@ static int __init qcom_cpufreq_hw_init(void)
 {
        return platform_driver_register(&qcom_cpufreq_hw_driver);
 }
-device_initcall(qcom_cpufreq_hw_init);
+postcore_initcall(qcom_cpufreq_hw_init);
 
 static void __exit qcom_cpufreq_hw_exit(void)
 {
index 88727b7..c0aeedd 100644 (file)
@@ -16,7 +16,7 @@ config CPU_IDLE
 if CPU_IDLE
 
 config CPU_IDLE_MULTIPLE_DRIVERS
-        bool
+       bool
 
 config CPU_IDLE_GOV_LADDER
        bool "Ladder governor (for periodic timer tick)"
@@ -63,13 +63,13 @@ source "drivers/cpuidle/Kconfig.powerpc"
 endmenu
 
 config HALTPOLL_CPUIDLE
-       tristate "Halt poll cpuidle driver"
-       depends on X86 && KVM_GUEST
-       default y
-       help
-         This option enables halt poll cpuidle driver, which allows to poll
-         before halting in the guest (more efficient than polling in the
-         host via halt_poll_ns for some scenarios).
+       tristate "Halt poll cpuidle driver"
+       depends on X86 && KVM_GUEST
+       default y
+       help
+        This option enables halt poll cpuidle driver, which allows to poll
+        before halting in the guest (more efficient than polling in the
+        host via halt_poll_ns for some scenarios).
 
 endif
 
index d853047..a224d33 100644 (file)
@@ -3,15 +3,15 @@
 # ARM CPU Idle drivers
 #
 config ARM_CPUIDLE
-        bool "Generic ARM/ARM64 CPU idle Driver"
-        select DT_IDLE_STATES
+       bool "Generic ARM/ARM64 CPU idle Driver"
+       select DT_IDLE_STATES
        select CPU_IDLE_MULTIPLE_DRIVERS
-        help
-          Select this to enable generic cpuidle driver for ARM.
-          It provides a generic idle driver whose idle states are configured
-          at run-time through DT nodes. The CPUidle suspend backend is
-          initialized by calling the CPU operations init idle hook
-          provided by architecture code.
+       help
+         Select this to enable generic cpuidle driver for ARM.
+         It provides a generic idle driver whose idle states are configured
+         at run-time through DT nodes. The CPUidle suspend backend is
+         initialized by calling the CPU operations init idle hook
+         provided by architecture code.
 
 config ARM_PSCI_CPUIDLE
        bool "PSCI CPU idle Driver"
@@ -65,21 +65,21 @@ config ARM_U8500_CPUIDLE
        bool "Cpu Idle Driver for the ST-E u8500 processors"
        depends on ARCH_U8500 && !ARM64
        help
-         Select this to enable cpuidle for ST-E u8500 processors
+         Select this to enable cpuidle for ST-E u8500 processors.
 
 config ARM_AT91_CPUIDLE
        bool "Cpu Idle Driver for the AT91 processors"
        default y
        depends on ARCH_AT91 && !ARM64
        help
-         Select this to enable cpuidle for AT91 processors
+         Select this to enable cpuidle for AT91 processors.
 
 config ARM_EXYNOS_CPUIDLE
        bool "Cpu Idle Driver for the Exynos processors"
        depends on ARCH_EXYNOS && !ARM64
        select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
        help
-         Select this to enable cpuidle for Exynos processors
+         Select this to enable cpuidle for Exynos processors.
 
 config ARM_MVEBU_V7_CPUIDLE
        bool "CPU Idle Driver for mvebu v7 family processors"
index 569dbac..0005be5 100644 (file)
@@ -572,7 +572,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
                return -EINVAL;
 
        for (i = 0; i < drv->state_count; i++)
-               if (drv->states[i].disabled)
+               if (drv->states[i].flags & CPUIDLE_FLAG_UNUSABLE)
                        dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
 
        per_cpu(cpuidle_devices, dev->cpu) = dev;
index 9f1ace9..f7e8361 100644 (file)
@@ -53,7 +53,6 @@ void cpuidle_poll_state_init(struct cpuidle_driver *drv)
        state->target_residency_ns = 0;
        state->power_usage = -1;
        state->enter = poll_idle;
-       state->disabled = false;
        state->flags = CPUIDLE_FLAG_POLLING;
 }
 EXPORT_SYMBOL_GPL(cpuidle_poll_state_init);
index 43ed1b6..91eb768 100644 (file)
@@ -289,6 +289,7 @@ config CRYPTO_DEV_TALITOS
        select CRYPTO_AUTHENC
        select CRYPTO_SKCIPHER
        select CRYPTO_HASH
+       select CRYPTO_LIB_DES
        select HW_RANDOM
        depends on FSL_SOC
        help
index dc1eb97..62b04e1 100644 (file)
@@ -179,14 +179,14 @@ static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx,
 
        qp_ctx->c_in_pool = hisi_acc_create_sgl_pool(dev, QM_Q_DEPTH,
                                                     SEC_SGL_SGE_NR);
-       if (!qp_ctx->c_in_pool) {
+       if (IS_ERR(qp_ctx->c_in_pool)) {
                dev_err(dev, "fail to create sgl pool for input!\n");
                goto err_free_req_list;
        }
 
        qp_ctx->c_out_pool = hisi_acc_create_sgl_pool(dev, QM_Q_DEPTH,
                                                      SEC_SGL_SGE_NR);
-       if (!qp_ctx->c_out_pool) {
+       if (IS_ERR(qp_ctx->c_out_pool)) {
                dev_err(dev, "fail to create sgl pool for output!\n");
                goto err_free_c_in_pool;
        }
index f840e61..425149e 100644 (file)
@@ -921,7 +921,9 @@ int devfreq_suspend_device(struct devfreq *devfreq)
        }
 
        if (devfreq->suspend_freq) {
+               mutex_lock(&devfreq->lock);
                ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0);
+               mutex_unlock(&devfreq->lock);
                if (ret)
                        return ret;
        }
@@ -949,7 +951,9 @@ int devfreq_resume_device(struct devfreq *devfreq)
                return 0;
 
        if (devfreq->resume_freq) {
+               mutex_lock(&devfreq->lock);
                ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0);
+               mutex_unlock(&devfreq->lock);
                if (ret)
                        return ret;
        }
index 7af874b..6fa1eba 100644 (file)
@@ -15,19 +15,19 @@ menuconfig DMADEVICES
          be empty in some cases.
 
 config DMADEVICES_DEBUG
-        bool "DMA Engine debugging"
-        depends on DMADEVICES != n
-        help
-          This is an option for use by developers; most people should
-          say N here.  This enables DMA engine core and driver debugging.
+       bool "DMA Engine debugging"
+       depends on DMADEVICES != n
+       help
+         This is an option for use by developers; most people should
+         say N here.  This enables DMA engine core and driver debugging.
 
 config DMADEVICES_VDEBUG
-        bool "DMA Engine verbose debugging"
-        depends on DMADEVICES_DEBUG != n
-        help
-          This is an option for use by developers; most people should
-          say N here.  This enables deeper (more verbose) debugging of
-          the DMA engine core and drivers.
+       bool "DMA Engine verbose debugging"
+       depends on DMADEVICES_DEBUG != n
+       help
+         This is an option for use by developers; most people should
+         say N here.  This enables deeper (more verbose) debugging of
+         the DMA engine core and drivers.
 
 
 if DMADEVICES
@@ -215,28 +215,28 @@ config FSL_EDMA
          This module can be found on Freescale Vybrid and LS-1 SoCs.
 
 config FSL_QDMA
-       tristate "NXP Layerscape qDMA engine support"
-       depends on ARM || ARM64
-       select DMA_ENGINE
-       select DMA_VIRTUAL_CHANNELS
-       select DMA_ENGINE_RAID
-       select ASYNC_TX_ENABLE_CHANNEL_SWITCH
-       help
-         Support the NXP Layerscape qDMA engine with command queue and legacy mode.
-         Channel virtualization is supported through enqueuing of DMA jobs to,
-         or dequeuing DMA jobs from, different work queues.
-         This module can be found on NXP Layerscape SoCs.
+       tristate "NXP Layerscape qDMA engine support"
+       depends on ARM || ARM64
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       select DMA_ENGINE_RAID
+       select ASYNC_TX_ENABLE_CHANNEL_SWITCH
+       help
+        Support the NXP Layerscape qDMA engine with command queue and legacy mode.
+        Channel virtualization is supported through enqueuing of DMA jobs to,
+        or dequeuing DMA jobs from, different work queues.
+        This module can be found on NXP Layerscape SoCs.
          The qdma driver only work on  SoCs with a DPAA hardware block.
 
 config FSL_RAID
-        tristate "Freescale RAID engine Support"
-        depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH
-        select DMA_ENGINE
-        select DMA_ENGINE_RAID
-        ---help---
-          Enable support for Freescale RAID Engine. RAID Engine is
-          available on some QorIQ SoCs (like P5020/P5040). It has
-          the capability to offload memcpy, xor and pq computation
+       tristate "Freescale RAID engine Support"
+       depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH
+       select DMA_ENGINE
+       select DMA_ENGINE_RAID
+       ---help---
+         Enable support for Freescale RAID Engine. RAID Engine is
+         available on some QorIQ SoCs (like P5020/P5040). It has
+         the capability to offload memcpy, xor and pq computation
          for raid5/6.
 
 config IMG_MDC_DMA
@@ -342,6 +342,26 @@ config MCF_EDMA
          minimal intervention from a host processor.
          This module can be found on Freescale ColdFire mcf5441x SoCs.
 
+config MILBEAUT_HDMAC
+       tristate "Milbeaut AHB DMA support"
+       depends on ARCH_MILBEAUT || COMPILE_TEST
+       depends on OF
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Say yes here to support the Socionext Milbeaut
+         HDMAC device.
+
+config MILBEAUT_XDMAC
+       tristate "Milbeaut AXI DMA support"
+       depends on ARCH_MILBEAUT || COMPILE_TEST
+       depends on OF
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Say yes here to support the Socionext Milbeaut
+         XDMAC device.
+
 config MMP_PDMA
        bool "MMP PDMA support"
        depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
@@ -635,6 +655,10 @@ config XILINX_DMA
          destination address.
          AXI DMA engine provides high-bandwidth one dimensional direct
          memory access between memory and AXI4-Stream target peripherals.
+         AXI MCDMA engine provides high-bandwidth direct memory access
+         between memory and AXI4-Stream target peripherals. It provides
+         the scatter gather interface with multiple channels independent
+         configuration support.
 
 config XILINX_ZYNQMP_DMA
        tristate "Xilinx ZynqMP DMA Engine"
@@ -665,10 +689,14 @@ source "drivers/dma/dw-edma/Kconfig"
 
 source "drivers/dma/hsu/Kconfig"
 
+source "drivers/dma/sf-pdma/Kconfig"
+
 source "drivers/dma/sh/Kconfig"
 
 source "drivers/dma/ti/Kconfig"
 
+source "drivers/dma/fsl-dpaa2-qdma/Kconfig"
+
 # clients
 comment "DMA Clients"
        depends on DMA_ENGINE
index f5ce866..42d7e2f 100644 (file)
@@ -45,6 +45,8 @@ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
 obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
 obj-$(CONFIG_K3_DMA) += k3dma.o
 obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o
+obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o
+obj-$(CONFIG_MILBEAUT_XDMAC) += milbeaut-xdmac.o
 obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
 obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
@@ -60,6 +62,7 @@ obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
 obj-$(CONFIG_PXA_DMA) += pxa_dma.o
 obj-$(CONFIG_RENESAS_DMA) += sh/
+obj-$(CONFIG_SF_PDMA) += sf-pdma/
 obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
 obj-$(CONFIG_STM32_DMA) += stm32-dma.o
@@ -75,6 +78,7 @@ obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
 obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
 obj-$(CONFIG_ZX_DMA) += zx_dma.o
 obj-$(CONFIG_ST_FDMA) += st_fdma.o
+obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma/
 
 obj-y += mediatek/
 obj-y += qcom/
index b58ac72..f71c9f7 100644 (file)
@@ -1957,21 +1957,16 @@ static int atmel_xdmac_resume(struct device *dev)
 
 static int at_xdmac_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct at_xdmac *atxdmac;
        int             irq, size, nr_channels, i, ret;
        void __iomem    *base;
        u32             reg;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
 
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index cafb1cc..fa626ac 100644 (file)
@@ -858,13 +858,7 @@ static int jz4780_dma_probe(struct platform_device *pdev)
        jzdma->soc_data = soc_data;
        platform_set_drvdata(pdev, jzdma);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(dev, "failed to get I/O memory\n");
-               return -EINVAL;
-       }
-
-       jzdma->chn_base = devm_ioremap_resource(dev, res);
+       jzdma->chn_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(jzdma->chn_base))
                return PTR_ERR(jzdma->chn_base);
 
@@ -987,6 +981,7 @@ static int jz4780_dma_remove(struct platform_device *pdev)
 
        of_dma_controller_free(pdev->dev.of_node);
 
+       clk_disable_unprepare(jzdma->clk);
        free_irq(jzdma->irq, jzdma);
 
        for (i = 0; i < jzdma->soc_data->nb_channels; i++)
@@ -1019,11 +1014,18 @@ static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
        .flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA,
 };
 
+static const struct jz4780_dma_soc_data x1000_dma_soc_data = {
+       .nb_channels = 8,
+       .transfer_ord_max = 7,
+       .flags = JZ_SOC_DATA_PROGRAMMABLE_DMA,
+};
+
 static const struct of_device_id jz4780_dma_dt_match[] = {
        { .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data },
        { .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data },
        { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
        { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
+       { .compatible = "ingenic,x1000-dma", .data = &x1000_dma_soc_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match);
index c90c798..0585d74 100644 (file)
@@ -66,7 +66,7 @@ static int dw_probe(struct platform_device *pdev)
 
        data->chip = chip;
 
-       chip->clk = devm_clk_get(chip->dev, "hclk");
+       chip->clk = devm_clk_get_optional(chip->dev, "hclk");
        if (IS_ERR(chip->clk))
                return PTR_ERR(chip->clk);
        err = clk_prepare_enable(chip->clk);
diff --git a/drivers/dma/fsl-dpaa2-qdma/Kconfig b/drivers/dma/fsl-dpaa2-qdma/Kconfig
new file mode 100644 (file)
index 0000000..258ed6b
--- /dev/null
@@ -0,0 +1,9 @@
+menuconfig FSL_DPAA2_QDMA
+       tristate "NXP DPAA2 QDMA"
+       depends on ARM64
+       depends on FSL_MC_BUS && FSL_MC_DPIO
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         NXP Data Path Acceleration Architecture 2 QDMA driver,
+         using the NXP MC bus driver.
diff --git a/drivers/dma/fsl-dpaa2-qdma/Makefile b/drivers/dma/fsl-dpaa2-qdma/Makefile
new file mode 100644 (file)
index 0000000..c1d0226
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for the NXP DPAA2 qDMA controllers
+obj-$(CONFIG_FSL_DPAA2_QDMA) += dpaa2-qdma.o dpdmai.o
diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
new file mode 100644 (file)
index 0000000..c70a796
--- /dev/null
@@ -0,0 +1,825 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dmapool.h>
+#include <linux/of_irq.h>
+#include <linux/iommu.h>
+#include <linux/sys_soc.h>
+#include <linux/fsl/mc.h>
+#include <soc/fsl/dpaa2-io.h>
+
+#include "../virt-dma.h"
+#include "dpdmai.h"
+#include "dpaa2-qdma.h"
+
+static bool smmu_disable = true;
+
+static struct dpaa2_qdma_chan *to_dpaa2_qdma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct dpaa2_qdma_chan, vchan.chan);
+}
+
+static struct dpaa2_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct dpaa2_qdma_comp, vdesc);
+}
+
+static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
+       struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma;
+       struct device *dev = &dpaa2_qdma->priv->dpdmai_dev->dev;
+
+       dpaa2_chan->fd_pool = dma_pool_create("fd_pool", dev,
+                                             sizeof(struct dpaa2_fd),
+                                             sizeof(struct dpaa2_fd), 0);
+       if (!dpaa2_chan->fd_pool)
+               goto err;
+
+       dpaa2_chan->fl_pool = dma_pool_create("fl_pool", dev,
+                                             sizeof(struct dpaa2_fl_entry),
+                                             sizeof(struct dpaa2_fl_entry), 0);
+       if (!dpaa2_chan->fl_pool)
+               goto err_fd;
+
+       dpaa2_chan->sdd_pool =
+               dma_pool_create("sdd_pool", dev,
+                               sizeof(struct dpaa2_qdma_sd_d),
+                               sizeof(struct dpaa2_qdma_sd_d), 0);
+       if (!dpaa2_chan->sdd_pool)
+               goto err_fl;
+
+       return dpaa2_qdma->desc_allocated++;
+err_fl:
+       dma_pool_destroy(dpaa2_chan->fl_pool);
+err_fd:
+       dma_pool_destroy(dpaa2_chan->fd_pool);
+err:
+       return -ENOMEM;
+}
+
+static void dpaa2_qdma_free_chan_resources(struct dma_chan *chan)
+{
+       struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
+       struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma;
+       unsigned long flags;
+
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&dpaa2_chan->vchan.lock, flags);
+       vchan_get_all_descriptors(&dpaa2_chan->vchan, &head);
+       spin_unlock_irqrestore(&dpaa2_chan->vchan.lock, flags);
+
+       vchan_dma_desc_free_list(&dpaa2_chan->vchan, &head);
+
+       dpaa2_dpdmai_free_comp(dpaa2_chan, &dpaa2_chan->comp_used);
+       dpaa2_dpdmai_free_comp(dpaa2_chan, &dpaa2_chan->comp_free);
+
+       dma_pool_destroy(dpaa2_chan->fd_pool);
+       dma_pool_destroy(dpaa2_chan->fl_pool);
+       dma_pool_destroy(dpaa2_chan->sdd_pool);
+       dpaa2_qdma->desc_allocated--;
+}
+
+/*
+ * Request a command descriptor for enqueue.
+ */
+static struct dpaa2_qdma_comp *
+dpaa2_qdma_request_desc(struct dpaa2_qdma_chan *dpaa2_chan)
+{
+       struct dpaa2_qdma_priv *qdma_priv = dpaa2_chan->qdma->priv;
+       struct device *dev = &qdma_priv->dpdmai_dev->dev;
+       struct dpaa2_qdma_comp *comp_temp = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dpaa2_chan->queue_lock, flags);
+       if (list_empty(&dpaa2_chan->comp_free)) {
+               spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);
+               comp_temp = kzalloc(sizeof(*comp_temp), GFP_NOWAIT);
+               if (!comp_temp)
+                       goto err;
+               comp_temp->fd_virt_addr =
+                       dma_pool_alloc(dpaa2_chan->fd_pool, GFP_NOWAIT,
+                                      &comp_temp->fd_bus_addr);
+               if (!comp_temp->fd_virt_addr)
+                       goto err_comp;
+
+               comp_temp->fl_virt_addr =
+                       dma_pool_alloc(dpaa2_chan->fl_pool, GFP_NOWAIT,
+                                      &comp_temp->fl_bus_addr);
+               if (!comp_temp->fl_virt_addr)
+                       goto err_fd_virt;
+
+               comp_temp->desc_virt_addr =
+                       dma_pool_alloc(dpaa2_chan->sdd_pool, GFP_NOWAIT,
+                                      &comp_temp->desc_bus_addr);
+               if (!comp_temp->desc_virt_addr)
+                       goto err_fl_virt;
+
+               comp_temp->qchan = dpaa2_chan;
+               return comp_temp;
+       }
+
+       comp_temp = list_first_entry(&dpaa2_chan->comp_free,
+                                    struct dpaa2_qdma_comp, list);
+       list_del(&comp_temp->list);
+       spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);
+
+       comp_temp->qchan = dpaa2_chan;
+
+       return comp_temp;
+
+err_fl_virt:
+               dma_pool_free(dpaa2_chan->fl_pool,
+                             comp_temp->fl_virt_addr,
+                             comp_temp->fl_bus_addr);
+err_fd_virt:
+               dma_pool_free(dpaa2_chan->fd_pool,
+                             comp_temp->fd_virt_addr,
+                             comp_temp->fd_bus_addr);
+err_comp:
+       kfree(comp_temp);
+err:
+       dev_err(dev, "Failed to request descriptor\n");
+       return NULL;
+}
+
+static void
+dpaa2_qdma_populate_fd(u32 format, struct dpaa2_qdma_comp *dpaa2_comp)
+{
+       struct dpaa2_fd *fd;
+
+       fd = dpaa2_comp->fd_virt_addr;
+       memset(fd, 0, sizeof(struct dpaa2_fd));
+
+       /* fd populated */
+       dpaa2_fd_set_addr(fd, dpaa2_comp->fl_bus_addr);
+
+       /*
+        * Bypass memory translation, Frame list format, short length disable
+        * we need to disable BMT if fsl-mc use iova addr
+        */
+       if (smmu_disable)
+               dpaa2_fd_set_bpid(fd, QMAN_FD_BMT_ENABLE);
+       dpaa2_fd_set_format(fd, QMAN_FD_FMT_ENABLE | QMAN_FD_SL_DISABLE);
+
+       dpaa2_fd_set_frc(fd, format | QDMA_SER_CTX);
+}
+
+/* first frame list for descriptor buffer */
+static void
+dpaa2_qdma_populate_first_framel(struct dpaa2_fl_entry *f_list,
+                                struct dpaa2_qdma_comp *dpaa2_comp,
+                                bool wrt_changed)
+{
+       struct dpaa2_qdma_sd_d *sdd;
+
+       sdd = dpaa2_comp->desc_virt_addr;
+       memset(sdd, 0, 2 * (sizeof(*sdd)));
+
+       /* source descriptor CMD */
+       sdd->cmd = cpu_to_le32(QDMA_SD_CMD_RDTTYPE_COHERENT);
+       sdd++;
+
+       /* dest descriptor CMD */
+       if (wrt_changed)
+               sdd->cmd = cpu_to_le32(LX2160_QDMA_DD_CMD_WRTTYPE_COHERENT);
+       else
+               sdd->cmd = cpu_to_le32(QDMA_DD_CMD_WRTTYPE_COHERENT);
+
+       memset(f_list, 0, sizeof(struct dpaa2_fl_entry));
+
+       /* first frame list to source descriptor */
+       dpaa2_fl_set_addr(f_list, dpaa2_comp->desc_bus_addr);
+       dpaa2_fl_set_len(f_list, 0x20);
+       dpaa2_fl_set_format(f_list, QDMA_FL_FMT_SBF | QDMA_FL_SL_LONG);
+
+       /* bypass memory translation */
+       if (smmu_disable)
+               f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);
+}
+
+/* source and destination frame list */
+static void
+dpaa2_qdma_populate_frames(struct dpaa2_fl_entry *f_list,
+                          dma_addr_t dst, dma_addr_t src,
+                          size_t len, uint8_t fmt)
+{
+       /* source frame list to source buffer */
+       memset(f_list, 0, sizeof(struct dpaa2_fl_entry));
+
+       dpaa2_fl_set_addr(f_list, src);
+       dpaa2_fl_set_len(f_list, len);
+
+       /* single buffer frame or scatter gather frame */
+       dpaa2_fl_set_format(f_list, (fmt | QDMA_FL_SL_LONG));
+
+       /* bypass memory translation */
+       if (smmu_disable)
+               f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);
+
+       f_list++;
+
+       /* destination frame list to destination buffer */
+       memset(f_list, 0, sizeof(struct dpaa2_fl_entry));
+
+       dpaa2_fl_set_addr(f_list, dst);
+       dpaa2_fl_set_len(f_list, len);
+       dpaa2_fl_set_format(f_list, (fmt | QDMA_FL_SL_LONG));
+       /* single buffer frame or scatter gather frame */
+       dpaa2_fl_set_final(f_list, QDMA_FL_F);
+       /* bypass memory translation */
+       if (smmu_disable)
+               f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);
+}
+
+static struct dma_async_tx_descriptor
+*dpaa2_qdma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst,
+                       dma_addr_t src, size_t len, ulong flags)
+{
+       struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
+       struct dpaa2_qdma_engine *dpaa2_qdma;
+       struct dpaa2_qdma_comp *dpaa2_comp;
+       struct dpaa2_fl_entry *f_list;
+       bool wrt_changed;
+
+       dpaa2_qdma = dpaa2_chan->qdma;
+       dpaa2_comp = dpaa2_qdma_request_desc(dpaa2_chan);
+       if (!dpaa2_comp)
+               return NULL;
+
+       wrt_changed = (bool)dpaa2_qdma->qdma_wrtype_fixup;
+
+       /* populate Frame descriptor */
+       dpaa2_qdma_populate_fd(QDMA_FD_LONG_FORMAT, dpaa2_comp);
+
+       f_list = dpaa2_comp->fl_virt_addr;
+
+       /* first frame list for descriptor buffer (logn format) */
+       dpaa2_qdma_populate_first_framel(f_list, dpaa2_comp, wrt_changed);
+
+       f_list++;
+
+       dpaa2_qdma_populate_frames(f_list, dst, src, len, QDMA_FL_FMT_SBF);
+
+       return vchan_tx_prep(&dpaa2_chan->vchan, &dpaa2_comp->vdesc, flags);
+}
+
+static void dpaa2_qdma_issue_pending(struct dma_chan *chan)
+{
+       struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
+       struct dpaa2_qdma_comp *dpaa2_comp;
+       struct virt_dma_desc *vdesc;
+       struct dpaa2_fd *fd;
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&dpaa2_chan->queue_lock, flags);
+       spin_lock(&dpaa2_chan->vchan.lock);
+       if (vchan_issue_pending(&dpaa2_chan->vchan)) {
+               vdesc = vchan_next_desc(&dpaa2_chan->vchan);
+               if (!vdesc)
+                       goto err_enqueue;
+               dpaa2_comp = to_fsl_qdma_comp(vdesc);
+
+               fd = dpaa2_comp->fd_virt_addr;
+
+               list_del(&vdesc->node);
+               list_add_tail(&dpaa2_comp->list, &dpaa2_chan->comp_used);
+
+               err = dpaa2_io_service_enqueue_fq(NULL, dpaa2_chan->fqid, fd);
+               if (err) {
+                       list_del(&dpaa2_comp->list);
+                       list_add_tail(&dpaa2_comp->list,
+                                     &dpaa2_chan->comp_free);
+               }
+       }
+err_enqueue:
+       spin_unlock(&dpaa2_chan->vchan.lock);
+       spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);
+}
+
+static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev)
+{
+       struct dpaa2_qdma_priv_per_prio *ppriv;
+       struct device *dev = &ls_dev->dev;
+       struct dpaa2_qdma_priv *priv;
+       u8 prio_def = DPDMAI_PRIO_NUM;
+       int err = -EINVAL;
+       int i;
+
+       priv = dev_get_drvdata(dev);
+
+       priv->dev = dev;
+       priv->dpqdma_id = ls_dev->obj_desc.id;
+
+       /* Get the handle for the DPDMAI this interface is associate with */
+       err = dpdmai_open(priv->mc_io, 0, priv->dpqdma_id, &ls_dev->mc_handle);
+       if (err) {
+               dev_err(dev, "dpdmai_open() failed\n");
+               return err;
+       }
+
+       dev_dbg(dev, "Opened dpdmai object successfully\n");
+
+       err = dpdmai_get_attributes(priv->mc_io, 0, ls_dev->mc_handle,
+                                   &priv->dpdmai_attr);
+       if (err) {
+               dev_err(dev, "dpdmai_get_attributes() failed\n");
+               goto exit;
+       }
+
+       if (priv->dpdmai_attr.version.major > DPDMAI_VER_MAJOR) {
+               dev_err(dev, "DPDMAI major version mismatch\n"
+                            "Found %u.%u, supported version is %u.%u\n",
+                               priv->dpdmai_attr.version.major,
+                               priv->dpdmai_attr.version.minor,
+                               DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR);
+               goto exit;
+       }
+
+       if (priv->dpdmai_attr.version.minor > DPDMAI_VER_MINOR) {
+               dev_err(dev, "DPDMAI minor version mismatch\n"
+                            "Found %u.%u, supported version is %u.%u\n",
+                               priv->dpdmai_attr.version.major,
+                               priv->dpdmai_attr.version.minor,
+                               DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR);
+               goto exit;
+       }
+
+       priv->num_pairs = min(priv->dpdmai_attr.num_of_priorities, prio_def);
+       ppriv = kcalloc(priv->num_pairs, sizeof(*ppriv), GFP_KERNEL);
+       if (!ppriv) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       priv->ppriv = ppriv;
+
+       for (i = 0; i < priv->num_pairs; i++) {
+               err = dpdmai_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle,
+                                         i, &priv->rx_queue_attr[i]);
+               if (err) {
+                       dev_err(dev, "dpdmai_get_rx_queue() failed\n");
+                       goto exit;
+               }
+               ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid;
+
+               err = dpdmai_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle,
+                                         i, &priv->tx_fqid[i]);
+               if (err) {
+                       dev_err(dev, "dpdmai_get_tx_queue() failed\n");
+                       goto exit;
+               }
+               ppriv->req_fqid = priv->tx_fqid[i];
+               ppriv->prio = i;
+               ppriv->priv = priv;
+               ppriv++;
+       }
+
+       return 0;
+exit:
+       dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);
+       return err;
+}
+
+static void dpaa2_qdma_fqdan_cb(struct dpaa2_io_notification_ctx *ctx)
+{
+       struct dpaa2_qdma_priv_per_prio *ppriv = container_of(ctx,
+                       struct dpaa2_qdma_priv_per_prio, nctx);
+       struct dpaa2_qdma_comp *dpaa2_comp, *_comp_tmp;
+       struct dpaa2_qdma_priv *priv = ppriv->priv;
+       u32 n_chans = priv->dpaa2_qdma->n_chans;
+       struct dpaa2_qdma_chan *qchan;
+       const struct dpaa2_fd *fd_eq;
+       const struct dpaa2_fd *fd;
+       struct dpaa2_dq *dq;
+       int is_last = 0;
+       int found;
+       u8 status;
+       int err;
+       int i;
+
+       do {
+               err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid,
+                                              ppriv->store);
+       } while (err);
+
+       while (!is_last) {
+               do {
+                       dq = dpaa2_io_store_next(ppriv->store, &is_last);
+               } while (!is_last && !dq);
+               if (!dq) {
+                       dev_err(priv->dev, "FQID returned no valid frames!\n");
+                       continue;
+               }
+
+               /* obtain FD and process the error */
+               fd = dpaa2_dq_fd(dq);
+
+               status = dpaa2_fd_get_ctrl(fd) & 0xff;
+               if (status)
+                       dev_err(priv->dev, "FD error occurred\n");
+               found = 0;
+               for (i = 0; i < n_chans; i++) {
+                       qchan = &priv->dpaa2_qdma->chans[i];
+                       spin_lock(&qchan->queue_lock);
+                       if (list_empty(&qchan->comp_used)) {
+                               spin_unlock(&qchan->queue_lock);
+                               continue;
+                       }
+                       list_for_each_entry_safe(dpaa2_comp, _comp_tmp,
+                                                &qchan->comp_used, list) {
+                               fd_eq = dpaa2_comp->fd_virt_addr;
+
+                               if (le64_to_cpu(fd_eq->simple.addr) ==
+                                   le64_to_cpu(fd->simple.addr)) {
+                                       spin_lock(&qchan->vchan.lock);
+                                       vchan_cookie_complete(&
+                                                       dpaa2_comp->vdesc);
+                                       spin_unlock(&qchan->vchan.lock);
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       spin_unlock(&qchan->queue_lock);
+                       if (found)
+                               break;
+               }
+       }
+
+       dpaa2_io_service_rearm(NULL, ctx);
+}
+
+static int __cold dpaa2_qdma_dpio_setup(struct dpaa2_qdma_priv *priv)
+{
+       struct dpaa2_qdma_priv_per_prio *ppriv;
+       struct device *dev = priv->dev;
+       int err = -EINVAL;
+       int i, num;
+
+       num = priv->num_pairs;
+       ppriv = priv->ppriv;
+       for (i = 0; i < num; i++) {
+               ppriv->nctx.is_cdan = 0;
+               ppriv->nctx.desired_cpu = DPAA2_IO_ANY_CPU;
+               ppriv->nctx.id = ppriv->rsp_fqid;
+               ppriv->nctx.cb = dpaa2_qdma_fqdan_cb;
+               err = dpaa2_io_service_register(NULL, &ppriv->nctx, dev);
+               if (err) {
+                       dev_err(dev, "Notification register failed\n");
+                       goto err_service;
+               }
+
+               ppriv->store =
+                       dpaa2_io_store_create(DPAA2_QDMA_STORE_SIZE, dev);
+               if (!ppriv->store) {
+                       dev_err(dev, "dpaa2_io_store_create() failed\n");
+                       goto err_store;
+               }
+
+               ppriv++;
+       }
+       return 0;
+
+err_store:
+       dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);
+err_service:
+       ppriv--;
+       while (ppriv >= priv->ppriv) {
+               dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);
+               dpaa2_io_store_destroy(ppriv->store);
+               ppriv--;
+       }
+       return err;
+}
+
+static void dpaa2_dpmai_store_free(struct dpaa2_qdma_priv *priv)
+{
+       struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;
+       int i;
+
+       for (i = 0; i < priv->num_pairs; i++) {
+               dpaa2_io_store_destroy(ppriv->store);
+               ppriv++;
+       }
+}
+
+static void dpaa2_dpdmai_dpio_free(struct dpaa2_qdma_priv *priv)
+{
+       struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;
+       struct device *dev = priv->dev;
+       int i;
+
+       for (i = 0; i < priv->num_pairs; i++) {
+               dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);
+               ppriv++;
+       }
+}
+
+static int __cold dpaa2_dpdmai_bind(struct dpaa2_qdma_priv *priv)
+{
+       struct dpdmai_rx_queue_cfg rx_queue_cfg;
+       struct dpaa2_qdma_priv_per_prio *ppriv;
+       struct device *dev = priv->dev;
+       struct fsl_mc_device *ls_dev;
+       int i, num;
+       int err;
+
+       ls_dev = to_fsl_mc_device(dev);
+       num = priv->num_pairs;
+       ppriv = priv->ppriv;
+       for (i = 0; i < num; i++) {
+               rx_queue_cfg.options = DPDMAI_QUEUE_OPT_USER_CTX |
+                                       DPDMAI_QUEUE_OPT_DEST;
+               rx_queue_cfg.user_ctx = ppriv->nctx.qman64;
+               rx_queue_cfg.dest_cfg.dest_type = DPDMAI_DEST_DPIO;
+               rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id;
+               rx_queue_cfg.dest_cfg.priority = ppriv->prio;
+               err = dpdmai_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle,
+                                         rx_queue_cfg.dest_cfg.priority,
+                                         &rx_queue_cfg);
+               if (err) {
+                       dev_err(dev, "dpdmai_set_rx_queue() failed\n");
+                       return err;
+               }
+
+               ppriv++;
+       }
+
+       return 0;
+}
+
+static int __cold dpaa2_dpdmai_dpio_unbind(struct dpaa2_qdma_priv *priv)
+{
+       struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;
+       struct device *dev = priv->dev;
+       struct fsl_mc_device *ls_dev;
+       int err = 0;
+       int i;
+
+       ls_dev = to_fsl_mc_device(dev);
+
+       for (i = 0; i < priv->num_pairs; i++) {
+               ppriv->nctx.qman64 = 0;
+               ppriv->nctx.dpio_id = 0;
+               ppriv++;
+       }
+
+       err = dpdmai_reset(priv->mc_io, 0, ls_dev->mc_handle);
+       if (err)
+               dev_err(dev, "dpdmai_reset() failed\n");
+
+       return err;
+}
+
+static void dpaa2_dpdmai_free_comp(struct dpaa2_qdma_chan *qchan,
+                                  struct list_head *head)
+{
+       struct dpaa2_qdma_comp *comp_tmp, *_comp_tmp;
+       unsigned long flags;
+
+       list_for_each_entry_safe(comp_tmp, _comp_tmp,
+                                head, list) {
+               spin_lock_irqsave(&qchan->queue_lock, flags);
+               list_del(&comp_tmp->list);
+               spin_unlock_irqrestore(&qchan->queue_lock, flags);
+               dma_pool_free(qchan->fd_pool,
+                             comp_tmp->fd_virt_addr,
+                             comp_tmp->fd_bus_addr);
+               dma_pool_free(qchan->fl_pool,
+                             comp_tmp->fl_virt_addr,
+                             comp_tmp->fl_bus_addr);
+               dma_pool_free(qchan->sdd_pool,
+                             comp_tmp->desc_virt_addr,
+                             comp_tmp->desc_bus_addr);
+               kfree(comp_tmp);
+       }
+}
+
+static void dpaa2_dpdmai_free_channels(struct dpaa2_qdma_engine *dpaa2_qdma)
+{
+       struct dpaa2_qdma_chan *qchan;
+       int num, i;
+
+       num = dpaa2_qdma->n_chans;
+       for (i = 0; i < num; i++) {
+               qchan = &dpaa2_qdma->chans[i];
+               dpaa2_dpdmai_free_comp(qchan, &qchan->comp_used);
+               dpaa2_dpdmai_free_comp(qchan, &qchan->comp_free);
+               dma_pool_destroy(qchan->fd_pool);
+               dma_pool_destroy(qchan->fl_pool);
+               dma_pool_destroy(qchan->sdd_pool);
+       }
+}
+
+static void dpaa2_qdma_free_desc(struct virt_dma_desc *vdesc)
+{
+       struct dpaa2_qdma_comp *dpaa2_comp;
+       struct dpaa2_qdma_chan *qchan;
+       unsigned long flags;
+
+       dpaa2_comp = to_fsl_qdma_comp(vdesc);
+       qchan = dpaa2_comp->qchan;
+       spin_lock_irqsave(&qchan->queue_lock, flags);
+       list_del(&dpaa2_comp->list);
+       list_add_tail(&dpaa2_comp->list, &qchan->comp_free);
+       spin_unlock_irqrestore(&qchan->queue_lock, flags);
+}
+
+static int dpaa2_dpdmai_init_channels(struct dpaa2_qdma_engine *dpaa2_qdma)
+{
+       struct dpaa2_qdma_priv *priv = dpaa2_qdma->priv;
+       struct dpaa2_qdma_chan *dpaa2_chan;
+       int num = priv->num_pairs;
+       int i;
+
+       INIT_LIST_HEAD(&dpaa2_qdma->dma_dev.channels);
+       for (i = 0; i < dpaa2_qdma->n_chans; i++) {
+               dpaa2_chan = &dpaa2_qdma->chans[i];
+               dpaa2_chan->qdma = dpaa2_qdma;
+               dpaa2_chan->fqid = priv->tx_fqid[i % num];
+               dpaa2_chan->vchan.desc_free = dpaa2_qdma_free_desc;
+               vchan_init(&dpaa2_chan->vchan, &dpaa2_qdma->dma_dev);
+               spin_lock_init(&dpaa2_chan->queue_lock);
+               INIT_LIST_HEAD(&dpaa2_chan->comp_used);
+               INIT_LIST_HEAD(&dpaa2_chan->comp_free);
+       }
+       return 0;
+}
+
+static int dpaa2_qdma_probe(struct fsl_mc_device *dpdmai_dev)
+{
+       struct device *dev = &dpdmai_dev->dev;
+       struct dpaa2_qdma_engine *dpaa2_qdma;
+       struct dpaa2_qdma_priv *priv;
+       int err;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       dev_set_drvdata(dev, priv);
+       priv->dpdmai_dev = dpdmai_dev;
+
+       priv->iommu_domain = iommu_get_domain_for_dev(dev);
+       if (priv->iommu_domain)
+               smmu_disable = false;
+
+       /* obtain a MC portal */
+       err = fsl_mc_portal_allocate(dpdmai_dev, 0, &priv->mc_io);
+       if (err) {
+               if (err == -ENXIO)
+                       err = -EPROBE_DEFER;
+               else
+                       dev_err(dev, "MC portal allocation failed\n");
+               goto err_mcportal;
+       }
+
+       /* DPDMAI initialization */
+       err = dpaa2_qdma_setup(dpdmai_dev);
+       if (err) {
+               dev_err(dev, "dpaa2_dpdmai_setup() failed\n");
+               goto err_dpdmai_setup;
+       }
+
+       /* DPIO */
+       err = dpaa2_qdma_dpio_setup(priv);
+       if (err) {
+               dev_err(dev, "dpaa2_dpdmai_dpio_setup() failed\n");
+               goto err_dpio_setup;
+       }
+
+       /* DPDMAI binding to DPIO */
+       err = dpaa2_dpdmai_bind(priv);
+       if (err) {
+               dev_err(dev, "dpaa2_dpdmai_bind() failed\n");
+               goto err_bind;
+       }
+
+       /* DPDMAI enable */
+       err = dpdmai_enable(priv->mc_io, 0, dpdmai_dev->mc_handle);
+       if (err) {
+               dev_err(dev, "dpdmai_enable() faile\n");
+               goto err_enable;
+       }
+
+       dpaa2_qdma = kzalloc(sizeof(*dpaa2_qdma), GFP_KERNEL);
+       if (!dpaa2_qdma) {
+               err = -ENOMEM;
+               goto err_eng;
+       }
+
+       priv->dpaa2_qdma = dpaa2_qdma;
+       dpaa2_qdma->priv = priv;
+
+       dpaa2_qdma->desc_allocated = 0;
+       dpaa2_qdma->n_chans = NUM_CH;
+
+       dpaa2_dpdmai_init_channels(dpaa2_qdma);
+
+       if (soc_device_match(soc_fixup_tuning))
+               dpaa2_qdma->qdma_wrtype_fixup = true;
+       else
+               dpaa2_qdma->qdma_wrtype_fixup = false;
+
+       dma_cap_set(DMA_PRIVATE, dpaa2_qdma->dma_dev.cap_mask);
+       dma_cap_set(DMA_SLAVE, dpaa2_qdma->dma_dev.cap_mask);
+       dma_cap_set(DMA_MEMCPY, dpaa2_qdma->dma_dev.cap_mask);
+
+       dpaa2_qdma->dma_dev.dev = dev;
+       dpaa2_qdma->dma_dev.device_alloc_chan_resources =
+               dpaa2_qdma_alloc_chan_resources;
+       dpaa2_qdma->dma_dev.device_free_chan_resources =
+               dpaa2_qdma_free_chan_resources;
+       dpaa2_qdma->dma_dev.device_tx_status = dma_cookie_status;
+       dpaa2_qdma->dma_dev.device_prep_dma_memcpy = dpaa2_qdma_prep_memcpy;
+       dpaa2_qdma->dma_dev.device_issue_pending = dpaa2_qdma_issue_pending;
+
+       err = dma_async_device_register(&dpaa2_qdma->dma_dev);
+       if (err) {
+               dev_err(dev, "Can't register NXP QDMA engine.\n");
+               goto err_dpaa2_qdma;
+       }
+
+       return 0;
+
+err_dpaa2_qdma:
+       kfree(dpaa2_qdma);
+err_eng:
+       dpdmai_disable(priv->mc_io, 0, dpdmai_dev->mc_handle);
+err_enable:
+       dpaa2_dpdmai_dpio_unbind(priv);
+err_bind:
+       dpaa2_dpmai_store_free(priv);
+       dpaa2_dpdmai_dpio_free(priv);
+err_dpio_setup:
+       kfree(priv->ppriv);
+       dpdmai_close(priv->mc_io, 0, dpdmai_dev->mc_handle);
+err_dpdmai_setup:
+       fsl_mc_portal_free(priv->mc_io);
+err_mcportal:
+       kfree(priv);
+       dev_set_drvdata(dev, NULL);
+       return err;
+}
+
+static int dpaa2_qdma_remove(struct fsl_mc_device *ls_dev)
+{
+       struct dpaa2_qdma_engine *dpaa2_qdma;
+       struct dpaa2_qdma_priv *priv;
+       struct device *dev;
+
+       dev = &ls_dev->dev;
+       priv = dev_get_drvdata(dev);
+       dpaa2_qdma = priv->dpaa2_qdma;
+
+       dpdmai_disable(priv->mc_io, 0, ls_dev->mc_handle);
+       dpaa2_dpdmai_dpio_unbind(priv);
+       dpaa2_dpmai_store_free(priv);
+       dpaa2_dpdmai_dpio_free(priv);
+       dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);
+       fsl_mc_portal_free(priv->mc_io);
+       dev_set_drvdata(dev, NULL);
+       dpaa2_dpdmai_free_channels(dpaa2_qdma);
+
+       dma_async_device_unregister(&dpaa2_qdma->dma_dev);
+       kfree(priv);
+       kfree(dpaa2_qdma);
+
+       return 0;
+}
+
+static const struct fsl_mc_device_id dpaa2_qdma_id_table[] = {
+       {
+               .vendor = FSL_MC_VENDOR_FREESCALE,
+               .obj_type = "dpdmai",
+       },
+       { .vendor = 0x0 }
+};
+
+static struct fsl_mc_driver dpaa2_qdma_driver = {
+       .driver         = {
+               .name   = "dpaa2-qdma",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = dpaa2_qdma_probe,
+       .remove         = dpaa2_qdma_remove,
+       .match_id_table = dpaa2_qdma_id_table
+};
+
+static int __init dpaa2_qdma_driver_init(void)
+{
+       return fsl_mc_driver_register(&(dpaa2_qdma_driver));
+}
+late_initcall(dpaa2_qdma_driver_init);
+
+static void __exit fsl_qdma_exit(void)
+{
+       fsl_mc_driver_unregister(&(dpaa2_qdma_driver));
+}
+module_exit(fsl_qdma_exit);
+
+MODULE_ALIAS("platform:fsl-dpaa2-qdma");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("NXP Layerscape DPAA2 qDMA engine driver");
diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h
new file mode 100644 (file)
index 0000000..7d57184
--- /dev/null
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2019 NXP */
+
+#ifndef __DPAA2_QDMA_H
+#define __DPAA2_QDMA_H
+
+#define DPAA2_QDMA_STORE_SIZE 16
+#define NUM_CH 8
+
+struct dpaa2_qdma_sd_d {
+       u32 rsv:32;
+       union {
+               struct {
+                       u32 ssd:12; /* souce stride distance */
+                       u32 sss:12; /* souce stride size */
+                       u32 rsv1:8;
+               } sdf;
+               struct {
+                       u32 dsd:12; /* Destination stride distance */
+                       u32 dss:12; /* Destination stride size */
+                       u32 rsv2:8;
+               } ddf;
+       } df;
+       u32 rbpcmd;     /* Route-by-port command */
+       u32 cmd;
+} __attribute__((__packed__));
+
+/* Source descriptor command read transaction type for RBP=0: */
+/* coherent copy of cacheable memory */
+#define QDMA_SD_CMD_RDTTYPE_COHERENT (0xb << 28)
+/* Destination descriptor command write transaction type for RBP=0: */
+/* coherent copy of cacheable memory */
+#define QDMA_DD_CMD_WRTTYPE_COHERENT (0x6 << 28)
+#define LX2160_QDMA_DD_CMD_WRTTYPE_COHERENT (0xb << 28)
+
+#define QMAN_FD_FMT_ENABLE     BIT(0) /* frame list table enable */
+#define QMAN_FD_BMT_ENABLE     BIT(15) /* bypass memory translation */
+#define QMAN_FD_BMT_DISABLE    (0) /* bypass memory translation */
+#define QMAN_FD_SL_DISABLE     (0) /* short lengthe disabled */
+#define QMAN_FD_SL_ENABLE      BIT(14) /* short lengthe enabled */
+
+#define QDMA_FINAL_BIT_DISABLE (0) /* final bit disable */
+#define QDMA_FINAL_BIT_ENABLE  BIT(31) /* final bit enable */
+
+#define QDMA_FD_SHORT_FORMAT   BIT(11) /* short format */
+#define QDMA_FD_LONG_FORMAT    (0) /* long format */
+#define QDMA_SER_DISABLE       (8) /* no notification */
+#define QDMA_SER_CTX           BIT(8) /* notification by FQD_CTX[fqid] */
+#define QDMA_SER_DEST          (2 << 8) /* notification by destination desc */
+#define QDMA_SER_BOTH          (3 << 8) /* soruce and dest notification */
+#define QDMA_FD_SPF_ENALBE     BIT(30) /* source prefetch enable */
+
+#define QMAN_FD_VA_ENABLE      BIT(14) /* Address used is virtual address */
+#define QMAN_FD_VA_DISABLE     (0)/* Address used is a real address */
+/* Flow Context: 49bit physical address */
+#define QMAN_FD_CBMT_ENABLE    BIT(15)
+#define QMAN_FD_CBMT_DISABLE   (0) /* Flow Context: 64bit virtual address */
+#define QMAN_FD_SC_DISABLE     (0) /* stashing control */
+
+#define QDMA_FL_FMT_SBF                (0x0) /* Single buffer frame */
+#define QDMA_FL_FMT_SGE                (0x2) /* Scatter gather frame */
+#define QDMA_FL_BMT_ENABLE     BIT(15) /* enable bypass memory translation */
+#define QDMA_FL_BMT_DISABLE    (0x0) /* enable bypass memory translation */
+#define QDMA_FL_SL_LONG                (0x0)/* long length */
+#define QDMA_FL_SL_SHORT       (0x1) /* short length */
+#define QDMA_FL_F              (0x1)/* last frame list bit */
+
+/*Description of Frame list table structure*/
+struct dpaa2_qdma_chan {
+       struct dpaa2_qdma_engine        *qdma;
+       struct virt_dma_chan            vchan;
+       struct virt_dma_desc            vdesc;
+       enum dma_status                 status;
+       u32                             fqid;
+
+       /* spinlock used by dpaa2 qdma driver */
+       spinlock_t                      queue_lock;
+       struct dma_pool                 *fd_pool;
+       struct dma_pool                 *fl_pool;
+       struct dma_pool                 *sdd_pool;
+
+       struct list_head                comp_used;
+       struct list_head                comp_free;
+
+};
+
+struct dpaa2_qdma_comp {
+       dma_addr_t              fd_bus_addr;
+       dma_addr_t              fl_bus_addr;
+       dma_addr_t              desc_bus_addr;
+       struct dpaa2_fd         *fd_virt_addr;
+       struct dpaa2_fl_entry   *fl_virt_addr;
+       struct dpaa2_qdma_sd_d  *desc_virt_addr;
+       struct dpaa2_qdma_chan  *qchan;
+       struct virt_dma_desc    vdesc;
+       struct list_head        list;
+};
+
+struct dpaa2_qdma_engine {
+       struct dma_device       dma_dev;
+       u32                     n_chans;
+       struct dpaa2_qdma_chan  chans[NUM_CH];
+       int                     qdma_wrtype_fixup;
+       int                     desc_allocated;
+
+       struct dpaa2_qdma_priv *priv;
+};
+
+/*
+ * dpaa2_qdma_priv - driver private data
+ */
+struct dpaa2_qdma_priv {
+       int dpqdma_id;
+
+       struct iommu_domain     *iommu_domain;
+       struct dpdmai_attr      dpdmai_attr;
+       struct device           *dev;
+       struct fsl_mc_io        *mc_io;
+       struct fsl_mc_device    *dpdmai_dev;
+       u8                      num_pairs;
+
+       struct dpaa2_qdma_engine        *dpaa2_qdma;
+       struct dpaa2_qdma_priv_per_prio *ppriv;
+
+       struct dpdmai_rx_queue_attr rx_queue_attr[DPDMAI_PRIO_NUM];
+       u32 tx_fqid[DPDMAI_PRIO_NUM];
+};
+
+struct dpaa2_qdma_priv_per_prio {
+       int req_fqid;
+       int rsp_fqid;
+       int prio;
+
+       struct dpaa2_io_store *store;
+       struct dpaa2_io_notification_ctx nctx;
+
+       struct dpaa2_qdma_priv *priv;
+};
+
+static struct soc_device_attribute soc_fixup_tuning[] = {
+       { .family = "QorIQ LX2160A"},
+       { },
+};
+
+/* FD pool size: one FD + 3 Frame list + 2 source/destination descriptor */
+#define FD_POOL_SIZE (sizeof(struct dpaa2_fd) + \
+               sizeof(struct dpaa2_fl_entry) * 3 + \
+               sizeof(struct dpaa2_qdma_sd_d) * 2)
+
+static void dpaa2_dpdmai_free_channels(struct dpaa2_qdma_engine *dpaa2_qdma);
+static void dpaa2_dpdmai_free_comp(struct dpaa2_qdma_chan *qchan,
+                                  struct list_head *head);
+#endif /* __DPAA2_QDMA_H */
diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c
new file mode 100644 (file)
index 0000000..f8d2211
--- /dev/null
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/fsl/mc.h>
+#include "dpdmai.h"
+
+struct dpdmai_rsp_get_attributes {
+       __le32 id;
+       u8 num_of_priorities;
+       u8 pad0[3];
+       __le16 major;
+       __le16 minor;
+};
+
+struct dpdmai_cmd_queue {
+       __le32 dest_id;
+       u8 priority;
+       u8 queue;
+       u8 dest_type;
+       u8 pad;
+       __le64 user_ctx;
+       union {
+               __le32 options;
+               __le32 fqid;
+       };
+};
+
+struct dpdmai_rsp_get_tx_queue {
+       __le64 pad;
+       __le32 fqid;
+};
+
+#define MC_CMD_OP(_cmd, _param, _offset, _width, _type, _arg) \
+       ((_cmd).params[_param] |= mc_enc((_offset), (_width), _arg))
+
+/* cmd, param, offset, width, type, arg_name */
+#define DPDMAI_CMD_CREATE(cmd, cfg) \
+do { \
+       MC_CMD_OP(cmd, 0, 8,  8,  u8,  (cfg)->priorities[0]);\
+       MC_CMD_OP(cmd, 0, 16, 8,  u8,  (cfg)->priorities[1]);\
+} while (0)
+
+static inline u64 mc_enc(int lsoffset, int width, u64 val)
+{
+       return (val & MAKE_UMASK64(width)) << lsoffset;
+}
+
+/**
+ * dpdmai_open() - Open a control session for the specified object
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @dpdmai_id: DPDMAI unique ID
+ * @token:     Returned token; use in subsequent API calls
+ *
+ * This function can be used to open a control session for an
+ * already created object; an object may have been declared in
+ * the DPL or by calling the dpdmai_create() function.
+ * This function returns a unique authentication token,
+ * associated with the specific object ID and the specific MC
+ * portal; this token must be used in all subsequent commands for
+ * this specific object.
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags,
+               int dpdmai_id, u16 *token)
+{
+       struct fsl_mc_command cmd = { 0 };
+       __le64 *cmd_dpdmai_id;
+       int err;
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_OPEN,
+                                         cmd_flags, 0);
+
+       cmd_dpdmai_id = cmd.params;
+       *cmd_dpdmai_id = cpu_to_le32(dpdmai_id);
+
+       /* send command to mc*/
+       err = mc_send_command(mc_io, &cmd);
+       if (err)
+               return err;
+
+       /* retrieve response parameters */
+       *token = mc_cmd_hdr_read_token(&cmd);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dpdmai_open);
+
+/**
+ * dpdmai_close() - Close the control session of the object
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ *
+ * After this function is called, no further operations are
+ * allowed on the object without opening a new control session.
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+       struct fsl_mc_command cmd = { 0 };
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CLOSE,
+                                         cmd_flags, token);
+
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+}
+EXPORT_SYMBOL_GPL(dpdmai_close);
+
+/**
+ * dpdmai_create() - Create the DPDMAI object
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @cfg:       Configuration structure
+ * @token:     Returned token; use in subsequent API calls
+ *
+ * Create the DPDMAI object, allocate required resources and
+ * perform required initialization.
+ *
+ * The object can be created either by declaring it in the
+ * DPL file, or by calling this function.
+ *
+ * This function returns a unique authentication token,
+ * associated with the specific object ID and the specific MC
+ * portal; this token must be used in all subsequent calls to
+ * this specific object. For objects that are created using the
+ * DPL file, call dpdmai_open() function to get an authentication
+ * token first.
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_create(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                 const struct dpdmai_cfg *cfg, u16 *token)
+{
+       struct fsl_mc_command cmd = { 0 };
+       int err;
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CREATE,
+                                         cmd_flags, 0);
+       DPDMAI_CMD_CREATE(cmd, cfg);
+
+       /* send command to mc*/
+       err = mc_send_command(mc_io, &cmd);
+       if (err)
+               return err;
+
+       /* retrieve response parameters */
+       *token = mc_cmd_hdr_read_token(&cmd);
+
+       return 0;
+}
+
+/**
+ * dpdmai_enable() - Enable the DPDMAI, allow sending and receiving frames.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+       struct fsl_mc_command cmd = { 0 };
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_ENABLE,
+                                         cmd_flags, token);
+
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+}
+EXPORT_SYMBOL_GPL(dpdmai_enable);
+
+/**
+ * dpdmai_disable() - Disable the DPDMAI, stop sending and receiving frames.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+       struct fsl_mc_command cmd = { 0 };
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_DISABLE,
+                                         cmd_flags, token);
+
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+}
+EXPORT_SYMBOL_GPL(dpdmai_disable);
+
+/**
+ * dpdmai_reset() - Reset the DPDMAI, returns the object to initial state.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+       struct fsl_mc_command cmd = { 0 };
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_RESET,
+                                         cmd_flags, token);
+
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+}
+EXPORT_SYMBOL_GPL(dpdmai_reset);
+
+/**
+ * dpdmai_get_attributes() - Retrieve DPDMAI attributes.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ * @attr:      Returned object's attributes
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                         u16 token, struct dpdmai_attr *attr)
+{
+       struct dpdmai_rsp_get_attributes *rsp_params;
+       struct fsl_mc_command cmd = { 0 };
+       int err;
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_ATTR,
+                                         cmd_flags, token);
+
+       /* send command to mc*/
+       err = mc_send_command(mc_io, &cmd);
+       if (err)
+               return err;
+
+       /* retrieve response parameters */
+       rsp_params = (struct dpdmai_rsp_get_attributes *)cmd.params;
+       attr->id = le32_to_cpu(rsp_params->id);
+       attr->version.major = le16_to_cpu(rsp_params->major);
+       attr->version.minor = le16_to_cpu(rsp_params->minor);
+       attr->num_of_priorities = rsp_params->num_of_priorities;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dpdmai_get_attributes);
+
+/**
+ * dpdmai_set_rx_queue() - Set Rx queue configuration
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ * @priority:  Select the queue relative to number of
+ *             priorities configured at DPDMAI creation
+ * @cfg:       Rx queue configuration
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                       u8 priority, const struct dpdmai_rx_queue_cfg *cfg)
+{
+       struct dpdmai_cmd_queue *cmd_params;
+       struct fsl_mc_command cmd = { 0 };
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_SET_RX_QUEUE,
+                                         cmd_flags, token);
+
+       cmd_params = (struct dpdmai_cmd_queue *)cmd.params;
+       cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
+       cmd_params->priority = cfg->dest_cfg.priority;
+       cmd_params->queue = priority;
+       cmd_params->dest_type = cfg->dest_cfg.dest_type;
+       cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx);
+       cmd_params->options = cpu_to_le32(cfg->options);
+
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+}
+EXPORT_SYMBOL_GPL(dpdmai_set_rx_queue);
+
+/**
+ * dpdmai_get_rx_queue() - Retrieve Rx queue attributes.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ * @priority:  Select the queue relative to number of
+ *                             priorities configured at DPDMAI creation
+ * @attr:      Returned Rx queue attributes
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                       u8 priority, struct dpdmai_rx_queue_attr *attr)
+{
+       struct dpdmai_cmd_queue *cmd_params;
+       struct fsl_mc_command cmd = { 0 };
+       int err;
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_RX_QUEUE,
+                                         cmd_flags, token);
+
+       cmd_params = (struct dpdmai_cmd_queue *)cmd.params;
+       cmd_params->queue = priority;
+
+       /* send command to mc*/
+       err = mc_send_command(mc_io, &cmd);
+       if (err)
+               return err;
+
+       /* retrieve response parameters */
+       attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id);
+       attr->dest_cfg.priority = cmd_params->priority;
+       attr->dest_cfg.dest_type = cmd_params->dest_type;
+       attr->user_ctx = le64_to_cpu(cmd_params->user_ctx);
+       attr->fqid = le32_to_cpu(cmd_params->fqid);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dpdmai_get_rx_queue);
+
+/**
+ * dpdmai_get_tx_queue() - Retrieve Tx queue attributes.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPDMAI object
+ * @priority:  Select the queue relative to number of
+ *                     priorities configured at DPDMAI creation
+ * @fqid:      Returned Tx queue
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                       u16 token, u8 priority, u32 *fqid)
+{
+       struct dpdmai_rsp_get_tx_queue *rsp_params;
+       struct dpdmai_cmd_queue *cmd_params;
+       struct fsl_mc_command cmd = { 0 };
+       int err;
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_TX_QUEUE,
+                                         cmd_flags, token);
+
+       cmd_params = (struct dpdmai_cmd_queue *)cmd.params;
+       cmd_params->queue = priority;
+
+       /* send command to mc*/
+       err = mc_send_command(mc_io, &cmd);
+       if (err)
+               return err;
+
+       /* retrieve response parameters */
+
+       rsp_params = (struct dpdmai_rsp_get_tx_queue *)cmd.params;
+       *fqid = le32_to_cpu(rsp_params->fqid);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dpdmai_get_tx_queue);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h
new file mode 100644 (file)
index 0000000..6d78509
--- /dev/null
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2019 NXP */
+
+#ifndef __FSL_DPDMAI_H
+#define __FSL_DPDMAI_H
+
+/* DPDMAI Version */
+#define DPDMAI_VER_MAJOR       2
+#define DPDMAI_VER_MINOR       2
+
+#define DPDMAI_CMD_BASE_VERSION        0
+#define DPDMAI_CMD_ID_OFFSET   4
+
+#define DPDMAI_CMDID_FORMAT(x) (((x) << DPDMAI_CMD_ID_OFFSET) | \
+                               DPDMAI_CMD_BASE_VERSION)
+
+/* Command IDs */
+#define DPDMAI_CMDID_CLOSE             DPDMAI_CMDID_FORMAT(0x800)
+#define DPDMAI_CMDID_OPEN               DPDMAI_CMDID_FORMAT(0x80E)
+#define DPDMAI_CMDID_CREATE             DPDMAI_CMDID_FORMAT(0x90E)
+
+#define DPDMAI_CMDID_ENABLE             DPDMAI_CMDID_FORMAT(0x002)
+#define DPDMAI_CMDID_DISABLE            DPDMAI_CMDID_FORMAT(0x003)
+#define DPDMAI_CMDID_GET_ATTR           DPDMAI_CMDID_FORMAT(0x004)
+#define DPDMAI_CMDID_RESET              DPDMAI_CMDID_FORMAT(0x005)
+#define DPDMAI_CMDID_IS_ENABLED         DPDMAI_CMDID_FORMAT(0x006)
+
+#define DPDMAI_CMDID_SET_IRQ            DPDMAI_CMDID_FORMAT(0x010)
+#define DPDMAI_CMDID_GET_IRQ            DPDMAI_CMDID_FORMAT(0x011)
+#define DPDMAI_CMDID_SET_IRQ_ENABLE     DPDMAI_CMDID_FORMAT(0x012)
+#define DPDMAI_CMDID_GET_IRQ_ENABLE     DPDMAI_CMDID_FORMAT(0x013)
+#define DPDMAI_CMDID_SET_IRQ_MASK       DPDMAI_CMDID_FORMAT(0x014)
+#define DPDMAI_CMDID_GET_IRQ_MASK       DPDMAI_CMDID_FORMAT(0x015)
+#define DPDMAI_CMDID_GET_IRQ_STATUS     DPDMAI_CMDID_FORMAT(0x016)
+#define DPDMAI_CMDID_CLEAR_IRQ_STATUS  DPDMAI_CMDID_FORMAT(0x017)
+
+#define DPDMAI_CMDID_SET_RX_QUEUE      DPDMAI_CMDID_FORMAT(0x1A0)
+#define DPDMAI_CMDID_GET_RX_QUEUE       DPDMAI_CMDID_FORMAT(0x1A1)
+#define DPDMAI_CMDID_GET_TX_QUEUE       DPDMAI_CMDID_FORMAT(0x1A2)
+
+#define MC_CMD_HDR_TOKEN_O 32  /* Token field offset */
+#define MC_CMD_HDR_TOKEN_S 16  /* Token field size */
+
+#define MAKE_UMASK64(_width) \
+       ((u64)((_width) < 64 ? ((u64)1 << (_width)) - 1 : (u64)-1))
+
+/* Data Path DMA Interface API
+ * Contains initialization APIs and runtime control APIs for DPDMAI
+ */
+
+/**
+ * Maximum number of Tx/Rx priorities per DPDMAI object
+ */
+#define DPDMAI_PRIO_NUM                2
+
+/* DPDMAI queue modification options */
+
+/**
+ * Select to modify the user's context associated with the queue
+ */
+#define DPDMAI_QUEUE_OPT_USER_CTX      0x1
+
+/**
+ * Select to modify the queue's destination
+ */
+#define DPDMAI_QUEUE_OPT_DEST          0x2
+
+/**
+ * struct dpdmai_cfg - Structure representing DPDMAI configuration
+ * @priorities: Priorities for the DMA hardware processing; valid priorities are
+ *     configured with values 1-8; the entry following last valid entry
+ *     should be configured with 0
+ */
+struct dpdmai_cfg {
+       u8 priorities[DPDMAI_PRIO_NUM];
+};
+
+/**
+ * struct dpdmai_attr - Structure representing DPDMAI attributes
+ * @id: DPDMAI object ID
+ * @version: DPDMAI version
+ * @num_of_priorities: number of priorities
+ */
+struct dpdmai_attr {
+       int     id;
+       /**
+        * struct version - DPDMAI version
+        * @major: DPDMAI major version
+        * @minor: DPDMAI minor version
+        */
+       struct {
+               u16 major;
+               u16 minor;
+       } version;
+       u8 num_of_priorities;
+};
+
+/**
+ * enum dpdmai_dest - DPDMAI destination types
+ * @DPDMAI_DEST_NONE: Unassigned destination; The queue is set in parked mode
+ *     and does not generate FQDAN notifications; user is expected to dequeue
+ *     from the queue based on polling or other user-defined method
+ * @DPDMAI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN
+ *     notifications to the specified DPIO; user is expected to dequeue
+ *     from the queue only after notification is received
+ * @DPDMAI_DEST_DPCON: The queue is set in schedule mode and does not generate
+ *     FQDAN notifications, but is connected to the specified DPCON object;
+ *     user is expected to dequeue from the DPCON channel
+ */
+enum dpdmai_dest {
+       DPDMAI_DEST_NONE = 0,
+       DPDMAI_DEST_DPIO = 1,
+       DPDMAI_DEST_DPCON = 2
+};
+
+/**
+ * struct dpdmai_dest_cfg - Structure representing DPDMAI destination parameters
+ * @dest_type: Destination type
+ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
+ * @priority: Priority selection within the DPIO or DPCON channel; valid values
+ *     are 0-1 or 0-7, depending on the number of priorities in that
+ *     channel; not relevant for 'DPDMAI_DEST_NONE' option
+ */
+struct dpdmai_dest_cfg {
+       enum dpdmai_dest dest_type;
+       int dest_id;
+       u8 priority;
+};
+
+/**
+ * struct dpdmai_rx_queue_cfg - DPDMAI RX queue configuration
+ * @options: Flags representing the suggested modifications to the queue;
+ *     Use any combination of 'DPDMAI_QUEUE_OPT_<X>' flags
+ * @user_ctx: User context value provided in the frame descriptor of each
+ *     dequeued frame;
+ *     valid only if 'DPDMAI_QUEUE_OPT_USER_CTX' is contained in 'options'
+ * @dest_cfg: Queue destination parameters;
+ *     valid only if 'DPDMAI_QUEUE_OPT_DEST' is contained in 'options'
+ */
+struct dpdmai_rx_queue_cfg {
+       struct dpdmai_dest_cfg dest_cfg;
+       u32 options;
+       u64 user_ctx;
+
+};
+
+/**
+ * struct dpdmai_rx_queue_attr - Structure representing attributes of Rx queues
+ * @user_ctx:  User context value provided in the frame descriptor of each
+ *      dequeued frame
+ * @dest_cfg: Queue destination configuration
+ * @fqid: Virtual FQID value to be used for dequeue operations
+ */
+struct dpdmai_rx_queue_attr {
+       struct dpdmai_dest_cfg  dest_cfg;
+       u64 user_ctx;
+       u32 fqid;
+};
+
+int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags,
+               int dpdmai_id, u16 *token);
+int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+int dpdmai_create(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                 const struct dpdmai_cfg *cfg, u16 *token);
+int dpdmai_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+int dpdmai_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+int dpdmai_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+int dpdmai_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                         u16 token, struct dpdmai_attr *attr);
+int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                       u8 priority, const struct dpdmai_rx_queue_cfg *cfg);
+int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                       u8 priority, struct dpdmai_rx_queue_attr *attr);
+int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                       u16 token, u8 priority, u32 *fqid);
+
+#endif /* __FSL_DPDMAI_H */
index 06664fb..8979208 100644 (file)
@@ -1155,6 +1155,9 @@ static int fsl_qdma_probe(struct platform_device *pdev)
                return ret;
 
        fsl_qdma->irq_base = platform_get_irq_byname(pdev, "qdma-queue0");
+       if (fsl_qdma->irq_base < 0)
+               return fsl_qdma->irq_base;
+
        fsl_qdma->feature = of_property_read_bool(np, "big-endian");
        INIT_LIST_HEAD(&fsl_qdma->dma_dev.channels);
 
index a3f942a..db0e274 100644 (file)
@@ -173,7 +173,7 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
                                        &iop_chan->chain, chain_node) {
                                        zero_sum_result |=
                                            iop_desc_get_zero_result(grp_iter);
-                                           pr_debug("\titer%d result: %d\n",
+                                       pr_debug("\titer%d result: %d\n",
                                            grp_iter->idx, zero_sum_result);
                                        slot_cnt -= slots_per_op;
                                        if (slot_cnt == 0)
@@ -1359,9 +1359,11 @@ static int iop_adma_probe(struct platform_device *pdev)
        iop_adma_device_clear_err_status(iop_chan);
 
        for (i = 0; i < 3; i++) {
-               irq_handler_t handler[] = { iop_adma_eot_handler,
-                                       iop_adma_eoc_handler,
-                                       iop_adma_err_handler };
+               static const irq_handler_t handler[] = {
+                       iop_adma_eot_handler,
+                       iop_adma_eoc_handler,
+                       iop_adma_err_handler
+               };
                int irq = platform_get_irq(pdev, i);
                if (irq < 0) {
                        ret = -ENXIO;
index 4b36c88..adecea5 100644 (file)
@@ -835,13 +835,8 @@ static int k3_dma_probe(struct platform_device *op)
        const struct k3dma_soc_data *soc_data;
        struct k3_dma_dev *d;
        const struct of_device_id *of_id;
-       struct resource *iores;
        int i, ret, irq = 0;
 
-       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -EINVAL;
-
        d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
        if (!d)
                return -ENOMEM;
@@ -850,7 +845,7 @@ static int k3_dma_probe(struct platform_device *op)
        if (!soc_data)
                return -EINVAL;
 
-       d->base = devm_ioremap_resource(&op->dev, iores);
+       d->base = devm_platform_ioremap_resource(op, 0);
        if (IS_ERR(d->base))
                return PTR_ERR(d->base);
 
index 723b11c..6bf838e 100644 (file)
@@ -819,15 +819,7 @@ static int mtk_cqdma_probe(struct platform_device *pdev)
                INIT_LIST_HEAD(&cqdma->pc[i]->queue);
                spin_lock_init(&cqdma->pc[i]->lock);
                refcount_set(&cqdma->pc[i]->refcnt, 0);
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               if (!res) {
-                       dev_err(&pdev->dev, "No mem resource for %s\n",
-                               dev_name(&pdev->dev));
-                       return -EINVAL;
-               }
-
-               cqdma->pc[i]->base = devm_ioremap_resource(&pdev->dev, res);
+               cqdma->pc[i]->base = devm_platform_ioremap_resource(pdev, i);
                if (IS_ERR(cqdma->pc[i]->base))
                        return PTR_ERR(cqdma->pc[i]->base);
 
index 1a2028e..4c58da7 100644 (file)
@@ -997,7 +997,7 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
        if (err) {
                dev_err(&pdev->dev,
                        "request_irq failed with err %d\n", err);
-               goto err_unregister;
+               goto err_free;
        }
 
        platform_set_drvdata(pdev, hsdma);
@@ -1006,6 +1006,8 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
 
        return 0;
 
+err_free:
+       of_dma_controller_free(pdev->dev.of_node);
 err_unregister:
        dma_async_device_unregister(dd);
 
index f40051d..c20e6bd 100644 (file)
@@ -475,7 +475,6 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct mtk_uart_apdmadev *mtkd;
        int bit_mask = 32, rc;
-       struct resource *res;
        struct mtk_chan *c;
        unsigned int i;
 
@@ -532,13 +531,7 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev)
                        goto err_no_dma;
                }
 
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               if (!res) {
-                       rc = -ENODEV;
-                       goto err_no_dma;
-               }
-
-               c->base = devm_ioremap_resource(&pdev->dev, res);
+               c->base = devm_platform_ioremap_resource(pdev, i);
                if (IS_ERR(c->base)) {
                        rc = PTR_ERR(c->base);
                        goto err_no_dma;
diff --git a/drivers/dma/milbeaut-hdmac.c b/drivers/dma/milbeaut-hdmac.c
new file mode 100644 (file)
index 0000000..8853d44
--- /dev/null
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Linaro Ltd.
+// Copyright (C) 2019 Socionext Inc.
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/bitfield.h>
+
+#include "virt-dma.h"
+
+#define MLB_HDMAC_DMACR                0x0     /* global */
+#define MLB_HDMAC_DE           BIT(31)
+#define MLB_HDMAC_DS           BIT(30)
+#define MLB_HDMAC_PR           BIT(28)
+#define MLB_HDMAC_DH           GENMASK(27, 24)
+
+#define MLB_HDMAC_CH_STRIDE    0x10
+
+#define MLB_HDMAC_DMACA                0x0     /* channel */
+#define MLB_HDMAC_EB           BIT(31)
+#define MLB_HDMAC_PB           BIT(30)
+#define MLB_HDMAC_ST           BIT(29)
+#define MLB_HDMAC_IS           GENMASK(28, 24)
+#define MLB_HDMAC_BT           GENMASK(23, 20)
+#define MLB_HDMAC_BC           GENMASK(19, 16)
+#define MLB_HDMAC_TC           GENMASK(15, 0)
+#define MLB_HDMAC_DMACB                0x4
+#define MLB_HDMAC_TT           GENMASK(31, 30)
+#define MLB_HDMAC_MS           GENMASK(29, 28)
+#define MLB_HDMAC_TW           GENMASK(27, 26)
+#define MLB_HDMAC_FS           BIT(25)
+#define MLB_HDMAC_FD           BIT(24)
+#define MLB_HDMAC_RC           BIT(23)
+#define MLB_HDMAC_RS           BIT(22)
+#define MLB_HDMAC_RD           BIT(21)
+#define MLB_HDMAC_EI           BIT(20)
+#define MLB_HDMAC_CI           BIT(19)
+#define HDMAC_PAUSE            0x7
+#define MLB_HDMAC_SS           GENMASK(18, 16)
+#define MLB_HDMAC_SP           GENMASK(15, 12)
+#define MLB_HDMAC_DP           GENMASK(11, 8)
+#define MLB_HDMAC_DMACSA       0x8
+#define MLB_HDMAC_DMACDA       0xc
+
+#define MLB_HDMAC_BUSWIDTHS            (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+                                       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+                                       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
+struct milbeaut_hdmac_desc {
+       struct virt_dma_desc vd;
+       struct scatterlist *sgl;
+       unsigned int sg_len;
+       unsigned int sg_cur;
+       enum dma_transfer_direction dir;
+};
+
+struct milbeaut_hdmac_chan {
+       struct virt_dma_chan vc;
+       struct milbeaut_hdmac_device *mdev;
+       struct milbeaut_hdmac_desc *md;
+       void __iomem *reg_ch_base;
+       unsigned int slave_id;
+       struct dma_slave_config cfg;
+};
+
+struct milbeaut_hdmac_device {
+       struct dma_device ddev;
+       struct clk *clk;
+       void __iomem *reg_base;
+       struct milbeaut_hdmac_chan channels[0];
+};
+
+static struct milbeaut_hdmac_chan *
+to_milbeaut_hdmac_chan(struct virt_dma_chan *vc)
+{
+       return container_of(vc, struct milbeaut_hdmac_chan, vc);
+}
+
+static struct milbeaut_hdmac_desc *
+to_milbeaut_hdmac_desc(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct milbeaut_hdmac_desc, vd);
+}
+
+/* mc->vc.lock must be held by caller */
+static struct milbeaut_hdmac_desc *
+milbeaut_hdmac_next_desc(struct milbeaut_hdmac_chan *mc)
+{
+       struct virt_dma_desc *vd;
+
+       vd = vchan_next_desc(&mc->vc);
+       if (!vd) {
+               mc->md = NULL;
+               return NULL;
+       }
+
+       list_del(&vd->node);
+
+       mc->md = to_milbeaut_hdmac_desc(vd);
+
+       return mc->md;
+}
+
+/* mc->vc.lock must be held by caller */
+static void milbeaut_chan_start(struct milbeaut_hdmac_chan *mc,
+                               struct milbeaut_hdmac_desc *md)
+{
+       struct scatterlist *sg;
+       u32 cb, ca, src_addr, dest_addr, len;
+       u32 width, burst;
+
+       sg = &md->sgl[md->sg_cur];
+       len = sg_dma_len(sg);
+
+       cb = MLB_HDMAC_CI | MLB_HDMAC_EI;
+       if (md->dir == DMA_MEM_TO_DEV) {
+               cb |= MLB_HDMAC_FD;
+               width = mc->cfg.dst_addr_width;
+               burst = mc->cfg.dst_maxburst;
+               src_addr = sg_dma_address(sg);
+               dest_addr = mc->cfg.dst_addr;
+       } else {
+               cb |= MLB_HDMAC_FS;
+               width = mc->cfg.src_addr_width;
+               burst = mc->cfg.src_maxburst;
+               src_addr = mc->cfg.src_addr;
+               dest_addr = sg_dma_address(sg);
+       }
+       cb |= FIELD_PREP(MLB_HDMAC_TW, (width >> 1));
+       cb |= FIELD_PREP(MLB_HDMAC_MS, 2);
+
+       writel_relaxed(MLB_HDMAC_DE, mc->mdev->reg_base + MLB_HDMAC_DMACR);
+       writel_relaxed(src_addr, mc->reg_ch_base + MLB_HDMAC_DMACSA);
+       writel_relaxed(dest_addr, mc->reg_ch_base + MLB_HDMAC_DMACDA);
+       writel_relaxed(cb, mc->reg_ch_base + MLB_HDMAC_DMACB);
+
+       ca = FIELD_PREP(MLB_HDMAC_IS, mc->slave_id);
+       if (burst == 16)
+               ca |= FIELD_PREP(MLB_HDMAC_BT, 0xf);
+       else if (burst == 8)
+               ca |= FIELD_PREP(MLB_HDMAC_BT, 0xd);
+       else if (burst == 4)
+               ca |= FIELD_PREP(MLB_HDMAC_BT, 0xb);
+       burst *= width;
+       ca |= FIELD_PREP(MLB_HDMAC_TC, (len / burst - 1));
+       writel_relaxed(ca, mc->reg_ch_base + MLB_HDMAC_DMACA);
+       ca |= MLB_HDMAC_EB;
+       writel_relaxed(ca, mc->reg_ch_base + MLB_HDMAC_DMACA);
+}
+
+/* mc->vc.lock must be held by caller */
+static void milbeaut_hdmac_start(struct milbeaut_hdmac_chan *mc)
+{
+       struct milbeaut_hdmac_desc *md;
+
+       md = milbeaut_hdmac_next_desc(mc);
+       if (md)
+               milbeaut_chan_start(mc, md);
+}
+
+static irqreturn_t milbeaut_hdmac_interrupt(int irq, void *dev_id)
+{
+       struct milbeaut_hdmac_chan *mc = dev_id;
+       struct milbeaut_hdmac_desc *md;
+       u32 val;
+
+       spin_lock(&mc->vc.lock);
+
+       /* Ack and Disable irqs */
+       val = readl_relaxed(mc->reg_ch_base + MLB_HDMAC_DMACB);
+       val &= ~(FIELD_PREP(MLB_HDMAC_SS, HDMAC_PAUSE));
+       writel_relaxed(val, mc->reg_ch_base + MLB_HDMAC_DMACB);
+       val &= ~MLB_HDMAC_EI;
+       val &= ~MLB_HDMAC_CI;
+       writel_relaxed(val, mc->reg_ch_base + MLB_HDMAC_DMACB);
+
+       md = mc->md;
+       if (!md)
+               goto out;
+
+       md->sg_cur++;
+
+       if (md->sg_cur >= md->sg_len) {
+               vchan_cookie_complete(&md->vd);
+               md = milbeaut_hdmac_next_desc(mc);
+               if (!md)
+                       goto out;
+       }
+
+       milbeaut_chan_start(mc, md);
+
+out:
+       spin_unlock(&mc->vc.lock);
+       return IRQ_HANDLED;
+}
+
+static void milbeaut_hdmac_free_chan_resources(struct dma_chan *chan)
+{
+       vchan_free_chan_resources(to_virt_chan(chan));
+}
+
+static int
+milbeaut_hdmac_chan_config(struct dma_chan *chan, struct dma_slave_config *cfg)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_hdmac_chan *mc = to_milbeaut_hdmac_chan(vc);
+
+       spin_lock(&mc->vc.lock);
+       mc->cfg = *cfg;
+       spin_unlock(&mc->vc.lock);
+
+       return 0;
+}
+
+static int milbeaut_hdmac_chan_pause(struct dma_chan *chan)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_hdmac_chan *mc = to_milbeaut_hdmac_chan(vc);
+       u32 val;
+
+       spin_lock(&mc->vc.lock);
+       val = readl_relaxed(mc->reg_ch_base + MLB_HDMAC_DMACA);
+       val |= MLB_HDMAC_PB;
+       writel_relaxed(val, mc->reg_ch_base + MLB_HDMAC_DMACA);
+       spin_unlock(&mc->vc.lock);
+
+       return 0;
+}
+
+static int milbeaut_hdmac_chan_resume(struct dma_chan *chan)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_hdmac_chan *mc = to_milbeaut_hdmac_chan(vc);
+       u32 val;
+
+       spin_lock(&mc->vc.lock);
+       val = readl_relaxed(mc->reg_ch_base + MLB_HDMAC_DMACA);
+       val &= ~MLB_HDMAC_PB;
+       writel_relaxed(val, mc->reg_ch_base + MLB_HDMAC_DMACA);
+       spin_unlock(&mc->vc.lock);
+
+       return 0;
+}
+
+static struct dma_async_tx_descriptor *
+milbeaut_hdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+                            unsigned int sg_len,
+                            enum dma_transfer_direction direction,
+                            unsigned long flags, void *context)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_hdmac_desc *md;
+       int i;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       md = kzalloc(sizeof(*md), GFP_NOWAIT);
+       if (!md)
+               return NULL;
+
+       md->sgl = kzalloc(sizeof(*sgl) * sg_len, GFP_NOWAIT);
+       if (!md->sgl) {
+               kfree(md);
+               return NULL;
+       }
+
+       for (i = 0; i < sg_len; i++)
+               md->sgl[i] = sgl[i];
+
+       md->sg_len = sg_len;
+       md->dir = direction;
+
+       return vchan_tx_prep(vc, &md->vd, flags);
+}
+
+static int milbeaut_hdmac_terminate_all(struct dma_chan *chan)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_hdmac_chan *mc = to_milbeaut_hdmac_chan(vc);
+       unsigned long flags;
+       u32 val;
+
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&vc->lock, flags);
+
+       val = readl_relaxed(mc->reg_ch_base + MLB_HDMAC_DMACA);
+       val &= ~MLB_HDMAC_EB; /* disable the channel */
+       writel_relaxed(val, mc->reg_ch_base + MLB_HDMAC_DMACA);
+
+       if (mc->md) {
+               vchan_terminate_vdesc(&mc->md->vd);
+               mc->md = NULL;
+       }
+
+       vchan_get_all_descriptors(vc, &head);
+
+       spin_unlock_irqrestore(&vc->lock, flags);
+
+       vchan_dma_desc_free_list(vc, &head);
+
+       return 0;
+}
+
+static void milbeaut_hdmac_synchronize(struct dma_chan *chan)
+{
+       vchan_synchronize(to_virt_chan(chan));
+}
+
+static enum dma_status milbeaut_hdmac_tx_status(struct dma_chan *chan,
+                                               dma_cookie_t cookie,
+                                               struct dma_tx_state *txstate)
+{
+       struct virt_dma_chan *vc;
+       struct virt_dma_desc *vd;
+       struct milbeaut_hdmac_chan *mc;
+       struct milbeaut_hdmac_desc *md = NULL;
+       enum dma_status stat;
+       unsigned long flags;
+       int i;
+
+       stat = dma_cookie_status(chan, cookie, txstate);
+       /* Return immediately if we do not need to compute the residue. */
+       if (stat == DMA_COMPLETE || !txstate)
+               return stat;
+
+       vc = to_virt_chan(chan);
+
+       spin_lock_irqsave(&vc->lock, flags);
+
+       mc = to_milbeaut_hdmac_chan(vc);
+
+       /* residue from the on-flight chunk */
+       if (mc->md && mc->md->vd.tx.cookie == cookie) {
+               struct scatterlist *sg;
+               u32 done;
+
+               md = mc->md;
+               sg = &md->sgl[md->sg_cur];
+
+               if (md->dir == DMA_DEV_TO_MEM)
+                       done = readl_relaxed(mc->reg_ch_base
+                                            + MLB_HDMAC_DMACDA);
+               else
+                       done = readl_relaxed(mc->reg_ch_base
+                                            + MLB_HDMAC_DMACSA);
+               done -= sg_dma_address(sg);
+
+               txstate->residue = -done;
+       }
+
+       if (!md) {
+               vd = vchan_find_desc(vc, cookie);
+               if (vd)
+                       md = to_milbeaut_hdmac_desc(vd);
+       }
+
+       if (md) {
+               /* residue from the queued chunks */
+               for (i = md->sg_cur; i < md->sg_len; i++)
+                       txstate->residue += sg_dma_len(&md->sgl[i]);
+       }
+
+       spin_unlock_irqrestore(&vc->lock, flags);
+
+       return stat;
+}
+
+static void milbeaut_hdmac_issue_pending(struct dma_chan *chan)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_hdmac_chan *mc = to_milbeaut_hdmac_chan(vc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&vc->lock, flags);
+
+       if (vchan_issue_pending(vc) && !mc->md)
+               milbeaut_hdmac_start(mc);
+
+       spin_unlock_irqrestore(&vc->lock, flags);
+}
+
+static void milbeaut_hdmac_desc_free(struct virt_dma_desc *vd)
+{
+       struct milbeaut_hdmac_desc *md = to_milbeaut_hdmac_desc(vd);
+
+       kfree(md->sgl);
+       kfree(md);
+}
+
+static struct dma_chan *
+milbeaut_hdmac_xlate(struct of_phandle_args *dma_spec, struct of_dma *of_dma)
+{
+       struct milbeaut_hdmac_device *mdev = of_dma->of_dma_data;
+       struct milbeaut_hdmac_chan *mc;
+       struct virt_dma_chan *vc;
+       struct dma_chan *chan;
+
+       if (dma_spec->args_count != 1)
+               return NULL;
+
+       chan = dma_get_any_slave_channel(&mdev->ddev);
+       if (!chan)
+               return NULL;
+
+       vc = to_virt_chan(chan);
+       mc = to_milbeaut_hdmac_chan(vc);
+       mc->slave_id = dma_spec->args[0];
+
+       return chan;
+}
+
+static int milbeaut_hdmac_chan_init(struct platform_device *pdev,
+                                   struct milbeaut_hdmac_device *mdev,
+                                   int chan_id)
+{
+       struct device *dev = &pdev->dev;
+       struct milbeaut_hdmac_chan *mc = &mdev->channels[chan_id];
+       char *irq_name;
+       int irq, ret;
+
+       irq = platform_get_irq(pdev, chan_id);
+       if (irq < 0)
+               return irq;
+
+       irq_name = devm_kasprintf(dev, GFP_KERNEL, "milbeaut-hdmac-%d",
+                                 chan_id);
+       if (!irq_name)
+               return -ENOMEM;
+
+       ret = devm_request_irq(dev, irq, milbeaut_hdmac_interrupt,
+                              IRQF_SHARED, irq_name, mc);
+       if (ret)
+               return ret;
+
+       mc->mdev = mdev;
+       mc->reg_ch_base = mdev->reg_base + MLB_HDMAC_CH_STRIDE * (chan_id + 1);
+       mc->vc.desc_free = milbeaut_hdmac_desc_free;
+       vchan_init(&mc->vc, &mdev->ddev);
+
+       return 0;
+}
+
+static int milbeaut_hdmac_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct milbeaut_hdmac_device *mdev;
+       struct dma_device *ddev;
+       int nr_chans, ret, i;
+
+       nr_chans = platform_irq_count(pdev);
+       if (nr_chans < 0)
+               return nr_chans;
+
+       ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
+                           GFP_KERNEL);
+       if (!mdev)
+               return -ENOMEM;
+
+       mdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(mdev->reg_base))
+               return PTR_ERR(mdev->reg_base);
+
+       mdev->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(mdev->clk)) {
+               dev_err(dev, "failed to get clock\n");
+               return PTR_ERR(mdev->clk);
+       }
+
+       ret = clk_prepare_enable(mdev->clk);
+       if (ret)
+               return ret;
+
+       ddev = &mdev->ddev;
+       ddev->dev = dev;
+       dma_cap_set(DMA_SLAVE, ddev->cap_mask);
+       dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
+       ddev->src_addr_widths = MLB_HDMAC_BUSWIDTHS;
+       ddev->dst_addr_widths = MLB_HDMAC_BUSWIDTHS;
+       ddev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+       ddev->device_free_chan_resources = milbeaut_hdmac_free_chan_resources;
+       ddev->device_config = milbeaut_hdmac_chan_config;
+       ddev->device_pause = milbeaut_hdmac_chan_pause;
+       ddev->device_resume = milbeaut_hdmac_chan_resume;
+       ddev->device_prep_slave_sg = milbeaut_hdmac_prep_slave_sg;
+       ddev->device_terminate_all = milbeaut_hdmac_terminate_all;
+       ddev->device_synchronize = milbeaut_hdmac_synchronize;
+       ddev->device_tx_status = milbeaut_hdmac_tx_status;
+       ddev->device_issue_pending = milbeaut_hdmac_issue_pending;
+       INIT_LIST_HEAD(&ddev->channels);
+
+       for (i = 0; i < nr_chans; i++) {
+               ret = milbeaut_hdmac_chan_init(pdev, mdev, i);
+               if (ret)
+                       goto disable_clk;
+       }
+
+       ret = dma_async_device_register(ddev);
+       if (ret)
+               goto disable_clk;
+
+       ret = of_dma_controller_register(dev->of_node,
+                                        milbeaut_hdmac_xlate, mdev);
+       if (ret)
+               goto unregister_dmac;
+
+       platform_set_drvdata(pdev, mdev);
+
+       return 0;
+
+unregister_dmac:
+       dma_async_device_unregister(ddev);
+disable_clk:
+       clk_disable_unprepare(mdev->clk);
+
+       return ret;
+}
+
+static int milbeaut_hdmac_remove(struct platform_device *pdev)
+{
+       struct milbeaut_hdmac_device *mdev = platform_get_drvdata(pdev);
+       struct dma_chan *chan;
+       int ret;
+
+       /*
+        * Before reaching here, almost all descriptors have been freed by the
+        * ->device_free_chan_resources() hook. However, each channel might
+        * be still holding one descriptor that was on-flight at that moment.
+        * Terminate it to make sure this hardware is no longer running. Then,
+        * free the channel resources once again to avoid memory leak.
+        */
+       list_for_each_entry(chan, &mdev->ddev.channels, device_node) {
+               ret = dmaengine_terminate_sync(chan);
+               if (ret)
+                       return ret;
+               milbeaut_hdmac_free_chan_resources(chan);
+       }
+
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&mdev->ddev);
+       clk_disable_unprepare(mdev->clk);
+
+       return 0;
+}
+
+static const struct of_device_id milbeaut_hdmac_match[] = {
+       { .compatible = "socionext,milbeaut-m10v-hdmac" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, milbeaut_hdmac_match);
+
+static struct platform_driver milbeaut_hdmac_driver = {
+       .probe = milbeaut_hdmac_probe,
+       .remove = milbeaut_hdmac_remove,
+       .driver = {
+               .name = "milbeaut-m10v-hdmac",
+               .of_match_table = milbeaut_hdmac_match,
+       },
+};
+module_platform_driver(milbeaut_hdmac_driver);
+
+MODULE_DESCRIPTION("Milbeaut HDMAC DmaEngine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/milbeaut-xdmac.c b/drivers/dma/milbeaut-xdmac.c
new file mode 100644 (file)
index 0000000..ab3d2f3
--- /dev/null
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Linaro Ltd.
+// Copyright (C) 2019 Socionext Inc.
+
+#include <linux/bits.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/bitfield.h>
+
+#include "virt-dma.h"
+
+/* global register */
+#define M10V_XDACS 0x00
+
+/* channel local register */
+#define M10V_XDTBC 0x10
+#define M10V_XDSSA 0x14
+#define M10V_XDDSA 0x18
+#define M10V_XDSAC 0x1C
+#define M10V_XDDAC 0x20
+#define M10V_XDDCC 0x24
+#define M10V_XDDES 0x28
+#define M10V_XDDPC 0x2C
+#define M10V_XDDSD 0x30
+
+#define M10V_XDACS_XE BIT(28)
+
+#define M10V_DEFBS     0x3
+#define M10V_DEFBL     0xf
+
+#define M10V_XDSAC_SBS GENMASK(17, 16)
+#define M10V_XDSAC_SBL GENMASK(11, 8)
+
+#define M10V_XDDAC_DBS GENMASK(17, 16)
+#define M10V_XDDAC_DBL GENMASK(11, 8)
+
+#define M10V_XDDES_CE  BIT(28)
+#define M10V_XDDES_SE  BIT(24)
+#define M10V_XDDES_SA  BIT(15)
+#define M10V_XDDES_TF  GENMASK(23, 20)
+#define M10V_XDDES_EI  BIT(1)
+#define M10V_XDDES_TI  BIT(0)
+
+#define M10V_XDDSD_IS_MASK     GENMASK(3, 0)
+#define M10V_XDDSD_IS_NORMAL   0x8
+
+#define MLB_XDMAC_BUSWIDTHS    (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+
+struct milbeaut_xdmac_desc {
+       struct virt_dma_desc vd;
+       size_t len;
+       dma_addr_t src;
+       dma_addr_t dst;
+};
+
+struct milbeaut_xdmac_chan {
+       struct virt_dma_chan vc;
+       struct milbeaut_xdmac_desc *md;
+       void __iomem *reg_ch_base;
+};
+
+struct milbeaut_xdmac_device {
+       struct dma_device ddev;
+       void __iomem *reg_base;
+       struct milbeaut_xdmac_chan channels[0];
+};
+
+static struct milbeaut_xdmac_chan *
+to_milbeaut_xdmac_chan(struct virt_dma_chan *vc)
+{
+       return container_of(vc, struct milbeaut_xdmac_chan, vc);
+}
+
+static struct milbeaut_xdmac_desc *
+to_milbeaut_xdmac_desc(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct milbeaut_xdmac_desc, vd);
+}
+
+/* mc->vc.lock must be held by caller */
+static struct milbeaut_xdmac_desc *
+milbeaut_xdmac_next_desc(struct milbeaut_xdmac_chan *mc)
+{
+       struct virt_dma_desc *vd;
+
+       vd = vchan_next_desc(&mc->vc);
+       if (!vd) {
+               mc->md = NULL;
+               return NULL;
+       }
+
+       list_del(&vd->node);
+
+       mc->md = to_milbeaut_xdmac_desc(vd);
+
+       return mc->md;
+}
+
+/* mc->vc.lock must be held by caller */
+static void milbeaut_chan_start(struct milbeaut_xdmac_chan *mc,
+                               struct milbeaut_xdmac_desc *md)
+{
+       u32 val;
+
+       /* Setup the channel */
+       val = md->len - 1;
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDTBC);
+
+       val = md->src;
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDSSA);
+
+       val = md->dst;
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDDSA);
+
+       val = readl_relaxed(mc->reg_ch_base + M10V_XDSAC);
+       val &= ~(M10V_XDSAC_SBS | M10V_XDSAC_SBL);
+       val |= FIELD_PREP(M10V_XDSAC_SBS, M10V_DEFBS) |
+               FIELD_PREP(M10V_XDSAC_SBL, M10V_DEFBL);
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDSAC);
+
+       val = readl_relaxed(mc->reg_ch_base + M10V_XDDAC);
+       val &= ~(M10V_XDDAC_DBS | M10V_XDDAC_DBL);
+       val |= FIELD_PREP(M10V_XDDAC_DBS, M10V_DEFBS) |
+               FIELD_PREP(M10V_XDDAC_DBL, M10V_DEFBL);
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDDAC);
+
+       /* Start the channel */
+       val = readl_relaxed(mc->reg_ch_base + M10V_XDDES);
+       val &= ~(M10V_XDDES_CE | M10V_XDDES_SE | M10V_XDDES_TF |
+                M10V_XDDES_EI | M10V_XDDES_TI);
+       val |= FIELD_PREP(M10V_XDDES_CE, 1) | FIELD_PREP(M10V_XDDES_SE, 1) |
+               FIELD_PREP(M10V_XDDES_TF, 1) | FIELD_PREP(M10V_XDDES_EI, 1) |
+               FIELD_PREP(M10V_XDDES_TI, 1);
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDDES);
+}
+
+/* mc->vc.lock must be held by caller */
+static void milbeaut_xdmac_start(struct milbeaut_xdmac_chan *mc)
+{
+       struct milbeaut_xdmac_desc *md;
+
+       md = milbeaut_xdmac_next_desc(mc);
+       if (md)
+               milbeaut_chan_start(mc, md);
+}
+
+static irqreturn_t milbeaut_xdmac_interrupt(int irq, void *dev_id)
+{
+       struct milbeaut_xdmac_chan *mc = dev_id;
+       struct milbeaut_xdmac_desc *md;
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&mc->vc.lock, flags);
+
+       /* Ack and Stop */
+       val = FIELD_PREP(M10V_XDDSD_IS_MASK, 0x0);
+       writel_relaxed(val, mc->reg_ch_base + M10V_XDDSD);
+
+       md = mc->md;
+       if (!md)
+               goto out;
+
+       vchan_cookie_complete(&md->vd);
+
+       milbeaut_xdmac_start(mc);
+out:
+       spin_unlock_irqrestore(&mc->vc.lock, flags);
+       return IRQ_HANDLED;
+}
+
+static void milbeaut_xdmac_free_chan_resources(struct dma_chan *chan)
+{
+       vchan_free_chan_resources(to_virt_chan(chan));
+}
+
+static struct dma_async_tx_descriptor *
+milbeaut_xdmac_prep_memcpy(struct dma_chan *chan, dma_addr_t dst,
+                          dma_addr_t src, size_t len, unsigned long flags)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_xdmac_desc *md;
+
+       md = kzalloc(sizeof(*md), GFP_NOWAIT);
+       if (!md)
+               return NULL;
+
+       md->len = len;
+       md->src = src;
+       md->dst = dst;
+
+       return vchan_tx_prep(vc, &md->vd, flags);
+}
+
+static int milbeaut_xdmac_terminate_all(struct dma_chan *chan)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_xdmac_chan *mc = to_milbeaut_xdmac_chan(vc);
+       unsigned long flags;
+       u32 val;
+
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&vc->lock, flags);
+
+       /* Halt the channel */
+       val = readl(mc->reg_ch_base + M10V_XDDES);
+       val &= ~M10V_XDDES_CE;
+       val |= FIELD_PREP(M10V_XDDES_CE, 0);
+       writel(val, mc->reg_ch_base + M10V_XDDES);
+
+       if (mc->md) {
+               vchan_terminate_vdesc(&mc->md->vd);
+               mc->md = NULL;
+       }
+
+       vchan_get_all_descriptors(vc, &head);
+
+       spin_unlock_irqrestore(&vc->lock, flags);
+
+       vchan_dma_desc_free_list(vc, &head);
+
+       return 0;
+}
+
+static void milbeaut_xdmac_synchronize(struct dma_chan *chan)
+{
+       vchan_synchronize(to_virt_chan(chan));
+}
+
+static void milbeaut_xdmac_issue_pending(struct dma_chan *chan)
+{
+       struct virt_dma_chan *vc = to_virt_chan(chan);
+       struct milbeaut_xdmac_chan *mc = to_milbeaut_xdmac_chan(vc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&vc->lock, flags);
+
+       if (vchan_issue_pending(vc) && !mc->md)
+               milbeaut_xdmac_start(mc);
+
+       spin_unlock_irqrestore(&vc->lock, flags);
+}
+
+static void milbeaut_xdmac_desc_free(struct virt_dma_desc *vd)
+{
+       kfree(to_milbeaut_xdmac_desc(vd));
+}
+
+static int milbeaut_xdmac_chan_init(struct platform_device *pdev,
+                                   struct milbeaut_xdmac_device *mdev,
+                                   int chan_id)
+{
+       struct device *dev = &pdev->dev;
+       struct milbeaut_xdmac_chan *mc = &mdev->channels[chan_id];
+       char *irq_name;
+       int irq, ret;
+
+       irq = platform_get_irq(pdev, chan_id);
+       if (irq < 0)
+               return irq;
+
+       irq_name = devm_kasprintf(dev, GFP_KERNEL, "milbeaut-xdmac-%d",
+                                 chan_id);
+       if (!irq_name)
+               return -ENOMEM;
+
+       ret = devm_request_irq(dev, irq, milbeaut_xdmac_interrupt,
+                              IRQF_SHARED, irq_name, mc);
+       if (ret)
+               return ret;
+
+       mc->reg_ch_base = mdev->reg_base + chan_id * 0x30;
+
+       mc->vc.desc_free = milbeaut_xdmac_desc_free;
+       vchan_init(&mc->vc, &mdev->ddev);
+
+       return 0;
+}
+
+static void enable_xdmac(struct milbeaut_xdmac_device *mdev)
+{
+       unsigned int val;
+
+       val = readl(mdev->reg_base + M10V_XDACS);
+       val |= M10V_XDACS_XE;
+       writel(val, mdev->reg_base + M10V_XDACS);
+}
+
+static void disable_xdmac(struct milbeaut_xdmac_device *mdev)
+{
+       unsigned int val;
+
+       val = readl(mdev->reg_base + M10V_XDACS);
+       val &= ~M10V_XDACS_XE;
+       writel(val, mdev->reg_base + M10V_XDACS);
+}
+
+static int milbeaut_xdmac_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct milbeaut_xdmac_device *mdev;
+       struct dma_device *ddev;
+       int nr_chans, ret, i;
+
+       nr_chans = platform_irq_count(pdev);
+       if (nr_chans < 0)
+               return nr_chans;
+
+       mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
+                           GFP_KERNEL);
+       if (!mdev)
+               return -ENOMEM;
+
+       mdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(mdev->reg_base))
+               return PTR_ERR(mdev->reg_base);
+
+       ddev = &mdev->ddev;
+       ddev->dev = dev;
+       dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
+       ddev->src_addr_widths = MLB_XDMAC_BUSWIDTHS;
+       ddev->dst_addr_widths = MLB_XDMAC_BUSWIDTHS;
+       ddev->device_free_chan_resources = milbeaut_xdmac_free_chan_resources;
+       ddev->device_prep_dma_memcpy = milbeaut_xdmac_prep_memcpy;
+       ddev->device_terminate_all = milbeaut_xdmac_terminate_all;
+       ddev->device_synchronize = milbeaut_xdmac_synchronize;
+       ddev->device_tx_status = dma_cookie_status;
+       ddev->device_issue_pending = milbeaut_xdmac_issue_pending;
+       INIT_LIST_HEAD(&ddev->channels);
+
+       for (i = 0; i < nr_chans; i++) {
+               ret = milbeaut_xdmac_chan_init(pdev, mdev, i);
+               if (ret)
+                       return ret;
+       }
+
+       enable_xdmac(mdev);
+
+       ret = dma_async_device_register(ddev);
+       if (ret)
+               return ret;
+
+       ret = of_dma_controller_register(dev->of_node,
+                                        of_dma_simple_xlate, mdev);
+       if (ret)
+               goto unregister_dmac;
+
+       platform_set_drvdata(pdev, mdev);
+
+       return 0;
+
+unregister_dmac:
+       dma_async_device_unregister(ddev);
+       return ret;
+}
+
+static int milbeaut_xdmac_remove(struct platform_device *pdev)
+{
+       struct milbeaut_xdmac_device *mdev = platform_get_drvdata(pdev);
+       struct dma_chan *chan;
+       int ret;
+
+       /*
+        * Before reaching here, almost all descriptors have been freed by the
+        * ->device_free_chan_resources() hook. However, each channel might
+        * be still holding one descriptor that was on-flight at that moment.
+        * Terminate it to make sure this hardware is no longer running. Then,
+        * free the channel resources once again to avoid memory leak.
+        */
+       list_for_each_entry(chan, &mdev->ddev.channels, device_node) {
+               ret = dmaengine_terminate_sync(chan);
+               if (ret)
+                       return ret;
+               milbeaut_xdmac_free_chan_resources(chan);
+       }
+
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&mdev->ddev);
+
+       disable_xdmac(mdev);
+
+       return 0;
+}
+
+static const struct of_device_id milbeaut_xdmac_match[] = {
+       { .compatible = "socionext,milbeaut-m10v-xdmac" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, milbeaut_xdmac_match);
+
+static struct platform_driver milbeaut_xdmac_driver = {
+       .probe = milbeaut_xdmac_probe,
+       .remove = milbeaut_xdmac_remove,
+       .driver = {
+               .name = "milbeaut-m10v-xdmac",
+               .of_match_table = milbeaut_xdmac_match,
+       },
+};
+module_platform_driver(milbeaut_xdmac_driver);
+
+MODULE_DESCRIPTION("Milbeaut XDMAC DmaEngine driver");
+MODULE_LICENSE("GPL v2");
index 7fe494f..ad06f26 100644 (file)
@@ -945,6 +945,8 @@ static int mmp_pdma_remove(struct platform_device *op)
        struct mmp_pdma_phy *phy;
        int i, irq = 0, irq_num = 0;
 
+       if (op->dev.of_node)
+               of_dma_controller_free(op->dev.of_node);
 
        for (i = 0; i < pdev->dma_channels; i++) {
                if (platform_get_irq(op, i) > 0)
index e7d1e12..10117f2 100644 (file)
@@ -544,6 +544,9 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan)
 
 static int mmp_tdma_remove(struct platform_device *pdev)
 {
+       if (pdev->dev.of_node)
+               of_dma_controller_free(pdev->dev.of_node);
+
        return 0;
 }
 
index 90bbcef..023f951 100644 (file)
@@ -1045,18 +1045,13 @@ static int owl_dma_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct owl_dma *od;
-       struct resource *res;
        int ret, i, nr_channels, nr_requests;
 
        od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
        if (!od)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-
-       od->base = devm_ioremap_resource(&pdev->dev, res);
+       od->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(od->base))
                return PTR_ERR(od->base);
 
diff --git a/drivers/dma/sf-pdma/Kconfig b/drivers/dma/sf-pdma/Kconfig
new file mode 100644 (file)
index 0000000..f8ffa02
--- /dev/null
@@ -0,0 +1,6 @@
+config SF_PDMA
+       tristate "Sifive PDMA controller driver"
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Support the SiFive PDMA controller.
diff --git a/drivers/dma/sf-pdma/Makefile b/drivers/dma/sf-pdma/Makefile
new file mode 100644 (file)
index 0000000..764552a
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SF_PDMA)   += sf-pdma.o
diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c
new file mode 100644 (file)
index 0000000..465256f
--- /dev/null
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SiFive FU540 Platform DMA driver
+ * Copyright (C) 2019 SiFive
+ *
+ * Based partially on:
+ * - drivers/dma/fsl-edma.c
+ * - drivers/dma/dw-edma/
+ * - drivers/dma/pxa-dma.c
+ *
+ * See the following sources for further documentation:
+ * - Chapter 12 "Platform DMA Engine (PDMA)" of
+ *   SiFive FU540-C000 v1.0
+ *   https://static.dev.sifive.com/FU540-C000-v1.0.pdf
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+
+#include "sf-pdma.h"
+
+#ifndef readq
+static inline unsigned long long readq(void __iomem *addr)
+{
+       return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(unsigned long long v, void __iomem *addr)
+{
+       writel(lower_32_bits(v), addr);
+       writel(upper_32_bits(v), addr + 4);
+}
+#endif
+
+static inline struct sf_pdma_chan *to_sf_pdma_chan(struct dma_chan *dchan)
+{
+       return container_of(dchan, struct sf_pdma_chan, vchan.chan);
+}
+
+static inline struct sf_pdma_desc *to_sf_pdma_desc(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct sf_pdma_desc, vdesc);
+}
+
+static struct sf_pdma_desc *sf_pdma_alloc_desc(struct sf_pdma_chan *chan)
+{
+       struct sf_pdma_desc *desc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       if (chan->desc && !chan->desc->in_use) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return chan->desc;
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
+       if (!desc)
+               return NULL;
+
+       desc->chan = chan;
+
+       return desc;
+}
+
+static void sf_pdma_fill_desc(struct sf_pdma_desc *desc,
+                             u64 dst, u64 src, u64 size)
+{
+       desc->xfer_type = PDMA_FULL_SPEED;
+       desc->xfer_size = size;
+       desc->dst_addr = dst;
+       desc->src_addr = src;
+}
+
+static void sf_pdma_disclaim_chan(struct sf_pdma_chan *chan)
+{
+       struct pdma_regs *regs = &chan->regs;
+
+       writel(PDMA_CLEAR_CTRL, regs->ctrl);
+}
+
+static struct dma_async_tx_descriptor *
+sf_pdma_prep_dma_memcpy(struct dma_chan *dchan,        dma_addr_t dest, dma_addr_t src,
+                       size_t len, unsigned long flags)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       struct sf_pdma_desc *desc;
+
+       if (chan && (!len || !dest || !src)) {
+               dev_err(chan->pdma->dma_dev.dev,
+                       "Please check dma len, dest, src!\n");
+               return NULL;
+       }
+
+       desc = sf_pdma_alloc_desc(chan);
+       if (!desc)
+               return NULL;
+
+       desc->in_use = true;
+       desc->dirn = DMA_MEM_TO_MEM;
+       desc->async_tx = vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+       chan->desc = desc;
+       sf_pdma_fill_desc(desc, dest, src, len);
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+       return desc->async_tx;
+}
+
+static int sf_pdma_slave_config(struct dma_chan *dchan,
+                               struct dma_slave_config *cfg)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+
+       memcpy(&chan->cfg, cfg, sizeof(*cfg));
+
+       return 0;
+}
+
+static int sf_pdma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       struct pdma_regs *regs = &chan->regs;
+
+       dma_cookie_init(dchan);
+       writel(PDMA_CLAIM_MASK, regs->ctrl);
+
+       return 0;
+}
+
+static void sf_pdma_disable_request(struct sf_pdma_chan *chan)
+{
+       struct pdma_regs *regs = &chan->regs;
+
+       writel(readl(regs->ctrl) & ~PDMA_RUN_MASK, regs->ctrl);
+}
+
+static void sf_pdma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+       sf_pdma_disable_request(chan);
+       kfree(chan->desc);
+       chan->desc = NULL;
+       vchan_get_all_descriptors(&chan->vchan, &head);
+       vchan_dma_desc_free_list(&chan->vchan, &head);
+       sf_pdma_disclaim_chan(chan);
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+}
+
+static size_t sf_pdma_desc_residue(struct sf_pdma_chan *chan,
+                                  dma_cookie_t cookie)
+{
+       struct virt_dma_desc *vd = NULL;
+       struct pdma_regs *regs = &chan->regs;
+       unsigned long flags;
+       u64 residue = 0;
+       struct sf_pdma_desc *desc;
+       struct dma_async_tx_descriptor *tx;
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+
+       tx = &chan->desc->vdesc.tx;
+       if (cookie == tx->chan->completed_cookie)
+               goto out;
+
+       if (cookie == tx->cookie) {
+               residue = readq(regs->residue);
+       } else {
+               vd = vchan_find_desc(&chan->vchan, cookie);
+               if (!vd)
+                       goto out;
+
+               desc = to_sf_pdma_desc(vd);
+               residue = desc->xfer_size;
+       }
+
+out:
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+       return residue;
+}
+
+static enum dma_status
+sf_pdma_tx_status(struct dma_chan *dchan,
+                 dma_cookie_t cookie,
+                 struct dma_tx_state *txstate)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       enum dma_status status;
+
+       status = dma_cookie_status(dchan, cookie, txstate);
+
+       if (txstate && status != DMA_ERROR)
+               dma_set_residue(txstate, sf_pdma_desc_residue(chan, cookie));
+
+       return status;
+}
+
+static int sf_pdma_terminate_all(struct dma_chan *dchan)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+       sf_pdma_disable_request(chan);
+       kfree(chan->desc);
+       chan->desc = NULL;
+       chan->xfer_err = false;
+       vchan_get_all_descriptors(&chan->vchan, &head);
+       vchan_dma_desc_free_list(&chan->vchan, &head);
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+       return 0;
+}
+
+static void sf_pdma_enable_request(struct sf_pdma_chan *chan)
+{
+       struct pdma_regs *regs = &chan->regs;
+       u32 v;
+
+       v = PDMA_CLAIM_MASK |
+               PDMA_ENABLE_DONE_INT_MASK |
+               PDMA_ENABLE_ERR_INT_MASK |
+               PDMA_RUN_MASK;
+
+       writel(v, regs->ctrl);
+}
+
+static void sf_pdma_xfer_desc(struct sf_pdma_chan *chan)
+{
+       struct sf_pdma_desc *desc = chan->desc;
+       struct pdma_regs *regs = &chan->regs;
+
+       if (!desc) {
+               dev_err(chan->pdma->dma_dev.dev, "NULL desc.\n");
+               return;
+       }
+
+       writel(desc->xfer_type, regs->xfer_type);
+       writeq(desc->xfer_size, regs->xfer_size);
+       writeq(desc->dst_addr, regs->dst_addr);
+       writeq(desc->src_addr, regs->src_addr);
+
+       chan->desc = desc;
+       chan->status = DMA_IN_PROGRESS;
+       sf_pdma_enable_request(chan);
+}
+
+static void sf_pdma_issue_pending(struct dma_chan *dchan)
+{
+       struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+
+       if (vchan_issue_pending(&chan->vchan) && chan->desc)
+               sf_pdma_xfer_desc(chan);
+
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+}
+
+static void sf_pdma_free_desc(struct virt_dma_desc *vdesc)
+{
+       struct sf_pdma_desc *desc;
+
+       desc = to_sf_pdma_desc(vdesc);
+       desc->in_use = false;
+}
+
+static void sf_pdma_donebh_tasklet(unsigned long arg)
+{
+       struct sf_pdma_chan *chan = (struct sf_pdma_chan *)arg;
+       struct sf_pdma_desc *desc = chan->desc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->xfer_err) {
+               chan->retries = MAX_RETRY;
+               chan->status = DMA_COMPLETE;
+               chan->xfer_err = false;
+       }
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       dmaengine_desc_get_callback_invoke(desc->async_tx, NULL);
+}
+
+static void sf_pdma_errbh_tasklet(unsigned long arg)
+{
+       struct sf_pdma_chan *chan = (struct sf_pdma_chan *)arg;
+       struct sf_pdma_desc *desc = chan->desc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->retries <= 0) {
+               /* fail to recover */
+               spin_unlock_irqrestore(&chan->lock, flags);
+               dmaengine_desc_get_callback_invoke(desc->async_tx, NULL);
+       } else {
+               /* retry */
+               chan->retries--;
+               chan->xfer_err = true;
+               chan->status = DMA_ERROR;
+
+               sf_pdma_enable_request(chan);
+               spin_unlock_irqrestore(&chan->lock, flags);
+       }
+}
+
+static irqreturn_t sf_pdma_done_isr(int irq, void *dev_id)
+{
+       struct sf_pdma_chan *chan = dev_id;
+       struct pdma_regs *regs = &chan->regs;
+       unsigned long flags;
+       u64 residue;
+
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+       writel((readl(regs->ctrl)) & ~PDMA_DONE_STATUS_MASK, regs->ctrl);
+       residue = readq(regs->residue);
+
+       if (!residue) {
+               list_del(&chan->desc->vdesc.node);
+               vchan_cookie_complete(&chan->desc->vdesc);
+       } else {
+               /* submit next trascatioin if possible */
+               struct sf_pdma_desc *desc = chan->desc;
+
+               desc->src_addr += desc->xfer_size - residue;
+               desc->dst_addr += desc->xfer_size - residue;
+               desc->xfer_size = residue;
+
+               sf_pdma_xfer_desc(chan);
+       }
+
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+       tasklet_hi_schedule(&chan->done_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sf_pdma_err_isr(int irq, void *dev_id)
+{
+       struct sf_pdma_chan *chan = dev_id;
+       struct pdma_regs *regs = &chan->regs;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       writel((readl(regs->ctrl)) & ~PDMA_ERR_STATUS_MASK, regs->ctrl);
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       tasklet_schedule(&chan->err_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * sf_pdma_irq_init() - Init PDMA IRQ Handlers
+ * @pdev: pointer of platform_device
+ * @pdma: pointer of PDMA engine. Caller should check NULL
+ *
+ * Initialize DONE and ERROR interrupt handler for 4 channels. Caller should
+ * make sure the pointer passed in are non-NULL. This function should be called
+ * only one time during the device probe.
+ *
+ * Context: Any context.
+ *
+ * Return:
+ * * 0         - OK to init all IRQ handlers
+ * * -EINVAL   - Fail to request IRQ
+ */
+static int sf_pdma_irq_init(struct platform_device *pdev, struct sf_pdma *pdma)
+{
+       int irq, r, i;
+       struct sf_pdma_chan *chan;
+
+       for (i = 0; i < pdma->n_chans; i++) {
+               chan = &pdma->chans[i];
+
+               irq = platform_get_irq(pdev, i * 2);
+               if (irq < 0) {
+                       dev_err(&pdev->dev, "ch(%d) Can't get done irq.\n", i);
+                       return -EINVAL;
+               }
+
+               r = devm_request_irq(&pdev->dev, irq, sf_pdma_done_isr, 0,
+                                    dev_name(&pdev->dev), (void *)chan);
+               if (r) {
+                       dev_err(&pdev->dev, "Fail to attach done ISR: %d\n", r);
+                       return -EINVAL;
+               }
+
+               chan->txirq = irq;
+
+               irq = platform_get_irq(pdev, (i * 2) + 1);
+               if (irq < 0) {
+                       dev_err(&pdev->dev, "ch(%d) Can't get err irq.\n", i);
+                       return -EINVAL;
+               }
+
+               r = devm_request_irq(&pdev->dev, irq, sf_pdma_err_isr, 0,
+                                    dev_name(&pdev->dev), (void *)chan);
+               if (r) {
+                       dev_err(&pdev->dev, "Fail to attach err ISR: %d\n", r);
+                       return -EINVAL;
+               }
+
+               chan->errirq = irq;
+       }
+
+       return 0;
+}
+
+/**
+ * sf_pdma_setup_chans() - Init settings of each channel
+ * @pdma: pointer of PDMA engine. Caller should check NULL
+ *
+ * Initialize all data structure and register base. Caller should make sure
+ * the pointer passed in are non-NULL. This function should be called only
+ * one time during the device probe.
+ *
+ * Context: Any context.
+ *
+ * Return: none
+ */
+static void sf_pdma_setup_chans(struct sf_pdma *pdma)
+{
+       int i;
+       struct sf_pdma_chan *chan;
+
+       INIT_LIST_HEAD(&pdma->dma_dev.channels);
+
+       for (i = 0; i < pdma->n_chans; i++) {
+               chan = &pdma->chans[i];
+
+               chan->regs.ctrl =
+                       SF_PDMA_REG_BASE(i) + PDMA_CTRL;
+               chan->regs.xfer_type =
+                       SF_PDMA_REG_BASE(i) + PDMA_XFER_TYPE;
+               chan->regs.xfer_size =
+                       SF_PDMA_REG_BASE(i) + PDMA_XFER_SIZE;
+               chan->regs.dst_addr =
+                       SF_PDMA_REG_BASE(i) + PDMA_DST_ADDR;
+               chan->regs.src_addr =
+                       SF_PDMA_REG_BASE(i) + PDMA_SRC_ADDR;
+               chan->regs.act_type =
+                       SF_PDMA_REG_BASE(i) + PDMA_ACT_TYPE;
+               chan->regs.residue =
+                       SF_PDMA_REG_BASE(i) + PDMA_REMAINING_BYTE;
+               chan->regs.cur_dst_addr =
+                       SF_PDMA_REG_BASE(i) + PDMA_CUR_DST_ADDR;
+               chan->regs.cur_src_addr =
+                       SF_PDMA_REG_BASE(i) + PDMA_CUR_SRC_ADDR;
+
+               chan->pdma = pdma;
+               chan->pm_state = RUNNING;
+               chan->slave_id = i;
+               chan->xfer_err = false;
+               spin_lock_init(&chan->lock);
+
+               chan->vchan.desc_free = sf_pdma_free_desc;
+               vchan_init(&chan->vchan, &pdma->dma_dev);
+
+               writel(PDMA_CLEAR_CTRL, chan->regs.ctrl);
+
+               tasklet_init(&chan->done_tasklet,
+                            sf_pdma_donebh_tasklet, (unsigned long)chan);
+               tasklet_init(&chan->err_tasklet,
+                            sf_pdma_errbh_tasklet, (unsigned long)chan);
+       }
+}
+
+static int sf_pdma_probe(struct platform_device *pdev)
+{
+       struct sf_pdma *pdma;
+       struct sf_pdma_chan *chan;
+       struct resource *res;
+       int len, chans;
+       int ret;
+       const enum dma_slave_buswidth widths =
+               DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES |
+               DMA_SLAVE_BUSWIDTH_4_BYTES | DMA_SLAVE_BUSWIDTH_8_BYTES |
+               DMA_SLAVE_BUSWIDTH_16_BYTES | DMA_SLAVE_BUSWIDTH_32_BYTES |
+               DMA_SLAVE_BUSWIDTH_64_BYTES;
+
+       chans = PDMA_NR_CH;
+       len = sizeof(*pdma) + sizeof(*chan) * chans;
+       pdma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+       if (!pdma)
+               return -ENOMEM;
+
+       pdma->n_chans = chans;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pdma->membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pdma->membase))
+               goto ERR_MEMBASE;
+
+       ret = sf_pdma_irq_init(pdev, pdma);
+       if (ret)
+               goto ERR_INITIRQ;
+
+       sf_pdma_setup_chans(pdma);
+
+       pdma->dma_dev.dev = &pdev->dev;
+
+       /* Setup capability */
+       dma_cap_set(DMA_MEMCPY, pdma->dma_dev.cap_mask);
+       pdma->dma_dev.copy_align = 2;
+       pdma->dma_dev.src_addr_widths = widths;
+       pdma->dma_dev.dst_addr_widths = widths;
+       pdma->dma_dev.directions = BIT(DMA_MEM_TO_MEM);
+       pdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+       pdma->dma_dev.descriptor_reuse = true;
+
+       /* Setup DMA APIs */
+       pdma->dma_dev.device_alloc_chan_resources =
+               sf_pdma_alloc_chan_resources;
+       pdma->dma_dev.device_free_chan_resources =
+               sf_pdma_free_chan_resources;
+       pdma->dma_dev.device_tx_status = sf_pdma_tx_status;
+       pdma->dma_dev.device_prep_dma_memcpy = sf_pdma_prep_dma_memcpy;
+       pdma->dma_dev.device_config = sf_pdma_slave_config;
+       pdma->dma_dev.device_terminate_all = sf_pdma_terminate_all;
+       pdma->dma_dev.device_issue_pending = sf_pdma_issue_pending;
+
+       platform_set_drvdata(pdev, pdma);
+
+       ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+       if (ret)
+               dev_warn(&pdev->dev,
+                        "Failed to set DMA mask. Fall back to default.\n");
+
+       ret = dma_async_device_register(&pdma->dma_dev);
+       if (ret)
+               goto ERR_REG_DMADEVICE;
+
+       return 0;
+
+ERR_MEMBASE:
+       devm_kfree(&pdev->dev, pdma);
+       return PTR_ERR(pdma->membase);
+
+ERR_INITIRQ:
+       devm_kfree(&pdev->dev, pdma);
+       return ret;
+
+ERR_REG_DMADEVICE:
+       devm_kfree(&pdev->dev, pdma);
+       dev_err(&pdev->dev,
+               "Can't register SiFive Platform DMA. (%d)\n", ret);
+       return ret;
+}
+
+static int sf_pdma_remove(struct platform_device *pdev)
+{
+       struct sf_pdma *pdma = platform_get_drvdata(pdev);
+       struct sf_pdma_chan *ch;
+       int i;
+
+       for (i = 0; i < PDMA_NR_CH; i++) {
+               ch = &pdma->chans[i];
+
+               devm_free_irq(&pdev->dev, ch->txirq, ch);
+               devm_free_irq(&pdev->dev, ch->errirq, ch);
+               list_del(&ch->vchan.chan.device_node);
+               tasklet_kill(&ch->vchan.task);
+               tasklet_kill(&ch->done_tasklet);
+               tasklet_kill(&ch->err_tasklet);
+       }
+
+       dma_async_device_unregister(&pdma->dma_dev);
+
+       return 0;
+}
+
+static const struct of_device_id sf_pdma_dt_ids[] = {
+       { .compatible = "sifive,fu540-c000-pdma" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sf_pdma_dt_ids);
+
+static struct platform_driver sf_pdma_driver = {
+       .probe          = sf_pdma_probe,
+       .remove         = sf_pdma_remove,
+       .driver         = {
+               .name   = "sf-pdma",
+               .of_match_table = of_match_ptr(sf_pdma_dt_ids),
+       },
+};
+
+static int __init sf_pdma_init(void)
+{
+       return platform_driver_register(&sf_pdma_driver);
+}
+
+static void __exit sf_pdma_exit(void)
+{
+       platform_driver_unregister(&sf_pdma_driver);
+}
+
+/* do early init */
+subsys_initcall(sf_pdma_init);
+module_exit(sf_pdma_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SiFive Platform DMA driver");
+MODULE_AUTHOR("Green Wan <green.wan@sifive.com>");
diff --git a/drivers/dma/sf-pdma/sf-pdma.h b/drivers/dma/sf-pdma/sf-pdma.h
new file mode 100644 (file)
index 0000000..0c20167
--- /dev/null
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * SiFive FU540 Platform DMA driver
+ * Copyright (C) 2019 SiFive
+ *
+ * Based partially on:
+ * - drivers/dma/fsl-edma.c
+ * - drivers/dma/dw-edma/
+ * - drivers/dma/pxa-dma.c
+ *
+ * See the following sources for further documentation:
+ * - Chapter 12 "Platform DMA Engine (PDMA)" of
+ *   SiFive FU540-C000 v1.0
+ *   https://static.dev.sifive.com/FU540-C000-v1.0.pdf
+ */
+#ifndef _SF_PDMA_H
+#define _SF_PDMA_H
+
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+
+#include "../dmaengine.h"
+#include "../virt-dma.h"
+
+#define PDMA_NR_CH                                     4
+
+#if (PDMA_NR_CH != 4)
+#error "Please define PDMA_NR_CH to 4"
+#endif
+
+#define PDMA_BASE_ADDR                                 0x3000000
+#define PDMA_CHAN_OFFSET                               0x1000
+
+/* Register Offset */
+#define PDMA_CTRL                                      0x000
+#define PDMA_XFER_TYPE                                 0x004
+#define PDMA_XFER_SIZE                                 0x008
+#define PDMA_DST_ADDR                                  0x010
+#define PDMA_SRC_ADDR                                  0x018
+#define PDMA_ACT_TYPE                                  0x104 /* Read-only */
+#define PDMA_REMAINING_BYTE                            0x108 /* Read-only */
+#define PDMA_CUR_DST_ADDR                              0x110 /* Read-only*/
+#define PDMA_CUR_SRC_ADDR                              0x118 /* Read-only*/
+
+/* CTRL */
+#define PDMA_CLEAR_CTRL                                        0x0
+#define PDMA_CLAIM_MASK                                        GENMASK(0, 0)
+#define PDMA_RUN_MASK                                  GENMASK(1, 1)
+#define PDMA_ENABLE_DONE_INT_MASK                      GENMASK(14, 14)
+#define PDMA_ENABLE_ERR_INT_MASK                       GENMASK(15, 15)
+#define PDMA_DONE_STATUS_MASK                          GENMASK(30, 30)
+#define PDMA_ERR_STATUS_MASK                           GENMASK(31, 31)
+
+/* Transfer Type */
+#define PDMA_FULL_SPEED                                        0xFF000008
+
+/* Error Recovery */
+#define MAX_RETRY                                      1
+
+#define SF_PDMA_REG_BASE(ch)   (pdma->membase + (PDMA_CHAN_OFFSET * (ch)))
+
+struct pdma_regs {
+       /* read-write regs */
+       void __iomem *ctrl;             /* 4 bytes */
+
+       void __iomem *xfer_type;        /* 4 bytes */
+       void __iomem *xfer_size;        /* 8 bytes */
+       void __iomem *dst_addr;         /* 8 bytes */
+       void __iomem *src_addr;         /* 8 bytes */
+
+       /* read-only */
+       void __iomem *act_type;         /* 4 bytes */
+       void __iomem *residue;          /* 8 bytes */
+       void __iomem *cur_dst_addr;     /* 8 bytes */
+       void __iomem *cur_src_addr;     /* 8 bytes */
+};
+
+struct sf_pdma_desc {
+       u32                             xfer_type;
+       u64                             xfer_size;
+       u64                             dst_addr;
+       u64                             src_addr;
+       struct virt_dma_desc            vdesc;
+       struct sf_pdma_chan             *chan;
+       bool                            in_use;
+       enum dma_transfer_direction     dirn;
+       struct dma_async_tx_descriptor *async_tx;
+};
+
+enum sf_pdma_pm_state {
+       RUNNING = 0,
+       SUSPENDED,
+};
+
+struct sf_pdma_chan {
+       struct virt_dma_chan            vchan;
+       enum dma_status                 status;
+       enum sf_pdma_pm_state           pm_state;
+       u32                             slave_id;
+       struct sf_pdma                  *pdma;
+       struct sf_pdma_desc             *desc;
+       struct dma_slave_config         cfg;
+       u32                             attr;
+       dma_addr_t                      dma_dev_addr;
+       u32                             dma_dev_size;
+       struct tasklet_struct           done_tasklet;
+       struct tasklet_struct           err_tasklet;
+       struct pdma_regs                regs;
+       spinlock_t                      lock; /* protect chan data */
+       bool                            xfer_err;
+       int                             txirq;
+       int                             errirq;
+       int                             retries;
+};
+
+struct sf_pdma {
+       struct dma_device       dma_dev;
+       void __iomem            *membase;
+       void __iomem            *mappedbase;
+       u32                     n_chans;
+       struct sf_pdma_chan     chans[PDMA_NR_CH];
+};
+
+#endif /* _SF_PDMA_H */
index 3993ab6..f06016d 100644 (file)
@@ -203,19 +203,27 @@ struct rcar_dmac {
 
        unsigned int n_channels;
        struct rcar_dmac_chan *channels;
-       unsigned int channels_mask;
+       u32 channels_mask;
 
        DECLARE_BITMAP(modules, 256);
 };
 
 #define to_rcar_dmac(d)                container_of(d, struct rcar_dmac, engine)
 
+/*
+ * struct rcar_dmac_of_data - This driver's OF data
+ * @chan_offset_base: DMAC channels base offset
+ * @chan_offset_stride: DMAC channels offset stride
+ */
+struct rcar_dmac_of_data {
+       u32 chan_offset_base;
+       u32 chan_offset_stride;
+};
+
 /* -----------------------------------------------------------------------------
  * Registers
  */
 
-#define RCAR_DMAC_CHAN_OFFSET(i)       (0x8000 + 0x80 * (i))
-
 #define RCAR_DMAISTA                   0x0020
 #define RCAR_DMASEC                    0x0030
 #define RCAR_DMAOR                     0x0060
@@ -1726,6 +1734,7 @@ static const struct dev_pm_ops rcar_dmac_pm = {
 
 static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
                                struct rcar_dmac_chan *rchan,
+                               const struct rcar_dmac_of_data *data,
                                unsigned int index)
 {
        struct platform_device *pdev = to_platform_device(dmac->dev);
@@ -1735,7 +1744,8 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
        int ret;
 
        rchan->index = index;
-       rchan->iomem = dmac->iomem + RCAR_DMAC_CHAN_OFFSET(index);
+       rchan->iomem = dmac->iomem + data->chan_offset_base +
+                      data->chan_offset_stride * index;
        rchan->mid_rid = -EINVAL;
 
        spin_lock_init(&rchan->lock);
@@ -1800,7 +1810,15 @@ static int rcar_dmac_parse_of(struct device *dev, struct rcar_dmac *dmac)
                return -EINVAL;
        }
 
+       /*
+        * If the driver is unable to read dma-channel-mask property,
+        * the driver assumes that it can use all channels.
+        */
        dmac->channels_mask = GENMASK(dmac->n_channels - 1, 0);
+       of_property_read_u32(np, "dma-channel-mask", &dmac->channels_mask);
+
+       /* If the property has out-of-channel mask, this driver clears it */
+       dmac->channels_mask &= GENMASK(dmac->n_channels - 1, 0);
 
        return 0;
 }
@@ -1813,10 +1831,14 @@ static int rcar_dmac_probe(struct platform_device *pdev)
                DMA_SLAVE_BUSWIDTH_32_BYTES | DMA_SLAVE_BUSWIDTH_64_BYTES;
        struct dma_device *engine;
        struct rcar_dmac *dmac;
-       struct resource *mem;
+       const struct rcar_dmac_of_data *data;
        unsigned int i;
        int ret;
 
+       data = of_device_get_match_data(&pdev->dev);
+       if (!data)
+               return -EINVAL;
+
        dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
        if (!dmac)
                return -ENOMEM;
@@ -1848,8 +1870,7 @@ static int rcar_dmac_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        /* Request resources. */
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dmac->iomem = devm_ioremap_resource(&pdev->dev, mem);
+       dmac->iomem = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dmac->iomem))
                return PTR_ERR(dmac->iomem);
 
@@ -1901,7 +1922,7 @@ static int rcar_dmac_probe(struct platform_device *pdev)
                if (!(dmac->channels_mask & BIT(i)))
                        continue;
 
-               ret = rcar_dmac_chan_probe(dmac, &dmac->channels[i], i);
+               ret = rcar_dmac_chan_probe(dmac, &dmac->channels[i], data, i);
                if (ret < 0)
                        goto error;
        }
@@ -1948,8 +1969,16 @@ static void rcar_dmac_shutdown(struct platform_device *pdev)
        rcar_dmac_stop_all_chan(dmac);
 }
 
+static const struct rcar_dmac_of_data rcar_dmac_data = {
+       .chan_offset_base = 0x8000,
+       .chan_offset_stride = 0x80,
+};
+
 static const struct of_device_id rcar_dmac_of_ids[] = {
-       { .compatible = "renesas,rcar-dmac", },
+       {
+               .compatible = "renesas,rcar-dmac",
+               .data = &rcar_dmac_data,
+       },
        { /* Sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, rcar_dmac_of_ids);
index 8546ad0..9a31a31 100644 (file)
@@ -99,6 +99,7 @@
 /* DMA_CHN_WARP_* register definition */
 #define SPRD_DMA_HIGH_ADDR_MASK                GENMASK(31, 28)
 #define SPRD_DMA_LOW_ADDR_MASK         GENMASK(31, 0)
+#define SPRD_DMA_WRAP_ADDR_MASK                GENMASK(27, 0)
 #define SPRD_DMA_HIGH_ADDR_OFFSET      4
 
 /* SPRD_DMA_CHN_INTC register definition */
 #define SPRD_DMA_SWT_MODE_OFFSET       26
 #define SPRD_DMA_REQ_MODE_OFFSET       24
 #define SPRD_DMA_REQ_MODE_MASK         GENMASK(1, 0)
+#define SPRD_DMA_WRAP_SEL_DEST         BIT(23)
+#define SPRD_DMA_WRAP_EN               BIT(22)
 #define SPRD_DMA_FIX_SEL_OFFSET                21
 #define SPRD_DMA_FIX_EN_OFFSET         20
 #define SPRD_DMA_LLIST_END             BIT(19)
@@ -804,6 +807,8 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
        temp |= req_mode << SPRD_DMA_REQ_MODE_OFFSET;
        temp |= fix_mode << SPRD_DMA_FIX_SEL_OFFSET;
        temp |= fix_en << SPRD_DMA_FIX_EN_OFFSET;
+       temp |= schan->linklist.wrap_addr ?
+               SPRD_DMA_WRAP_EN | SPRD_DMA_WRAP_SEL_DEST : 0;
        temp |= slave_cfg->src_maxburst & SPRD_DMA_FRG_LEN_MASK;
        hw->frg_len = temp;
 
@@ -831,6 +836,12 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
                hw->llist_ptr = lower_32_bits(llist_ptr);
                hw->src_blk_step = (upper_32_bits(llist_ptr) << SPRD_DMA_LLIST_HIGH_SHIFT) &
                        SPRD_DMA_LLIST_HIGH_MASK;
+
+               if (schan->linklist.wrap_addr) {
+                       hw->wrap_ptr |= schan->linklist.wrap_addr &
+                               SPRD_DMA_WRAP_ADDR_MASK;
+                       hw->wrap_to |= dst & SPRD_DMA_WRAP_ADDR_MASK;
+               }
        } else {
                hw->llist_ptr = 0;
                hw->src_blk_step = 0;
@@ -939,9 +950,11 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
                schan->linklist.phy_addr = ll_cfg->phy_addr;
                schan->linklist.virt_addr = ll_cfg->virt_addr;
+               schan->linklist.wrap_addr = ll_cfg->wrap_addr;
        } else {
                schan->linklist.phy_addr = 0;
                schan->linklist.virt_addr = 0;
+               schan->linklist.wrap_addr = 0;
        }
 
        /*
@@ -1080,7 +1093,6 @@ static int sprd_dma_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct sprd_dma_dev *sdev;
        struct sprd_dma_chn *dma_chn;
-       struct resource *res;
        u32 chn_count;
        int ret, i;
 
@@ -1126,8 +1138,7 @@ static int sprd_dma_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "no interrupts for the dma controller\n");
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sdev->glb_base = devm_ioremap_resource(&pdev->dev, res);
+       sdev->glb_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sdev->glb_base))
                return PTR_ERR(sdev->glb_base);
 
index ba7c4f0..756a3c9 100644 (file)
@@ -260,6 +260,13 @@ struct edma_cc {
         */
        unsigned long *slot_inuse;
 
+       /*
+        * For tracking reserved channels used by DSP.
+        * If the bit is cleared, the channel is allocated to be used by DSP
+        * and Linux must not touch it.
+        */
+       unsigned long *channels_mask;
+
        struct dma_device               dma_slave;
        struct dma_device               *dma_memcpy;
        struct edma_chan                *slave_chans;
@@ -716,6 +723,12 @@ static int edma_alloc_channel(struct edma_chan *echan,
        struct edma_cc *ecc = echan->ecc;
        int channel = EDMA_CHAN_SLOT(echan->ch_num);
 
+       if (!test_bit(echan->ch_num, ecc->channels_mask)) {
+               dev_err(ecc->dev, "Channel%d is reserved, can not be used!\n",
+                       echan->ch_num);
+               return -EINVAL;
+       }
+
        /* ensure access through shadow region 0 */
        edma_or_array2(ecc, EDMA_DRAE, 0, EDMA_REG_ARRAY_INDEX(channel),
                       EDMA_CHANNEL_BIT(channel));
@@ -2249,10 +2262,8 @@ static int edma_probe(struct platform_device *pdev)
 {
        struct edma_soc_info    *info = pdev->dev.platform_data;
        s8                      (*queue_priority_mapping)[2];
-       int                     i, off;
-       const s16               (*rsv_slots)[2];
-       const s16               (*xbar_chans)[2];
-       int                     irq;
+       const s16               (*reserved)[2];
+       int                     i, irq;
        char                    *irq_name;
        struct resource         *mem;
        struct device_node      *node = pdev->dev.of_node;
@@ -2331,15 +2342,32 @@ static int edma_probe(struct platform_device *pdev)
        if (!ecc->slot_inuse)
                return -ENOMEM;
 
+       ecc->channels_mask = devm_kcalloc(dev,
+                                          BITS_TO_LONGS(ecc->num_channels),
+                                          sizeof(unsigned long), GFP_KERNEL);
+       if (!ecc->channels_mask)
+               return -ENOMEM;
+
+       /* Mark all channels available initially */
+       bitmap_fill(ecc->channels_mask, ecc->num_channels);
+
        ecc->default_queue = info->default_queue;
 
        if (info->rsv) {
                /* Set the reserved slots in inuse list */
-               rsv_slots = info->rsv->rsv_slots;
-               if (rsv_slots) {
-                       for (i = 0; rsv_slots[i][0] != -1; i++)
-                               bitmap_set(ecc->slot_inuse, rsv_slots[i][0],
-                                          rsv_slots[i][1]);
+               reserved = info->rsv->rsv_slots;
+               if (reserved) {
+                       for (i = 0; reserved[i][0] != -1; i++)
+                               bitmap_set(ecc->slot_inuse, reserved[i][0],
+                                          reserved[i][1]);
+               }
+
+               /* Clear channels not usable for Linux */
+               reserved = info->rsv->rsv_chans;
+               if (reserved) {
+                       for (i = 0; reserved[i][0] != -1; i++)
+                               bitmap_clear(ecc->channels_mask, reserved[i][0],
+                                            reserved[i][1]);
                }
        }
 
@@ -2349,14 +2377,6 @@ static int edma_probe(struct platform_device *pdev)
                        edma_write_slot(ecc, i, &dummy_paramset);
        }
 
-       /* Clear the xbar mapped channels in unused list */
-       xbar_chans = info->xbar_chans;
-       if (xbar_chans) {
-               for (i = 0; xbar_chans[i][1] != -1; i++) {
-                       off = xbar_chans[i][1];
-               }
-       }
-
        irq = platform_get_irq_byname(pdev, "edma3_ccint");
        if (irq < 0 && node)
                irq = irq_of_parse_and_map(node, 0);
@@ -2399,12 +2419,15 @@ static int edma_probe(struct platform_device *pdev)
 
        if (!ecc->legacy_mode) {
                int lowest_priority = 0;
+               unsigned int array_max;
                struct of_phandle_args tc_args;
 
                ecc->tc_list = devm_kcalloc(dev, ecc->num_tc,
                                            sizeof(*ecc->tc_list), GFP_KERNEL);
-               if (!ecc->tc_list)
-                       return -ENOMEM;
+               if (!ecc->tc_list) {
+                       ret = -ENOMEM;
+                       goto err_reg1;
+               }
 
                for (i = 0;; i++) {
                        ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs",
@@ -2420,6 +2443,18 @@ static int edma_probe(struct platform_device *pdev)
                                info->default_queue = i;
                        }
                }
+
+               /* See if we have optional dma-channel-mask array */
+               array_max = DIV_ROUND_UP(ecc->num_channels, BITS_PER_TYPE(u32));
+               ret = of_property_read_variable_u32_array(node,
+                                               "dma-channel-mask",
+                                               (u32 *)ecc->channels_mask,
+                                               1, array_max);
+               if (ret > 0 && ret != array_max)
+                       dev_warn(dev, "dma-channel-mask is not complete.\n");
+               else if (ret == -EOVERFLOW || ret == -ENODATA)
+                       dev_warn(dev,
+                                "dma-channel-mask is out of range or empty\n");
        }
 
        /* Event queue priority mapping */
@@ -2437,6 +2472,10 @@ static int edma_probe(struct platform_device *pdev)
        edma_dma_init(ecc, legacy_mode);
 
        for (i = 0; i < ecc->num_channels; i++) {
+               /* Do not touch reserved channels */
+               if (!test_bit(i, ecc->channels_mask))
+                       continue;
+
                /* Assign all channels to the default queue */
                edma_assign_channel_eventq(&ecc->slave_chans[i],
                                           info->default_queue);
index fde5468..21b8f11 100644 (file)
@@ -382,7 +382,6 @@ static int uniphier_mdmac_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct uniphier_mdmac_device *mdev;
        struct dma_device *ddev;
-       struct resource *res;
        int nr_chans, ret, i;
 
        nr_chans = platform_irq_count(pdev);
@@ -398,8 +397,7 @@ static int uniphier_mdmac_probe(struct platform_device *pdev)
        if (!mdev)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mdev->reg_base = devm_ioremap_resource(dev, res);
+       mdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mdev->reg_base))
                return PTR_ERR(mdev->reg_base);
 
index 5d56f1e..a9c5d5c 100644 (file)
  * The AXI CDMA, is a soft IP, which provides high-bandwidth Direct Memory
  * Access (DMA) between a memory-mapped source address and a memory-mapped
  * destination address.
+ *
+ * The AXI Multichannel Direct Memory Access (AXI MCDMA) core is a soft
+ * Xilinx IP that provides high-bandwidth direct memory access between
+ * memory and AXI4-Stream target peripherals. It provides scatter gather
+ * (SG) interface with multiple channels independent configuration support.
+ *
  */
 
 #include <linux/bitops.h>
 #define XILINX_DMA_NUM_DESCS           255
 #define XILINX_DMA_NUM_APP_WORDS       5
 
-/* Multi-Channel DMA Descriptor offsets*/
-#define XILINX_DMA_MCRX_CDESC(x)       (0x40 + (x-1) * 0x20)
-#define XILINX_DMA_MCRX_TDESC(x)       (0x48 + (x-1) * 0x20)
-
-/* Multi-Channel DMA Masks/Shifts */
-#define XILINX_DMA_BD_HSIZE_MASK       GENMASK(15, 0)
-#define XILINX_DMA_BD_STRIDE_MASK      GENMASK(15, 0)
-#define XILINX_DMA_BD_VSIZE_MASK       GENMASK(31, 19)
-#define XILINX_DMA_BD_TDEST_MASK       GENMASK(4, 0)
-#define XILINX_DMA_BD_STRIDE_SHIFT     0
-#define XILINX_DMA_BD_VSIZE_SHIFT      19
-
 /* AXI CDMA Specific Registers/Offsets */
 #define XILINX_CDMA_REG_SRCADDR                0x18
 #define XILINX_CDMA_REG_DSTADDR                0x20
 
 #define xilinx_prep_dma_addr_t(addr)   \
        ((dma_addr_t)((u64)addr##_##msb << 32 | (addr)))
+
+/* AXI MCDMA Specific Registers/Offsets */
+#define XILINX_MCDMA_MM2S_CTRL_OFFSET          0x0000
+#define XILINX_MCDMA_S2MM_CTRL_OFFSET          0x0500
+#define XILINX_MCDMA_CHEN_OFFSET               0x0008
+#define XILINX_MCDMA_CH_ERR_OFFSET             0x0010
+#define XILINX_MCDMA_RXINT_SER_OFFSET          0x0020
+#define XILINX_MCDMA_TXINT_SER_OFFSET          0x0028
+#define XILINX_MCDMA_CHAN_CR_OFFSET(x)         (0x40 + (x) * 0x40)
+#define XILINX_MCDMA_CHAN_SR_OFFSET(x)         (0x44 + (x) * 0x40)
+#define XILINX_MCDMA_CHAN_CDESC_OFFSET(x)      (0x48 + (x) * 0x40)
+#define XILINX_MCDMA_CHAN_TDESC_OFFSET(x)      (0x50 + (x) * 0x40)
+
+/* AXI MCDMA Specific Masks/Shifts */
+#define XILINX_MCDMA_COALESCE_SHIFT            16
+#define XILINX_MCDMA_COALESCE_MAX              24
+#define XILINX_MCDMA_IRQ_ALL_MASK              GENMASK(7, 5)
+#define XILINX_MCDMA_COALESCE_MASK             GENMASK(23, 16)
+#define XILINX_MCDMA_CR_RUNSTOP_MASK           BIT(0)
+#define XILINX_MCDMA_IRQ_IOC_MASK              BIT(5)
+#define XILINX_MCDMA_IRQ_DELAY_MASK            BIT(6)
+#define XILINX_MCDMA_IRQ_ERR_MASK              BIT(7)
+#define XILINX_MCDMA_BD_EOP                    BIT(30)
+#define XILINX_MCDMA_BD_SOP                    BIT(31)
+
 /**
  * struct xilinx_vdma_desc_hw - Hardware Descriptor
  * @next_desc: Next Descriptor Pointer @0x00
@@ -221,8 +240,8 @@ struct xilinx_vdma_desc_hw {
  * @next_desc_msb: MSB of Next Descriptor Pointer @0x04
  * @buf_addr: Buffer address @0x08
  * @buf_addr_msb: MSB of Buffer address @0x0C
- * @mcdma_control: Control field for mcdma @0x10
- * @vsize_stride: Vsize and Stride field for mcdma @0x14
+ * @reserved1: Reserved @0x10
+ * @reserved2: Reserved @0x14
  * @control: Control field @0x18
  * @status: Status field @0x1C
  * @app: APP Fields @0x20 - 0x30
@@ -232,13 +251,37 @@ struct xilinx_axidma_desc_hw {
        u32 next_desc_msb;
        u32 buf_addr;
        u32 buf_addr_msb;
-       u32 mcdma_control;
-       u32 vsize_stride;
+       u32 reserved1;
+       u32 reserved2;
        u32 control;
        u32 status;
        u32 app[XILINX_DMA_NUM_APP_WORDS];
 } __aligned(64);
 
+/**
+ * struct xilinx_aximcdma_desc_hw - Hardware Descriptor for AXI MCDMA
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @next_desc_msb: MSB of Next Descriptor Pointer @0x04
+ * @buf_addr: Buffer address @0x08
+ * @buf_addr_msb: MSB of Buffer address @0x0C
+ * @rsvd: Reserved field @0x10
+ * @control: Control Information field @0x14
+ * @status: Status field @0x18
+ * @sideband_status: Status of sideband signals @0x1C
+ * @app: APP Fields @0x20 - 0x30
+ */
+struct xilinx_aximcdma_desc_hw {
+       u32 next_desc;
+       u32 next_desc_msb;
+       u32 buf_addr;
+       u32 buf_addr_msb;
+       u32 rsvd;
+       u32 control;
+       u32 status;
+       u32 sideband_status;
+       u32 app[XILINX_DMA_NUM_APP_WORDS];
+} __aligned(64);
+
 /**
  * struct xilinx_cdma_desc_hw - Hardware Descriptor
  * @next_desc: Next Descriptor Pointer @0x00
@@ -285,6 +328,18 @@ struct xilinx_axidma_tx_segment {
        dma_addr_t phys;
 } __aligned(64);
 
+/**
+ * struct xilinx_aximcdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_aximcdma_tx_segment {
+       struct xilinx_aximcdma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
 /**
  * struct xilinx_cdma_tx_segment - Descriptor segment
  * @hw: Hardware descriptor
@@ -303,12 +358,16 @@ struct xilinx_cdma_tx_segment {
  * @segments: TX segments list
  * @node: Node in the channel descriptors list
  * @cyclic: Check for cyclic transfers.
+ * @err: Whether the descriptor has an error.
+ * @residue: Residue of the completed descriptor
  */
 struct xilinx_dma_tx_descriptor {
        struct dma_async_tx_descriptor async_tx;
        struct list_head segments;
        struct list_head node;
        bool cyclic;
+       bool err;
+       u32 residue;
 };
 
 /**
@@ -339,8 +398,8 @@ struct xilinx_dma_tx_descriptor {
  * @desc_pendingcount: Descriptor pending count
  * @ext_addr: Indicates 64 bit addressing is supported by dma channel
  * @desc_submitcount: Descriptor h/w submitted count
- * @residue: Residue for AXI DMA
  * @seg_v: Statically allocated segments base
+ * @seg_mv: Statically allocated segments base for MCDMA
  * @seg_p: Physical allocated segments base
  * @cyclic_seg_v: Statically allocated segment base for cyclic transfers
  * @cyclic_seg_p: Physical allocated segments base for cyclic dma
@@ -376,8 +435,8 @@ struct xilinx_dma_chan {
        u32 desc_pendingcount;
        bool ext_addr;
        u32 desc_submitcount;
-       u32 residue;
        struct xilinx_axidma_tx_segment *seg_v;
+       struct xilinx_aximcdma_tx_segment *seg_mv;
        dma_addr_t seg_p;
        struct xilinx_axidma_tx_segment *cyclic_seg_v;
        dma_addr_t cyclic_seg_p;
@@ -393,12 +452,14 @@ struct xilinx_dma_chan {
  * @XDMA_TYPE_AXIDMA: Axi dma ip.
  * @XDMA_TYPE_CDMA: Axi cdma ip.
  * @XDMA_TYPE_VDMA: Axi vdma ip.
+ * @XDMA_TYPE_AXIMCDMA: Axi MCDMA ip.
  *
  */
 enum xdma_ip_type {
        XDMA_TYPE_AXIDMA = 0,
        XDMA_TYPE_CDMA,
        XDMA_TYPE_VDMA,
+       XDMA_TYPE_AXIMCDMA
 };
 
 struct xilinx_dma_config {
@@ -406,6 +467,7 @@ struct xilinx_dma_config {
        int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk,
                        struct clk **tx_clk, struct clk **txs_clk,
                        struct clk **rx_clk, struct clk **rxs_clk);
+       irqreturn_t (*irq_handler)(int irq, void *data);
 };
 
 /**
@@ -414,7 +476,6 @@ struct xilinx_dma_config {
  * @dev: Device Structure
  * @common: DMA device structure
  * @chan: Driver specific DMA channel
- * @mcdma: Specifies whether Multi-Channel is present or not
  * @flush_on_fsync: Flush on frame sync
  * @ext_addr: Indicates 64 bit addressing is supported by dma device
  * @pdev: Platform device structure pointer
@@ -427,13 +488,13 @@ struct xilinx_dma_config {
  * @nr_channels: Number of channels DMA device supports
  * @chan_id: DMA channel identifier
  * @max_buffer_len: Max buffer length
+ * @s2mm_index: S2MM channel index
  */
 struct xilinx_dma_device {
        void __iomem *regs;
        struct device *dev;
        struct dma_device common;
        struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE];
-       bool mcdma;
        u32 flush_on_fsync;
        bool ext_addr;
        struct platform_device  *pdev;
@@ -446,6 +507,7 @@ struct xilinx_dma_device {
        u32 nr_channels;
        u32 chan_id;
        u32 max_buffer_len;
+       u32 s2mm_index;
 };
 
 /* Macros */
@@ -546,6 +608,18 @@ static inline void xilinx_axidma_buf(struct xilinx_dma_chan *chan,
        }
 }
 
+static inline void xilinx_aximcdma_buf(struct xilinx_dma_chan *chan,
+                                      struct xilinx_aximcdma_desc_hw *hw,
+                                      dma_addr_t buf_addr, size_t sg_used)
+{
+       if (chan->ext_addr) {
+               hw->buf_addr = lower_32_bits(buf_addr + sg_used);
+               hw->buf_addr_msb = upper_32_bits(buf_addr + sg_used);
+       } else {
+               hw->buf_addr = buf_addr + sg_used;
+       }
+}
+
 /* -----------------------------------------------------------------------------
  * Descriptors and segments alloc and free
  */
@@ -613,6 +687,33 @@ xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan)
        }
        spin_unlock_irqrestore(&chan->lock, flags);
 
+       if (!segment)
+               dev_dbg(chan->dev, "Could not find free tx segment\n");
+
+       return segment;
+}
+
+/**
+ * xilinx_aximcdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_aximcdma_tx_segment *
+xilinx_aximcdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_aximcdma_tx_segment *segment = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (!list_empty(&chan->free_seg_list)) {
+               segment = list_first_entry(&chan->free_seg_list,
+                                          struct xilinx_aximcdma_tx_segment,
+                                          node);
+               list_del(&segment->node);
+       }
+       spin_unlock_irqrestore(&chan->lock, flags);
+
        return segment;
 }
 
@@ -627,6 +728,17 @@ static void xilinx_dma_clean_hw_desc(struct xilinx_axidma_desc_hw *hw)
        hw->next_desc_msb = next_desc_msb;
 }
 
+static void xilinx_mcdma_clean_hw_desc(struct xilinx_aximcdma_desc_hw *hw)
+{
+       u32 next_desc = hw->next_desc;
+       u32 next_desc_msb = hw->next_desc_msb;
+
+       memset(hw, 0, sizeof(struct xilinx_aximcdma_desc_hw));
+
+       hw->next_desc = next_desc;
+       hw->next_desc_msb = next_desc_msb;
+}
+
 /**
  * xilinx_dma_free_tx_segment - Free transaction segment
  * @chan: Driver specific DMA channel
@@ -640,6 +752,20 @@ static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan,
        list_add_tail(&segment->node, &chan->free_seg_list);
 }
 
+/**
+ * xilinx_mcdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_mcdma_free_tx_segment(struct xilinx_dma_chan *chan,
+                                        struct xilinx_aximcdma_tx_segment *
+                                        segment)
+{
+       xilinx_mcdma_clean_hw_desc(&segment->hw);
+
+       list_add_tail(&segment->node, &chan->free_seg_list);
+}
+
 /**
  * xilinx_cdma_free_tx_segment - Free transaction segment
  * @chan: Driver specific DMA channel
@@ -694,6 +820,7 @@ xilinx_dma_free_tx_descriptor(struct xilinx_dma_chan *chan,
        struct xilinx_vdma_tx_segment *segment, *next;
        struct xilinx_cdma_tx_segment *cdma_segment, *cdma_next;
        struct xilinx_axidma_tx_segment *axidma_segment, *axidma_next;
+       struct xilinx_aximcdma_tx_segment *aximcdma_segment, *aximcdma_next;
 
        if (!desc)
                return;
@@ -709,12 +836,18 @@ xilinx_dma_free_tx_descriptor(struct xilinx_dma_chan *chan,
                        list_del(&cdma_segment->node);
                        xilinx_cdma_free_tx_segment(chan, cdma_segment);
                }
-       } else {
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
                list_for_each_entry_safe(axidma_segment, axidma_next,
                                         &desc->segments, node) {
                        list_del(&axidma_segment->node);
                        xilinx_dma_free_tx_segment(chan, axidma_segment);
                }
+       } else {
+               list_for_each_entry_safe(aximcdma_segment, aximcdma_next,
+                                        &desc->segments, node) {
+                       list_del(&aximcdma_segment->node);
+                       xilinx_mcdma_free_tx_segment(chan, aximcdma_segment);
+               }
        }
 
        kfree(desc);
@@ -783,10 +916,61 @@ static void xilinx_dma_free_chan_resources(struct dma_chan *dchan)
                                  chan->cyclic_seg_v, chan->cyclic_seg_p);
        }
 
-       if (chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIDMA) {
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
+               spin_lock_irqsave(&chan->lock, flags);
+               INIT_LIST_HEAD(&chan->free_seg_list);
+               spin_unlock_irqrestore(&chan->lock, flags);
+
+               /* Free memory that is allocated for BD */
+               dma_free_coherent(chan->dev, sizeof(*chan->seg_mv) *
+                                 XILINX_DMA_NUM_DESCS, chan->seg_mv,
+                                 chan->seg_p);
+       }
+
+       if (chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIDMA &&
+           chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIMCDMA) {
                dma_pool_destroy(chan->desc_pool);
                chan->desc_pool = NULL;
        }
+
+}
+
+/**
+ * xilinx_dma_get_residue - Compute residue for a given descriptor
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ *
+ * Return: The number of residue bytes for the descriptor.
+ */
+static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
+                                 struct xilinx_dma_tx_descriptor *desc)
+{
+       struct xilinx_cdma_tx_segment *cdma_seg;
+       struct xilinx_axidma_tx_segment *axidma_seg;
+       struct xilinx_cdma_desc_hw *cdma_hw;
+       struct xilinx_axidma_desc_hw *axidma_hw;
+       struct list_head *entry;
+       u32 residue = 0;
+
+       list_for_each(entry, &desc->segments) {
+               if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+                       cdma_seg = list_entry(entry,
+                                             struct xilinx_cdma_tx_segment,
+                                             node);
+                       cdma_hw = &cdma_seg->hw;
+                       residue += (cdma_hw->control - cdma_hw->status) &
+                                  chan->xdev->max_buffer_len;
+               } else {
+                       axidma_seg = list_entry(entry,
+                                               struct xilinx_axidma_tx_segment,
+                                               node);
+                       axidma_hw = &axidma_seg->hw;
+                       residue += (axidma_hw->control - axidma_hw->status) &
+                                  chan->xdev->max_buffer_len;
+               }
+       }
+
+       return residue;
 }
 
 /**
@@ -823,7 +1007,7 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
        spin_lock_irqsave(&chan->lock, flags);
 
        list_for_each_entry_safe(desc, next, &chan->done_list, node) {
-               struct dmaengine_desc_callback cb;
+               struct dmaengine_result result;
 
                if (desc->cyclic) {
                        xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
@@ -833,14 +1017,22 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
                /* Remove from the list of running transactions */
                list_del(&desc->node);
 
-               /* Run the link descriptor callback function */
-               dmaengine_desc_get_callback(&desc->async_tx, &cb);
-               if (dmaengine_desc_callback_valid(&cb)) {
-                       spin_unlock_irqrestore(&chan->lock, flags);
-                       dmaengine_desc_callback_invoke(&cb, NULL);
-                       spin_lock_irqsave(&chan->lock, flags);
+               if (unlikely(desc->err)) {
+                       if (chan->direction == DMA_DEV_TO_MEM)
+                               result.result = DMA_TRANS_READ_FAILED;
+                       else
+                               result.result = DMA_TRANS_WRITE_FAILED;
+               } else {
+                       result.result = DMA_TRANS_NOERROR;
                }
 
+               result.residue = desc->residue;
+
+               /* Run the link descriptor callback function */
+               spin_unlock_irqrestore(&chan->lock, flags);
+               dmaengine_desc_get_callback_invoke(&desc->async_tx, &result);
+               spin_lock_irqsave(&chan->lock, flags);
+
                /* Run any dependencies, then free the descriptor */
                dma_run_dependencies(&desc->async_tx);
                xilinx_dma_free_tx_descriptor(chan, desc);
@@ -922,6 +1114,30 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
                        list_add_tail(&chan->seg_v[i].node,
                                      &chan->free_seg_list);
                }
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
+               /* Allocate the buffer descriptors. */
+               chan->seg_mv = dma_alloc_coherent(chan->dev,
+                                                 sizeof(*chan->seg_mv) *
+                                                 XILINX_DMA_NUM_DESCS,
+                                                 &chan->seg_p, GFP_KERNEL);
+               if (!chan->seg_mv) {
+                       dev_err(chan->dev,
+                               "unable to allocate channel %d descriptors\n",
+                               chan->id);
+                       return -ENOMEM;
+               }
+               for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) {
+                       chan->seg_mv[i].hw.next_desc =
+                       lower_32_bits(chan->seg_p + sizeof(*chan->seg_mv) *
+                               ((i + 1) % XILINX_DMA_NUM_DESCS));
+                       chan->seg_mv[i].hw.next_desc_msb =
+                       upper_32_bits(chan->seg_p + sizeof(*chan->seg_mv) *
+                               ((i + 1) % XILINX_DMA_NUM_DESCS));
+                       chan->seg_mv[i].phys = chan->seg_p +
+                               sizeof(*chan->seg_v) * i;
+                       list_add_tail(&chan->seg_mv[i].node,
+                                     &chan->free_seg_list);
+               }
        } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
                chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
                                   chan->dev,
@@ -937,7 +1153,8 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
        }
 
        if (!chan->desc_pool &&
-           (chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIDMA)) {
+           ((chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIDMA) &&
+               chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIMCDMA)) {
                dev_err(chan->dev,
                        "unable to allocate channel %d descriptor pool\n",
                        chan->id);
@@ -1003,8 +1220,6 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
 {
        struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
        struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_axidma_tx_segment *segment;
-       struct xilinx_axidma_desc_hw *hw;
        enum dma_status ret;
        unsigned long flags;
        u32 residue = 0;
@@ -1013,23 +1228,20 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
        if (ret == DMA_COMPLETE || !txstate)
                return ret;
 
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               spin_lock_irqsave(&chan->lock, flags);
+       spin_lock_irqsave(&chan->lock, flags);
 
-               desc = list_last_entry(&chan->active_list,
-                                      struct xilinx_dma_tx_descriptor, node);
-               if (chan->has_sg) {
-                       list_for_each_entry(segment, &desc->segments, node) {
-                               hw = &segment->hw;
-                               residue += (hw->control - hw->status) &
-                                          chan->xdev->max_buffer_len;
-                       }
-               }
-               spin_unlock_irqrestore(&chan->lock, flags);
+       desc = list_last_entry(&chan->active_list,
+                              struct xilinx_dma_tx_descriptor, node);
+       /*
+        * VDMA and simple mode do not support residue reporting, so the
+        * residue field will always be 0.
+        */
+       if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA)
+               residue = xilinx_dma_get_residue(chan, desc);
 
-               chan->residue = residue;
-               dma_set_residue(txstate, chan->residue);
-       }
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       dma_set_residue(txstate, residue);
 
        return ret;
 }
@@ -1301,53 +1513,23 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
                dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
        }
 
-       if (chan->has_sg && !chan->xdev->mcdma)
+       if (chan->has_sg)
                xilinx_write(chan, XILINX_DMA_REG_CURDESC,
                             head_desc->async_tx.phys);
 
-       if (chan->has_sg && chan->xdev->mcdma) {
-               if (chan->direction == DMA_MEM_TO_DEV) {
-                       dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                                      head_desc->async_tx.phys);
-               } else {
-                       if (!chan->tdest) {
-                               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                                      head_desc->async_tx.phys);
-                       } else {
-                               dma_ctrl_write(chan,
-                                       XILINX_DMA_MCRX_CDESC(chan->tdest),
-                                      head_desc->async_tx.phys);
-                       }
-               }
-       }
-
        xilinx_dma_start(chan);
 
        if (chan->err)
                return;
 
        /* Start the transfer */
-       if (chan->has_sg && !chan->xdev->mcdma) {
+       if (chan->has_sg) {
                if (chan->cyclic)
                        xilinx_write(chan, XILINX_DMA_REG_TAILDESC,
                                     chan->cyclic_seg_v->phys);
                else
                        xilinx_write(chan, XILINX_DMA_REG_TAILDESC,
                                     tail_segment->phys);
-       } else if (chan->has_sg && chan->xdev->mcdma) {
-               if (chan->direction == DMA_MEM_TO_DEV) {
-                       dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                              tail_segment->phys);
-               } else {
-                       if (!chan->tdest) {
-                               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                                              tail_segment->phys);
-                       } else {
-                               dma_ctrl_write(chan,
-                                       XILINX_DMA_MCRX_TDESC(chan->tdest),
-                                       tail_segment->phys);
-                       }
-               }
        } else {
                struct xilinx_axidma_tx_segment *segment;
                struct xilinx_axidma_desc_hw *hw;
@@ -1370,6 +1552,76 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
        chan->idle = false;
 }
 
+/**
+ * xilinx_mcdma_start_transfer - Starts MCDMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_mcdma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
+       struct xilinx_axidma_tx_segment *tail_segment;
+       u32 reg;
+
+       /*
+        * lock has been held by calling functions, so we don't need it
+        * to take it here again.
+        */
+
+       if (chan->err)
+               return;
+
+       if (!chan->idle)
+               return;
+
+       if (list_empty(&chan->pending_list))
+               return;
+
+       head_desc = list_first_entry(&chan->pending_list,
+                                    struct xilinx_dma_tx_descriptor, node);
+       tail_desc = list_last_entry(&chan->pending_list,
+                                   struct xilinx_dma_tx_descriptor, node);
+       tail_segment = list_last_entry(&tail_desc->segments,
+                                      struct xilinx_axidma_tx_segment, node);
+
+       reg = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_CR_OFFSET(chan->tdest));
+
+       if (chan->desc_pendingcount <= XILINX_MCDMA_COALESCE_MAX) {
+               reg &= ~XILINX_MCDMA_COALESCE_MASK;
+               reg |= chan->desc_pendingcount <<
+                       XILINX_MCDMA_COALESCE_SHIFT;
+       }
+
+       reg |= XILINX_MCDMA_IRQ_ALL_MASK;
+       dma_ctrl_write(chan, XILINX_MCDMA_CHAN_CR_OFFSET(chan->tdest), reg);
+
+       /* Program current descriptor */
+       xilinx_write(chan, XILINX_MCDMA_CHAN_CDESC_OFFSET(chan->tdest),
+                    head_desc->async_tx.phys);
+
+       /* Program channel enable register */
+       reg = dma_ctrl_read(chan, XILINX_MCDMA_CHEN_OFFSET);
+       reg |= BIT(chan->tdest);
+       dma_ctrl_write(chan, XILINX_MCDMA_CHEN_OFFSET, reg);
+
+       /* Start the fetch of BDs for the channel */
+       reg = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_CR_OFFSET(chan->tdest));
+       reg |= XILINX_MCDMA_CR_RUNSTOP_MASK;
+       dma_ctrl_write(chan, XILINX_MCDMA_CHAN_CR_OFFSET(chan->tdest), reg);
+
+       xilinx_dma_start(chan);
+
+       if (chan->err)
+               return;
+
+       /* Start the transfer */
+       xilinx_write(chan, XILINX_MCDMA_CHAN_TDESC_OFFSET(chan->tdest),
+                    tail_segment->phys);
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       chan->desc_pendingcount = 0;
+       chan->idle = false;
+}
+
 /**
  * xilinx_dma_issue_pending - Issue pending transactions
  * @dchan: DMA channel
@@ -1399,6 +1651,13 @@ static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
                return;
 
        list_for_each_entry_safe(desc, next, &chan->active_list, node) {
+               if (chan->has_sg && chan->xdev->dma_config->dmatype !=
+                   XDMA_TYPE_VDMA)
+                       desc->residue = xilinx_dma_get_residue(chan, desc);
+               else
+                       desc->residue = 0;
+               desc->err = chan->err;
+
                list_del(&desc->node);
                if (!desc->cyclic)
                        dma_cookie_complete(&desc->async_tx);
@@ -1433,6 +1692,7 @@ static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
 
        chan->err = false;
        chan->idle = true;
+       chan->desc_pendingcount = 0;
        chan->desc_submitcount = 0;
 
        return err;
@@ -1460,6 +1720,74 @@ static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
        return 0;
 }
 
+/**
+ * xilinx_mcdma_irq_handler - MCDMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the Xilinx MCDMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data)
+{
+       struct xilinx_dma_chan *chan = data;
+       u32 status, ser_offset, chan_sermask, chan_offset = 0, chan_id;
+
+       if (chan->direction == DMA_DEV_TO_MEM)
+               ser_offset = XILINX_MCDMA_RXINT_SER_OFFSET;
+       else
+               ser_offset = XILINX_MCDMA_TXINT_SER_OFFSET;
+
+       /* Read the channel id raising the interrupt*/
+       chan_sermask = dma_ctrl_read(chan, ser_offset);
+       chan_id = ffs(chan_sermask);
+
+       if (!chan_id)
+               return IRQ_NONE;
+
+       if (chan->direction == DMA_DEV_TO_MEM)
+               chan_offset = chan->xdev->s2mm_index;
+
+       chan_offset = chan_offset + (chan_id - 1);
+       chan = chan->xdev->chan[chan_offset];
+       /* Read the status and ack the interrupts. */
+       status = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest));
+       if (!(status & XILINX_MCDMA_IRQ_ALL_MASK))
+               return IRQ_NONE;
+
+       dma_ctrl_write(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest),
+                      status & XILINX_MCDMA_IRQ_ALL_MASK);
+
+       if (status & XILINX_MCDMA_IRQ_ERR_MASK) {
+               dev_err(chan->dev, "Channel %p has errors %x cdr %x tdr %x\n",
+                       chan,
+                       dma_ctrl_read(chan, XILINX_MCDMA_CH_ERR_OFFSET),
+                       dma_ctrl_read(chan, XILINX_MCDMA_CHAN_CDESC_OFFSET
+                                     (chan->tdest)),
+                       dma_ctrl_read(chan, XILINX_MCDMA_CHAN_TDESC_OFFSET
+                                     (chan->tdest)));
+               chan->err = true;
+       }
+
+       if (status & XILINX_MCDMA_IRQ_DELAY_MASK) {
+               /*
+                * Device takes too long to do the transfer when user requires
+                * responsiveness.
+                */
+               dev_dbg(chan->dev, "Inter-packet latency too long\n");
+       }
+
+       if (status & XILINX_MCDMA_IRQ_IOC_MASK) {
+               spin_lock(&chan->lock);
+               xilinx_dma_complete_descriptor(chan);
+               chan->idle = true;
+               chan->start_transfer(chan);
+               spin_unlock(&chan->lock);
+       }
+
+       tasklet_schedule(&chan->tasklet);
+       return IRQ_HANDLED;
+}
+
 /**
  * xilinx_dma_irq_handler - DMA Interrupt handler
  * @irq: IRQ number
@@ -1967,31 +2295,32 @@ error:
 }
 
 /**
- * xilinx_dma_prep_interleaved - prepare a descriptor for a
- *     DMA_SLAVE transaction
+ * xilinx_mcdma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
  * @dchan: DMA channel
- * @xt: Interleaved template pointer
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
  * @flags: transfer ack flags
+ * @context: APP words of the descriptor
  *
  * Return: Async transaction descriptor on success and NULL on failure
  */
 static struct dma_async_tx_descriptor *
-xilinx_dma_prep_interleaved(struct dma_chan *dchan,
-                                struct dma_interleaved_template *xt,
-                                unsigned long flags)
+xilinx_mcdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+                          unsigned int sg_len,
+                          enum dma_transfer_direction direction,
+                          unsigned long flags, void *context)
 {
        struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
        struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_axidma_tx_segment *segment;
-       struct xilinx_axidma_desc_hw *hw;
-
-       if (!is_slave_direction(xt->dir))
-               return NULL;
-
-       if (!xt->numf || !xt->sgl[0].size)
-               return NULL;
+       struct xilinx_aximcdma_tx_segment *segment = NULL;
+       u32 *app_w = (u32 *)context;
+       struct scatterlist *sg;
+       size_t copy;
+       size_t sg_used;
+       unsigned int i;
 
-       if (xt->frame_size != 1)
+       if (!is_slave_direction(direction))
                return NULL;
 
        /* Allocate a transaction descriptor. */
@@ -1999,54 +2328,67 @@ xilinx_dma_prep_interleaved(struct dma_chan *dchan,
        if (!desc)
                return NULL;
 
-       chan->direction = xt->dir;
        dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
        desc->async_tx.tx_submit = xilinx_dma_tx_submit;
 
-       /* Get a free segment */
-       segment = xilinx_axidma_alloc_tx_segment(chan);
-       if (!segment)
-               goto error;
+       /* Build transactions using information in the scatter gather list */
+       for_each_sg(sgl, sg, sg_len, i) {
+               sg_used = 0;
 
-       hw = &segment->hw;
+               /* Loop until the entire scatterlist entry is used */
+               while (sg_used < sg_dma_len(sg)) {
+                       struct xilinx_aximcdma_desc_hw *hw;
 
-       /* Fill in the descriptor */
-       if (xt->dir != DMA_MEM_TO_DEV)
-               hw->buf_addr = xt->dst_start;
-       else
-               hw->buf_addr = xt->src_start;
+                       /* Get a free segment */
+                       segment = xilinx_aximcdma_alloc_tx_segment(chan);
+                       if (!segment)
+                               goto error;
 
-       hw->mcdma_control = chan->tdest & XILINX_DMA_BD_TDEST_MASK;
-       hw->vsize_stride = (xt->numf << XILINX_DMA_BD_VSIZE_SHIFT) &
-                           XILINX_DMA_BD_VSIZE_MASK;
-       hw->vsize_stride |= (xt->sgl[0].icg + xt->sgl[0].size) &
-                           XILINX_DMA_BD_STRIDE_MASK;
-       hw->control = xt->sgl[0].size & XILINX_DMA_BD_HSIZE_MASK;
+                       /*
+                        * Calculate the maximum number of bytes to transfer,
+                        * making sure it is less than the hw limit
+                        */
+                       copy = min_t(size_t, sg_dma_len(sg) - sg_used,
+                                    chan->xdev->max_buffer_len);
+                       hw = &segment->hw;
 
-       /*
-        * Insert the segment into the descriptor segments
-        * list.
-        */
-       list_add_tail(&segment->node, &desc->segments);
+                       /* Fill in the descriptor */
+                       xilinx_aximcdma_buf(chan, hw, sg_dma_address(sg),
+                                           sg_used);
+                       hw->control = copy;
 
+                       if (chan->direction == DMA_MEM_TO_DEV && app_w) {
+                               memcpy(hw->app, app_w, sizeof(u32) *
+                                      XILINX_DMA_NUM_APP_WORDS);
+                       }
+
+                       sg_used += copy;
+                       /*
+                        * Insert the segment into the descriptor segments
+                        * list.
+                        */
+                       list_add_tail(&segment->node, &desc->segments);
+               }
+       }
 
        segment = list_first_entry(&desc->segments,
-                                  struct xilinx_axidma_tx_segment, node);
+                                  struct xilinx_aximcdma_tx_segment, node);
        desc->async_tx.phys = segment->phys;
 
        /* For the last DMA_MEM_TO_DEV transfer, set EOP */
-       if (xt->dir == DMA_MEM_TO_DEV) {
-               segment->hw.control |= XILINX_DMA_BD_SOP;
+       if (chan->direction == DMA_MEM_TO_DEV) {
+               segment->hw.control |= XILINX_MCDMA_BD_SOP;
                segment = list_last_entry(&desc->segments,
-                                         struct xilinx_axidma_tx_segment,
+                                         struct xilinx_aximcdma_tx_segment,
                                          node);
-               segment->hw.control |= XILINX_DMA_BD_EOP;
+               segment->hw.control |= XILINX_MCDMA_BD_EOP;
        }
 
        return &desc->async_tx;
 
 error:
        xilinx_dma_free_tx_descriptor(chan, desc);
+
        return NULL;
 }
 
@@ -2194,7 +2536,9 @@ static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
        *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
        if (IS_ERR(*axi_clk)) {
                err = PTR_ERR(*axi_clk);
-               dev_err(&pdev->dev, "failed to get axi_aclk (%d)\n", err);
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get axi_aclk (%d)\n",
+                               err);
                return err;
        }
 
@@ -2259,14 +2603,18 @@ static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
        *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
        if (IS_ERR(*axi_clk)) {
                err = PTR_ERR(*axi_clk);
-               dev_err(&pdev->dev, "failed to get axi_clk (%d)\n", err);
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get axi_clk (%d)\n",
+                               err);
                return err;
        }
 
        *dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk");
        if (IS_ERR(*dev_clk)) {
                err = PTR_ERR(*dev_clk);
-               dev_err(&pdev->dev, "failed to get dev_clk (%d)\n", err);
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get dev_clk (%d)\n",
+                               err);
                return err;
        }
 
@@ -2299,7 +2647,9 @@ static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
        *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
        if (IS_ERR(*axi_clk)) {
                err = PTR_ERR(*axi_clk);
-               dev_err(&pdev->dev, "failed to get axi_aclk (%d)\n", err);
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get axi_aclk (%d)\n",
+                               err);
                return err;
        }
 
@@ -2321,7 +2671,8 @@ static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
 
        err = clk_prepare_enable(*axi_clk);
        if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%d)\n", err);
+               dev_err(&pdev->dev, "failed to enable axi_clk (%d)\n",
+                       err);
                return err;
        }
 
@@ -2454,6 +2805,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
                                           "xlnx,axi-dma-s2mm-channel")) {
                chan->direction = DMA_DEV_TO_MEM;
                chan->id = chan_id;
+               xdev->s2mm_index = xdev->nr_channels;
                chan->tdest = chan_id - xdev->nr_channels;
                chan->has_vflip = of_property_read_bool(node,
                                        "xlnx,enable-vert-flip");
@@ -2463,7 +2815,11 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
                                XILINX_VDMA_ENABLE_VERTICAL_FLIP;
                }
 
-               chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
+               if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA)
+                       chan->ctrl_offset = XILINX_MCDMA_S2MM_CTRL_OFFSET;
+               else
+                       chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
+
                if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
                        chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
                        chan->config.park = 1;
@@ -2478,9 +2834,9 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
        }
 
        /* Request the interrupt */
-       chan->irq = irq_of_parse_and_map(node, 0);
-       err = request_irq(chan->irq, xilinx_dma_irq_handler, IRQF_SHARED,
-                         "xilinx-dma-controller", chan);
+       chan->irq = irq_of_parse_and_map(node, chan->tdest);
+       err = request_irq(chan->irq, xdev->dma_config->irq_handler,
+                         IRQF_SHARED, "xilinx-dma-controller", chan);
        if (err) {
                dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
                return err;
@@ -2489,6 +2845,9 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
        if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
                chan->start_transfer = xilinx_dma_start_transfer;
                chan->stop_transfer = xilinx_dma_stop_transfer;
+       } else if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
+               chan->start_transfer = xilinx_mcdma_start_transfer;
+               chan->stop_transfer = xilinx_dma_stop_transfer;
        } else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
                chan->start_transfer = xilinx_cdma_start_transfer;
                chan->stop_transfer = xilinx_cdma_stop_transfer;
@@ -2545,7 +2904,7 @@ static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev,
        int ret, i, nr_channels = 1;
 
        ret = of_property_read_u32(node, "dma-channels", &nr_channels);
-       if ((ret < 0) && xdev->mcdma)
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA && ret < 0)
                dev_warn(xdev->dev, "missing dma-channels property\n");
 
        for (i = 0; i < nr_channels; i++)
@@ -2578,22 +2937,31 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
 static const struct xilinx_dma_config axidma_config = {
        .dmatype = XDMA_TYPE_AXIDMA,
        .clk_init = axidma_clk_init,
+       .irq_handler = xilinx_dma_irq_handler,
 };
 
+static const struct xilinx_dma_config aximcdma_config = {
+       .dmatype = XDMA_TYPE_AXIMCDMA,
+       .clk_init = axidma_clk_init,
+       .irq_handler = xilinx_mcdma_irq_handler,
+};
 static const struct xilinx_dma_config axicdma_config = {
        .dmatype = XDMA_TYPE_CDMA,
        .clk_init = axicdma_clk_init,
+       .irq_handler = xilinx_dma_irq_handler,
 };
 
 static const struct xilinx_dma_config axivdma_config = {
        .dmatype = XDMA_TYPE_VDMA,
        .clk_init = axivdma_clk_init,
+       .irq_handler = xilinx_dma_irq_handler,
 };
 
 static const struct of_device_id xilinx_dma_of_ids[] = {
        { .compatible = "xlnx,axi-dma-1.00.a", .data = &axidma_config },
        { .compatible = "xlnx,axi-cdma-1.00.a", .data = &axicdma_config },
        { .compatible = "xlnx,axi-vdma-1.00.a", .data = &axivdma_config },
+       { .compatible = "xlnx,axi-mcdma-1.00.a", .data = &aximcdma_config },
        {}
 };
 MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
@@ -2612,7 +2980,6 @@ static int xilinx_dma_probe(struct platform_device *pdev)
        struct device_node *node = pdev->dev.of_node;
        struct xilinx_dma_device *xdev;
        struct device_node *child, *np = pdev->dev.of_node;
-       struct resource *io;
        u32 num_frames, addr_width, len_width;
        int i, err;
 
@@ -2638,16 +3005,15 @@ static int xilinx_dma_probe(struct platform_device *pdev)
                return err;
 
        /* Request and map I/O memory */
-       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xdev->regs = devm_ioremap_resource(&pdev->dev, io);
+       xdev->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xdev->regs))
                return PTR_ERR(xdev->regs);
 
        /* Retrieve the DMA engine properties from the device tree */
        xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0);
 
-       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma");
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA ||
+           xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
                if (!of_property_read_u32(node, "xlnx,sg-length-width",
                                          &len_width)) {
                        if (len_width < XILINX_DMA_MAX_TRANS_LEN_MIN ||
@@ -2712,14 +3078,17 @@ static int xilinx_dma_probe(struct platform_device *pdev)
                xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg;
                xdev->common.device_prep_dma_cyclic =
                                          xilinx_dma_prep_dma_cyclic;
-               xdev->common.device_prep_interleaved_dma =
-                                       xilinx_dma_prep_interleaved;
-               /* Residue calculation is supported by only AXI DMA */
+               /* Residue calculation is supported by only AXI DMA and CDMA */
                xdev->common.residue_granularity =
                                          DMA_RESIDUE_GRANULARITY_SEGMENT;
        } else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
                dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
                xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
+               /* Residue calculation is supported by only AXI DMA and CDMA */
+               xdev->common.residue_granularity =
+                                         DMA_RESIDUE_GRANULARITY_SEGMENT;
+       } else if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
+               xdev->common.device_prep_slave_sg = xilinx_mcdma_prep_slave_sg;
        } else {
                xdev->common.device_prep_interleaved_dma =
                                xilinx_vdma_dma_prep_interleaved;
@@ -2755,6 +3124,8 @@ static int xilinx_dma_probe(struct platform_device *pdev)
                dev_info(&pdev->dev, "Xilinx AXI DMA Engine Driver Probed!!\n");
        else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA)
                dev_info(&pdev->dev, "Xilinx AXI CDMA Engine Driver Probed!!\n");
+       else if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA)
+               dev_info(&pdev->dev, "Xilinx AXI MCDMA Engine Driver Probed!!\n");
        else
                dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n");
 
index 9f4436f..5fe2e8b 100644 (file)
@@ -754,18 +754,13 @@ static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
 static int zx_dma_probe(struct platform_device *op)
 {
        struct zx_dma_dev *d;
-       struct resource *iores;
        int i, ret = 0;
 
-       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -EINVAL;
-
        d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
        if (!d)
                return -ENOMEM;
 
-       d->base = devm_ioremap_resource(&op->dev, iores);
+       d->base = devm_platform_ioremap_resource(op, 0);
        if (IS_ERR(d->base))
                return PTR_ERR(d->base);
 
@@ -894,7 +889,6 @@ static int zx_dma_remove(struct platform_device *op)
                list_del(&c->vc.chan.device_node);
        }
        clk_disable_unprepare(d->clk);
-       dmam_pool_destroy(d->pool);
 
        return 0;
 }
index c777088..6e291d8 100644 (file)
@@ -1686,7 +1686,8 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
        if (ret < 0)
                goto fail;
 
-       ret = fw_iso_buffer_map_vma(&client->buffer, vma);
+       ret = vm_map_pages_zero(vma, client->buffer.pages,
+                               client->buffer.page_count);
        if (ret < 0)
                goto fail;
 
index df8a56a..185b0b7 100644 (file)
@@ -91,13 +91,6 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_iso_buffer_init);
 
-int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
-                         struct vm_area_struct *vma)
-{
-       return vm_map_pages_zero(vma, buffer->pages,
-                                       buffer->page_count);
-}
-
 void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
                           struct fw_card *card)
 {
index 0f0bed3..4b0e4ee 100644 (file)
@@ -158,8 +158,6 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
 int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count);
 int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
                          enum dma_data_direction direction);
-int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
-                         struct vm_area_struct *vma);
 
 
 /* -topology */
index 522f3ad..3326931 100644 (file)
@@ -1752,7 +1752,7 @@ static u32 update_bus_time(struct fw_ohci *ohci)
 
        if (unlikely(!ohci->bus_time_running)) {
                reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_cycle64Seconds);
-               ohci->bus_time = (lower_32_bits(get_seconds()) & ~0x7f) |
+               ohci->bus_time = (lower_32_bits(ktime_get_seconds()) & ~0x7f) |
                                 (cycle_time_seconds & 0x40);
                ohci->bus_time_running = true;
        }
index 4a8012e..601af4e 100644 (file)
@@ -323,7 +323,7 @@ static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
 
                if (db->mask)
                        val = ioread64_hi_lo(db->addr) & db->mask;
-               iowrite64_hi_lo(db->set, db->addr);
+               iowrite64_hi_lo(db->set | val, db->addr);
        }
 #endif
 }
index 1e21fc3..2045566 100644 (file)
@@ -35,6 +35,7 @@ static struct dmi_memdev_info {
        const char *bank;
        u64 size;               /* bytes */
        u16 handle;
+       u8 type;                /* DDR2, DDR3, DDR4 etc */
 } *dmi_memdev;
 static int dmi_memdev_nr;
 
@@ -391,7 +392,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v)
        u64 bytes;
        u16 size;
 
-       if (dm->type != DMI_ENTRY_MEM_DEVICE || dm->length < 0x12)
+       if (dm->type != DMI_ENTRY_MEM_DEVICE || dm->length < 0x13)
                return;
        if (nr >= dmi_memdev_nr) {
                pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n");
@@ -400,6 +401,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v)
        dmi_memdev[nr].handle = get_unaligned(&dm->handle);
        dmi_memdev[nr].device = dmi_string(dm, d[0x10]);
        dmi_memdev[nr].bank = dmi_string(dm, d[0x11]);
+       dmi_memdev[nr].type = d[0x12];
 
        size = get_unaligned((u16 *)&d[0xC]);
        if (size == 0)
@@ -1128,3 +1130,40 @@ u64 dmi_memdev_size(u16 handle)
        return ~0ull;
 }
 EXPORT_SYMBOL_GPL(dmi_memdev_size);
+
+/**
+ * dmi_memdev_type - get the memory type
+ * @handle: DMI structure handle
+ *
+ * Return the DMI memory type of the module in the slot associated with the
+ * given DMI handle, or 0x0 if no such DMI handle exists.
+ */
+u8 dmi_memdev_type(u16 handle)
+{
+       int n;
+
+       if (dmi_memdev) {
+               for (n = 0; n < dmi_memdev_nr; n++) {
+                       if (handle == dmi_memdev[n].handle)
+                               return dmi_memdev[n].type;
+               }
+       }
+       return 0x0;     /* Not a valid value */
+}
+EXPORT_SYMBOL_GPL(dmi_memdev_type);
+
+/**
+ *     dmi_memdev_handle - get the DMI handle of a memory slot
+ *     @slot: slot number
+ *
+ *     Return the DMI handle associated with a given memory slot, or %0xFFFF
+ *      if there is no such slot.
+ */
+u16 dmi_memdev_handle(int slot)
+{
+       if (dmi_memdev && slot >= 0 && slot < dmi_memdev_nr)
+               return dmi_memdev[slot].handle;
+
+       return 0xffff;  /* Not a valid value */
+}
+EXPORT_SYMBOL_GPL(dmi_memdev_handle);
index a43d2db..4265e9d 100644 (file)
@@ -114,7 +114,7 @@ static int imx_dsp_probe(struct platform_device *pdev)
 
        dev_info(dev, "NXP i.MX DSP IPC initialized\n");
 
-       return devm_of_platform_populate(dev);
+       return 0;
 out:
        kfree(chan_name);
        for (j = 0; j < i; j++) {
index 687121f..db655e8 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <dt-bindings/firmware/imx/rsrc.h>
 #include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/sci.h>
 #include <linux/mailbox_client.h>
 
 #define IMX_SC_IRQ_FUNC_ENABLE 1
index 04a24a8..03b43b7 100644 (file)
@@ -107,6 +107,12 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
        struct imx_sc_rpc_msg *hdr;
        u32 *data = msg;
 
+       if (!sc_ipc->msg) {
+               dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n",
+                               sc_chan->idx, *data);
+               return;
+       }
+
        if (sc_chan->idx == 0) {
                hdr = msg;
                sc_ipc->rx_size = hdr->size;
@@ -156,6 +162,7 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
  */
 int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
 {
+       uint8_t saved_svc, saved_func;
        struct imx_sc_rpc_msg *hdr;
        int ret;
 
@@ -165,7 +172,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
        mutex_lock(&sc_ipc->lock);
        reinit_completion(&sc_ipc->done);
 
-       sc_ipc->msg = msg;
+       if (have_resp) {
+               sc_ipc->msg = msg;
+               saved_svc = ((struct imx_sc_rpc_msg *)msg)->svc;
+               saved_func = ((struct imx_sc_rpc_msg *)msg)->func;
+       }
        sc_ipc->count = 0;
        ret = imx_scu_ipc_write(sc_ipc, msg);
        if (ret < 0) {
@@ -184,9 +195,20 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
                /* response status is stored in hdr->func field */
                hdr = msg;
                ret = hdr->func;
+               /*
+                * Some special SCU firmware APIs do NOT have return value
+                * in hdr->func, but they do have response data, those special
+                * APIs are defined as void function in SCU firmware, so they
+                * should be treated as return success always.
+                */
+               if ((saved_svc == IMX_SC_RPC_SVC_MISC) &&
+                       (saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID ||
+                        saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS))
+                       ret = 0;
        }
 
 out:
+       sc_ipc->msg = NULL;
        mutex_unlock(&sc_ipc->lock);
 
        dev_dbg(sc_ipc->dev, "RPC SVC done\n");
index 8d908a8..1d5b4d7 100644 (file)
@@ -35,7 +35,7 @@ struct meson_sm_chip {
        struct meson_sm_cmd cmd[];
 };
 
-struct meson_sm_chip gxbb_chip = {
+static const struct meson_sm_chip gxbb_chip = {
        .shmem_size             = SZ_4K,
        .cmd_shmem_in_base      = 0x82000020,
        .cmd_shmem_out_base     = 0x82000021,
@@ -54,8 +54,6 @@ struct meson_sm_firmware {
        void __iomem *sm_shmem_out_base;
 };
 
-static struct meson_sm_firmware fw;
-
 static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
                            unsigned int cmd_index)
 {
@@ -90,6 +88,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
 /**
  * meson_sm_call - generic SMC32 call to the secure-monitor
  *
+ * @fw:                Pointer to secure-monitor firmware
  * @cmd_index: Index of the SMC32 function ID
  * @ret:       Returned value
  * @arg0:      SMC32 Argument 0
@@ -100,15 +99,15 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
  *
  * Return:     0 on success, a negative value on error
  */
-int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0,
-                 u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
+                 u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
 {
        u32 cmd, lret;
 
-       if (!fw.chip)
+       if (!fw->chip)
                return -ENOENT;
 
-       cmd = meson_sm_get_cmd(fw.chip, cmd_index);
+       cmd = meson_sm_get_cmd(fw->chip, cmd_index);
        if (!cmd)
                return -EINVAL;
 
@@ -124,6 +123,7 @@ EXPORT_SYMBOL(meson_sm_call);
 /**
  * meson_sm_call_read - retrieve data from secure-monitor
  *
+ * @fw:                Pointer to secure-monitor firmware
  * @buffer:    Buffer to store the retrieved data
  * @bsize:     Size of the buffer
  * @cmd_index: Index of the SMC32 function ID
@@ -137,22 +137,23 @@ EXPORT_SYMBOL(meson_sm_call);
  *             When 0 is returned there is no guarantee about the amount of
  *             data read and bsize bytes are copied in buffer.
  */
-int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
-                      u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
+                      unsigned int bsize, unsigned int cmd_index, u32 arg0,
+                      u32 arg1, u32 arg2, u32 arg3, u32 arg4)
 {
        u32 size;
        int ret;
 
-       if (!fw.chip)
+       if (!fw->chip)
                return -ENOENT;
 
-       if (!fw.chip->cmd_shmem_out_base)
+       if (!fw->chip->cmd_shmem_out_base)
                return -EINVAL;
 
-       if (bsize > fw.chip->shmem_size)
+       if (bsize > fw->chip->shmem_size)
                return -EINVAL;
 
-       if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
+       if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
                return -EINVAL;
 
        if (size > bsize)
@@ -164,7 +165,7 @@ int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
                size = bsize;
 
        if (buffer)
-               memcpy(buffer, fw.sm_shmem_out_base, size);
+               memcpy(buffer, fw->sm_shmem_out_base, size);
 
        return ret;
 }
@@ -173,6 +174,7 @@ EXPORT_SYMBOL(meson_sm_call_read);
 /**
  * meson_sm_call_write - send data to secure-monitor
  *
+ * @fw:                Pointer to secure-monitor firmware
  * @buffer:    Buffer containing data to send
  * @size:      Size of the data to send
  * @cmd_index: Index of the SMC32 function ID
@@ -184,23 +186,24 @@ EXPORT_SYMBOL(meson_sm_call_read);
  *
  * Return:     size of sent data on success, a negative value on error
  */
-int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
-                       u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
+                       unsigned int size, unsigned int cmd_index, u32 arg0,
+                       u32 arg1, u32 arg2, u32 arg3, u32 arg4)
 {
        u32 written;
 
-       if (!fw.chip)
+       if (!fw->chip)
                return -ENOENT;
 
-       if (size > fw.chip->shmem_size)
+       if (size > fw->chip->shmem_size)
                return -EINVAL;
 
-       if (!fw.chip->cmd_shmem_in_base)
+       if (!fw->chip->cmd_shmem_in_base)
                return -EINVAL;
 
-       memcpy(fw.sm_shmem_in_base, buffer, size);
+       memcpy(fw->sm_shmem_in_base, buffer, size);
 
-       if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
+       if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
                return -EINVAL;
 
        if (!written)
@@ -210,6 +213,24 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
 }
 EXPORT_SYMBOL(meson_sm_call_write);
 
+/**
+ * meson_sm_get - get pointer to meson_sm_firmware structure.
+ *
+ * @sm_node:           Pointer to the secure-monitor Device Tree node.
+ *
+ * Return:             NULL is the secure-monitor device is not ready.
+ */
+struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node)
+{
+       struct platform_device *pdev = of_find_device_by_node(sm_node);
+
+       if (!pdev)
+               return NULL;
+
+       return platform_get_drvdata(pdev);
+}
+EXPORT_SYMBOL_GPL(meson_sm_get);
+
 #define SM_CHIP_ID_LENGTH      119
 #define SM_CHIP_ID_OFFSET      4
 #define SM_CHIP_ID_SIZE                12
@@ -217,33 +238,25 @@ EXPORT_SYMBOL(meson_sm_call_write);
 static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
+       struct platform_device *pdev = to_platform_device(dev);
+       struct meson_sm_firmware *fw;
        uint8_t *id_buf;
        int ret;
 
+       fw = platform_get_drvdata(pdev);
+
        id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL);
        if (!id_buf)
                return -ENOMEM;
 
-       ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
+       ret = meson_sm_call_read(fw, id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
                                 0, 0, 0, 0, 0);
        if (ret < 0) {
                kfree(id_buf);
                return ret;
        }
 
-       ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-                       id_buf[SM_CHIP_ID_OFFSET + 0],
-                       id_buf[SM_CHIP_ID_OFFSET + 1],
-                       id_buf[SM_CHIP_ID_OFFSET + 2],
-                       id_buf[SM_CHIP_ID_OFFSET + 3],
-                       id_buf[SM_CHIP_ID_OFFSET + 4],
-                       id_buf[SM_CHIP_ID_OFFSET + 5],
-                       id_buf[SM_CHIP_ID_OFFSET + 6],
-                       id_buf[SM_CHIP_ID_OFFSET + 7],
-                       id_buf[SM_CHIP_ID_OFFSET + 8],
-                       id_buf[SM_CHIP_ID_OFFSET + 9],
-                       id_buf[SM_CHIP_ID_OFFSET + 10],
-                       id_buf[SM_CHIP_ID_OFFSET + 11]);
+       ret = sprintf(buf, "%12phN\n", &id_buf[SM_CHIP_ID_OFFSET]);
 
        kfree(id_buf);
 
@@ -268,25 +281,34 @@ static const struct of_device_id meson_sm_ids[] = {
 
 static int __init meson_sm_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        const struct meson_sm_chip *chip;
+       struct meson_sm_firmware *fw;
+
+       fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
+       if (!fw)
+               return -ENOMEM;
 
-       chip = of_match_device(meson_sm_ids, &pdev->dev)->data;
+       chip = of_match_device(meson_sm_ids, dev)->data;
 
        if (chip->cmd_shmem_in_base) {
-               fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
-                                                        chip->shmem_size);
-               if (WARN_ON(!fw.sm_shmem_in_base))
+               fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
+                                                         chip->shmem_size);
+               if (WARN_ON(!fw->sm_shmem_in_base))
                        goto out;
        }
 
        if (chip->cmd_shmem_out_base) {
-               fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
-                                                         chip->shmem_size);
-               if (WARN_ON(!fw.sm_shmem_out_base))
+               fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
+                                                          chip->shmem_size);
+               if (WARN_ON(!fw->sm_shmem_out_base))
                        goto out_in_base;
        }
 
-       fw.chip = chip;
+       fw->chip = chip;
+
+       platform_set_drvdata(pdev, fw);
+
        pr_info("secure-monitor enabled\n");
 
        if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
@@ -295,7 +317,7 @@ static int __init meson_sm_probe(struct platform_device *pdev)
        return 0;
 
 out_in_base:
-       iounmap(fw.sm_shmem_in_base);
+       iounmap(fw->sm_shmem_in_base);
 out:
        return -EINVAL;
 }
index 215061c..bee8729 100644 (file)
@@ -614,3 +614,8 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
        return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
                                     addr, val);
 }
+
+int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
+{
+       return -ENODEV;
+}
index 91d5ad7..e1cd933 100644 (file)
@@ -62,32 +62,72 @@ static DEFINE_MUTEX(qcom_scm_lock);
 #define FIRST_EXT_ARG_IDX 3
 #define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
 
-/**
- * qcom_scm_call() - Invoke a syscall in the secure world
- * @dev:       device
- * @svc_id:    service identifier
- * @cmd_id:    command identifier
- * @desc:      Descriptor structure containing arguments and return values
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This should *only* be called in pre-emptible context.
-*/
-static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
-                        const struct qcom_scm_desc *desc,
-                        struct arm_smccc_res *res)
+static void __qcom_scm_call_do(const struct qcom_scm_desc *desc,
+                              struct arm_smccc_res *res, u32 fn_id,
+                              u64 x5, u32 type)
+{
+       u64 cmd;
+       struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
+
+       cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention,
+                                ARM_SMCCC_OWNER_SIP, fn_id);
+
+       quirk.state.a6 = 0;
+
+       do {
+               arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
+                                   desc->args[1], desc->args[2], x5,
+                                   quirk.state.a6, 0, res, &quirk);
+
+               if (res->a0 == QCOM_SCM_INTERRUPTED)
+                       cmd = res->a0;
+
+       } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+static void qcom_scm_call_do(const struct qcom_scm_desc *desc,
+                            struct arm_smccc_res *res, u32 fn_id,
+                            u64 x5, bool atomic)
+{
+       int retry_count = 0;
+
+       if (atomic) {
+               __qcom_scm_call_do(desc, res, fn_id, x5, ARM_SMCCC_FAST_CALL);
+               return;
+       }
+
+       do {
+               mutex_lock(&qcom_scm_lock);
+
+               __qcom_scm_call_do(desc, res, fn_id, x5,
+                                  ARM_SMCCC_STD_CALL);
+
+               mutex_unlock(&qcom_scm_lock);
+
+               if (res->a0 == QCOM_SCM_V2_EBUSY) {
+                       if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
+                               break;
+                       msleep(QCOM_SCM_EBUSY_WAIT_MS);
+               }
+       }  while (res->a0 == QCOM_SCM_V2_EBUSY);
+}
+
+static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
+                           const struct qcom_scm_desc *desc,
+                           struct arm_smccc_res *res, bool atomic)
 {
        int arglen = desc->arginfo & 0xf;
-       int retry_count = 0, i;
+       int i;
        u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
-       u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX];
+       u64 x5 = desc->args[FIRST_EXT_ARG_IDX];
        dma_addr_t args_phys = 0;
        void *args_virt = NULL;
        size_t alloc_len;
-       struct arm_smccc_quirk quirk = {.id = ARM_SMCCC_QUIRK_QCOM_A6};
+       gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
 
        if (unlikely(arglen > N_REGISTER_ARGS)) {
                alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
-               args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
+               args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
 
                if (!args_virt)
                        return -ENOMEM;
@@ -117,45 +157,55 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
                x5 = args_phys;
        }
 
-       do {
-               mutex_lock(&qcom_scm_lock);
-
-               cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
-                                        qcom_smccc_convention,
-                                        ARM_SMCCC_OWNER_SIP, fn_id);
-
-               quirk.state.a6 = 0;
-
-               do {
-                       arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
-                                     desc->args[1], desc->args[2], x5,
-                                     quirk.state.a6, 0, res, &quirk);
-
-                       if (res->a0 == QCOM_SCM_INTERRUPTED)
-                               cmd = res->a0;
-
-               } while (res->a0 == QCOM_SCM_INTERRUPTED);
-
-               mutex_unlock(&qcom_scm_lock);
-
-               if (res->a0 == QCOM_SCM_V2_EBUSY) {
-                       if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
-                               break;
-                       msleep(QCOM_SCM_EBUSY_WAIT_MS);
-               }
-       }  while (res->a0 == QCOM_SCM_V2_EBUSY);
+       qcom_scm_call_do(desc, res, fn_id, x5, atomic);
 
        if (args_virt) {
                dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
                kfree(args_virt);
        }
 
-       if (res->a0 < 0)
+       if ((long)res->a0 < 0)
                return qcom_scm_remap_error(res->a0);
 
        return 0;
 }
 
+/**
+ * qcom_scm_call() - Invoke a syscall in the secure world
+ * @dev:       device
+ * @svc_id:    service identifier
+ * @cmd_id:    command identifier
+ * @desc:      Descriptor structure containing arguments and return values
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This should *only* be called in pre-emptible context.
+ */
+static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
+                        const struct qcom_scm_desc *desc,
+                        struct arm_smccc_res *res)
+{
+       might_sleep();
+       return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, false);
+}
+
+/**
+ * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
+ * @dev:       device
+ * @svc_id:    service identifier
+ * @cmd_id:    command identifier
+ * @desc:      Descriptor structure containing arguments and return values
+ * @res:       Structure containing results from SMC/HVC call
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This can be called in atomic context.
+ */
+static int qcom_scm_call_atomic(struct device *dev, u32 svc_id, u32 cmd_id,
+                               const struct qcom_scm_desc *desc,
+                               struct arm_smccc_res *res)
+{
+       return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, true);
+}
+
 /**
  * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
  * @entry: Entry point function for the cpus
@@ -502,3 +552,16 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
        return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
                             &desc, &res);
 }
+
+int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
+{
+       struct qcom_scm_desc desc = {0};
+       struct arm_smccc_res res;
+
+       desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL;
+       desc.args[1] = en;
+       desc.arginfo = QCOM_SCM_ARGS(2);
+
+       return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
+                                   QCOM_SCM_CONFIG_ERRATA1, &desc, &res);
+}
index 4802ab1..a729e05 100644 (file)
@@ -345,6 +345,12 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
 }
 EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
 
+int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
+{
+       return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
+}
+EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
+
 int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
 {
        return __qcom_scm_io_readl(__scm->dev, addr, val);
index 99506bd..baee744 100644 (file)
@@ -91,10 +91,15 @@ extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
                                      u32 spare);
 #define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE        3
 #define QCOM_SCM_IOMMU_SECURE_PTBL_INIT        4
+#define QCOM_SCM_SVC_SMMU_PROGRAM      0x15
+#define QCOM_SCM_CONFIG_ERRATA1                0x3
+#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL     0x2
 extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
                                             size_t *size);
 extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
                                             u32 size, u32 spare);
+extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
+                                               bool enable);
 #define QCOM_MEM_PROT_ASSIGN_ID        0x16
 extern int  __qcom_scm_assign_mem(struct device *dev,
                                  phys_addr_t mem_region, size_t mem_sz,
index 19c5613..6741fcd 100644 (file)
@@ -804,7 +804,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops tegra_bpmp_pm_ops = {
-       .resume_early = tegra_bpmp_resume,
+       .resume_noirq = tegra_bpmp_resume,
 };
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
index fd3d837..75bdfaa 100644 (file)
@@ -711,8 +711,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
        int ret;
 
        np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
-       if (!np)
-               return 0;
+       if (!np) {
+               np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
+               if (!np)
+                       return 0;
+       }
        of_node_put(np);
 
        ret = get_set_conduit_method(dev->of_node);
@@ -770,6 +773,7 @@ static int zynqmp_firmware_remove(struct platform_device *pdev)
 
 static const struct of_device_id zynqmp_firmware_of_match[] = {
        {.compatible = "xlnx,zynqmp-firmware"},
+       {.compatible = "xlnx,versal-firmware"},
        {},
 };
 MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
index 400c09b..1f7d9bb 100644 (file)
@@ -178,46 +178,25 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
        return !!(port_state & mask);
 }
 
+static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+
 static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
        unsigned long *bits)
 {
        struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-       size_t i;
-       static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
-       const unsigned int gpio_reg_size = 8;
-       unsigned int bits_offset;
-       size_t word_index;
-       unsigned int word_offset;
-       unsigned long word_mask;
-       const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
+       unsigned long offset;
+       unsigned long gpio_mask;
+       unsigned int port_addr;
        unsigned long port_state;
 
        /* clear bits array to a clean slate */
        bitmap_zero(bits, chip->ngpio);
 
-       /* get bits are evaluated a gpio port register at a time */
-       for (i = 0; i < ARRAY_SIZE(ports); i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
-
-               /* word index for bits array */
-               word_index = BIT_WORD(bits_offset);
-
-               /* gpio offset within current word of bits array */
-               word_offset = bits_offset % BITS_PER_LONG;
-
-               /* mask of get bits for current gpio within current word */
-               word_mask = mask[word_index] & (port_mask << word_offset);
-               if (!word_mask) {
-                       /* no get bits in this port so skip to next one */
-                       continue;
-               }
-
-               /* read bits from current gpio port */
-               port_state = inb(dio48egpio->base + ports[i]);
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               port_addr = dio48egpio->base + ports[offset / 8];
+               port_state = inb(port_addr) & gpio_mask;
 
-               /* store acquired bits at respective bits array offset */
-               bits[word_index] |= (port_state << word_offset) & word_mask;
+               bitmap_set_value8(bits, port_state, offset);
        }
 
        return 0;
@@ -247,37 +226,27 @@ static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-       unsigned int i;
-       const unsigned int gpio_reg_size = 8;
-       unsigned int port;
-       unsigned int out_port;
-       unsigned int bitmask;
+       unsigned long offset;
+       unsigned long gpio_mask;
+       size_t index;
+       unsigned int port_addr;
+       unsigned long bitmask;
        unsigned long flags;
 
-       /* set bits are evaluated a gpio register size at a time */
-       for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
-               /* no more set bits in this mask word; skip to the next word */
-               if (!mask[BIT_WORD(i)]) {
-                       i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
-                       continue;
-               }
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               index = offset / 8;
+               port_addr = dio48egpio->base + ports[index];
 
-               port = i / gpio_reg_size;
-               out_port = (port > 2) ? port + 1 : port;
-               bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
+               bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
 
                raw_spin_lock_irqsave(&dio48egpio->lock, flags);
 
                /* update output state data and set device gpio register */
-               dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)];
-               dio48egpio->out_state[port] |= bitmask;
-               outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
+               dio48egpio->out_state[index] &= ~gpio_mask;
+               dio48egpio->out_state[index] |= bitmask;
+               outb(dio48egpio->out_state[index], port_addr);
 
                raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
-
-               /* prepare for next gpio register set */
-               mask[BIT_WORD(i)] >>= gpio_reg_size;
-               bits[BIT_WORD(i)] >>= gpio_reg_size;
        }
 }
 
index c50329a..d350ac0 100644 (file)
@@ -85,42 +85,20 @@ static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
        unsigned long *bits)
 {
        struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
-       size_t i;
+       unsigned long offset;
+       unsigned long gpio_mask;
        static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
-       const unsigned int gpio_reg_size = 8;
-       unsigned int bits_offset;
-       size_t word_index;
-       unsigned int word_offset;
-       unsigned long word_mask;
-       const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
+       unsigned int port_addr;
        unsigned long port_state;
 
        /* clear bits array to a clean slate */
        bitmap_zero(bits, chip->ngpio);
 
-       /* get bits are evaluated a gpio port register at a time */
-       for (i = 0; i < ARRAY_SIZE(ports); i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               port_addr = idi48gpio->base + ports[offset / 8];
+               port_state = inb(port_addr) & gpio_mask;
 
-               /* word index for bits array */
-               word_index = BIT_WORD(bits_offset);
-
-               /* gpio offset within current word of bits array */
-               word_offset = bits_offset % BITS_PER_LONG;
-
-               /* mask of get bits for current gpio within current word */
-               word_mask = mask[word_index] & (port_mask << word_offset);
-               if (!word_mask) {
-                       /* no get bits in this port so skip to next one */
-                       continue;
-               }
-
-               /* read bits from current gpio port */
-               port_state = inb(idi48gpio->base + ports[i]);
-
-               /* store acquired bits at respective bits array offset */
-               bits[word_index] |= (port_state << word_offset) & word_mask;
+               bitmap_set_value8(bits, port_state, offset);
        }
 
        return 0;
index e81307f..05637d5 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com>
  */
 
+#include <linux/bitops.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 #include <linux/module.h>
@@ -72,20 +73,18 @@ static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask,
                                    unsigned long *bits)
 {
        struct gen_74x164_chip *chip = gpiochip_get_data(gc);
-       unsigned int i, idx, shift;
-       u8 bank, bankmask;
+       unsigned long offset;
+       unsigned long bankmask;
+       size_t bank;
+       unsigned long bitmask;
 
        mutex_lock(&chip->lock);
-       for (i = 0, bank = chip->registers - 1; i < chip->registers;
-            i++, bank--) {
-               idx = i / sizeof(*mask);
-               shift = i % sizeof(*mask) * BITS_PER_BYTE;
-               bankmask = mask[idx] >> shift;
-               if (!bankmask)
-                       continue;
+       for_each_set_clump8(offset, bankmask, mask, chip->registers * 8) {
+               bank = chip->registers - 1 - offset / 8;
+               bitmask = bitmap_get_value8(bits, offset) & bankmask;
 
                chip->buffer[bank] &= ~bankmask;
-               chip->buffer[bank] |= bankmask & (bits[idx] >> shift);
+               chip->buffer[bank] |= bitmask;
        }
        __gen_74x164_write_config(chip);
        mutex_unlock(&chip->lock);
index c22d6f9..b89b8c5 100644 (file)
@@ -167,46 +167,25 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
        return !!(port_state & mask);
 }
 
+static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+
 static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
        unsigned long *bits)
 {
        struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-       size_t i;
-       static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
-       const unsigned int gpio_reg_size = 8;
-       unsigned int bits_offset;
-       size_t word_index;
-       unsigned int word_offset;
-       unsigned long word_mask;
-       const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
+       unsigned long offset;
+       unsigned long gpio_mask;
+       unsigned int port_addr;
        unsigned long port_state;
 
        /* clear bits array to a clean slate */
        bitmap_zero(bits, chip->ngpio);
 
-       /* get bits are evaluated a gpio port register at a time */
-       for (i = 0; i < ARRAY_SIZE(ports); i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
-
-               /* word index for bits array */
-               word_index = BIT_WORD(bits_offset);
-
-               /* gpio offset within current word of bits array */
-               word_offset = bits_offset % BITS_PER_LONG;
-
-               /* mask of get bits for current gpio within current word */
-               word_mask = mask[word_index] & (port_mask << word_offset);
-               if (!word_mask) {
-                       /* no get bits in this port so skip to next one */
-                       continue;
-               }
-
-               /* read bits from current gpio port */
-               port_state = inb(gpiommgpio->base + ports[i]);
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               port_addr = gpiommgpio->base + ports[offset / 8];
+               port_state = inb(port_addr) & gpio_mask;
 
-               /* store acquired bits at respective bits array offset */
-               bits[word_index] |= (port_state << word_offset) & word_mask;
+               bitmap_set_value8(bits, port_state, offset);
        }
 
        return 0;
@@ -237,37 +216,27 @@ static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-       unsigned int i;
-       const unsigned int gpio_reg_size = 8;
-       unsigned int port;
-       unsigned int out_port;
-       unsigned int bitmask;
+       unsigned long offset;
+       unsigned long gpio_mask;
+       size_t index;
+       unsigned int port_addr;
+       unsigned long bitmask;
        unsigned long flags;
 
-       /* set bits are evaluated a gpio register size at a time */
-       for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
-               /* no more set bits in this mask word; skip to the next word */
-               if (!mask[BIT_WORD(i)]) {
-                       i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
-                       continue;
-               }
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               index = offset / 8;
+               port_addr = gpiommgpio->base + ports[index];
 
-               port = i / gpio_reg_size;
-               out_port = (port > 2) ? port + 1 : port;
-               bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
+               bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
 
                spin_lock_irqsave(&gpiommgpio->lock, flags);
 
                /* update output state data and set device gpio register */
-               gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)];
-               gpiommgpio->out_state[port] |= bitmask;
-               outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
+               gpiommgpio->out_state[index] &= ~gpio_mask;
+               gpiommgpio->out_state[index] |= bitmask;
+               outb(gpiommgpio->out_state[index], port_addr);
 
                spin_unlock_irqrestore(&gpiommgpio->lock, flags);
-
-               /* prepare for next gpio register set */
-               mask[BIT_WORD(i)] >>= gpio_reg_size;
-               bits[BIT_WORD(i)] >>= gpio_reg_size;
        }
 }
 
index 0696d5a..310d1a2 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <linux/bitmap.h>
+#include <linux/bitops.h>
 #include <linux/crc8.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
@@ -232,16 +233,20 @@ static int max3191x_get_multiple(struct gpio_chip *gpio, unsigned long *mask,
                                 unsigned long *bits)
 {
        struct max3191x_chip *max3191x = gpiochip_get_data(gpio);
-       int ret, bit = 0, wordlen = max3191x_wordlen(max3191x);
+       const unsigned int wordlen = max3191x_wordlen(max3191x);
+       int ret;
+       unsigned long bit;
+       unsigned long gpio_mask;
+       unsigned long in;
 
        mutex_lock(&max3191x->lock);
        ret = max3191x_readout_locked(max3191x);
        if (ret)
                goto out_unlock;
 
-       while ((bit = find_next_bit(mask, gpio->ngpio, bit)) != gpio->ngpio) {
+       bitmap_zero(bits, gpio->ngpio);
+       for_each_set_clump8(bit, gpio_mask, mask, gpio->ngpio) {
                unsigned int chipnum = bit / MAX3191X_NGPIO;
-               unsigned long in, shift, index;
 
                if (max3191x_chip_is_faulting(max3191x, chipnum)) {
                        ret = -EIO;
@@ -249,12 +254,8 @@ static int max3191x_get_multiple(struct gpio_chip *gpio, unsigned long *mask,
                }
 
                in = ((u8 *)max3191x->xfer.rx_buf)[chipnum * wordlen];
-               shift = round_down(bit % BITS_PER_LONG, MAX3191X_NGPIO);
-               index = bit / BITS_PER_LONG;
-               bits[index] &= ~(mask[index] & (0xff << shift));
-               bits[index] |= mask[index] & (in << shift); /* copy bits */
-
-               bit = (chipnum + 1) * MAX3191X_NGPIO; /* go to next chip */
+               in &= gpio_mask;
+               bitmap_set_value8(bits, in, bit);
        }
 
 out_unlock:
index 82122c3..6652bee 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #include <linux/acpi.h>
-#include <linux/bits.h>
+#include <linux/bitmap.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
@@ -115,6 +115,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
 
 #define MAX_BANK 5
 #define BANK_SZ 8
+#define MAX_LINE       (MAX_BANK * BANK_SZ)
 
 #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
 
@@ -146,10 +147,10 @@ struct pca953x_chip {
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
        struct mutex irq_lock;
-       u8 irq_mask[MAX_BANK];
-       u8 irq_stat[MAX_BANK];
-       u8 irq_trig_raise[MAX_BANK];
-       u8 irq_trig_fall[MAX_BANK];
+       DECLARE_BITMAP(irq_mask, MAX_LINE);
+       DECLARE_BITMAP(irq_stat, MAX_LINE);
+       DECLARE_BITMAP(irq_trig_raise, MAX_LINE);
+       DECLARE_BITMAP(irq_trig_fall, MAX_LINE);
        struct irq_chip irq_chip;
 #endif
        atomic_t wakeup_path;
@@ -333,12 +334,16 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off,
        return regaddr;
 }
 
-static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
 {
        u8 regaddr = pca953x_recalc_addr(chip, reg, 0, true, true);
-       int ret;
+       u8 value[MAX_BANK];
+       int i, ret;
+
+       for (i = 0; i < NBANK(chip); i++)
+               value[i] = bitmap_get_value8(val, i * BANK_SZ);
 
-       ret = regmap_bulk_write(chip->regmap, regaddr, val, NBANK(chip));
+       ret = regmap_bulk_write(chip->regmap, regaddr, value, NBANK(chip));
        if (ret < 0) {
                dev_err(&chip->client->dev, "failed writing register\n");
                return ret;
@@ -347,17 +352,21 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
        return 0;
 }
 
-static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
 {
        u8 regaddr = pca953x_recalc_addr(chip, reg, 0, false, true);
-       int ret;
+       u8 value[MAX_BANK];
+       int i, ret;
 
-       ret = regmap_bulk_read(chip->regmap, regaddr, val, NBANK(chip));
+       ret = regmap_bulk_read(chip->regmap, regaddr, value, NBANK(chip));
        if (ret < 0) {
                dev_err(&chip->client->dev, "failed reading register\n");
                return ret;
        }
 
+       for (i = 0; i < NBANK(chip); i++)
+               bitmap_set_value8(val, value[i], i * BANK_SZ);
+
        return 0;
 }
 
@@ -412,7 +421,9 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
        ret = regmap_read(chip->regmap, inreg, &reg_val);
        mutex_unlock(&chip->i2c_lock);
        if (ret < 0) {
-               /* NOTE:  diagnostic already emitted; that's all we should
+               /*
+                * NOTE:
+                * diagnostic already emitted; that's all we should
                 * do unless gpio_*_value_cansleep() calls become different
                 * from their nonsleeping siblings (and report faults).
                 */
@@ -459,9 +470,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
                                      unsigned long *mask, unsigned long *bits)
 {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       unsigned int bank_mask, bank_val;
-       int bank;
-       u8 reg_val[MAX_BANK];
+       DECLARE_BITMAP(reg_val, MAX_LINE);
        int ret;
 
        mutex_lock(&chip->i2c_lock);
@@ -469,16 +478,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
        if (ret)
                goto exit;
 
-       for (bank = 0; bank < NBANK(chip); bank++) {
-               bank_mask = mask[bank / sizeof(*mask)] >>
-                          ((bank % sizeof(*mask)) * 8);
-               if (bank_mask) {
-                       bank_val = bits[bank / sizeof(*bits)] >>
-                                 ((bank % sizeof(*bits)) * 8);
-                       bank_val &= bank_mask;
-                       reg_val[bank] = (reg_val[bank] & ~bank_mask) | bank_val;
-               }
-       }
+       bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio);
 
        pca953x_write_regs(chip, chip->regs->output, reg_val);
 exit:
@@ -605,10 +605,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 new_irqs;
-       int level, i;
-       u8 invert_irq_mask[MAX_BANK];
-       u8 reg_direction[MAX_BANK];
+       DECLARE_BITMAP(irq_mask, MAX_LINE);
+       DECLARE_BITMAP(reg_direction, MAX_LINE);
+       int level;
 
        pca953x_read_regs(chip, chip->regs->direction, reg_direction);
 
@@ -616,25 +615,18 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
                /* Enable latch on interrupt-enabled inputs */
                pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
 
-               for (i = 0; i < NBANK(chip); i++)
-                       invert_irq_mask[i] = ~chip->irq_mask[i];
+               bitmap_complement(irq_mask, chip->irq_mask, gc->ngpio);
 
                /* Unmask enabled interrupts */
-               pca953x_write_regs(chip, PCAL953X_INT_MASK, invert_irq_mask);
+               pca953x_write_regs(chip, PCAL953X_INT_MASK, irq_mask);
        }
 
+       bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
+       bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio);
+
        /* Look for any newly setup interrupt */
-       for (i = 0; i < NBANK(chip); i++) {
-               new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
-               new_irqs &= reg_direction[i];
-
-               while (new_irqs) {
-                       level = __ffs(new_irqs);
-                       pca953x_gpio_direction_input(&chip->gpio_chip,
-                                                       level + (BANK_SZ * i));
-                       new_irqs &= ~(1 << level);
-               }
-       }
+       for_each_set_bit(level, irq_mask, gc->ngpio)
+               pca953x_gpio_direction_input(&chip->gpio_chip, level);
 
        mutex_unlock(&chip->irq_lock);
 }
@@ -675,15 +667,15 @@ static void pca953x_irq_shutdown(struct irq_data *d)
        chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask;
 }
 
-static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
+static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pending)
 {
-       u8 cur_stat[MAX_BANK];
-       u8 old_stat[MAX_BANK];
-       bool pending_seen = false;
-       bool trigger_seen = false;
-       u8 trigger[MAX_BANK];
-       u8 reg_direction[MAX_BANK];
-       int ret, i;
+       struct gpio_chip *gc = &chip->gpio_chip;
+       DECLARE_BITMAP(reg_direction, MAX_LINE);
+       DECLARE_BITMAP(old_stat, MAX_LINE);
+       DECLARE_BITMAP(cur_stat, MAX_LINE);
+       DECLARE_BITMAP(new_stat, MAX_LINE);
+       DECLARE_BITMAP(trigger, MAX_LINE);
+       int ret;
 
        if (chip->driver_data & PCA_PCAL) {
                /* Read the current interrupt status from the device */
@@ -692,20 +684,16 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
                        return false;
 
                /* Check latched inputs and clear interrupt status */
-               ret = pca953x_read_regs(chip, PCA953X_INPUT, cur_stat);
+               ret = pca953x_read_regs(chip, chip->regs->input, cur_stat);
                if (ret)
                        return false;
 
-               for (i = 0; i < NBANK(chip); i++) {
-                       /* Apply filter for rising/falling edge selection */
-                       pending[i] = (~cur_stat[i] & chip->irq_trig_fall[i]) |
-                               (cur_stat[i] & chip->irq_trig_raise[i]);
-                       pending[i] &= trigger[i];
-                       if (pending[i])
-                               pending_seen = true;
-               }
+               /* Apply filter for rising/falling edge selection */
+               bitmap_replace(new_stat, chip->irq_trig_fall, chip->irq_trig_raise, cur_stat, gc->ngpio);
+
+               bitmap_and(pending, new_stat, trigger, gc->ngpio);
 
-               return pending_seen;
+               return !bitmap_empty(pending, gc->ngpio);
        }
 
        ret = pca953x_read_regs(chip, chip->regs->input, cur_stat);
@@ -714,64 +702,49 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
 
        /* Remove output pins from the equation */
        pca953x_read_regs(chip, chip->regs->direction, reg_direction);
-       for (i = 0; i < NBANK(chip); i++)
-               cur_stat[i] &= reg_direction[i];
 
-       memcpy(old_stat, chip->irq_stat, NBANK(chip));
+       bitmap_copy(old_stat, chip->irq_stat, gc->ngpio);
 
-       for (i = 0; i < NBANK(chip); i++) {
-               trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
-               if (trigger[i])
-                       trigger_seen = true;
-       }
+       bitmap_and(new_stat, cur_stat, reg_direction, gc->ngpio);
+       bitmap_xor(cur_stat, new_stat, old_stat, gc->ngpio);
+       bitmap_and(trigger, cur_stat, chip->irq_mask, gc->ngpio);
 
-       if (!trigger_seen)
+       if (bitmap_empty(trigger, gc->ngpio))
                return false;
 
-       memcpy(chip->irq_stat, cur_stat, NBANK(chip));
+       bitmap_copy(chip->irq_stat, new_stat, gc->ngpio);
 
-       for (i = 0; i < NBANK(chip); i++) {
-               pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
-                       (cur_stat[i] & chip->irq_trig_raise[i]);
-               pending[i] &= trigger[i];
-               if (pending[i])
-                       pending_seen = true;
-       }
+       bitmap_and(cur_stat, chip->irq_trig_fall, old_stat, gc->ngpio);
+       bitmap_and(old_stat, chip->irq_trig_raise, new_stat, gc->ngpio);
+       bitmap_or(new_stat, old_stat, cur_stat, gc->ngpio);
+       bitmap_and(pending, new_stat, trigger, gc->ngpio);
 
-       return pending_seen;
+       return !bitmap_empty(pending, gc->ngpio);
 }
 
 static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 {
        struct pca953x_chip *chip = devid;
-       u8 pending[MAX_BANK];
-       u8 level;
-       unsigned nhandled = 0;
-       int i;
+       struct gpio_chip *gc = &chip->gpio_chip;
+       DECLARE_BITMAP(pending, MAX_LINE);
+       int level;
 
        if (!pca953x_irq_pending(chip, pending))
                return IRQ_NONE;
 
-       for (i = 0; i < NBANK(chip); i++) {
-               while (pending[i]) {
-                       level = __ffs(pending[i]);
-                       handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
-                                                       level + (BANK_SZ * i)));
-                       pending[i] &= ~(1 << level);
-                       nhandled++;
-               }
-       }
+       for_each_set_bit(level, pending, gc->ngpio)
+               handle_nested_irq(irq_find_mapping(gc->irq.domain, level));
 
-       return (nhandled > 0) ? IRQ_HANDLED : IRQ_NONE;
+       return IRQ_HANDLED;
 }
 
-static int pca953x_irq_setup(struct pca953x_chip *chip,
-                            int irq_base)
+static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
 {
        struct i2c_client *client = chip->client;
        struct irq_chip *irq_chip = &chip->irq_chip;
-       u8 reg_direction[MAX_BANK];
-       int ret, i;
+       DECLARE_BITMAP(reg_direction, MAX_LINE);
+       DECLARE_BITMAP(irq_stat, MAX_LINE);
+       int ret;
 
        if (!client->irq)
                return 0;
@@ -782,7 +755,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        if (!(chip->driver_data & PCA_INT))
                return 0;
 
-       ret = pca953x_read_regs(chip, chip->regs->input, chip->irq_stat);
+       ret = pca953x_read_regs(chip, chip->regs->input, irq_stat);
        if (ret)
                return ret;
 
@@ -792,8 +765,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
         * this purpose.
         */
        pca953x_read_regs(chip, chip->regs->direction, reg_direction);
-       for (i = 0; i < NBANK(chip); i++)
-               chip->irq_stat[i] &= reg_direction[i];
+       bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio);
        mutex_init(&chip->irq_lock);
 
        ret = devm_request_threaded_irq(&client->dev, client->irq,
@@ -816,9 +788,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        irq_chip->irq_set_type = pca953x_irq_set_type;
        irq_chip->irq_shutdown = pca953x_irq_shutdown;
 
-       ret =  gpiochip_irqchip_add_nested(&chip->gpio_chip, irq_chip,
-                                          irq_base, handle_simple_irq,
-                                          IRQ_TYPE_NONE);
+       ret = gpiochip_irqchip_add_nested(&chip->gpio_chip, irq_chip,
+                                         irq_base, handle_simple_irq,
+                                         IRQ_TYPE_NONE);
        if (ret) {
                dev_err(&client->dev,
                        "could not connect irqchip to gpiochip\n");
@@ -845,8 +817,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 
 static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
 {
+       DECLARE_BITMAP(val, MAX_LINE);
        int ret;
-       u8 val[MAX_BANK];
 
        ret = regcache_sync_region(chip->regmap, chip->regs->output,
                                   chip->regs->output + NBANK(chip));
@@ -860,9 +832,9 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
 
        /* set platform specific polarity inversion */
        if (invert)
-               memset(val, 0xFF, NBANK(chip));
+               bitmap_fill(val, MAX_LINE);
        else
-               memset(val, 0, NBANK(chip));
+               bitmap_zero(val, MAX_LINE);
 
        ret = pca953x_write_regs(chip, chip->regs->invert, val);
 out:
@@ -871,8 +843,8 @@ out:
 
 static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 {
+       DECLARE_BITMAP(val, MAX_LINE);
        int ret;
-       u8 val[MAX_BANK];
 
        ret = device_pca95xx_init(chip, invert);
        if (ret)
@@ -892,7 +864,7 @@ out:
 static const struct of_device_id pca953x_dt_ids[];
 
 static int pca953x_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *i2c_id)
+                        const struct i2c_device_id *i2c_id)
 {
        struct pca953x_platform_data *pdata;
        struct pca953x_chip *chip;
@@ -901,8 +873,7 @@ static int pca953x_probe(struct i2c_client *client,
        u32 invert = 0;
        struct regulator *reg;
 
-       chip = devm_kzalloc(&client->dev,
-                       sizeof(struct pca953x_chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (chip == NULL)
                return -ENOMEM;
 
@@ -1016,7 +987,7 @@ static int pca953x_probe(struct i2c_client *client,
 
        if (pdata && pdata->setup) {
                ret = pdata->setup(client, chip->gpio_chip.base,
-                               chip->gpio_chip.ngpio, pdata->context);
+                                  chip->gpio_chip.ngpio, pdata->context);
                if (ret < 0)
                        dev_warn(&client->dev, "setup failed, %d\n", ret);
        }
@@ -1036,7 +1007,7 @@ static int pca953x_remove(struct i2c_client *client)
 
        if (pdata && pdata->teardown) {
                ret = pdata->teardown(client, chip->gpio_chip.base,
-                               chip->gpio_chip.ngpio, pdata->context);
+                                     chip->gpio_chip.ngpio, pdata->context);
                if (ret < 0)
                        dev_err(&client->dev, "teardown failed, %d\n", ret);
        } else {
index df51dd0..638d665 100644 (file)
@@ -100,45 +100,23 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-       size_t i;
-       const unsigned int gpio_reg_size = 8;
-       unsigned int bits_offset;
-       size_t word_index;
-       unsigned int word_offset;
-       unsigned long word_mask;
-       const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
-       unsigned long port_state;
+       unsigned long offset;
+       unsigned long gpio_mask;
        void __iomem *ports[] = {
                &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
                &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
        };
+       void __iomem *port_addr;
+       unsigned long port_state;
 
        /* clear bits array to a clean slate */
        bitmap_zero(bits, chip->ngpio);
 
-       /* get bits are evaluated a gpio port register at a time */
-       for (i = 0; i < ARRAY_SIZE(ports); i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
-
-               /* word index for bits array */
-               word_index = BIT_WORD(bits_offset);
-
-               /* gpio offset within current word of bits array */
-               word_offset = bits_offset % BITS_PER_LONG;
-
-               /* mask of get bits for current gpio within current word */
-               word_mask = mask[word_index] & (port_mask << word_offset);
-               if (!word_mask) {
-                       /* no get bits in this port so skip to next one */
-                       continue;
-               }
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               port_addr = ports[offset / 8];
+               port_state = ioread8(port_addr) & gpio_mask;
 
-               /* read bits from current gpio port */
-               port_state = ioread8(ports[i]);
-
-               /* store acquired bits at respective bits array offset */
-               bits[word_index] |= (port_state << word_offset) & word_mask;
+               bitmap_set_value8(bits, port_state, offset);
        }
 
        return 0;
@@ -178,30 +156,31 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+       unsigned long offset;
+       unsigned long gpio_mask;
+       void __iomem *ports[] = {
+               &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
+       };
+       size_t index;
+       void __iomem *port_addr;
+       unsigned long bitmask;
        unsigned long flags;
-       unsigned int out_state;
+       unsigned long out_state;
 
-       raw_spin_lock_irqsave(&idio16gpio->lock, flags);
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               index = offset / 8;
+               port_addr = ports[index];
 
-       /* process output lines 0-7 */
-       if (*mask & 0xFF) {
-               out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask;
-               out_state |= *mask & *bits;
-               iowrite8(out_state, &idio16gpio->reg->out0_7);
-       }
+               bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
+
+               raw_spin_lock_irqsave(&idio16gpio->lock, flags);
 
-       /* shift to next output line word */
-       *mask >>= 8;
+               out_state = ioread8(port_addr) & ~gpio_mask;
+               out_state |= bitmask;
+               iowrite8(out_state, port_addr);
 
-       /* process output lines 8-15 */
-       if (*mask & 0xFF) {
-               *bits >>= 8;
-               out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask;
-               out_state |= *mask & *bits;
-               iowrite8(out_state, &idio16gpio->reg->out8_15);
+               raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
        }
-
-       raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
 }
 
 static void idio_16_irq_ack(struct irq_data *data)
index 44c1e4f..1d47579 100644 (file)
@@ -201,52 +201,34 @@ static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
-       size_t i;
-       const unsigned int gpio_reg_size = 8;
-       unsigned int bits_offset;
-       size_t word_index;
-       unsigned int word_offset;
-       unsigned long word_mask;
-       const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
-       unsigned long port_state;
+       unsigned long offset;
+       unsigned long gpio_mask;
        void __iomem *ports[] = {
                &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
                &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7,
                &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23,
        };
+       size_t index;
+       unsigned long port_state;
        const unsigned long out_mode_mask = BIT(1);
 
        /* clear bits array to a clean slate */
        bitmap_zero(bits, chip->ngpio);
 
-       /* get bits are evaluated a gpio port register at a time */
-       for (i = 0; i < ARRAY_SIZE(ports) + 1; i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
-
-               /* word index for bits array */
-               word_index = BIT_WORD(bits_offset);
-
-               /* gpio offset within current word of bits array */
-               word_offset = bits_offset % BITS_PER_LONG;
-
-               /* mask of get bits for current gpio within current word */
-               word_mask = mask[word_index] & (port_mask << word_offset);
-               if (!word_mask) {
-                       /* no get bits in this port so skip to next one */
-                       continue;
-               }
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               index = offset / 8;
 
                /* read bits from current gpio port (port 6 is TTL GPIO) */
-               if (i < 6)
-                       port_state = ioread8(ports[i]);
+               if (index < 6)
+                       port_state = ioread8(ports[index]);
                else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
                        port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
                else
                        port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
 
-               /* store acquired bits at respective bits array offset */
-               bits[word_index] |= (port_state << word_offset) & word_mask;
+               port_state &= gpio_mask;
+
+               bitmap_set_value8(bits, port_state, offset);
        }
 
        return 0;
@@ -297,59 +279,48 @@ static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
-       size_t i;
-       unsigned long bits_offset;
+       unsigned long offset;
        unsigned long gpio_mask;
-       const unsigned int gpio_reg_size = 8;
-       const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
-       unsigned long flags;
-       unsigned int out_state;
        void __iomem *ports[] = {
                &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
                &idio24gpio->reg->out16_23
        };
+       size_t index;
+       unsigned long bitmask;
+       unsigned long flags;
+       unsigned long out_state;
        const unsigned long out_mode_mask = BIT(1);
-       const unsigned int ttl_offset = 48;
-       const size_t ttl_i = BIT_WORD(ttl_offset);
-       const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
-       const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
-       const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
-
-       /* set bits are processed a gpio port register at a time */
-       for (i = 0; i < ARRAY_SIZE(ports); i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
-
-               /* check if any set bits for current port */
-               gpio_mask = (*mask >> bits_offset) & port_mask;
-               if (!gpio_mask) {
-                       /* no set bits for this port so move on to next port */
-                       continue;
-               }
 
-               raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+       for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
+               index = offset / 8;
 
-               /* process output lines */
-               out_state = ioread8(ports[i]) & ~gpio_mask;
-               out_state |= (*bits >> bits_offset) & gpio_mask;
-               iowrite8(out_state, ports[i]);
+               bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
 
-               raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
-       }
+               raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 
-       /* check if setting TTL lines and if they are in output mode */
-       if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
-               return;
+               /* read bits from current gpio port (port 6 is TTL GPIO) */
+               if (index < 6) {
+                       out_state = ioread8(ports[index]);
+               } else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) {
+                       out_state = ioread8(&idio24gpio->reg->ttl_out0_7);
+               } else {
+                       /* skip TTL GPIO if set for input */
+                       raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+                       continue;
+               }
 
-       /* handle TTL output */
-       raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+               /* set requested bit states */
+               out_state &= ~gpio_mask;
+               out_state |= bitmask;
 
-       /* process output lines */
-       out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
-       out_state |= ttl_bits;
-       iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
+               /* write bits for current gpio port (port 6 is TTL GPIO) */
+               if (index < 6)
+                       iowrite8(out_state, ports[index]);
+               else
+                       iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
 
-       raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+               raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+       }
 }
 
 static void idio_24_irq_ack(struct irq_data *data)
index 1331b2a..6698fea 100644 (file)
@@ -96,16 +96,16 @@ static int pisosr_gpio_get_multiple(struct gpio_chip *chip,
                                    unsigned long *mask, unsigned long *bits)
 {
        struct pisosr_gpio *gpio = gpiochip_get_data(chip);
-       unsigned int nbytes = DIV_ROUND_UP(chip->ngpio, 8);
-       unsigned int i, j;
+       unsigned long offset;
+       unsigned long gpio_mask;
+       unsigned long buffer_state;
 
        pisosr_gpio_refresh(gpio);
 
        bitmap_zero(bits, chip->ngpio);
-       for (i = 0; i < nbytes; i++) {
-               j = i / sizeof(unsigned long);
-               bits[j] |= ((unsigned long) gpio->buffer[i])
-                          << (8 * (i % sizeof(unsigned long)));
+       for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
+               buffer_state = gpio->buffer[offset / 8] & gpio_mask;
+               bitmap_set_value8(bits, buffer_state, offset);
        }
 
        return 0;
index bd203e8..7ec9749 100644 (file)
@@ -15,9 +15,6 @@
 #include <linux/spinlock.h>
 #include <dt-bindings/gpio/uniphier-gpio.h>
 
-#define UNIPHIER_GPIO_BANK_MASK                \
-                               GENMASK((UNIPHIER_GPIO_LINES_PER_BANK) - 1, 0)
-
 #define UNIPHIER_GPIO_IRQ_MAX_NUM      24
 
 #define UNIPHIER_GPIO_PORT_DATA                0x0     /* data */
@@ -150,15 +147,11 @@ static void uniphier_gpio_set(struct gpio_chip *chip,
 static void uniphier_gpio_set_multiple(struct gpio_chip *chip,
                                       unsigned long *mask, unsigned long *bits)
 {
-       unsigned int bank, shift, bank_mask, bank_bits;
-       int i;
+       unsigned long i, bank, bank_mask, bank_bits;
 
-       for (i = 0; i < chip->ngpio; i += UNIPHIER_GPIO_LINES_PER_BANK) {
+       for_each_set_clump8(i, bank_mask, mask, chip->ngpio) {
                bank = i / UNIPHIER_GPIO_LINES_PER_BANK;
-               shift = i % BITS_PER_LONG;
-               bank_mask = (mask[BIT_WORD(i)] >> shift) &
-                                               UNIPHIER_GPIO_BANK_MASK;
-               bank_bits = bits[BIT_WORD(i)] >> shift;
+               bank_bits = bitmap_get_value8(bits, i);
 
                uniphier_gpio_bank_write(chip, bank, UNIPHIER_GPIO_PORT_DATA,
                                         bank_mask, bank_bits);
index fe456be..cb510df 100644 (file)
@@ -129,42 +129,19 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned int gpio_reg_size = 8;
-       size_t i;
-       const size_t num_ports = chip->ngpio / gpio_reg_size;
-       unsigned int bits_offset;
-       size_t word_index;
-       unsigned int word_offset;
-       unsigned long word_mask;
-       const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
+       unsigned long offset;
+       unsigned long gpio_mask;
+       unsigned int port_addr;
        unsigned long port_state;
 
        /* clear bits array to a clean slate */
        bitmap_zero(bits, chip->ngpio);
 
-       /* get bits are evaluated a gpio port register at a time */
-       for (i = 0; i < num_ports; i++) {
-               /* gpio offset in bits array */
-               bits_offset = i * gpio_reg_size;
+       for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
+               port_addr = ws16c48gpio->base + offset / 8;
+               port_state = inb(port_addr) & gpio_mask;
 
-               /* word index for bits array */
-               word_index = BIT_WORD(bits_offset);
-
-               /* gpio offset within current word of bits array */
-               word_offset = bits_offset % BITS_PER_LONG;
-
-               /* mask of get bits for current gpio within current word */
-               word_mask = mask[word_index] & (port_mask << word_offset);
-               if (!word_mask) {
-                       /* no get bits in this port so skip to next one */
-                       continue;
-               }
-
-               /* read bits from current gpio port */
-               port_state = inb(ws16c48gpio->base + i);
-
-               /* store acquired bits at respective bits array offset */
-               bits[word_index] |= (port_state << word_offset) & word_mask;
+               bitmap_set_value8(bits, port_state, offset);
        }
 
        return 0;
@@ -198,39 +175,29 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
        unsigned long *mask, unsigned long *bits)
 {
        struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       unsigned int i;
-       const unsigned int gpio_reg_size = 8;
-       unsigned int port;
-       unsigned int iomask;
-       unsigned int bitmask;
+       unsigned long offset;
+       unsigned long gpio_mask;
+       size_t index;
+       unsigned int port_addr;
+       unsigned long bitmask;
        unsigned long flags;
 
-       /* set bits are evaluated a gpio register size at a time */
-       for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
-               /* no more set bits in this mask word; skip to the next word */
-               if (!mask[BIT_WORD(i)]) {
-                       i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
-                       continue;
-               }
-
-               port = i / gpio_reg_size;
+       for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
+               index = offset / 8;
+               port_addr = ws16c48gpio->base + index;
 
                /* mask out GPIO configured for input */
-               iomask = mask[BIT_WORD(i)] & ~ws16c48gpio->io_state[port];
-               bitmask = iomask & bits[BIT_WORD(i)];
+               gpio_mask &= ~ws16c48gpio->io_state[index];
+               bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
 
                raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
 
                /* update output state data and set device gpio register */
-               ws16c48gpio->out_state[port] &= ~iomask;
-               ws16c48gpio->out_state[port] |= bitmask;
-               outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
+               ws16c48gpio->out_state[index] &= ~gpio_mask;
+               ws16c48gpio->out_state[index] |= bitmask;
+               outb(ws16c48gpio->out_state[index], port_addr);
 
                raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-
-               /* prepare for next gpio register set */
-               mask[BIT_WORD(i)] >>= gpio_reg_size;
-               bits[BIT_WORD(i)] >>= gpio_reg_size;
        }
 }
 
index 2d64d27..7a43993 100644 (file)
@@ -1441,7 +1441,6 @@ static int cik_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk)
 static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
 {
        struct pci_dev *root = adev->pdev->bus->self;
-       int bridge_pos, gpu_pos;
        u32 speed_cntl, current_data_rate;
        int i;
        u16 tmp16;
@@ -1476,12 +1475,7 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
                DRM_INFO("enabling PCIE gen 2 link speeds, disable with amdgpu.pcie_gen2=0\n");
        }
 
-       bridge_pos = pci_pcie_cap(root);
-       if (!bridge_pos)
-               return;
-
-       gpu_pos = pci_pcie_cap(adev->pdev);
-       if (!gpu_pos)
+       if (!pci_is_pcie(root) || !pci_is_pcie(adev->pdev))
                return;
 
        if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
@@ -1491,14 +1485,17 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
                        u16 bridge_cfg2, gpu_cfg2;
                        u32 max_lw, current_lw, tmp;
 
-                       pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                       pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                       pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                 &bridge_cfg);
+                       pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL,
+                                                 &gpu_cfg);
 
                        tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16);
 
                        tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL,
+                                                  tmp16);
 
                        tmp = RREG32_PCIE(ixPCIE_LC_STATUS1);
                        max_lw = (tmp & PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH_MASK) >>
@@ -1522,15 +1519,23 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
 
                        for (i = 0; i < 10; i++) {
                                /* check status */
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_DEVSTA,
+                                                         &tmp16);
                                if (tmp16 & PCI_EXP_DEVSTA_TRPND)
                                        break;
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &bridge_cfg);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &gpu_cfg);
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &bridge_cfg2);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &gpu_cfg2);
 
                                tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
                                tmp |= PCIE_LC_CNTL4__LC_SET_QUIESCE_MASK;
@@ -1543,26 +1548,45 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
                                msleep(100);
 
                                /* linkctl */
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(root, PCI_EXP_LNKCTL,
+                                                          tmp16);
 
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(adev->pdev,
+                                                          PCI_EXP_LNKCTL,
+                                                          tmp16);
 
                                /* linkctl2 */
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (bridge_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(root,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
+
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (gpu_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(adev->pdev,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
 
                                tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
                                tmp &= ~PCIE_LC_CNTL4__LC_SET_QUIESCE_MASK;
@@ -1577,15 +1601,16 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
        speed_cntl &= ~PCIE_LC_SPEED_CNTL__LC_FORCE_DIS_SW_SPEED_CHANGE_MASK;
        WREG32_PCIE(ixPCIE_LC_SPEED_CNTL, speed_cntl);
 
-       pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-       tmp16 &= ~0xf;
+       pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+       tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
+
        if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-               tmp16 |= 3; /* gen3 */
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
        else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
-               tmp16 |= 2; /* gen2 */
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
        else
-               tmp16 |= 1; /* gen1 */
-       pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+       pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
        speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
        speed_cntl |= PCIE_LC_SPEED_CNTL__LC_INITIATE_LINK_SPEED_CHANGE_MASK;
index 29024e6..f2d70a4 100644 (file)
@@ -1644,7 +1644,6 @@ static void si_init_golden_registers(struct amdgpu_device *adev)
 static void si_pcie_gen3_enable(struct amdgpu_device *adev)
 {
        struct pci_dev *root = adev->pdev->bus->self;
-       int bridge_pos, gpu_pos;
        u32 speed_cntl, current_data_rate;
        int i;
        u16 tmp16;
@@ -1679,12 +1678,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
                DRM_INFO("enabling PCIE gen 2 link speeds, disable with amdgpu.pcie_gen2=0\n");
        }
 
-       bridge_pos = pci_pcie_cap(root);
-       if (!bridge_pos)
-               return;
-
-       gpu_pos = pci_pcie_cap(adev->pdev);
-       if (!gpu_pos)
+       if (!pci_is_pcie(root) || !pci_is_pcie(adev->pdev))
                return;
 
        if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
@@ -1693,14 +1687,17 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
                        u16 bridge_cfg2, gpu_cfg2;
                        u32 max_lw, current_lw, tmp;
 
-                       pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                       pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                       pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                 &bridge_cfg);
+                       pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL,
+                                                 &gpu_cfg);
 
                        tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16);
 
                        tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL,
+                                                  tmp16);
 
                        tmp = RREG32_PCIE(PCIE_LC_STATUS1);
                        max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -1717,15 +1714,23 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
                        }
 
                        for (i = 0; i < 10; i++) {
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_DEVSTA,
+                                                         &tmp16);
                                if (tmp16 & PCI_EXP_DEVSTA_TRPND)
                                        break;
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &bridge_cfg);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &gpu_cfg);
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &bridge_cfg2);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &gpu_cfg2);
 
                                tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
                                tmp |= LC_SET_QUIESCE;
@@ -1737,25 +1742,44 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
 
                                mdelay(100);
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(root, PCI_EXP_LNKCTL,
+                                                          tmp16);
 
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
-
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+                               pcie_capability_write_word(adev->pdev,
+                                                          PCI_EXP_LNKCTL,
+                                                          tmp16);
+
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (bridge_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(root,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
+
+                               pcie_capability_read_word(adev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (gpu_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(adev->pdev,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
 
                                tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
                                tmp &= ~LC_SET_QUIESCE;
@@ -1768,15 +1792,16 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
        speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
        WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
 
-       pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-       tmp16 &= ~0xf;
+       pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+       tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
+
        if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-               tmp16 |= 3;
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
        else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
-               tmp16 |= 2;
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
        else
-               tmp16 |= 1;
-       pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+       pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
        speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
        speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
index 892ce63..6ee0480 100644 (file)
@@ -561,7 +561,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
        struct drm_property_blob *blob;
        int ret;
 
-       if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
+       if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
                return ERR_PTR(-EINVAL);
 
        blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
index 0b1f786..438040f 100644 (file)
@@ -7,7 +7,6 @@ config DRM_I915_WERROR
        # We use the dependency on !COMPILE_TEST to not be enabled in
        # allmodconfig or allyesconfig configurations
        depends on !COMPILE_TEST
-       select HEADER_TEST
        default n
        help
          Add -Werror to the build flags for (and only for) i915.ko.
index acabeaf..40a7e70 100644 (file)
@@ -9500,7 +9500,6 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
 {
        struct pci_dev *root = rdev->pdev->bus->self;
        enum pci_bus_speed speed_cap;
-       int bridge_pos, gpu_pos;
        u32 speed_cntl, current_data_rate;
        int i;
        u16 tmp16;
@@ -9542,12 +9541,7 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
                DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n");
        }
 
-       bridge_pos = pci_pcie_cap(root);
-       if (!bridge_pos)
-               return;
-
-       gpu_pos = pci_pcie_cap(rdev->pdev);
-       if (!gpu_pos)
+       if (!pci_is_pcie(root) || !pci_is_pcie(rdev->pdev))
                return;
 
        if (speed_cap == PCIE_SPEED_8_0GT) {
@@ -9557,14 +9551,17 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
                        u16 bridge_cfg2, gpu_cfg2;
                        u32 max_lw, current_lw, tmp;
 
-                       pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                       pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                       pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                 &bridge_cfg);
+                       pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL,
+                                                 &gpu_cfg);
 
                        tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16);
 
                        tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL,
+                                                  tmp16);
 
                        tmp = RREG32_PCIE_PORT(PCIE_LC_STATUS1);
                        max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -9582,15 +9579,23 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
 
                        for (i = 0; i < 10; i++) {
                                /* check status */
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_DEVSTA,
+                                                         &tmp16);
                                if (tmp16 & PCI_EXP_DEVSTA_TRPND)
                                        break;
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &bridge_cfg);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &gpu_cfg);
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &bridge_cfg2);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &gpu_cfg2);
 
                                tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
                                tmp |= LC_SET_QUIESCE;
@@ -9603,26 +9608,45 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
                                msleep(100);
 
                                /* linkctl */
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(root, PCI_EXP_LNKCTL,
+                                                          tmp16);
 
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(rdev->pdev,
+                                                          PCI_EXP_LNKCTL,
+                                                          tmp16);
 
                                /* linkctl2 */
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (bridge_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(root,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
+
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (gpu_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(rdev->pdev,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
 
                                tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
                                tmp &= ~LC_SET_QUIESCE;
@@ -9636,15 +9660,15 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
        speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
        WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
 
-       pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-       tmp16 &= ~0xf;
+       pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+       tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
        if (speed_cap == PCIE_SPEED_8_0GT)
-               tmp16 |= 3; /* gen3 */
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
        else if (speed_cap == PCIE_SPEED_5_0GT)
-               tmp16 |= 2; /* gen2 */
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
        else
-               tmp16 |= 1; /* gen1 */
-       pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+       pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
        speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
        speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
index 1d8efb0..d7eea75 100644 (file)
@@ -3257,7 +3257,7 @@ static void si_gpu_init(struct radeon_device *rdev)
                /* XXX what about 12? */
                rdev->config.si.tile_config |= (3 << 0);
                break;
-       }       
+       }
        switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
        case 0: /* four banks */
                rdev->config.si.tile_config |= 0 << 4;
@@ -7087,7 +7087,6 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
 {
        struct pci_dev *root = rdev->pdev->bus->self;
        enum pci_bus_speed speed_cap;
-       int bridge_pos, gpu_pos;
        u32 speed_cntl, current_data_rate;
        int i;
        u16 tmp16;
@@ -7129,12 +7128,7 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
                DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n");
        }
 
-       bridge_pos = pci_pcie_cap(root);
-       if (!bridge_pos)
-               return;
-
-       gpu_pos = pci_pcie_cap(rdev->pdev);
-       if (!gpu_pos)
+       if (!pci_is_pcie(root) || !pci_is_pcie(rdev->pdev))
                return;
 
        if (speed_cap == PCIE_SPEED_8_0GT) {
@@ -7144,14 +7138,17 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
                        u16 bridge_cfg2, gpu_cfg2;
                        u32 max_lw, current_lw, tmp;
 
-                       pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                       pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                       pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                 &bridge_cfg);
+                       pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL,
+                                                 &gpu_cfg);
 
                        tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16);
 
                        tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-                       pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                       pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL,
+                                                  tmp16);
 
                        tmp = RREG32_PCIE(PCIE_LC_STATUS1);
                        max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -7169,15 +7166,23 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
 
                        for (i = 0; i < 10; i++) {
                                /* check status */
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_DEVSTA,
+                                                         &tmp16);
                                if (tmp16 & PCI_EXP_DEVSTA_TRPND)
                                        break;
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &bridge_cfg);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &gpu_cfg);
 
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &bridge_cfg2);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &gpu_cfg2);
 
                                tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
                                tmp |= LC_SET_QUIESCE;
@@ -7190,26 +7195,46 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
                                msleep(100);
 
                                /* linkctl */
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(root,
+                                                          PCI_EXP_LNKCTL,
+                                                          tmp16);
 
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL,
+                                                         &tmp16);
                                tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
                                tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-                               pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+                               pcie_capability_write_word(rdev->pdev,
+                                                          PCI_EXP_LNKCTL,
+                                                          tmp16);
 
                                /* linkctl2 */
-                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-                               pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-                               tmp16 &= ~((1 << 4) | (7 << 9));
-                               tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-                               pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+                               pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (bridge_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(root,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
+
+                               pcie_capability_read_word(rdev->pdev,
+                                                         PCI_EXP_LNKCTL2,
+                                                         &tmp16);
+                               tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN);
+                               tmp16 |= (gpu_cfg2 &
+                                         (PCI_EXP_LNKCTL2_ENTER_COMP |
+                                          PCI_EXP_LNKCTL2_TX_MARGIN));
+                               pcie_capability_write_word(rdev->pdev,
+                                                          PCI_EXP_LNKCTL2,
+                                                          tmp16);
 
                                tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
                                tmp &= ~LC_SET_QUIESCE;
@@ -7223,15 +7248,15 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
        speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
        WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
 
-       pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-       tmp16 &= ~0xf;
+       pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+       tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
        if (speed_cap == PCIE_SPEED_8_0GT)
-               tmp16 |= 3; /* gen3 */
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
        else if (speed_cap == PCIE_SPEED_5_0GT)
-               tmp16 |= 2; /* gen2 */
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
        else
-               tmp16 |= 1; /* gen1 */
-       pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+               tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+       pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
        speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
        speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
index 7f4cf4f..b155d00 100644 (file)
@@ -682,9 +682,7 @@ static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
                __ClearPageOffline(pg);
 
        /* This frame is currently backed; online the page. */
-       __online_page_set_limits(pg);
-       __online_page_increment_counters(pg);
-       __online_page_free(pg);
+       generic_online_page(pg, 0);
 
        lockdep_assert_held(&dm_device.ha_lock);
        dm_device.num_pages_onlined++;
index 347b08b..75fd2a7 100644 (file)
@@ -1291,8 +1291,8 @@ static void sklh_idle_state_table_update(void)
                        return;
        }
 
-       skl_cstates[5].disabled = 1;    /* C8-SKL */
-       skl_cstates[6].disabled = 1;    /* C9-SKL */
+       skl_cstates[5].flags |= CPUIDLE_FLAG_UNUSABLE;  /* C8-SKL */
+       skl_cstates[6].flags |= CPUIDLE_FLAG_UNUSABLE;  /* C9-SKL */
 }
 /*
  * intel_idle_state_table_update()
@@ -1355,7 +1355,7 @@ static void __init intel_idle_cpuidle_driver_init(void)
                        continue;
 
                /* if state marked as disabled, skip it */
-               if (cpuidle_state_table[cstate].disabled != 0) {
+               if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_UNUSABLE) {
                        pr_debug("state %s is disabled\n",
                                 cpuidle_state_table[cstate].name);
                        continue;
index fcc3f99..65f85fa 100644 (file)
@@ -163,16 +163,10 @@ static const struct iio_chan_spec cros_ec_accel_legacy_channels[] = {
 static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
        struct iio_dev *indio_dev;
        struct cros_ec_sensors_core_state *state;
        int ret;
 
-       if (!ec || !ec->ec_dev) {
-               dev_warn(&pdev->dev, "No EC device found.\n");
-               return -EINVAL;
-       }
-
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
        if (!indio_dev)
                return -ENOMEM;
index cdbb29c..fefad95 100644 (file)
@@ -4,7 +4,7 @@
 #
 config IIO_CROS_EC_SENSORS_CORE
        tristate "ChromeOS EC Sensors Core"
-       depends on SYSFS && CROS_EC
+       depends on SYSFS && CROS_EC_SENSORHUB
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index a698772..7dce044 100644 (file)
@@ -222,17 +222,11 @@ static const struct iio_info ec_sensors_info = {
 static int cros_ec_sensors_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
        struct iio_dev *indio_dev;
        struct cros_ec_sensors_state *state;
        struct iio_chan_spec *channel;
        int ret, i;
 
-       if (!ec_dev || !ec_dev->ec_dev) {
-               dev_warn(&pdev->dev, "No CROS EC device found.\n");
-               return -EINVAL;
-       }
-
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
        if (!indio_dev)
                return -ENOMEM;
index d2609e6..81a7f69 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/platform_data/cros_ec_commands.h>
 #include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_ec_sensorhub.h>
 #include <linux/platform_device.h>
 
 static char *cros_ec_loc[] = {
@@ -88,7 +89,8 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
 {
        struct device *dev = &pdev->dev;
        struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
-       struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
+       struct cros_ec_sensorhub *sensor_hub = dev_get_drvdata(dev->parent);
+       struct cros_ec_dev *ec = sensor_hub->ec;
        struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
        u32 ver_mask;
        int ret, i;
index c5263b5..d85a391 100644 (file)
@@ -169,17 +169,11 @@ static const struct iio_info cros_ec_light_prox_info = {
 static int cros_ec_light_prox_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
        struct iio_dev *indio_dev;
        struct cros_ec_light_prox_state *state;
        struct iio_chan_spec *channel;
        int ret;
 
-       if (!ec_dev || !ec_dev->ec_dev) {
-               dev_warn(dev, "No CROS EC device found.\n");
-               return -EINVAL;
-       }
-
        indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
        if (!indio_dev)
                return -ENOMEM;
index 8d4d978..2b71c5a 100644 (file)
@@ -226,8 +226,6 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
 {
        struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
                                                  notifier);
-       uint8_t mkbp_event_type = ckdev->ec->event_data.event_type &
-                                 EC_MKBP_EVENT_TYPE_MASK;
        u32 val;
        unsigned int ev_type;
 
@@ -239,7 +237,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
        if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
                return NOTIFY_OK;
 
-       switch (mkbp_event_type) {
+       switch (ckdev->ec->event_data.event_type) {
        case EC_MKBP_EVENT_KEY_MATRIX:
                pm_wakeup_event(ckdev->dev, 0);
 
@@ -266,7 +264,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
        case EC_MKBP_EVENT_SWITCH:
                pm_wakeup_event(ckdev->dev, 0);
 
-               if (mkbp_event_type == EC_MKBP_EVENT_BUTTON) {
+               if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
                        val = get_unaligned_le32(
                                        &ckdev->ec->event_data.data.buttons);
                        ev_type = EV_KEY;
index f1086ea..0b9d78a 100644 (file)
@@ -3,6 +3,10 @@
 config IOMMU_IOVA
        tristate
 
+# The IOASID library may also be used by non-IOMMU_API users
+config IOASID
+       tristate
+
 # IOMMU_API always gets selected by whoever wants it.
 config IOMMU_API
        bool
@@ -138,6 +142,7 @@ config AMD_IOMMU
        select PCI_PASID
        select IOMMU_API
        select IOMMU_IOVA
+       select IOMMU_DMA
        depends on X86_64 && PCI && ACPI
        ---help---
          With this option you can enable support for AMD IOMMU hardware in
@@ -207,6 +212,7 @@ config INTEL_IOMMU_SVM
        bool "Support for Shared Virtual Memory with Intel IOMMU"
        depends on INTEL_IOMMU && X86
        select PCI_PASID
+       select PCI_PRI
        select MMU_NOTIFIER
        help
          Shared Virtual Memory (SVM) provides a facility for devices
index 4f405f9..97814cc 100644 (file)
@@ -7,13 +7,14 @@ obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o
 obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o
 obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o
 obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
+obj-$(CONFIG_IOASID) += ioasid.o
 obj-$(CONFIG_IOMMU_IOVA) += iova.o
 obj-$(CONFIG_OF_IOMMU) += of_iommu.o
 obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o amd_iommu_quirks.o
 obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd_iommu_debugfs.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
-obj-$(CONFIG_ARM_SMMU) += arm-smmu.o arm-smmu-impl.o
+obj-$(CONFIG_ARM_SMMU) += arm-smmu.o arm-smmu-impl.o arm-smmu-qcom.o
 obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
 obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o
index 12e5039..bd25674 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-direct.h>
+#include <linux/dma-iommu.h>
 #include <linux/iommu-helper.h>
 #include <linux/iommu.h>
 #include <linux/delay.h>
@@ -88,8 +89,6 @@ const struct iommu_ops amd_iommu_ops;
 static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
 int amd_iommu_max_glx_val = -1;
 
-static const struct dma_map_ops amd_iommu_dma_ops;
-
 /*
  * general struct to manage commands send to an IOMMU
  */
@@ -102,21 +101,6 @@ struct kmem_cache *amd_iommu_irq_cache;
 static void update_domain(struct protection_domain *domain);
 static int protection_domain_init(struct protection_domain *domain);
 static void detach_device(struct device *dev);
-static void iova_domain_flush_tlb(struct iova_domain *iovad);
-
-/*
- * Data container for a dma_ops specific protection domain
- */
-struct dma_ops_domain {
-       /* generic protection domain information */
-       struct protection_domain domain;
-
-       /* IOVA RB-Tree */
-       struct iova_domain iovad;
-};
-
-static struct iova_domain reserved_iova_ranges;
-static struct lock_class_key reserved_rbtree_key;
 
 /****************************************************************************
  *
@@ -167,12 +151,6 @@ static struct protection_domain *to_pdomain(struct iommu_domain *dom)
        return container_of(dom, struct protection_domain, domain);
 }
 
-static struct dma_ops_domain* to_dma_ops_domain(struct protection_domain *domain)
-{
-       BUG_ON(domain->flags != PD_DMA_OPS_MASK);
-       return container_of(domain, struct dma_ops_domain, domain);
-}
-
 static struct iommu_dev_data *alloc_dev_data(u16 devid)
 {
        struct iommu_dev_data *dev_data;
@@ -206,71 +184,61 @@ static struct iommu_dev_data *search_dev_data(u16 devid)
        return NULL;
 }
 
-static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
-{
-       *(u16 *)data = alias;
-       return 0;
-}
-
-static u16 get_alias(struct device *dev)
+static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       u16 devid, ivrs_alias, pci_alias;
-
-       /* The callers make sure that get_device_id() does not fail here */
-       devid = get_device_id(dev);
+       u16 devid = pci_dev_id(pdev);
 
-       /* For ACPI HID devices, we simply return the devid as such */
-       if (!dev_is_pci(dev))
-               return devid;
+       if (devid == alias)
+               return 0;
 
-       ivrs_alias = amd_iommu_alias_table[devid];
+       amd_iommu_rlookup_table[alias] =
+               amd_iommu_rlookup_table[devid];
+       memcpy(amd_iommu_dev_table[alias].data,
+              amd_iommu_dev_table[devid].data,
+              sizeof(amd_iommu_dev_table[alias].data));
 
-       pci_for_each_dma_alias(pdev, __last_alias, &pci_alias);
+       return 0;
+}
 
-       if (ivrs_alias == pci_alias)
-               return ivrs_alias;
+static void clone_aliases(struct pci_dev *pdev)
+{
+       if (!pdev)
+               return;
 
        /*
-        * DMA alias showdown
-        *
-        * The IVRS is fairly reliable in telling us about aliases, but it
-        * can't know about every screwy device.  If we don't have an IVRS
-        * reported alias, use the PCI reported alias.  In that case we may
-        * still need to initialize the rlookup and dev_table entries if the
-        * alias is to a non-existent device.
+        * The IVRS alias stored in the alias table may not be
+        * part of the PCI DMA aliases if it's bus differs
+        * from the original device.
         */
-       if (ivrs_alias == devid) {
-               if (!amd_iommu_rlookup_table[pci_alias]) {
-                       amd_iommu_rlookup_table[pci_alias] =
-                               amd_iommu_rlookup_table[devid];
-                       memcpy(amd_iommu_dev_table[pci_alias].data,
-                              amd_iommu_dev_table[devid].data,
-                              sizeof(amd_iommu_dev_table[pci_alias].data));
-               }
+       clone_alias(pdev, amd_iommu_alias_table[pci_dev_id(pdev)], NULL);
 
-               return pci_alias;
-       }
+       pci_for_each_dma_alias(pdev, clone_alias, NULL);
+}
 
-       pci_info(pdev, "Using IVRS reported alias %02x:%02x.%d "
-               "for device [%04x:%04x], kernel reported alias "
-               "%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias),
-               PCI_FUNC(ivrs_alias), pdev->vendor, pdev->device,
-               PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias),
-               PCI_FUNC(pci_alias));
+static struct pci_dev *setup_aliases(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       u16 ivrs_alias;
+
+       /* For ACPI HID devices, there are no aliases */
+       if (!dev_is_pci(dev))
+               return NULL;
 
        /*
-        * If we don't have a PCI DMA alias and the IVRS alias is on the same
-        * bus, then the IVRS table may know about a quirk that we don't.
+        * Add the IVRS alias to the pci aliases if it is on the same
+        * bus. The IVRS table may know about a quirk that we don't.
         */
-       if (pci_alias == devid &&
+       ivrs_alias = amd_iommu_alias_table[pci_dev_id(pdev)];
+       if (ivrs_alias != pci_dev_id(pdev) &&
            PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) {
                pci_add_dma_alias(pdev, ivrs_alias & 0xff);
                pci_info(pdev, "Added PCI DMA alias %02x.%d\n",
                        PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias));
        }
 
-       return ivrs_alias;
+       clone_aliases(pdev);
+
+       return pdev;
 }
 
 static struct iommu_dev_data *find_dev_data(u16 devid)
@@ -408,7 +376,7 @@ static int iommu_init_device(struct device *dev)
        if (!dev_data)
                return -ENOMEM;
 
-       dev_data->alias = get_alias(dev);
+       dev_data->pdev = setup_aliases(dev);
 
        /*
         * By default we use passthrough mode for IOMMUv2 capable device.
@@ -433,20 +401,16 @@ static int iommu_init_device(struct device *dev)
 
 static void iommu_ignore_device(struct device *dev)
 {
-       u16 alias;
        int devid;
 
        devid = get_device_id(dev);
        if (devid < 0)
                return;
 
-       alias = get_alias(dev);
-
+       amd_iommu_rlookup_table[devid] = NULL;
        memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
-       memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));
 
-       amd_iommu_rlookup_table[devid] = NULL;
-       amd_iommu_rlookup_table[alias] = NULL;
+       setup_aliases(dev);
 }
 
 static void iommu_uninit_device(struct device *dev)
@@ -620,8 +584,7 @@ retry:
                        pasid, address, flags);
                break;
        case EVENT_TYPE_INV_PPR_REQ:
-               pasid = ((event[0] >> 16) & 0xFFFF)
-                       | ((event[1] << 6) & 0xF0000);
+               pasid = PPR_PASID(*((u64 *)__evt));
                tag = event[1] & 0x03FF;
                dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x tag=0x%03x]\n",
                        PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
@@ -856,17 +819,18 @@ static void copy_cmd_to_buffer(struct amd_iommu *iommu,
                               struct iommu_cmd *cmd)
 {
        u8 *target;
-
-       target = iommu->cmd_buf + iommu->cmd_buf_tail;
-
-       iommu->cmd_buf_tail += sizeof(*cmd);
-       iommu->cmd_buf_tail %= CMD_BUFFER_SIZE;
+       u32 tail;
 
        /* Copy command to buffer */
+       tail = iommu->cmd_buf_tail;
+       target = iommu->cmd_buf + tail;
        memcpy(target, cmd, sizeof(*cmd));
 
+       tail = (tail + sizeof(*cmd)) % CMD_BUFFER_SIZE;
+       iommu->cmd_buf_tail = tail;
+
        /* Tell the IOMMU about it */
-       writel(iommu->cmd_buf_tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+       writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
 }
 
 static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
@@ -1216,6 +1180,13 @@ static int device_flush_iotlb(struct iommu_dev_data *dev_data,
        return iommu_queue_command(iommu, &cmd);
 }
 
+static int device_flush_dte_alias(struct pci_dev *pdev, u16 alias, void *data)
+{
+       struct amd_iommu *iommu = data;
+
+       return iommu_flush_dte(iommu, alias);
+}
+
 /*
  * Command send function for invalidating a device table entry
  */
@@ -1226,14 +1197,22 @@ static int device_flush_dte(struct iommu_dev_data *dev_data)
        int ret;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
-       alias = dev_data->alias;
 
-       ret = iommu_flush_dte(iommu, dev_data->devid);
-       if (!ret && alias != dev_data->devid)
-               ret = iommu_flush_dte(iommu, alias);
+       if (dev_data->pdev)
+               ret = pci_for_each_dma_alias(dev_data->pdev,
+                                            device_flush_dte_alias, iommu);
+       else
+               ret = iommu_flush_dte(iommu, dev_data->devid);
        if (ret)
                return ret;
 
+       alias = amd_iommu_alias_table[dev_data->devid];
+       if (alias != dev_data->devid) {
+               ret = iommu_flush_dte(iommu, alias);
+               if (ret)
+                       return ret;
+       }
+
        if (dev_data->ats.enabled)
                ret = device_flush_iotlb(dev_data, 0, ~0UL);
 
@@ -1282,12 +1261,6 @@ static void domain_flush_pages(struct protection_domain *domain,
        __domain_flush_pages(domain, address, size, 0);
 }
 
-/* Flush the whole IO/TLB for a given protection domain */
-static void domain_flush_tlb(struct protection_domain *domain)
-{
-       __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0);
-}
-
 /* Flush the whole IO/TLB for a given protection domain - including PDE */
 static void domain_flush_tlb_pde(struct protection_domain *domain)
 {
@@ -1733,43 +1706,6 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
        return unmapped;
 }
 
-/****************************************************************************
- *
- * The next functions belong to the address allocator for the dma_ops
- * interface functions.
- *
- ****************************************************************************/
-
-
-static unsigned long dma_ops_alloc_iova(struct device *dev,
-                                       struct dma_ops_domain *dma_dom,
-                                       unsigned int pages, u64 dma_mask)
-{
-       unsigned long pfn = 0;
-
-       pages = __roundup_pow_of_two(pages);
-
-       if (dma_mask > DMA_BIT_MASK(32))
-               pfn = alloc_iova_fast(&dma_dom->iovad, pages,
-                                     IOVA_PFN(DMA_BIT_MASK(32)), false);
-
-       if (!pfn)
-               pfn = alloc_iova_fast(&dma_dom->iovad, pages,
-                                     IOVA_PFN(dma_mask), true);
-
-       return (pfn << PAGE_SHIFT);
-}
-
-static void dma_ops_free_iova(struct dma_ops_domain *dma_dom,
-                             unsigned long address,
-                             unsigned int pages)
-{
-       pages = __roundup_pow_of_two(pages);
-       address >>= PAGE_SHIFT;
-
-       free_iova_fast(&dma_dom->iovad, address, pages);
-}
-
 /****************************************************************************
  *
  * The next functions belong to the domain allocation. A domain is
@@ -1846,42 +1782,23 @@ static void free_gcr3_table(struct protection_domain *domain)
        free_page((unsigned long)domain->gcr3_tbl);
 }
 
-static void dma_ops_domain_flush_tlb(struct dma_ops_domain *dom)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dom->domain.lock, flags);
-       domain_flush_tlb(&dom->domain);
-       domain_flush_complete(&dom->domain);
-       spin_unlock_irqrestore(&dom->domain.lock, flags);
-}
-
-static void iova_domain_flush_tlb(struct iova_domain *iovad)
-{
-       struct dma_ops_domain *dom;
-
-       dom = container_of(iovad, struct dma_ops_domain, iovad);
-
-       dma_ops_domain_flush_tlb(dom);
-}
-
 /*
  * Free a domain, only used if something went wrong in the
  * allocation path and we need to free an already allocated page table
  */
-static void dma_ops_domain_free(struct dma_ops_domain *dom)
+static void dma_ops_domain_free(struct protection_domain *domain)
 {
-       if (!dom)
+       if (!domain)
                return;
 
-       put_iova_domain(&dom->iovad);
+       iommu_put_dma_cookie(&domain->domain);
 
-       free_pagetable(&dom->domain);
+       free_pagetable(domain);
 
-       if (dom->domain.id)
-               domain_id_free(dom->domain.id);
+       if (domain->id)
+               domain_id_free(domain->id);
 
-       kfree(dom);
+       kfree(domain);
 }
 
 /*
@@ -1889,35 +1806,30 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
  * It also initializes the page table and the address allocator data
  * structures required for the dma_ops interface
  */
-static struct dma_ops_domain *dma_ops_domain_alloc(void)
+static struct protection_domain *dma_ops_domain_alloc(void)
 {
-       struct dma_ops_domain *dma_dom;
+       struct protection_domain *domain;
 
-       dma_dom = kzalloc(sizeof(struct dma_ops_domain), GFP_KERNEL);
-       if (!dma_dom)
+       domain = kzalloc(sizeof(struct protection_domain), GFP_KERNEL);
+       if (!domain)
                return NULL;
 
-       if (protection_domain_init(&dma_dom->domain))
-               goto free_dma_dom;
-
-       dma_dom->domain.mode = PAGE_MODE_3_LEVEL;
-       dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL);
-       dma_dom->domain.flags = PD_DMA_OPS_MASK;
-       if (!dma_dom->domain.pt_root)
-               goto free_dma_dom;
-
-       init_iova_domain(&dma_dom->iovad, PAGE_SIZE, IOVA_START_PFN);
+       if (protection_domain_init(domain))
+               goto free_domain;
 
-       if (init_iova_flush_queue(&dma_dom->iovad, iova_domain_flush_tlb, NULL))
-               goto free_dma_dom;
+       domain->mode = PAGE_MODE_3_LEVEL;
+       domain->pt_root = (void *)get_zeroed_page(GFP_KERNEL);
+       domain->flags = PD_DMA_OPS_MASK;
+       if (!domain->pt_root)
+               goto free_domain;
 
-       /* Initialize reserved ranges */
-       copy_reserved_iova(&reserved_iova_ranges, &dma_dom->iovad);
+       if (iommu_get_dma_cookie(&domain->domain) == -ENOMEM)
+               goto free_domain;
 
-       return dma_dom;
+       return domain;
 
-free_dma_dom:
-       dma_ops_domain_free(dma_dom);
+free_domain:
+       dma_ops_domain_free(domain);
 
        return NULL;
 }
@@ -2015,11 +1927,9 @@ static void do_attach(struct iommu_dev_data *dev_data,
                      struct protection_domain *domain)
 {
        struct amd_iommu *iommu;
-       u16 alias;
        bool ats;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
-       alias = dev_data->alias;
        ats   = dev_data->ats.enabled;
 
        /* Update data structures */
@@ -2032,8 +1942,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
 
        /* Update device table */
        set_dte_entry(dev_data->devid, domain, ats, dev_data->iommu_v2);
-       if (alias != dev_data->devid)
-               set_dte_entry(alias, domain, ats, dev_data->iommu_v2);
+       clone_aliases(dev_data->pdev);
 
        device_flush_dte(dev_data);
 }
@@ -2042,17 +1951,14 @@ static void do_detach(struct iommu_dev_data *dev_data)
 {
        struct protection_domain *domain = dev_data->domain;
        struct amd_iommu *iommu;
-       u16 alias;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
-       alias = dev_data->alias;
 
        /* Update data structures */
        dev_data->domain = NULL;
        list_del(&dev_data->list);
        clear_dte_entry(dev_data->devid);
-       if (alias != dev_data->devid)
-               clear_dte_entry(alias);
+       clone_aliases(dev_data->pdev);
 
        /* Flush the DTE entry */
        device_flush_dte(dev_data);
@@ -2285,8 +2191,8 @@ static int amd_iommu_add_device(struct device *dev)
        domain = iommu_get_domain_for_dev(dev);
        if (domain->type == IOMMU_DOMAIN_IDENTITY)
                dev_data->passthrough = true;
-       else
-               dev->dma_ops = &amd_iommu_dma_ops;
+       else if (domain->type == IOMMU_DOMAIN_DMA)
+               iommu_setup_dma_ops(dev, IOVA_START_PFN << PAGE_SHIFT, 0);
 
 out:
        iommu_completion_wait(iommu);
@@ -2320,43 +2226,32 @@ static struct iommu_group *amd_iommu_device_group(struct device *dev)
        return acpihid_device_group(dev);
 }
 
+static int amd_iommu_domain_get_attr(struct iommu_domain *domain,
+               enum iommu_attr attr, void *data)
+{
+       switch (domain->type) {
+       case IOMMU_DOMAIN_UNMANAGED:
+               return -ENODEV;
+       case IOMMU_DOMAIN_DMA:
+               switch (attr) {
+               case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
+                       *(int *)data = !amd_iommu_unmap_flush;
+                       return 0;
+               default:
+                       return -ENODEV;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+}
+
 /*****************************************************************************
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
  *
  *****************************************************************************/
 
-/*
- * In the dma_ops path we only have the struct device. This function
- * finds the corresponding IOMMU, the protection domain and the
- * requestor id for a given device.
- * If the device is not yet associated with a domain this is also done
- * in this function.
- */
-static struct protection_domain *get_domain(struct device *dev)
-{
-       struct protection_domain *domain;
-       struct iommu_domain *io_domain;
-
-       if (!check_device(dev))
-               return ERR_PTR(-EINVAL);
-
-       domain = get_dev_data(dev)->domain;
-       if (domain == NULL && get_dev_data(dev)->defer_attach) {
-               get_dev_data(dev)->defer_attach = false;
-               io_domain = iommu_get_domain_for_dev(dev);
-               domain = to_pdomain(io_domain);
-               attach_device(dev, domain);
-       }
-       if (domain == NULL)
-               return ERR_PTR(-EBUSY);
-
-       if (!dma_ops_domain(domain))
-               return ERR_PTR(-EBUSY);
-
-       return domain;
-}
-
 static void update_device_table(struct protection_domain *domain)
 {
        struct iommu_dev_data *dev_data;
@@ -2364,13 +2259,7 @@ static void update_device_table(struct protection_domain *domain)
        list_for_each_entry(dev_data, &domain->dev_list, list) {
                set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled,
                              dev_data->iommu_v2);
-
-               if (dev_data->devid == dev_data->alias)
-                       continue;
-
-               /* There is an alias, update device table entry for it */
-               set_dte_entry(dev_data->alias, domain, dev_data->ats.enabled,
-                             dev_data->iommu_v2);
+               clone_aliases(dev_data->pdev);
        }
 }
 
@@ -2382,458 +2271,6 @@ static void update_domain(struct protection_domain *domain)
        domain_flush_tlb_pde(domain);
 }
 
-static int dir2prot(enum dma_data_direction direction)
-{
-       if (direction == DMA_TO_DEVICE)
-               return IOMMU_PROT_IR;
-       else if (direction == DMA_FROM_DEVICE)
-               return IOMMU_PROT_IW;
-       else if (direction == DMA_BIDIRECTIONAL)
-               return IOMMU_PROT_IW | IOMMU_PROT_IR;
-       else
-               return 0;
-}
-
-/*
- * This function contains common code for mapping of a physically
- * contiguous memory region into DMA address space. It is used by all
- * mapping functions provided with this IOMMU driver.
- * Must be called with the domain lock held.
- */
-static dma_addr_t __map_single(struct device *dev,
-                              struct dma_ops_domain *dma_dom,
-                              phys_addr_t paddr,
-                              size_t size,
-                              enum dma_data_direction direction,
-                              u64 dma_mask)
-{
-       dma_addr_t offset = paddr & ~PAGE_MASK;
-       dma_addr_t address, start, ret;
-       unsigned long flags;
-       unsigned int pages;
-       int prot = 0;
-       int i;
-
-       pages = iommu_num_pages(paddr, size, PAGE_SIZE);
-       paddr &= PAGE_MASK;
-
-       address = dma_ops_alloc_iova(dev, dma_dom, pages, dma_mask);
-       if (!address)
-               goto out;
-
-       prot = dir2prot(direction);
-
-       start = address;
-       for (i = 0; i < pages; ++i) {
-               ret = iommu_map_page(&dma_dom->domain, start, paddr,
-                                    PAGE_SIZE, prot, GFP_ATOMIC);
-               if (ret)
-                       goto out_unmap;
-
-               paddr += PAGE_SIZE;
-               start += PAGE_SIZE;
-       }
-       address += offset;
-
-       domain_flush_np_cache(&dma_dom->domain, address, size);
-
-out:
-       return address;
-
-out_unmap:
-
-       for (--i; i >= 0; --i) {
-               start -= PAGE_SIZE;
-               iommu_unmap_page(&dma_dom->domain, start, PAGE_SIZE);
-       }
-
-       spin_lock_irqsave(&dma_dom->domain.lock, flags);
-       domain_flush_tlb(&dma_dom->domain);
-       domain_flush_complete(&dma_dom->domain);
-       spin_unlock_irqrestore(&dma_dom->domain.lock, flags);
-
-       dma_ops_free_iova(dma_dom, address, pages);
-
-       return DMA_MAPPING_ERROR;
-}
-
-/*
- * Does the reverse of the __map_single function. Must be called with
- * the domain lock held too
- */
-static void __unmap_single(struct dma_ops_domain *dma_dom,
-                          dma_addr_t dma_addr,
-                          size_t size,
-                          int dir)
-{
-       dma_addr_t i, start;
-       unsigned int pages;
-
-       pages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
-       dma_addr &= PAGE_MASK;
-       start = dma_addr;
-
-       for (i = 0; i < pages; ++i) {
-               iommu_unmap_page(&dma_dom->domain, start, PAGE_SIZE);
-               start += PAGE_SIZE;
-       }
-
-       if (amd_iommu_unmap_flush) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&dma_dom->domain.lock, flags);
-               domain_flush_tlb(&dma_dom->domain);
-               domain_flush_complete(&dma_dom->domain);
-               spin_unlock_irqrestore(&dma_dom->domain.lock, flags);
-               dma_ops_free_iova(dma_dom, dma_addr, pages);
-       } else {
-               pages = __roundup_pow_of_two(pages);
-               queue_iova(&dma_dom->iovad, dma_addr >> PAGE_SHIFT, pages, 0);
-       }
-}
-
-/*
- * The exported map_single function for dma_ops.
- */
-static dma_addr_t map_page(struct device *dev, struct page *page,
-                          unsigned long offset, size_t size,
-                          enum dma_data_direction dir,
-                          unsigned long attrs)
-{
-       phys_addr_t paddr = page_to_phys(page) + offset;
-       struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
-       u64 dma_mask;
-
-       domain = get_domain(dev);
-       if (PTR_ERR(domain) == -EINVAL)
-               return (dma_addr_t)paddr;
-       else if (IS_ERR(domain))
-               return DMA_MAPPING_ERROR;
-
-       dma_mask = *dev->dma_mask;
-       dma_dom = to_dma_ops_domain(domain);
-
-       return __map_single(dev, dma_dom, paddr, size, dir, dma_mask);
-}
-
-/*
- * The exported unmap_single function for dma_ops.
- */
-static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-                      enum dma_data_direction dir, unsigned long attrs)
-{
-       struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
-
-       domain = get_domain(dev);
-       if (IS_ERR(domain))
-               return;
-
-       dma_dom = to_dma_ops_domain(domain);
-
-       __unmap_single(dma_dom, dma_addr, size, dir);
-}
-
-static int sg_num_pages(struct device *dev,
-                       struct scatterlist *sglist,
-                       int nelems)
-{
-       unsigned long mask, boundary_size;
-       struct scatterlist *s;
-       int i, npages = 0;
-
-       mask          = dma_get_seg_boundary(dev);
-       boundary_size = mask + 1 ? ALIGN(mask + 1, PAGE_SIZE) >> PAGE_SHIFT :
-                                  1UL << (BITS_PER_LONG - PAGE_SHIFT);
-
-       for_each_sg(sglist, s, nelems, i) {
-               int p, n;
-
-               s->dma_address = npages << PAGE_SHIFT;
-               p = npages % boundary_size;
-               n = iommu_num_pages(sg_phys(s), s->length, PAGE_SIZE);
-               if (p + n > boundary_size)
-                       npages += boundary_size - p;
-               npages += n;
-       }
-
-       return npages;
-}
-
-/*
- * The exported map_sg function for dma_ops (handles scatter-gather
- * lists).
- */
-static int map_sg(struct device *dev, struct scatterlist *sglist,
-                 int nelems, enum dma_data_direction direction,
-                 unsigned long attrs)
-{
-       int mapped_pages = 0, npages = 0, prot = 0, i;
-       struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
-       struct scatterlist *s;
-       unsigned long address;
-       u64 dma_mask;
-       int ret;
-
-       domain = get_domain(dev);
-       if (IS_ERR(domain))
-               return 0;
-
-       dma_dom  = to_dma_ops_domain(domain);
-       dma_mask = *dev->dma_mask;
-
-       npages = sg_num_pages(dev, sglist, nelems);
-
-       address = dma_ops_alloc_iova(dev, dma_dom, npages, dma_mask);
-       if (!address)
-               goto out_err;
-
-       prot = dir2prot(direction);
-
-       /* Map all sg entries */
-       for_each_sg(sglist, s, nelems, i) {
-               int j, pages = iommu_num_pages(sg_phys(s), s->length, PAGE_SIZE);
-
-               for (j = 0; j < pages; ++j) {
-                       unsigned long bus_addr, phys_addr;
-
-                       bus_addr  = address + s->dma_address + (j << PAGE_SHIFT);
-                       phys_addr = (sg_phys(s) & PAGE_MASK) + (j << PAGE_SHIFT);
-                       ret = iommu_map_page(domain, bus_addr, phys_addr,
-                                            PAGE_SIZE, prot,
-                                            GFP_ATOMIC | __GFP_NOWARN);
-                       if (ret)
-                               goto out_unmap;
-
-                       mapped_pages += 1;
-               }
-       }
-
-       /* Everything is mapped - write the right values into s->dma_address */
-       for_each_sg(sglist, s, nelems, i) {
-               /*
-                * Add in the remaining piece of the scatter-gather offset that
-                * was masked out when we were determining the physical address
-                * via (sg_phys(s) & PAGE_MASK) earlier.
-                */
-               s->dma_address += address + (s->offset & ~PAGE_MASK);
-               s->dma_length   = s->length;
-       }
-
-       if (s)
-               domain_flush_np_cache(domain, s->dma_address, s->dma_length);
-
-       return nelems;
-
-out_unmap:
-       dev_err(dev, "IOMMU mapping error in map_sg (io-pages: %d reason: %d)\n",
-               npages, ret);
-
-       for_each_sg(sglist, s, nelems, i) {
-               int j, pages = iommu_num_pages(sg_phys(s), s->length, PAGE_SIZE);
-
-               for (j = 0; j < pages; ++j) {
-                       unsigned long bus_addr;
-
-                       bus_addr  = address + s->dma_address + (j << PAGE_SHIFT);
-                       iommu_unmap_page(domain, bus_addr, PAGE_SIZE);
-
-                       if (--mapped_pages == 0)
-                               goto out_free_iova;
-               }
-       }
-
-out_free_iova:
-       free_iova_fast(&dma_dom->iovad, address >> PAGE_SHIFT, npages);
-
-out_err:
-       return 0;
-}
-
-/*
- * The exported map_sg function for dma_ops (handles scatter-gather
- * lists).
- */
-static void unmap_sg(struct device *dev, struct scatterlist *sglist,
-                    int nelems, enum dma_data_direction dir,
-                    unsigned long attrs)
-{
-       struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
-       unsigned long startaddr;
-       int npages;
-
-       domain = get_domain(dev);
-       if (IS_ERR(domain))
-               return;
-
-       startaddr = sg_dma_address(sglist) & PAGE_MASK;
-       dma_dom   = to_dma_ops_domain(domain);
-       npages    = sg_num_pages(dev, sglist, nelems);
-
-       __unmap_single(dma_dom, startaddr, npages << PAGE_SHIFT, dir);
-}
-
-/*
- * The exported alloc_coherent function for dma_ops.
- */
-static void *alloc_coherent(struct device *dev, size_t size,
-                           dma_addr_t *dma_addr, gfp_t flag,
-                           unsigned long attrs)
-{
-       u64 dma_mask = dev->coherent_dma_mask;
-       struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
-       struct page *page;
-
-       domain = get_domain(dev);
-       if (PTR_ERR(domain) == -EINVAL) {
-               page = alloc_pages(flag, get_order(size));
-               *dma_addr = page_to_phys(page);
-               return page_address(page);
-       } else if (IS_ERR(domain))
-               return NULL;
-
-       dma_dom   = to_dma_ops_domain(domain);
-       size      = PAGE_ALIGN(size);
-       dma_mask  = dev->coherent_dma_mask;
-       flag     &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
-       flag     |= __GFP_ZERO;
-
-       page = alloc_pages(flag | __GFP_NOWARN,  get_order(size));
-       if (!page) {
-               if (!gfpflags_allow_blocking(flag))
-                       return NULL;
-
-               page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
-                                       get_order(size), flag & __GFP_NOWARN);
-               if (!page)
-                       return NULL;
-       }
-
-       if (!dma_mask)
-               dma_mask = *dev->dma_mask;
-
-       *dma_addr = __map_single(dev, dma_dom, page_to_phys(page),
-                                size, DMA_BIDIRECTIONAL, dma_mask);
-
-       if (*dma_addr == DMA_MAPPING_ERROR)
-               goto out_free;
-
-       return page_address(page);
-
-out_free:
-
-       if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
-               __free_pages(page, get_order(size));
-
-       return NULL;
-}
-
-/*
- * The exported free_coherent function for dma_ops.
- */
-static void free_coherent(struct device *dev, size_t size,
-                         void *virt_addr, dma_addr_t dma_addr,
-                         unsigned long attrs)
-{
-       struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
-       struct page *page;
-
-       page = virt_to_page(virt_addr);
-       size = PAGE_ALIGN(size);
-
-       domain = get_domain(dev);
-       if (IS_ERR(domain))
-               goto free_mem;
-
-       dma_dom = to_dma_ops_domain(domain);
-
-       __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL);
-
-free_mem:
-       if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
-               __free_pages(page, get_order(size));
-}
-
-/*
- * This function is called by the DMA layer to find out if we can handle a
- * particular device. It is part of the dma_ops.
- */
-static int amd_iommu_dma_supported(struct device *dev, u64 mask)
-{
-       if (!dma_direct_supported(dev, mask))
-               return 0;
-       return check_device(dev);
-}
-
-static const struct dma_map_ops amd_iommu_dma_ops = {
-       .alloc          = alloc_coherent,
-       .free           = free_coherent,
-       .map_page       = map_page,
-       .unmap_page     = unmap_page,
-       .map_sg         = map_sg,
-       .unmap_sg       = unmap_sg,
-       .dma_supported  = amd_iommu_dma_supported,
-       .mmap           = dma_common_mmap,
-       .get_sgtable    = dma_common_get_sgtable,
-};
-
-static int init_reserved_iova_ranges(void)
-{
-       struct pci_dev *pdev = NULL;
-       struct iova *val;
-
-       init_iova_domain(&reserved_iova_ranges, PAGE_SIZE, IOVA_START_PFN);
-
-       lockdep_set_class(&reserved_iova_ranges.iova_rbtree_lock,
-                         &reserved_rbtree_key);
-
-       /* MSI memory range */
-       val = reserve_iova(&reserved_iova_ranges,
-                          IOVA_PFN(MSI_RANGE_START), IOVA_PFN(MSI_RANGE_END));
-       if (!val) {
-               pr_err("Reserving MSI range failed\n");
-               return -ENOMEM;
-       }
-
-       /* HT memory range */
-       val = reserve_iova(&reserved_iova_ranges,
-                          IOVA_PFN(HT_RANGE_START), IOVA_PFN(HT_RANGE_END));
-       if (!val) {
-               pr_err("Reserving HT range failed\n");
-               return -ENOMEM;
-       }
-
-       /*
-        * Memory used for PCI resources
-        * FIXME: Check whether we can reserve the PCI-hole completly
-        */
-       for_each_pci_dev(pdev) {
-               int i;
-
-               for (i = 0; i < PCI_NUM_RESOURCES; ++i) {
-                       struct resource *r = &pdev->resource[i];
-
-                       if (!(r->flags & IORESOURCE_MEM))
-                               continue;
-
-                       val = reserve_iova(&reserved_iova_ranges,
-                                          IOVA_PFN(r->start),
-                                          IOVA_PFN(r->end));
-                       if (!val) {
-                               pci_err(pdev, "Reserve pci-resource range %pR failed\n", r);
-                               return -ENOMEM;
-                       }
-               }
-       }
-
-       return 0;
-}
-
 int __init amd_iommu_init_api(void)
 {
        int ret, err = 0;
@@ -2842,10 +2279,6 @@ int __init amd_iommu_init_api(void)
        if (ret)
                return ret;
 
-       ret = init_reserved_iova_ranges();
-       if (ret)
-               return ret;
-
        err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
        if (err)
                return err;
@@ -2916,7 +2349,6 @@ static void protection_domain_free(struct protection_domain *domain)
 static int protection_domain_init(struct protection_domain *domain)
 {
        spin_lock_init(&domain->lock);
-       mutex_init(&domain->api_lock);
        domain->id = domain_id_alloc();
        if (!domain->id)
                return -ENOMEM;
@@ -2947,7 +2379,6 @@ out_err:
 static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 {
        struct protection_domain *pdomain;
-       struct dma_ops_domain *dma_domain;
 
        switch (type) {
        case IOMMU_DOMAIN_UNMANAGED:
@@ -2968,12 +2399,11 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 
                break;
        case IOMMU_DOMAIN_DMA:
-               dma_domain = dma_ops_domain_alloc();
-               if (!dma_domain) {
+               pdomain = dma_ops_domain_alloc();
+               if (!pdomain) {
                        pr_err("Failed to allocate\n");
                        return NULL;
                }
-               pdomain = &dma_domain->domain;
                break;
        case IOMMU_DOMAIN_IDENTITY:
                pdomain = protection_domain_alloc();
@@ -2992,7 +2422,6 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 static void amd_iommu_domain_free(struct iommu_domain *dom)
 {
        struct protection_domain *domain;
-       struct dma_ops_domain *dma_dom;
 
        domain = to_pdomain(dom);
 
@@ -3007,8 +2436,7 @@ static void amd_iommu_domain_free(struct iommu_domain *dom)
        switch (dom->type) {
        case IOMMU_DOMAIN_DMA:
                /* Now release the domain */
-               dma_dom = to_dma_ops_domain(domain);
-               dma_ops_domain_free(dma_dom);
+               dma_ops_domain_free(domain);
                break;
        default:
                if (domain->mode != PAGE_MODE_NONE)
@@ -3064,6 +2492,7 @@ static int amd_iommu_attach_device(struct iommu_domain *dom,
                return -EINVAL;
 
        dev_data = dev->archdata.iommu;
+       dev_data->defer_attach = false;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
        if (!iommu)
@@ -3089,7 +2518,8 @@ static int amd_iommu_attach_device(struct iommu_domain *dom,
 }
 
 static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
-                        phys_addr_t paddr, size_t page_size, int iommu_prot)
+                        phys_addr_t paddr, size_t page_size, int iommu_prot,
+                        gfp_t gfp)
 {
        struct protection_domain *domain = to_pdomain(dom);
        int prot = 0;
@@ -3103,9 +2533,7 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
        if (iommu_prot & IOMMU_WRITE)
                prot |= IOMMU_PROT_IW;
 
-       mutex_lock(&domain->api_lock);
-       ret = iommu_map_page(domain, iova, paddr, page_size, prot, GFP_KERNEL);
-       mutex_unlock(&domain->api_lock);
+       ret = iommu_map_page(domain, iova, paddr, page_size, prot, gfp);
 
        domain_flush_np_cache(domain, iova, page_size);
 
@@ -3117,16 +2545,11 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
                              struct iommu_iotlb_gather *gather)
 {
        struct protection_domain *domain = to_pdomain(dom);
-       size_t unmap_size;
 
        if (domain->mode == PAGE_MODE_NONE)
                return 0;
 
-       mutex_lock(&domain->api_lock);
-       unmap_size = iommu_unmap_page(domain, iova, page_size);
-       mutex_unlock(&domain->api_lock);
-
-       return unmap_size;
+       return iommu_unmap_page(domain, iova, page_size);
 }
 
 static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
@@ -3227,19 +2650,6 @@ static void amd_iommu_put_resv_regions(struct device *dev,
                kfree(entry);
 }
 
-static void amd_iommu_apply_resv_region(struct device *dev,
-                                     struct iommu_domain *domain,
-                                     struct iommu_resv_region *region)
-{
-       struct dma_ops_domain *dma_dom = to_dma_ops_domain(to_pdomain(domain));
-       unsigned long start, end;
-
-       start = IOVA_PFN(region->start);
-       end   = IOVA_PFN(region->start + region->length - 1);
-
-       WARN_ON_ONCE(reserve_iova(&dma_dom->iovad, start, end) == NULL);
-}
-
 static bool amd_iommu_is_attach_deferred(struct iommu_domain *domain,
                                         struct device *dev)
 {
@@ -3276,9 +2686,9 @@ const struct iommu_ops amd_iommu_ops = {
        .add_device = amd_iommu_add_device,
        .remove_device = amd_iommu_remove_device,
        .device_group = amd_iommu_device_group,
+       .domain_get_attr = amd_iommu_domain_get_attr,
        .get_resv_regions = amd_iommu_get_resv_regions,
        .put_resv_regions = amd_iommu_put_resv_regions,
-       .apply_resv_region = amd_iommu_apply_resv_region,
        .is_attach_deferred = amd_iommu_is_attach_deferred,
        .pgsize_bitmap  = AMD_IOMMU_PGSIZES,
        .flush_iotlb_all = amd_iommu_flush_iotlb_all,
@@ -3590,9 +3000,23 @@ EXPORT_SYMBOL(amd_iommu_complete_ppr);
 struct iommu_domain *amd_iommu_get_v2_domain(struct pci_dev *pdev)
 {
        struct protection_domain *pdomain;
+       struct iommu_domain *io_domain;
+       struct device *dev = &pdev->dev;
+
+       if (!check_device(dev))
+               return NULL;
 
-       pdomain = get_domain(&pdev->dev);
-       if (IS_ERR(pdomain))
+       pdomain = get_dev_data(dev)->domain;
+       if (pdomain == NULL && get_dev_data(dev)->defer_attach) {
+               get_dev_data(dev)->defer_attach = false;
+               io_domain = iommu_get_domain_for_dev(dev);
+               pdomain = to_pdomain(io_domain);
+               attach_device(dev, pdomain);
+       }
+       if (pdomain == NULL)
+               return NULL;
+
+       if (!dma_ops_domain(pdomain))
                return NULL;
 
        /* Only return IOMMUv2 domains */
@@ -3732,7 +3156,20 @@ static void set_remap_table_entry(struct amd_iommu *iommu, u16 devid,
        iommu_flush_dte(iommu, devid);
 }
 
-static struct irq_remap_table *alloc_irq_table(u16 devid)
+static int set_remap_table_entry_alias(struct pci_dev *pdev, u16 alias,
+                                      void *data)
+{
+       struct irq_remap_table *table = data;
+
+       irq_lookup_table[alias] = table;
+       set_dte_irq_entry(alias, table);
+
+       iommu_flush_dte(amd_iommu_rlookup_table[alias], alias);
+
+       return 0;
+}
+
+static struct irq_remap_table *alloc_irq_table(u16 devid, struct pci_dev *pdev)
 {
        struct irq_remap_table *table = NULL;
        struct irq_remap_table *new_table = NULL;
@@ -3778,7 +3215,12 @@ static struct irq_remap_table *alloc_irq_table(u16 devid)
        table = new_table;
        new_table = NULL;
 
-       set_remap_table_entry(iommu, devid, table);
+       if (pdev)
+               pci_for_each_dma_alias(pdev, set_remap_table_entry_alias,
+                                      table);
+       else
+               set_remap_table_entry(iommu, devid, table);
+
        if (devid != alias)
                set_remap_table_entry(iommu, alias, table);
 
@@ -3795,7 +3237,8 @@ out_unlock:
        return table;
 }
 
-static int alloc_irq_index(u16 devid, int count, bool align)
+static int alloc_irq_index(u16 devid, int count, bool align,
+                          struct pci_dev *pdev)
 {
        struct irq_remap_table *table;
        int index, c, alignment = 1;
@@ -3805,7 +3248,7 @@ static int alloc_irq_index(u16 devid, int count, bool align)
        if (!iommu)
                return -ENODEV;
 
-       table = alloc_irq_table(devid);
+       table = alloc_irq_table(devid, pdev);
        if (!table)
                return -ENODEV;
 
@@ -4238,7 +3681,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
                struct irq_remap_table *table;
                struct amd_iommu *iommu;
 
-               table = alloc_irq_table(devid);
+               table = alloc_irq_table(devid, NULL);
                if (table) {
                        if (!table->min_index) {
                                /*
@@ -4255,11 +3698,15 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
                } else {
                        index = -ENOMEM;
                }
-       } else {
+       } else if (info->type == X86_IRQ_ALLOC_TYPE_MSI ||
+                  info->type == X86_IRQ_ALLOC_TYPE_MSIX) {
                bool align = (info->type == X86_IRQ_ALLOC_TYPE_MSI);
 
-               index = alloc_irq_index(devid, nr_irqs, align);
+               index = alloc_irq_index(devid, nr_irqs, align, info->msi_dev);
+       } else {
+               index = alloc_irq_index(devid, nr_irqs, false, NULL);
        }
+
        if (index < 0) {
                pr_warn("Failed to allocate IRTE\n");
                ret = index;
index 17bd5a3..f52f59d 100644 (file)
@@ -468,7 +468,6 @@ struct protection_domain {
        struct iommu_domain domain; /* generic domain handle used by
                                       iommu core code */
        spinlock_t lock;        /* mostly used to lock the page table*/
-       struct mutex api_lock;  /* protect page tables in the iommu-api path */
        u16 id;                 /* the domain id written to the device table */
        int mode;               /* paging mode (0-6 levels) */
        u64 *pt_root;           /* page table root pointer */
@@ -639,8 +638,8 @@ struct iommu_dev_data {
        struct list_head list;            /* For domain->dev_list */
        struct llist_node dev_data_list;  /* For global dev_data_list */
        struct protection_domain *domain; /* Domain the device is bound to */
+       struct pci_dev *pdev;
        u16 devid;                        /* PCI Device ID */
-       u16 alias;                        /* Alias Device ID */
        bool iommu_v2;                    /* Device can make use of IOMMUv2 */
        bool passthrough;                 /* Device is identity mapped */
        struct {
index 5c87a38..b2fe72a 100644 (file)
@@ -109,7 +109,7 @@ static struct arm_smmu_device *cavium_smmu_impl_init(struct arm_smmu_device *smm
 #define ARM_MMU500_ACR_S2CRB_TLBEN     (1 << 10)
 #define ARM_MMU500_ACR_SMTNMB_TLBEN    (1 << 8)
 
-static int arm_mmu500_reset(struct arm_smmu_device *smmu)
+int arm_mmu500_reset(struct arm_smmu_device *smmu)
 {
        u32 reg, major;
        int i;
@@ -170,5 +170,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
                                  "calxeda,smmu-secure-config-access"))
                smmu->impl = &calxeda_impl;
 
+       if (of_device_is_compatible(smmu->dev->of_node, "qcom,sdm845-smmu-500"))
+               return qcom_smmu_impl_init(smmu);
+
        return smmu;
 }
diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c
new file mode 100644 (file)
index 0000000..24c071c
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/qcom_scm.h>
+
+#include "arm-smmu.h"
+
+struct qcom_smmu {
+       struct arm_smmu_device smmu;
+};
+
+static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
+{
+       int ret;
+
+       arm_mmu500_reset(smmu);
+
+       /*
+        * To address performance degradation in non-real time clients,
+        * such as USB and UFS, turn off wait-for-safe on sdm845 based boards,
+        * such as MTP and db845, whose firmwares implement secure monitor
+        * call handlers to turn on/off the wait-for-safe logic.
+        */
+       ret = qcom_scm_qsmmu500_wait_safe_toggle(0);
+       if (ret)
+               dev_warn(smmu->dev, "Failed to turn off SAFE logic\n");
+
+       return ret;
+}
+
+static const struct arm_smmu_impl qcom_smmu_impl = {
+       .reset = qcom_sdm845_smmu500_reset,
+};
+
+struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu)
+{
+       struct qcom_smmu *qsmmu;
+
+       qsmmu = devm_kzalloc(smmu->dev, sizeof(*qsmmu), GFP_KERNEL);
+       if (!qsmmu)
+               return ERR_PTR(-ENOMEM);
+
+       qsmmu->smmu = *smmu;
+
+       qsmmu->smmu.impl = &qcom_smmu_impl;
+       devm_kfree(smmu->dev, smmu);
+
+       return &qsmmu->smmu;
+}
index 8da93e7..effe72e 100644 (file)
@@ -2172,7 +2172,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
        cfg->cd.asid    = (u16)asid;
        cfg->cd.ttbr    = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
        cfg->cd.tcr     = pgtbl_cfg->arm_lpae_s1_cfg.tcr;
-       cfg->cd.mair    = pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
+       cfg->cd.mair    = pgtbl_cfg->arm_lpae_s1_cfg.mair;
        return 0;
 
 out_free_asid:
@@ -2448,7 +2448,7 @@ out_unlock:
 }
 
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
-                       phys_addr_t paddr, size_t size, int prot)
+                       phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
 
@@ -3611,19 +3611,19 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 
        /* Interrupt lines */
 
-       irq = platform_get_irq_byname(pdev, "combined");
+       irq = platform_get_irq_byname_optional(pdev, "combined");
        if (irq > 0)
                smmu->combined_irq = irq;
        else {
-               irq = platform_get_irq_byname(pdev, "eventq");
+               irq = platform_get_irq_byname_optional(pdev, "eventq");
                if (irq > 0)
                        smmu->evtq.q.irq = irq;
 
-               irq = platform_get_irq_byname(pdev, "priq");
+               irq = platform_get_irq_byname_optional(pdev, "priq");
                if (irq > 0)
                        smmu->priq.q.irq = irq;
 
-               irq = platform_get_irq_byname(pdev, "gerror");
+               irq = platform_get_irq_byname_optional(pdev, "gerror");
                if (irq > 0)
                        smmu->gerr_irq = irq;
        }
index 7c503a6..4f1a350 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/ratelimit.h>
 #include <linux/slab.h>
 
 #include <linux/amba/bus.h>
@@ -122,7 +123,7 @@ static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
 static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
 {
        if (pm_runtime_enabled(smmu->dev))
-               pm_runtime_put(smmu->dev);
+               pm_runtime_put_autosuspend(smmu->dev);
 }
 
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
@@ -244,6 +245,9 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
        unsigned int spin_cnt, delay;
        u32 reg;
 
+       if (smmu->impl && unlikely(smmu->impl->tlb_sync))
+               return smmu->impl->tlb_sync(smmu, page, sync, status);
+
        arm_smmu_writel(smmu, page, sync, QCOM_DUMMY_VAL);
        for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) {
                for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) {
@@ -268,9 +272,8 @@ static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu)
        spin_unlock_irqrestore(&smmu->global_sync_lock, flags);
 }
 
-static void arm_smmu_tlb_sync_context(void *cookie)
+static void arm_smmu_tlb_sync_context(struct arm_smmu_domain *smmu_domain)
 {
-       struct arm_smmu_domain *smmu_domain = cookie;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
        unsigned long flags;
 
@@ -280,13 +283,6 @@ static void arm_smmu_tlb_sync_context(void *cookie)
        spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
 }
 
-static void arm_smmu_tlb_sync_vmid(void *cookie)
-{
-       struct arm_smmu_domain *smmu_domain = cookie;
-
-       arm_smmu_tlb_sync_global(smmu_domain->smmu);
-}
-
 static void arm_smmu_tlb_inv_context_s1(void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
@@ -297,7 +293,7 @@ static void arm_smmu_tlb_inv_context_s1(void *cookie)
        wmb();
        arm_smmu_cb_write(smmu_domain->smmu, smmu_domain->cfg.cbndx,
                          ARM_SMMU_CB_S1_TLBIASID, smmu_domain->cfg.asid);
-       arm_smmu_tlb_sync_context(cookie);
+       arm_smmu_tlb_sync_context(smmu_domain);
 }
 
 static void arm_smmu_tlb_inv_context_s2(void *cookie)
@@ -312,18 +308,16 @@ static void arm_smmu_tlb_inv_context_s2(void *cookie)
 }
 
 static void arm_smmu_tlb_inv_range_s1(unsigned long iova, size_t size,
-                                     size_t granule, bool leaf, void *cookie)
+                                     size_t granule, void *cookie, int reg)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
        struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
-       int reg, idx = cfg->cbndx;
+       int idx = cfg->cbndx;
 
        if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
                wmb();
 
-       reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
-
        if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) {
                iova = (iova >> 12) << 12;
                iova |= cfg->asid;
@@ -342,16 +336,15 @@ static void arm_smmu_tlb_inv_range_s1(unsigned long iova, size_t size,
 }
 
 static void arm_smmu_tlb_inv_range_s2(unsigned long iova, size_t size,
-                                     size_t granule, bool leaf, void *cookie)
+                                     size_t granule, void *cookie, int reg)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
-       int reg, idx = smmu_domain->cfg.cbndx;
+       int idx = smmu_domain->cfg.cbndx;
 
        if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
                wmb();
 
-       reg = leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L : ARM_SMMU_CB_S2_TLBIIPAS2;
        iova >>= 12;
        do {
                if (smmu_domain->cfg.fmt == ARM_SMMU_CTX_FMT_AARCH64)
@@ -362,85 +355,98 @@ static void arm_smmu_tlb_inv_range_s2(unsigned long iova, size_t size,
        } while (size -= granule);
 }
 
-/*
- * On MMU-401 at least, the cost of firing off multiple TLBIVMIDs appears
- * almost negligible, but the benefit of getting the first one in as far ahead
- * of the sync as possible is significant, hence we don't just make this a
- * no-op and set .tlb_sync to arm_smmu_tlb_inv_context_s2() as you might think.
- */
-static void arm_smmu_tlb_inv_vmid_nosync(unsigned long iova, size_t size,
-                                        size_t granule, bool leaf, void *cookie)
+static void arm_smmu_tlb_inv_walk_s1(unsigned long iova, size_t size,
+                                    size_t granule, void *cookie)
 {
-       struct arm_smmu_domain *smmu_domain = cookie;
-       struct arm_smmu_device *smmu = smmu_domain->smmu;
-
-       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
-               wmb();
+       arm_smmu_tlb_inv_range_s1(iova, size, granule, cookie,
+                                 ARM_SMMU_CB_S1_TLBIVA);
+       arm_smmu_tlb_sync_context(cookie);
+}
 
-       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIVMID, smmu_domain->cfg.vmid);
+static void arm_smmu_tlb_inv_leaf_s1(unsigned long iova, size_t size,
+                                    size_t granule, void *cookie)
+{
+       arm_smmu_tlb_inv_range_s1(iova, size, granule, cookie,
+                                 ARM_SMMU_CB_S1_TLBIVAL);
+       arm_smmu_tlb_sync_context(cookie);
 }
 
-static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
-                                 size_t granule, void *cookie)
+static void arm_smmu_tlb_add_page_s1(struct iommu_iotlb_gather *gather,
+                                    unsigned long iova, size_t granule,
+                                    void *cookie)
 {
-       struct arm_smmu_domain *smmu_domain = cookie;
-       const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops;
+       arm_smmu_tlb_inv_range_s1(iova, granule, granule, cookie,
+                                 ARM_SMMU_CB_S1_TLBIVAL);
+}
 
-       ops->tlb_inv_range(iova, size, granule, false, cookie);
-       ops->tlb_sync(cookie);
+static void arm_smmu_tlb_inv_walk_s2(unsigned long iova, size_t size,
+                                    size_t granule, void *cookie)
+{
+       arm_smmu_tlb_inv_range_s2(iova, size, granule, cookie,
+                                 ARM_SMMU_CB_S2_TLBIIPAS2);
+       arm_smmu_tlb_sync_context(cookie);
 }
 
-static void arm_smmu_tlb_inv_leaf(unsigned long iova, size_t size,
-                                 size_t granule, void *cookie)
+static void arm_smmu_tlb_inv_leaf_s2(unsigned long iova, size_t size,
+                                    size_t granule, void *cookie)
 {
-       struct arm_smmu_domain *smmu_domain = cookie;
-       const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops;
+       arm_smmu_tlb_inv_range_s2(iova, size, granule, cookie,
+                                 ARM_SMMU_CB_S2_TLBIIPAS2L);
+       arm_smmu_tlb_sync_context(cookie);
+}
 
-       ops->tlb_inv_range(iova, size, granule, true, cookie);
-       ops->tlb_sync(cookie);
+static void arm_smmu_tlb_add_page_s2(struct iommu_iotlb_gather *gather,
+                                    unsigned long iova, size_t granule,
+                                    void *cookie)
+{
+       arm_smmu_tlb_inv_range_s2(iova, granule, granule, cookie,
+                                 ARM_SMMU_CB_S2_TLBIIPAS2L);
 }
 
-static void arm_smmu_tlb_add_page(struct iommu_iotlb_gather *gather,
-                                 unsigned long iova, size_t granule,
-                                 void *cookie)
+static void arm_smmu_tlb_inv_any_s2_v1(unsigned long iova, size_t size,
+                                      size_t granule, void *cookie)
+{
+       arm_smmu_tlb_inv_context_s2(cookie);
+}
+/*
+ * On MMU-401 at least, the cost of firing off multiple TLBIVMIDs appears
+ * almost negligible, but the benefit of getting the first one in as far ahead
+ * of the sync as possible is significant, hence we don't just make this a
+ * no-op and call arm_smmu_tlb_inv_context_s2() from .iotlb_sync as you might
+ * think.
+ */
+static void arm_smmu_tlb_add_page_s2_v1(struct iommu_iotlb_gather *gather,
+                                       unsigned long iova, size_t granule,
+                                       void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
-       const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops;
+       struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+               wmb();
 
-       ops->tlb_inv_range(iova, granule, granule, true, cookie);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIVMID, smmu_domain->cfg.vmid);
 }
 
-static const struct arm_smmu_flush_ops arm_smmu_s1_tlb_ops = {
-       .tlb = {
-               .tlb_flush_all  = arm_smmu_tlb_inv_context_s1,
-               .tlb_flush_walk = arm_smmu_tlb_inv_walk,
-               .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
-               .tlb_add_page   = arm_smmu_tlb_add_page,
-       },
-       .tlb_inv_range          = arm_smmu_tlb_inv_range_s1,
-       .tlb_sync               = arm_smmu_tlb_sync_context,
+static const struct iommu_flush_ops arm_smmu_s1_tlb_ops = {
+       .tlb_flush_all  = arm_smmu_tlb_inv_context_s1,
+       .tlb_flush_walk = arm_smmu_tlb_inv_walk_s1,
+       .tlb_flush_leaf = arm_smmu_tlb_inv_leaf_s1,
+       .tlb_add_page   = arm_smmu_tlb_add_page_s1,
 };
 
-static const struct arm_smmu_flush_ops arm_smmu_s2_tlb_ops_v2 = {
-       .tlb = {
-               .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
-               .tlb_flush_walk = arm_smmu_tlb_inv_walk,
-               .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
-               .tlb_add_page   = arm_smmu_tlb_add_page,
-       },
-       .tlb_inv_range          = arm_smmu_tlb_inv_range_s2,
-       .tlb_sync               = arm_smmu_tlb_sync_context,
+static const struct iommu_flush_ops arm_smmu_s2_tlb_ops_v2 = {
+       .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
+       .tlb_flush_walk = arm_smmu_tlb_inv_walk_s2,
+       .tlb_flush_leaf = arm_smmu_tlb_inv_leaf_s2,
+       .tlb_add_page   = arm_smmu_tlb_add_page_s2,
 };
 
-static const struct arm_smmu_flush_ops arm_smmu_s2_tlb_ops_v1 = {
-       .tlb = {
-               .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
-               .tlb_flush_walk = arm_smmu_tlb_inv_walk,
-               .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
-               .tlb_add_page   = arm_smmu_tlb_add_page,
-       },
-       .tlb_inv_range          = arm_smmu_tlb_inv_vmid_nosync,
-       .tlb_sync               = arm_smmu_tlb_sync_vmid,
+static const struct iommu_flush_ops arm_smmu_s2_tlb_ops_v1 = {
+       .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
+       .tlb_flush_walk = arm_smmu_tlb_inv_any_s2_v1,
+       .tlb_flush_leaf = arm_smmu_tlb_inv_any_s2_v1,
+       .tlb_add_page   = arm_smmu_tlb_add_page_s2_v1,
 };
 
 static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
@@ -472,6 +478,8 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
 {
        u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
        struct arm_smmu_device *smmu = dev;
+       static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
+                                     DEFAULT_RATELIMIT_BURST);
 
        gfsr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR);
        gfsynr0 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR0);
@@ -481,11 +489,19 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
        if (!gfsr)
                return IRQ_NONE;
 
-       dev_err_ratelimited(smmu->dev,
-               "Unexpected global fault, this could be serious\n");
-       dev_err_ratelimited(smmu->dev,
-               "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
-               gfsr, gfsynr0, gfsynr1, gfsynr2);
+       if (__ratelimit(&rs)) {
+               if (IS_ENABLED(CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT) &&
+                   (gfsr & sGFSR_USF))
+                       dev_err(smmu->dev,
+                               "Blocked unknown Stream ID 0x%hx; boot with \"arm-smmu.disable_bypass=0\" to allow, but this may have security implications\n",
+                               (u16)gfsynr1);
+               else
+                       dev_err(smmu->dev,
+                               "Unexpected global fault, this could be serious\n");
+               dev_err(smmu->dev,
+                       "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
+                       gfsr, gfsynr0, gfsynr1, gfsynr2);
+       }
 
        arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, gfsr);
        return IRQ_HANDLED;
@@ -536,8 +552,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
                        cb->mair[0] = pgtbl_cfg->arm_v7s_cfg.prrr;
                        cb->mair[1] = pgtbl_cfg->arm_v7s_cfg.nmrr;
                } else {
-                       cb->mair[0] = pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
-                       cb->mair[1] = pgtbl_cfg->arm_lpae_s1_cfg.mair[1];
+                       cb->mair[0] = pgtbl_cfg->arm_lpae_s1_cfg.mair;
+                       cb->mair[1] = pgtbl_cfg->arm_lpae_s1_cfg.mair >> 32;
                }
        }
 }
@@ -770,7 +786,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
                .ias            = ias,
                .oas            = oas,
                .coherent_walk  = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK,
-               .tlb            = &smmu_domain->flush_ops->tlb,
+               .tlb            = smmu_domain->flush_ops,
                .iommu_dev      = smmu->dev,
        };
 
@@ -1039,8 +1055,6 @@ static int arm_smmu_master_alloc_smes(struct device *dev)
        }
 
        group = iommu_group_get_for_dev(dev);
-       if (!group)
-               group = ERR_PTR(-ENOMEM);
        if (IS_ERR(group)) {
                ret = PTR_ERR(group);
                goto out_err;
@@ -1154,13 +1168,27 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        /* Looks ok, so add the device to the domain */
        ret = arm_smmu_domain_add_master(smmu_domain, fwspec);
 
+       /*
+        * Setup an autosuspend delay to avoid bouncing runpm state.
+        * Otherwise, if a driver for a suspended consumer device
+        * unmaps buffers, it will runpm resume/suspend for each one.
+        *
+        * For example, when used by a GPU device, when an application
+        * or game exits, it can trigger unmapping 100s or 1000s of
+        * buffers.  With a runpm cycle for each buffer, that adds up
+        * to 5-10sec worth of reprogramming the context bank, while
+        * the system appears to be locked up to the user.
+        */
+       pm_runtime_set_autosuspend_delay(smmu->dev, 20);
+       pm_runtime_use_autosuspend(smmu->dev);
+
 rpm_put:
        arm_smmu_rpm_put(smmu);
        return ret;
 }
 
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
-                       phys_addr_t paddr, size_t size, int prot)
+                       phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
        struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
@@ -1200,7 +1228,7 @@ static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
 
        if (smmu_domain->flush_ops) {
                arm_smmu_rpm_get(smmu);
-               smmu_domain->flush_ops->tlb.tlb_flush_all(smmu_domain);
+               smmu_domain->flush_ops->tlb_flush_all(smmu_domain);
                arm_smmu_rpm_put(smmu);
        }
 }
@@ -1211,11 +1239,16 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct arm_smmu_device *smmu = smmu_domain->smmu;
 
-       if (smmu_domain->flush_ops) {
-               arm_smmu_rpm_get(smmu);
-               smmu_domain->flush_ops->tlb_sync(smmu_domain);
-               arm_smmu_rpm_put(smmu);
-       }
+       if (!smmu)
+               return;
+
+       arm_smmu_rpm_get(smmu);
+       if (smmu->version == ARM_SMMU_V2 ||
+           smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
+               arm_smmu_tlb_sync_context(smmu_domain);
+       else
+               arm_smmu_tlb_sync_global(smmu);
+       arm_smmu_rpm_put(smmu);
 }
 
 static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
@@ -2062,10 +2095,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
        for (i = 0; i < num_irqs; ++i) {
                int irq = platform_get_irq(pdev, i);
 
-               if (irq < 0) {
-                       dev_err(dev, "failed to get irq index %d\n", i);
+               if (irq < 0)
                        return -ENODEV;
-               }
                smmu->irqs[i] = irq;
        }
 
index b19b6ca..62b9f0c 100644 (file)
@@ -79,6 +79,8 @@
 #define ID7_MINOR                      GENMASK(3, 0)
 
 #define ARM_SMMU_GR0_sGFSR             0x48
+#define sGFSR_USF                      BIT(1)
+
 #define ARM_SMMU_GR0_sGFSYNR0          0x50
 #define ARM_SMMU_GR0_sGFSYNR1          0x54
 #define ARM_SMMU_GR0_sGFSYNR2          0x58
@@ -304,17 +306,10 @@ enum arm_smmu_domain_stage {
        ARM_SMMU_DOMAIN_BYPASS,
 };
 
-struct arm_smmu_flush_ops {
-       struct iommu_flush_ops          tlb;
-       void (*tlb_inv_range)(unsigned long iova, size_t size, size_t granule,
-                             bool leaf, void *cookie);
-       void (*tlb_sync)(void *cookie);
-};
-
 struct arm_smmu_domain {
        struct arm_smmu_device          *smmu;
        struct io_pgtable_ops           *pgtbl_ops;
-       const struct arm_smmu_flush_ops *flush_ops;
+       const struct iommu_flush_ops    *flush_ops;
        struct arm_smmu_cfg             cfg;
        enum arm_smmu_domain_stage      stage;
        bool                            non_strict;
@@ -335,6 +330,8 @@ struct arm_smmu_impl {
        int (*cfg_probe)(struct arm_smmu_device *smmu);
        int (*reset)(struct arm_smmu_device *smmu);
        int (*init_context)(struct arm_smmu_domain *smmu_domain);
+       void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync,
+                        int status);
 };
 
 static inline void __iomem *arm_smmu_page(struct arm_smmu_device *smmu, int n)
@@ -398,5 +395,8 @@ static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page,
        arm_smmu_writeq((s), ARM_SMMU_CB((s), (n)), (o), (v))
 
 struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu);
+struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu);
+
+int arm_mmu500_reset(struct arm_smmu_device *smmu);
 
 #endif /* _ARM_SMMU_H */
index 646332f..0cc702a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pci.h>
 #include <linux/scatterlist.h>
 #include <linux/vmalloc.h>
+#include <linux/crash_dump.h>
 
 struct iommu_dma_msi_page {
        struct list_head        list;
@@ -353,6 +354,21 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
        return iova_reserve_iommu_regions(dev, domain);
 }
 
+static int iommu_dma_deferred_attach(struct device *dev,
+               struct iommu_domain *domain)
+{
+       const struct iommu_ops *ops = domain->ops;
+
+       if (!is_kdump_kernel())
+               return 0;
+
+       if (unlikely(ops->is_attach_deferred &&
+                       ops->is_attach_deferred(domain, dev)))
+               return iommu_attach_device(domain, dev);
+
+       return 0;
+}
+
 /**
  * dma_info_to_prot - Translate DMA API directions and attributes to IOMMU API
  *                    page flags.
@@ -461,7 +477,7 @@ static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr,
 }
 
 static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
-               size_t size, int prot)
+               size_t size, int prot, dma_addr_t dma_mask)
 {
        struct iommu_domain *domain = iommu_get_dma_domain(dev);
        struct iommu_dma_cookie *cookie = domain->iova_cookie;
@@ -469,13 +485,16 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
        size_t iova_off = iova_offset(iovad, phys);
        dma_addr_t iova;
 
+       if (unlikely(iommu_dma_deferred_attach(dev, domain)))
+               return DMA_MAPPING_ERROR;
+
        size = iova_align(iovad, size + iova_off);
 
-       iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
+       iova = iommu_dma_alloc_iova(domain, size, dma_mask, dev);
        if (!iova)
                return DMA_MAPPING_ERROR;
 
-       if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
+       if (iommu_map_atomic(domain, iova, phys - iova_off, size, prot)) {
                iommu_dma_free_iova(cookie, iova, size);
                return DMA_MAPPING_ERROR;
        }
@@ -578,6 +597,9 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
 
        *dma_handle = DMA_MAPPING_ERROR;
 
+       if (unlikely(iommu_dma_deferred_attach(dev, domain)))
+               return NULL;
+
        min_size = alloc_sizes & -alloc_sizes;
        if (min_size < PAGE_SIZE) {
                min_size = PAGE_SIZE;
@@ -610,7 +632,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
                        arch_dma_prep_coherent(sg_page(sg), sg->length);
        }
 
-       if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, ioprot)
+       if (iommu_map_sg_atomic(domain, iova, sgt.sgl, sgt.orig_nents, ioprot)
                        < size)
                goto out_free_sg;
 
@@ -710,7 +732,7 @@ static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
        int prot = dma_info_to_prot(dir, coherent, attrs);
        dma_addr_t dma_handle;
 
-       dma_handle =__iommu_dma_map(dev, phys, size, prot);
+       dma_handle = __iommu_dma_map(dev, phys, size, prot, dma_get_mask(dev));
        if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
            dma_handle != DMA_MAPPING_ERROR)
                arch_sync_dma_for_device(phys, size, dir);
@@ -820,6 +842,9 @@ static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
        unsigned long mask = dma_get_seg_boundary(dev);
        int i;
 
+       if (unlikely(iommu_dma_deferred_attach(dev, domain)))
+               return 0;
+
        if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
                iommu_dma_sync_sg_for_device(dev, sg, nents, dir);
 
@@ -870,7 +895,7 @@ static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
         * We'll leave any physical concatenation to the IOMMU driver's
         * implementation - it knows better than we do.
         */
-       if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len)
+       if (iommu_map_sg_atomic(domain, iova, sg, nents, prot) < iova_len)
                goto out_free_iova;
 
        return __finalise_sg(dev, sg, nents, iova);
@@ -910,7 +935,8 @@ static dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
                size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
        return __iommu_dma_map(dev, phys, size,
-                       dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO);
+                       dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO,
+                       dma_get_mask(dev));
 }
 
 static void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
@@ -1016,7 +1042,8 @@ static void *iommu_dma_alloc(struct device *dev, size_t size,
        if (!cpu_addr)
                return NULL;
 
-       *handle = __iommu_dma_map(dev, page_to_phys(page), size, ioprot);
+       *handle = __iommu_dma_map(dev, page_to_phys(page), size, ioprot,
+                       dev->coherent_dma_mask);
        if (*handle == DMA_MAPPING_ERROR) {
                __iommu_dma_free(dev, size, cpu_addr);
                return NULL;
index eecd6a4..3acfa6a 100644 (file)
@@ -895,8 +895,11 @@ int __init detect_intel_iommu(void)
        }
 
 #ifdef CONFIG_X86
-       if (!ret)
+       if (!ret) {
                x86_init.iommu.iommu_init = intel_iommu_init;
+               x86_platform.iommu_shutdown = intel_iommu_shutdown;
+       }
+
 #endif
 
        if (dmar_tbl) {
index 9c94e16..186ff5c 100644 (file)
@@ -1073,7 +1073,7 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size,
  */
 static int exynos_iommu_map(struct iommu_domain *iommu_domain,
                            unsigned long l_iova, phys_addr_t paddr, size_t size,
-                           int prot)
+                           int prot, gfp_t gfp)
 {
        struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
        sysmmu_pte_t *entry;
index 6db6d96..0c8d81f 100644 (file)
@@ -2420,14 +2420,24 @@ static void domain_remove_dev_info(struct dmar_domain *domain)
        spin_unlock_irqrestore(&device_domain_lock, flags);
 }
 
-/*
- * find_domain
- * Note: we use struct device->archdata.iommu stores the info
- */
 static struct dmar_domain *find_domain(struct device *dev)
 {
        struct device_domain_info *info;
 
+       if (unlikely(dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO ||
+                    dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO))
+               return NULL;
+
+       /* No lock here, assumes no domain exit in normal case */
+       info = dev->archdata.iommu;
+       if (likely(info))
+               return info->domain;
+
+       return NULL;
+}
+
+static struct dmar_domain *deferred_attach_domain(struct device *dev)
+{
        if (unlikely(dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO)) {
                struct iommu_domain *domain;
 
@@ -2437,12 +2447,7 @@ static struct dmar_domain *find_domain(struct device *dev)
                        intel_iommu_attach_device(domain, dev);
        }
 
-       /* No lock here, assumes no domain exit in normal case */
-       info = dev->archdata.iommu;
-
-       if (likely(info))
-               return info->domain;
-       return NULL;
+       return find_domain(dev);
 }
 
 static inline struct device_domain_info *
@@ -3512,7 +3517,7 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
 
        BUG_ON(dir == DMA_NONE);
 
-       domain = find_domain(dev);
+       domain = deferred_attach_domain(dev);
        if (!domain)
                return DMA_MAPPING_ERROR;
 
@@ -3732,7 +3737,7 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
        if (!iommu_need_mapping(dev))
                return dma_direct_map_sg(dev, sglist, nelems, dir, attrs);
 
-       domain = find_domain(dev);
+       domain = deferred_attach_domain(dev);
        if (!domain)
                return 0;
 
@@ -3827,7 +3832,7 @@ bounce_map_single(struct device *dev, phys_addr_t paddr, size_t size,
        int prot = 0;
        int ret;
 
-       domain = find_domain(dev);
+       domain = deferred_attach_domain(dev);
        if (WARN_ON(dir == DMA_NONE || !domain))
                return DMA_MAPPING_ERROR;
 
@@ -4314,13 +4319,19 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
 {
        struct acpi_dmar_reserved_memory *rmrr;
        struct dmar_rmrr_unit *rmrru;
+       int ret;
+
+       rmrr = (struct acpi_dmar_reserved_memory *)header;
+       ret = arch_rmrr_sanity_check(rmrr);
+       if (ret)
+               return ret;
 
        rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
        if (!rmrru)
                goto out;
 
        rmrru->hdr = header;
-       rmrr = (struct acpi_dmar_reserved_memory *)header;
+
        rmrru->base_address = rmrr->base_address;
        rmrru->end_address = rmrr->end_address;
 
@@ -4759,6 +4770,26 @@ static void intel_disable_iommus(void)
                iommu_disable_translation(iommu);
 }
 
+void intel_iommu_shutdown(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu = NULL;
+
+       if (no_iommu || dmar_disabled)
+               return;
+
+       down_write(&dmar_global_lock);
+
+       /* Disable PMRs explicitly here. */
+       for_each_iommu(iommu, drhd)
+               iommu_disable_protect_mem_regions(iommu);
+
+       /* Make sure the IOMMUs are switched off */
+       intel_disable_iommus();
+
+       up_write(&dmar_global_lock);
+}
+
 static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
 {
        struct iommu_device *iommu_dev = dev_to_iommu_device(dev);
@@ -5440,7 +5471,7 @@ static void intel_iommu_aux_detach_device(struct iommu_domain *domain,
 
 static int intel_iommu_map(struct iommu_domain *domain,
                           unsigned long iova, phys_addr_t hpa,
-                          size_t size, int iommu_prot)
+                          size_t size, int iommu_prot, gfp_t gfp)
 {
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
        u64 max_addr;
index 4cb3949..7c3bd2c 100644 (file)
@@ -846,27 +846,28 @@ struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns = {
 
 #ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S_SELFTEST
 
-static struct io_pgtable_cfg *cfg_cookie;
+static struct io_pgtable_cfg *cfg_cookie __initdata;
 
-static void dummy_tlb_flush_all(void *cookie)
+static void __init dummy_tlb_flush_all(void *cookie)
 {
        WARN_ON(cookie != cfg_cookie);
 }
 
-static void dummy_tlb_flush(unsigned long iova, size_t size, size_t granule,
-                           void *cookie)
+static void __init dummy_tlb_flush(unsigned long iova, size_t size,
+                                  size_t granule, void *cookie)
 {
        WARN_ON(cookie != cfg_cookie);
        WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
 }
 
-static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
-                              unsigned long iova, size_t granule, void *cookie)
+static void __init dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
+                                     unsigned long iova, size_t granule,
+                                     void *cookie)
 {
        dummy_tlb_flush(iova, granule, granule, cookie);
 }
 
-static const struct iommu_flush_ops dummy_tlb_ops = {
+static const struct iommu_flush_ops dummy_tlb_ops __initconst = {
        .tlb_flush_all  = dummy_tlb_flush_all,
        .tlb_flush_walk = dummy_tlb_flush,
        .tlb_flush_leaf = dummy_tlb_flush,
index ca51036..bdf47f7 100644 (file)
 #define io_pgtable_ops_to_data(x)                                      \
        io_pgtable_to_data(io_pgtable_ops_to_pgtable(x))
 
-/*
- * For consistency with the architecture, we always consider
- * ARM_LPAE_MAX_LEVELS levels, with the walk starting at level n >=0
- */
-#define ARM_LPAE_START_LVL(d)          (ARM_LPAE_MAX_LEVELS - (d)->levels)
-
 /*
  * Calculate the right shift amount to get to the portion describing level l
  * in a virtual address mapped by the pagetable in d.
  */
 #define ARM_LPAE_LVL_SHIFT(l,d)                                                \
-       ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1))             \
-         * (d)->bits_per_level) + (d)->pg_shift)
+       (((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level) +          \
+       ilog2(sizeof(arm_lpae_iopte)))
 
-#define ARM_LPAE_GRANULE(d)            (1UL << (d)->pg_shift)
-
-#define ARM_LPAE_PAGES_PER_PGD(d)                                      \
-       DIV_ROUND_UP((d)->pgd_size, ARM_LPAE_GRANULE(d))
+#define ARM_LPAE_GRANULE(d)                                            \
+       (sizeof(arm_lpae_iopte) << (d)->bits_per_level)
+#define ARM_LPAE_PGD_SIZE(d)                                           \
+       (sizeof(arm_lpae_iopte) << (d)->pgd_bits)
 
 /*
  * Calculate the index at level l used to map virtual address a using the
  * pagetable in d.
  */
 #define ARM_LPAE_PGD_IDX(l,d)                                          \
-       ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0)
+       ((l) == (d)->start_level ? (d)->pgd_bits - (d)->bits_per_level : 0)
 
 #define ARM_LPAE_LVL_IDX(a,l,d)                                                \
        (((u64)(a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                        \
         ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1))
 
 /* Calculate the block/page mapping size at level l for pagetable in d. */
-#define ARM_LPAE_BLOCK_SIZE(l,d)                                       \
-       (1ULL << (ilog2(sizeof(arm_lpae_iopte)) +                       \
-               ((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level)))
+#define ARM_LPAE_BLOCK_SIZE(l,d)       (1ULL << ARM_LPAE_LVL_SHIFT(l,d))
 
 /* Page table bits */
 #define ARM_LPAE_PTE_TYPE_SHIFT                0
 struct arm_lpae_io_pgtable {
        struct io_pgtable       iop;
 
-       int                     levels;
-       size_t                  pgd_size;
-       unsigned long           pg_shift;
-       unsigned long           bits_per_level;
+       int                     pgd_bits;
+       int                     start_level;
+       int                     bits_per_level;
 
        void                    *pgd;
 };
@@ -213,7 +204,7 @@ static phys_addr_t iopte_to_paddr(arm_lpae_iopte pte,
 {
        u64 paddr = pte & ARM_LPAE_PTE_ADDR_MASK;
 
-       if (data->pg_shift < 16)
+       if (ARM_LPAE_GRANULE(data) < SZ_64K)
                return paddr;
 
        /* Rotate the packed high-order bits back to the top */
@@ -392,7 +383,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
        ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);
 
        /* If we can install a leaf entry at this level, then do so */
-       if (size == block_size && (size & cfg->pgsize_bitmap))
+       if (size == block_size)
                return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep);
 
        /* We can't allocate tables at the final level */
@@ -464,7 +455,7 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
                else if (prot & IOMMU_CACHE)
                        pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
                                << ARM_LPAE_PTE_ATTRINDX_SHIFT);
-               else if (prot & IOMMU_QCOM_SYS_CACHE)
+               else if (prot & IOMMU_SYS_CACHE_ONLY)
                        pte |= (ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE
                                << ARM_LPAE_PTE_ATTRINDX_SHIFT);
        }
@@ -479,16 +470,19 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
                        phys_addr_t paddr, size_t size, int iommu_prot)
 {
        struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+       struct io_pgtable_cfg *cfg = &data->iop.cfg;
        arm_lpae_iopte *ptep = data->pgd;
-       int ret, lvl = ARM_LPAE_START_LVL(data);
+       int ret, lvl = data->start_level;
        arm_lpae_iopte prot;
 
        /* If no access, then nothing to do */
        if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
                return 0;
 
-       if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias) ||
-                   paddr >= (1ULL << data->iop.cfg.oas)))
+       if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
+               return -EINVAL;
+
+       if (WARN_ON(iova >> data->iop.cfg.ias || paddr >> data->iop.cfg.oas))
                return -ERANGE;
 
        prot = arm_lpae_prot_to_pte(data, iommu_prot);
@@ -508,8 +502,8 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
        arm_lpae_iopte *start, *end;
        unsigned long table_size;
 
-       if (lvl == ARM_LPAE_START_LVL(data))
-               table_size = data->pgd_size;
+       if (lvl == data->start_level)
+               table_size = ARM_LPAE_PGD_SIZE(data);
        else
                table_size = ARM_LPAE_GRANULE(data);
 
@@ -537,7 +531,7 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop)
 {
        struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop);
 
-       __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd);
+       __arm_lpae_free_pgtable(data, data->start_level, data->pgd);
        kfree(data);
 }
 
@@ -652,13 +646,16 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
                             size_t size, struct iommu_iotlb_gather *gather)
 {
        struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+       struct io_pgtable_cfg *cfg = &data->iop.cfg;
        arm_lpae_iopte *ptep = data->pgd;
-       int lvl = ARM_LPAE_START_LVL(data);
 
-       if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias)))
+       if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
+               return 0;
+
+       if (WARN_ON(iova >> data->iop.cfg.ias))
                return 0;
 
-       return __arm_lpae_unmap(data, gather, iova, size, lvl, ptep);
+       return __arm_lpae_unmap(data, gather, iova, size, data->start_level, ptep);
 }
 
 static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
@@ -666,7 +663,7 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
 {
        struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
        arm_lpae_iopte pte, *ptep = data->pgd;
-       int lvl = ARM_LPAE_START_LVL(data);
+       int lvl = data->start_level;
 
        do {
                /* Valid IOPTE pointer? */
@@ -743,8 +740,8 @@ static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg)
 static struct arm_lpae_io_pgtable *
 arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
 {
-       unsigned long va_bits, pgd_bits;
        struct arm_lpae_io_pgtable *data;
+       int levels, va_bits, pg_shift;
 
        arm_lpae_restrict_pgsizes(cfg);
 
@@ -766,15 +763,15 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
        if (!data)
                return NULL;
 
-       data->pg_shift = __ffs(cfg->pgsize_bitmap);
-       data->bits_per_level = data->pg_shift - ilog2(sizeof(arm_lpae_iopte));
+       pg_shift = __ffs(cfg->pgsize_bitmap);
+       data->bits_per_level = pg_shift - ilog2(sizeof(arm_lpae_iopte));
 
-       va_bits = cfg->ias - data->pg_shift;
-       data->levels = DIV_ROUND_UP(va_bits, data->bits_per_level);
+       va_bits = cfg->ias - pg_shift;
+       levels = DIV_ROUND_UP(va_bits, data->bits_per_level);
+       data->start_level = ARM_LPAE_MAX_LEVELS - levels;
 
        /* Calculate the actual size of our pgd (without concatenation) */
-       pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1));
-       data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte)));
+       data->pgd_bits = va_bits - (data->bits_per_level * (levels - 1));
 
        data->iop.ops = (struct io_pgtable_ops) {
                .map            = arm_lpae_map,
@@ -864,11 +861,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
              (ARM_LPAE_MAIR_ATTR_INC_OWBRWA
               << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE));
 
-       cfg->arm_lpae_s1_cfg.mair[0] = reg;
-       cfg->arm_lpae_s1_cfg.mair[1] = 0;
+       cfg->arm_lpae_s1_cfg.mair = reg;
 
        /* Looking good; allocate a pgd */
-       data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg);
+       data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data),
+                                          GFP_KERNEL, cfg);
        if (!data->pgd)
                goto out_free_data;
 
@@ -903,13 +900,13 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
         * Concatenate PGDs at level 1 if possible in order to reduce
         * the depth of the stage-2 walk.
         */
-       if (data->levels == ARM_LPAE_MAX_LEVELS) {
+       if (data->start_level == 0) {
                unsigned long pgd_pages;
 
-               pgd_pages = data->pgd_size >> ilog2(sizeof(arm_lpae_iopte));
+               pgd_pages = ARM_LPAE_PGD_SIZE(data) / sizeof(arm_lpae_iopte);
                if (pgd_pages <= ARM_LPAE_S2_MAX_CONCAT_PAGES) {
-                       data->pgd_size = pgd_pages << data->pg_shift;
-                       data->levels--;
+                       data->pgd_bits += data->bits_per_level;
+                       data->start_level++;
                }
        }
 
@@ -919,7 +916,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
             (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
             (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
 
-       sl = ARM_LPAE_START_LVL(data);
+       sl = data->start_level;
 
        switch (ARM_LPAE_GRANULE(data)) {
        case SZ_4K:
@@ -965,7 +962,8 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
        cfg->arm_lpae_s2_cfg.vtcr = reg;
 
        /* Allocate pgd pages */
-       data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg);
+       data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data),
+                                          GFP_KERNEL, cfg);
        if (!data->pgd)
                goto out_free_data;
 
@@ -1034,9 +1032,9 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
                return NULL;
 
        /* Mali seems to need a full 4-level table regardless of IAS */
-       if (data->levels < ARM_LPAE_MAX_LEVELS) {
-               data->levels = ARM_LPAE_MAX_LEVELS;
-               data->pgd_size = sizeof(arm_lpae_iopte);
+       if (data->start_level > 0) {
+               data->start_level = 0;
+               data->pgd_bits = 0;
        }
        /*
         * MEMATTR: Mali has no actual notion of a non-cacheable type, so the
@@ -1053,7 +1051,8 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
                (ARM_MALI_LPAE_MEMATTR_IMP_DEF
                 << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV));
 
-       data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg);
+       data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data), GFP_KERNEL,
+                                          cfg);
        if (!data->pgd)
                goto out_free_data;
 
@@ -1097,22 +1096,23 @@ struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = {
 
 #ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST
 
-static struct io_pgtable_cfg *cfg_cookie;
+static struct io_pgtable_cfg *cfg_cookie __initdata;
 
-static void dummy_tlb_flush_all(void *cookie)
+static void __init dummy_tlb_flush_all(void *cookie)
 {
        WARN_ON(cookie != cfg_cookie);
 }
 
-static void dummy_tlb_flush(unsigned long iova, size_t size, size_t granule,
-                           void *cookie)
+static void __init dummy_tlb_flush(unsigned long iova, size_t size,
+                                  size_t granule, void *cookie)
 {
        WARN_ON(cookie != cfg_cookie);
        WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
 }
 
-static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
-                              unsigned long iova, size_t granule, void *cookie)
+static void __init dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
+                                     unsigned long iova, size_t granule,
+                                     void *cookie)
 {
        dummy_tlb_flush(iova, granule, granule, cookie);
 }
@@ -1131,9 +1131,9 @@ static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops)
 
        pr_err("cfg: pgsize_bitmap 0x%lx, ias %u-bit\n",
                cfg->pgsize_bitmap, cfg->ias);
-       pr_err("data: %d levels, 0x%zx pgd_size, %lu pg_shift, %lu bits_per_level, pgd @ %p\n",
-               data->levels, data->pgd_size, data->pg_shift,
-               data->bits_per_level, data->pgd);
+       pr_err("data: %d levels, 0x%zx pgd_size, %u pg_shift, %u bits_per_level, pgd @ %p\n",
+               ARM_LPAE_MAX_LEVELS - data->start_level, ARM_LPAE_PGD_SIZE(data),
+               ilog2(ARM_LPAE_GRANULE(data)), data->bits_per_level, data->pgd);
 }
 
 #define __FAIL(ops, i) ({                                              \
@@ -1145,7 +1145,7 @@ static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops)
 
 static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
 {
-       static const enum io_pgtable_fmt fmts[] = {
+       static const enum io_pgtable_fmt fmts[] __initconst = {
                ARM_64_LPAE_S1,
                ARM_64_LPAE_S2,
        };
@@ -1244,13 +1244,13 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
 
 static int __init arm_lpae_do_selftests(void)
 {
-       static const unsigned long pgsize[] = {
+       static const unsigned long pgsize[] __initconst = {
                SZ_4K | SZ_2M | SZ_1G,
                SZ_16K | SZ_32M,
                SZ_64K | SZ_512M,
        };
 
-       static const unsigned int ias[] = {
+       static const unsigned int ias[] __initconst = {
                32, 36, 40, 42, 44, 48,
        };
 
diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c
new file mode 100644 (file)
index 0000000..0f8dd37
--- /dev/null
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * I/O Address Space ID allocator. There is one global IOASID space, split into
+ * subsets. Users create a subset with DECLARE_IOASID_SET, then allocate and
+ * free IOASIDs with ioasid_alloc and ioasid_free.
+ */
+#include <linux/ioasid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/xarray.h>
+
+struct ioasid_data {
+       ioasid_t id;
+       struct ioasid_set *set;
+       void *private;
+       struct rcu_head rcu;
+};
+
+/*
+ * struct ioasid_allocator_data - Internal data structure to hold information
+ * about an allocator. There are two types of allocators:
+ *
+ * - Default allocator always has its own XArray to track the IOASIDs allocated.
+ * - Custom allocators may share allocation helpers with different private data.
+ *   Custom allocators that share the same helper functions also share the same
+ *   XArray.
+ * Rules:
+ * 1. Default allocator is always available, not dynamically registered. This is
+ *    to prevent race conditions with early boot code that want to register
+ *    custom allocators or allocate IOASIDs.
+ * 2. Custom allocators take precedence over the default allocator.
+ * 3. When all custom allocators sharing the same helper functions are
+ *    unregistered (e.g. due to hotplug), all outstanding IOASIDs must be
+ *    freed. Otherwise, outstanding IOASIDs will be lost and orphaned.
+ * 4. When switching between custom allocators sharing the same helper
+ *    functions, outstanding IOASIDs are preserved.
+ * 5. When switching between custom allocator and default allocator, all IOASIDs
+ *    must be freed to ensure unadulterated space for the new allocator.
+ *
+ * @ops:       allocator helper functions and its data
+ * @list:      registered custom allocators
+ * @slist:     allocators share the same ops but different data
+ * @flags:     attributes of the allocator
+ * @xa:                xarray holds the IOASID space
+ * @rcu:       used for kfree_rcu when unregistering allocator
+ */
+struct ioasid_allocator_data {
+       struct ioasid_allocator_ops *ops;
+       struct list_head list;
+       struct list_head slist;
+#define IOASID_ALLOCATOR_CUSTOM BIT(0) /* Needs framework to track results */
+       unsigned long flags;
+       struct xarray xa;
+       struct rcu_head rcu;
+};
+
+static DEFINE_SPINLOCK(ioasid_allocator_lock);
+static LIST_HEAD(allocators_list);
+
+static ioasid_t default_alloc(ioasid_t min, ioasid_t max, void *opaque);
+static void default_free(ioasid_t ioasid, void *opaque);
+
+static struct ioasid_allocator_ops default_ops = {
+       .alloc = default_alloc,
+       .free = default_free,
+};
+
+static struct ioasid_allocator_data default_allocator = {
+       .ops = &default_ops,
+       .flags = 0,
+       .xa = XARRAY_INIT(ioasid_xa, XA_FLAGS_ALLOC),
+};
+
+static struct ioasid_allocator_data *active_allocator = &default_allocator;
+
+static ioasid_t default_alloc(ioasid_t min, ioasid_t max, void *opaque)
+{
+       ioasid_t id;
+
+       if (xa_alloc(&default_allocator.xa, &id, opaque, XA_LIMIT(min, max), GFP_ATOMIC)) {
+               pr_err("Failed to alloc ioasid from %d to %d\n", min, max);
+               return INVALID_IOASID;
+       }
+
+       return id;
+}
+
+static void default_free(ioasid_t ioasid, void *opaque)
+{
+       struct ioasid_data *ioasid_data;
+
+       ioasid_data = xa_erase(&default_allocator.xa, ioasid);
+       kfree_rcu(ioasid_data, rcu);
+}
+
+/* Allocate and initialize a new custom allocator with its helper functions */
+static struct ioasid_allocator_data *ioasid_alloc_allocator(struct ioasid_allocator_ops *ops)
+{
+       struct ioasid_allocator_data *ia_data;
+
+       ia_data = kzalloc(sizeof(*ia_data), GFP_ATOMIC);
+       if (!ia_data)
+               return NULL;
+
+       xa_init_flags(&ia_data->xa, XA_FLAGS_ALLOC);
+       INIT_LIST_HEAD(&ia_data->slist);
+       ia_data->flags |= IOASID_ALLOCATOR_CUSTOM;
+       ia_data->ops = ops;
+
+       /* For tracking custom allocators that share the same ops */
+       list_add_tail(&ops->list, &ia_data->slist);
+
+       return ia_data;
+}
+
+static bool use_same_ops(struct ioasid_allocator_ops *a, struct ioasid_allocator_ops *b)
+{
+       return (a->free == b->free) && (a->alloc == b->alloc);
+}
+
+/**
+ * ioasid_register_allocator - register a custom allocator
+ * @ops: the custom allocator ops to be registered
+ *
+ * Custom allocators take precedence over the default xarray based allocator.
+ * Private data associated with the IOASID allocated by the custom allocators
+ * are managed by IOASID framework similar to data stored in xa by default
+ * allocator.
+ *
+ * There can be multiple allocators registered but only one is active. In case
+ * of runtime removal of a custom allocator, the next one is activated based
+ * on the registration ordering.
+ *
+ * Multiple allocators can share the same alloc() function, in this case the
+ * IOASID space is shared.
+ */
+int ioasid_register_allocator(struct ioasid_allocator_ops *ops)
+{
+       struct ioasid_allocator_data *ia_data;
+       struct ioasid_allocator_data *pallocator;
+       int ret = 0;
+
+       spin_lock(&ioasid_allocator_lock);
+
+       ia_data = ioasid_alloc_allocator(ops);
+       if (!ia_data) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       /*
+        * No particular preference, we activate the first one and keep
+        * the later registered allocators in a list in case the first one gets
+        * removed due to hotplug.
+        */
+       if (list_empty(&allocators_list)) {
+               WARN_ON(active_allocator != &default_allocator);
+               /* Use this new allocator if default is not active */
+               if (xa_empty(&active_allocator->xa)) {
+                       rcu_assign_pointer(active_allocator, ia_data);
+                       list_add_tail(&ia_data->list, &allocators_list);
+                       goto out_unlock;
+               }
+               pr_warn("Default allocator active with outstanding IOASID\n");
+               ret = -EAGAIN;
+               goto out_free;
+       }
+
+       /* Check if the allocator is already registered */
+       list_for_each_entry(pallocator, &allocators_list, list) {
+               if (pallocator->ops == ops) {
+                       pr_err("IOASID allocator already registered\n");
+                       ret = -EEXIST;
+                       goto out_free;
+               } else if (use_same_ops(pallocator->ops, ops)) {
+                       /*
+                        * If the new allocator shares the same ops,
+                        * then they will share the same IOASID space.
+                        * We should put them under the same xarray.
+                        */
+                       list_add_tail(&ops->list, &pallocator->slist);
+                       goto out_free;
+               }
+       }
+       list_add_tail(&ia_data->list, &allocators_list);
+
+       spin_unlock(&ioasid_allocator_lock);
+       return 0;
+out_free:
+       kfree(ia_data);
+out_unlock:
+       spin_unlock(&ioasid_allocator_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ioasid_register_allocator);
+
+/**
+ * ioasid_unregister_allocator - Remove a custom IOASID allocator ops
+ * @ops: the custom allocator to be removed
+ *
+ * Remove an allocator from the list, activate the next allocator in
+ * the order it was registered. Or revert to default allocator if all
+ * custom allocators are unregistered without outstanding IOASIDs.
+ */
+void ioasid_unregister_allocator(struct ioasid_allocator_ops *ops)
+{
+       struct ioasid_allocator_data *pallocator;
+       struct ioasid_allocator_ops *sops;
+
+       spin_lock(&ioasid_allocator_lock);
+       if (list_empty(&allocators_list)) {
+               pr_warn("No custom IOASID allocators active!\n");
+               goto exit_unlock;
+       }
+
+       list_for_each_entry(pallocator, &allocators_list, list) {
+               if (!use_same_ops(pallocator->ops, ops))
+                       continue;
+
+               if (list_is_singular(&pallocator->slist)) {
+                       /* No shared helper functions */
+                       list_del(&pallocator->list);
+                       /*
+                        * All IOASIDs should have been freed before
+                        * the last allocator that shares the same ops
+                        * is unregistered.
+                        */
+                       WARN_ON(!xa_empty(&pallocator->xa));
+                       if (list_empty(&allocators_list)) {
+                               pr_info("No custom IOASID allocators, switch to default.\n");
+                               rcu_assign_pointer(active_allocator, &default_allocator);
+                       } else if (pallocator == active_allocator) {
+                               rcu_assign_pointer(active_allocator,
+                                               list_first_entry(&allocators_list,
+                                                               struct ioasid_allocator_data, list));
+                               pr_info("IOASID allocator changed");
+                       }
+                       kfree_rcu(pallocator, rcu);
+                       break;
+               }
+               /*
+                * Find the matching shared ops to delete,
+                * but keep outstanding IOASIDs
+                */
+               list_for_each_entry(sops, &pallocator->slist, list) {
+                       if (sops == ops) {
+                               list_del(&ops->list);
+                               break;
+                       }
+               }
+               break;
+       }
+
+exit_unlock:
+       spin_unlock(&ioasid_allocator_lock);
+}
+EXPORT_SYMBOL_GPL(ioasid_unregister_allocator);
+
+/**
+ * ioasid_set_data - Set private data for an allocated ioasid
+ * @ioasid: the ID to set data
+ * @data:   the private data
+ *
+ * For IOASID that is already allocated, private data can be set
+ * via this API. Future lookup can be done via ioasid_find.
+ */
+int ioasid_set_data(ioasid_t ioasid, void *data)
+{
+       struct ioasid_data *ioasid_data;
+       int ret = 0;
+
+       spin_lock(&ioasid_allocator_lock);
+       ioasid_data = xa_load(&active_allocator->xa, ioasid);
+       if (ioasid_data)
+               rcu_assign_pointer(ioasid_data->private, data);
+       else
+               ret = -ENOENT;
+       spin_unlock(&ioasid_allocator_lock);
+
+       /*
+        * Wait for readers to stop accessing the old private data, so the
+        * caller can free it.
+        */
+       if (!ret)
+               synchronize_rcu();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ioasid_set_data);
+
+/**
+ * ioasid_alloc - Allocate an IOASID
+ * @set: the IOASID set
+ * @min: the minimum ID (inclusive)
+ * @max: the maximum ID (inclusive)
+ * @private: data private to the caller
+ *
+ * Allocate an ID between @min and @max. The @private pointer is stored
+ * internally and can be retrieved with ioasid_find().
+ *
+ * Return: the allocated ID on success, or %INVALID_IOASID on failure.
+ */
+ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
+                     void *private)
+{
+       struct ioasid_data *data;
+       void *adata;
+       ioasid_t id;
+
+       data = kzalloc(sizeof(*data), GFP_ATOMIC);
+       if (!data)
+               return INVALID_IOASID;
+
+       data->set = set;
+       data->private = private;
+
+       /*
+        * Custom allocator needs allocator data to perform platform specific
+        * operations.
+        */
+       spin_lock(&ioasid_allocator_lock);
+       adata = active_allocator->flags & IOASID_ALLOCATOR_CUSTOM ? active_allocator->ops->pdata : data;
+       id = active_allocator->ops->alloc(min, max, adata);
+       if (id == INVALID_IOASID) {
+               pr_err("Failed ASID allocation %lu\n", active_allocator->flags);
+               goto exit_free;
+       }
+
+       if ((active_allocator->flags & IOASID_ALLOCATOR_CUSTOM) &&
+            xa_alloc(&active_allocator->xa, &id, data, XA_LIMIT(id, id), GFP_ATOMIC)) {
+               /* Custom allocator needs framework to store and track allocation results */
+               pr_err("Failed to alloc ioasid from %d\n", id);
+               active_allocator->ops->free(id, active_allocator->ops->pdata);
+               goto exit_free;
+       }
+       data->id = id;
+
+       spin_unlock(&ioasid_allocator_lock);
+       return id;
+exit_free:
+       spin_unlock(&ioasid_allocator_lock);
+       kfree(data);
+       return INVALID_IOASID;
+}
+EXPORT_SYMBOL_GPL(ioasid_alloc);
+
+/**
+ * ioasid_free - Free an IOASID
+ * @ioasid: the ID to remove
+ */
+void ioasid_free(ioasid_t ioasid)
+{
+       struct ioasid_data *ioasid_data;
+
+       spin_lock(&ioasid_allocator_lock);
+       ioasid_data = xa_load(&active_allocator->xa, ioasid);
+       if (!ioasid_data) {
+               pr_err("Trying to free unknown IOASID %u\n", ioasid);
+               goto exit_unlock;
+       }
+
+       active_allocator->ops->free(ioasid, active_allocator->ops->pdata);
+       /* Custom allocator needs additional steps to free the xa element */
+       if (active_allocator->flags & IOASID_ALLOCATOR_CUSTOM) {
+               ioasid_data = xa_erase(&active_allocator->xa, ioasid);
+               kfree_rcu(ioasid_data, rcu);
+       }
+
+exit_unlock:
+       spin_unlock(&ioasid_allocator_lock);
+}
+EXPORT_SYMBOL_GPL(ioasid_free);
+
+/**
+ * ioasid_find - Find IOASID data
+ * @set: the IOASID set
+ * @ioasid: the IOASID to find
+ * @getter: function to call on the found object
+ *
+ * The optional getter function allows to take a reference to the found object
+ * under the rcu lock. The function can also check if the object is still valid:
+ * if @getter returns false, then the object is invalid and NULL is returned.
+ *
+ * If the IOASID exists, return the private pointer passed to ioasid_alloc.
+ * Private data can be NULL if not set. Return an error if the IOASID is not
+ * found, or if @set is not NULL and the IOASID does not belong to the set.
+ */
+void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
+                 bool (*getter)(void *))
+{
+       void *priv;
+       struct ioasid_data *ioasid_data;
+       struct ioasid_allocator_data *idata;
+
+       rcu_read_lock();
+       idata = rcu_dereference(active_allocator);
+       ioasid_data = xa_load(&idata->xa, ioasid);
+       if (!ioasid_data) {
+               priv = ERR_PTR(-ENOENT);
+               goto unlock;
+       }
+       if (set && ioasid_data->set != set) {
+               /* data found but does not belong to the set */
+               priv = ERR_PTR(-EACCES);
+               goto unlock;
+       }
+       /* Now IOASID and its set is verified, we can return the private data */
+       priv = rcu_dereference(ioasid_data->private);
+       if (getter && !getter(priv))
+               priv = NULL;
+unlock:
+       rcu_read_unlock();
+
+       return priv;
+}
+EXPORT_SYMBOL_GPL(ioasid_find);
+
+MODULE_AUTHOR("Jean-Philippe Brucker <jean-philippe.brucker@arm.com>");
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
+MODULE_DESCRIPTION("IO Address Space ID (IOASID) allocator");
+MODULE_LICENSE("GPL");
index d658c7c..db7bfd4 100644 (file)
@@ -1665,6 +1665,36 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(iommu_attach_device);
 
+int iommu_cache_invalidate(struct iommu_domain *domain, struct device *dev,
+                          struct iommu_cache_invalidate_info *inv_info)
+{
+       if (unlikely(!domain->ops->cache_invalidate))
+               return -ENODEV;
+
+       return domain->ops->cache_invalidate(domain, dev, inv_info);
+}
+EXPORT_SYMBOL_GPL(iommu_cache_invalidate);
+
+int iommu_sva_bind_gpasid(struct iommu_domain *domain,
+                          struct device *dev, struct iommu_gpasid_bind_data *data)
+{
+       if (unlikely(!domain->ops->sva_bind_gpasid))
+               return -ENODEV;
+
+       return domain->ops->sva_bind_gpasid(domain, dev, data);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_bind_gpasid);
+
+int iommu_sva_unbind_gpasid(struct iommu_domain *domain, struct device *dev,
+                            ioasid_t pasid)
+{
+       if (unlikely(!domain->ops->sva_unbind_gpasid))
+               return -ENODEV;
+
+       return domain->ops->sva_unbind_gpasid(dev, pasid);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_unbind_gpasid);
+
 static void __iommu_detach_device(struct iommu_domain *domain,
                                  struct device *dev)
 {
@@ -1854,8 +1884,8 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
        return pgsize;
 }
 
-int iommu_map(struct iommu_domain *domain, unsigned long iova,
-             phys_addr_t paddr, size_t size, int prot)
+int __iommu_map(struct iommu_domain *domain, unsigned long iova,
+             phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        const struct iommu_ops *ops = domain->ops;
        unsigned long orig_iova = iova;
@@ -1892,8 +1922,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
 
                pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
                         iova, &paddr, pgsize);
+               ret = ops->map(domain, iova, paddr, pgsize, prot, gfp);
 
-               ret = ops->map(domain, iova, paddr, pgsize, prot);
                if (ret)
                        break;
 
@@ -1913,8 +1943,22 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
 
        return ret;
 }
+
+int iommu_map(struct iommu_domain *domain, unsigned long iova,
+             phys_addr_t paddr, size_t size, int prot)
+{
+       might_sleep();
+       return __iommu_map(domain, iova, paddr, size, prot, GFP_KERNEL);
+}
 EXPORT_SYMBOL_GPL(iommu_map);
 
+int iommu_map_atomic(struct iommu_domain *domain, unsigned long iova,
+             phys_addr_t paddr, size_t size, int prot)
+{
+       return __iommu_map(domain, iova, paddr, size, prot, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(iommu_map_atomic);
+
 static size_t __iommu_unmap(struct iommu_domain *domain,
                            unsigned long iova, size_t size,
                            struct iommu_iotlb_gather *iotlb_gather)
@@ -1991,8 +2035,9 @@ size_t iommu_unmap_fast(struct iommu_domain *domain,
 }
 EXPORT_SYMBOL_GPL(iommu_unmap_fast);
 
-size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
-                   struct scatterlist *sg, unsigned int nents, int prot)
+size_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+                   struct scatterlist *sg, unsigned int nents, int prot,
+                   gfp_t gfp)
 {
        size_t len = 0, mapped = 0;
        phys_addr_t start;
@@ -2003,7 +2048,9 @@ size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
                phys_addr_t s_phys = sg_phys(sg);
 
                if (len && s_phys != start + len) {
-                       ret = iommu_map(domain, iova + mapped, start, len, prot);
+                       ret = __iommu_map(domain, iova + mapped, start,
+                                       len, prot, gfp);
+
                        if (ret)
                                goto out_err;
 
@@ -2031,8 +2078,22 @@ out_err:
        return 0;
 
 }
+
+size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+                   struct scatterlist *sg, unsigned int nents, int prot)
+{
+       might_sleep();
+       return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_KERNEL);
+}
 EXPORT_SYMBOL_GPL(iommu_map_sg);
 
+size_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova,
+                   struct scatterlist *sg, unsigned int nents, int prot)
+{
+       return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(iommu_map_sg_atomic);
+
 int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
                               phys_addr_t paddr, u64 size, int prot)
 {
index 2639fc7..d02edd2 100644 (file)
@@ -50,6 +50,9 @@ struct ipmmu_features {
        bool twobit_imttbcr_sl0;
        bool reserved_context;
        bool cache_snoop;
+       unsigned int ctx_offset_base;
+       unsigned int ctx_offset_stride;
+       unsigned int utlb_offset_base;
 };
 
 struct ipmmu_vmsa_device {
@@ -99,125 +102,49 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
 
 #define IM_NS_ALIAS_OFFSET             0x800
 
-#define IM_CTX_SIZE                    0x40
-
-#define IMCTR                          0x0000
-#define IMCTR_TRE                      (1 << 17)
-#define IMCTR_AFE                      (1 << 16)
-#define IMCTR_RTSEL_MASK               (3 << 4)
-#define IMCTR_RTSEL_SHIFT              4
-#define IMCTR_TREN                     (1 << 3)
-#define IMCTR_INTEN                    (1 << 2)
-#define IMCTR_FLUSH                    (1 << 1)
-#define IMCTR_MMUEN                    (1 << 0)
-
-#define IMCAAR                         0x0004
-
-#define IMTTBCR                                0x0008
-#define IMTTBCR_EAE                    (1 << 31)
-#define IMTTBCR_PMB                    (1 << 30)
-#define IMTTBCR_SH1_NON_SHAREABLE      (0 << 28)       /* R-Car Gen2 only */
-#define IMTTBCR_SH1_OUTER_SHAREABLE    (2 << 28)       /* R-Car Gen2 only */
-#define IMTTBCR_SH1_INNER_SHAREABLE    (3 << 28)       /* R-Car Gen2 only */
-#define IMTTBCR_SH1_MASK               (3 << 28)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN1_NC               (0 << 26)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN1_WB_WA            (1 << 26)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN1_WT               (2 << 26)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN1_WB               (3 << 26)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN1_MASK             (3 << 26)       /* R-Car Gen2 only */
-#define IMTTBCR_IRGN1_NC               (0 << 24)       /* R-Car Gen2 only */
-#define IMTTBCR_IRGN1_WB_WA            (1 << 24)       /* R-Car Gen2 only */
-#define IMTTBCR_IRGN1_WT               (2 << 24)       /* R-Car Gen2 only */
-#define IMTTBCR_IRGN1_WB               (3 << 24)       /* R-Car Gen2 only */
-#define IMTTBCR_IRGN1_MASK             (3 << 24)       /* R-Car Gen2 only */
-#define IMTTBCR_TSZ1_MASK              (7 << 16)
-#define IMTTBCR_TSZ1_SHIFT             16
-#define IMTTBCR_SH0_NON_SHAREABLE      (0 << 12)       /* R-Car Gen2 only */
-#define IMTTBCR_SH0_OUTER_SHAREABLE    (2 << 12)       /* R-Car Gen2 only */
+/* MMU "context" registers */
+#define IMCTR                          0x0000          /* R-Car Gen2/3 */
+#define IMCTR_INTEN                    (1 << 2)        /* R-Car Gen2/3 */
+#define IMCTR_FLUSH                    (1 << 1)        /* R-Car Gen2/3 */
+#define IMCTR_MMUEN                    (1 << 0)        /* R-Car Gen2/3 */
+
+#define IMTTBCR                                0x0008          /* R-Car Gen2/3 */
+#define IMTTBCR_EAE                    (1 << 31)       /* R-Car Gen2/3 */
 #define IMTTBCR_SH0_INNER_SHAREABLE    (3 << 12)       /* R-Car Gen2 only */
-#define IMTTBCR_SH0_MASK               (3 << 12)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN0_NC               (0 << 10)       /* R-Car Gen2 only */
 #define IMTTBCR_ORGN0_WB_WA            (1 << 10)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN0_WT               (2 << 10)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN0_WB               (3 << 10)       /* R-Car Gen2 only */
-#define IMTTBCR_ORGN0_MASK             (3 << 10)       /* R-Car Gen2 only */
-#define IMTTBCR_IRGN0_NC               (0 << 8)        /* R-Car Gen2 only */
 #define IMTTBCR_IRGN0_WB_WA            (1 << 8)        /* R-Car Gen2 only */
-#define IMTTBCR_IRGN0_WT               (2 << 8)        /* R-Car Gen2 only */
-#define IMTTBCR_IRGN0_WB               (3 << 8)        /* R-Car Gen2 only */
-#define IMTTBCR_IRGN0_MASK             (3 << 8)        /* R-Car Gen2 only */
-#define IMTTBCR_SL0_TWOBIT_LVL_3       (0 << 6)        /* R-Car Gen3 only */
-#define IMTTBCR_SL0_TWOBIT_LVL_2       (1 << 6)        /* R-Car Gen3 only */
 #define IMTTBCR_SL0_TWOBIT_LVL_1       (2 << 6)        /* R-Car Gen3 only */
-#define IMTTBCR_SL0_LVL_2              (0 << 4)
-#define IMTTBCR_SL0_LVL_1              (1 << 4)
-#define IMTTBCR_TSZ0_MASK              (7 << 0)
-#define IMTTBCR_TSZ0_SHIFT             O
-
-#define IMBUSCR                                0x000c
-#define IMBUSCR_DVM                    (1 << 2)
-#define IMBUSCR_BUSSEL_SYS             (0 << 0)
-#define IMBUSCR_BUSSEL_CCI             (1 << 0)
-#define IMBUSCR_BUSSEL_IMCAAR          (2 << 0)
-#define IMBUSCR_BUSSEL_CCI_IMCAAR      (3 << 0)
-#define IMBUSCR_BUSSEL_MASK            (3 << 0)
-
-#define IMTTLBR0                       0x0010
-#define IMTTUBR0                       0x0014
-#define IMTTLBR1                       0x0018
-#define IMTTUBR1                       0x001c
-
-#define IMSTR                          0x0020
-#define IMSTR_ERRLVL_MASK              (3 << 12)
-#define IMSTR_ERRLVL_SHIFT             12
-#define IMSTR_ERRCODE_TLB_FORMAT       (1 << 8)
-#define IMSTR_ERRCODE_ACCESS_PERM      (4 << 8)
-#define IMSTR_ERRCODE_SECURE_ACCESS    (5 << 8)
-#define IMSTR_ERRCODE_MASK             (7 << 8)
-#define IMSTR_MHIT                     (1 << 4)
-#define IMSTR_ABORT                    (1 << 2)
-#define IMSTR_PF                       (1 << 1)
-#define IMSTR_TF                       (1 << 0)
-
-#define IMMAIR0                                0x0028
-#define IMMAIR1                                0x002c
-#define IMMAIR_ATTR_MASK               0xff
-#define IMMAIR_ATTR_DEVICE             0x04
-#define IMMAIR_ATTR_NC                 0x44
-#define IMMAIR_ATTR_WBRWA              0xff
-#define IMMAIR_ATTR_SHIFT(n)           ((n) << 3)
-#define IMMAIR_ATTR_IDX_NC             0
-#define IMMAIR_ATTR_IDX_WBRWA          1
-#define IMMAIR_ATTR_IDX_DEV            2
-
-#define IMELAR                         0x0030  /* IMEAR on R-Car Gen2 */
-#define IMEUAR                         0x0034  /* R-Car Gen3 only */
-
-#define IMPCTR                         0x0200
-#define IMPSTR                         0x0208
-#define IMPEAR                         0x020c
-#define IMPMBA(n)                      (0x0280 + ((n) * 4))
-#define IMPMBD(n)                      (0x02c0 + ((n) * 4))
+#define IMTTBCR_SL0_LVL_1              (1 << 4)        /* R-Car Gen2 only */
+
+#define IMBUSCR                                0x000c          /* R-Car Gen2 only */
+#define IMBUSCR_DVM                    (1 << 2)        /* R-Car Gen2 only */
+#define IMBUSCR_BUSSEL_MASK            (3 << 0)        /* R-Car Gen2 only */
+
+#define IMTTLBR0                       0x0010          /* R-Car Gen2/3 */
+#define IMTTUBR0                       0x0014          /* R-Car Gen2/3 */
+
+#define IMSTR                          0x0020          /* R-Car Gen2/3 */
+#define IMSTR_MHIT                     (1 << 4)        /* R-Car Gen2/3 */
+#define IMSTR_ABORT                    (1 << 2)        /* R-Car Gen2/3 */
+#define IMSTR_PF                       (1 << 1)        /* R-Car Gen2/3 */
+#define IMSTR_TF                       (1 << 0)        /* R-Car Gen2/3 */
 
+#define IMMAIR0                                0x0028          /* R-Car Gen2/3 */
+
+#define IMELAR                         0x0030          /* R-Car Gen2/3, IMEAR on R-Car Gen2 */
+#define IMEUAR                         0x0034          /* R-Car Gen3 only */
+
+/* uTLB registers */
 #define IMUCTR(n)                      ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n))
-#define IMUCTR0(n)                     (0x0300 + ((n) * 16))
-#define IMUCTR32(n)                    (0x0600 + (((n) - 32) * 16))
-#define IMUCTR_FIXADDEN                        (1 << 31)
-#define IMUCTR_FIXADD_MASK             (0xff << 16)
-#define IMUCTR_FIXADD_SHIFT            16
-#define IMUCTR_TTSEL_MMU(n)            ((n) << 4)
-#define IMUCTR_TTSEL_PMB               (8 << 4)
-#define IMUCTR_TTSEL_MASK              (15 << 4)
-#define IMUCTR_FLUSH                   (1 << 1)
-#define IMUCTR_MMUEN                   (1 << 0)
+#define IMUCTR0(n)                     (0x0300 + ((n) * 16))           /* R-Car Gen2/3 */
+#define IMUCTR32(n)                    (0x0600 + (((n) - 32) * 16))    /* R-Car Gen3 only */
+#define IMUCTR_TTSEL_MMU(n)            ((n) << 4)      /* R-Car Gen2/3 */
+#define IMUCTR_FLUSH                   (1 << 1)        /* R-Car Gen2/3 */
+#define IMUCTR_MMUEN                   (1 << 0)        /* R-Car Gen2/3 */
 
 #define IMUASID(n)                     ((n) < 32 ? IMUASID0(n) : IMUASID32(n))
-#define IMUASID0(n)                    (0x0308 + ((n) * 16))
-#define IMUASID32(n)                   (0x0608 + (((n) - 32) * 16))
-#define IMUASID_ASID8_MASK             (0xff << 8)
-#define IMUASID_ASID8_SHIFT            8
-#define IMUASID_ASID0_MASK             (0xff << 0)
-#define IMUASID_ASID0_SHIFT            0
+#define IMUASID0(n)                    (0x0308 + ((n) * 16))           /* R-Car Gen2/3 */
+#define IMUASID32(n)                   (0x0608 + (((n) - 32) * 16))    /* R-Car Gen3 only */
 
 /* -----------------------------------------------------------------------------
  * Root device handling
@@ -264,29 +191,61 @@ static void ipmmu_write(struct ipmmu_vmsa_device *mmu, unsigned int offset,
        iowrite32(data, mmu->base + offset);
 }
 
+static unsigned int ipmmu_ctx_reg(struct ipmmu_vmsa_device *mmu,
+                                 unsigned int context_id, unsigned int reg)
+{
+       return mmu->features->ctx_offset_base +
+              context_id * mmu->features->ctx_offset_stride + reg;
+}
+
+static u32 ipmmu_ctx_read(struct ipmmu_vmsa_device *mmu,
+                         unsigned int context_id, unsigned int reg)
+{
+       return ipmmu_read(mmu, ipmmu_ctx_reg(mmu, context_id, reg));
+}
+
+static void ipmmu_ctx_write(struct ipmmu_vmsa_device *mmu,
+                           unsigned int context_id, unsigned int reg, u32 data)
+{
+       ipmmu_write(mmu, ipmmu_ctx_reg(mmu, context_id, reg), data);
+}
+
 static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain,
                               unsigned int reg)
 {
-       return ipmmu_read(domain->mmu->root,
-                         domain->context_id * IM_CTX_SIZE + reg);
+       return ipmmu_ctx_read(domain->mmu->root, domain->context_id, reg);
 }
 
 static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain,
                                 unsigned int reg, u32 data)
 {
-       ipmmu_write(domain->mmu->root,
-                   domain->context_id * IM_CTX_SIZE + reg, data);
+       ipmmu_ctx_write(domain->mmu->root, domain->context_id, reg, data);
 }
 
 static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain,
                                unsigned int reg, u32 data)
 {
        if (domain->mmu != domain->mmu->root)
-               ipmmu_write(domain->mmu,
-                           domain->context_id * IM_CTX_SIZE + reg, data);
+               ipmmu_ctx_write(domain->mmu, domain->context_id, reg, data);
 
-       ipmmu_write(domain->mmu->root,
-                   domain->context_id * IM_CTX_SIZE + reg, data);
+       ipmmu_ctx_write(domain->mmu->root, domain->context_id, reg, data);
+}
+
+static u32 ipmmu_utlb_reg(struct ipmmu_vmsa_device *mmu, unsigned int reg)
+{
+       return mmu->features->utlb_offset_base + reg;
+}
+
+static void ipmmu_imuasid_write(struct ipmmu_vmsa_device *mmu,
+                               unsigned int utlb, u32 data)
+{
+       ipmmu_write(mmu, ipmmu_utlb_reg(mmu, IMUASID(utlb)), data);
+}
+
+static void ipmmu_imuctr_write(struct ipmmu_vmsa_device *mmu,
+                              unsigned int utlb, u32 data)
+{
+       ipmmu_write(mmu, ipmmu_utlb_reg(mmu, IMUCTR(utlb)), data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -334,11 +293,10 @@ static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
         */
 
        /* TODO: What should we set the ASID to ? */
-       ipmmu_write(mmu, IMUASID(utlb), 0);
+       ipmmu_imuasid_write(mmu, utlb, 0);
        /* TODO: Do we need to flush the microTLB ? */
-       ipmmu_write(mmu, IMUCTR(utlb),
-                   IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_FLUSH |
-                   IMUCTR_MMUEN);
+       ipmmu_imuctr_write(mmu, utlb, IMUCTR_TTSEL_MMU(domain->context_id) |
+                                     IMUCTR_FLUSH | IMUCTR_MMUEN);
        mmu->utlb_ctx[utlb] = domain->context_id;
 }
 
@@ -350,7 +308,7 @@ static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
 {
        struct ipmmu_vmsa_device *mmu = domain->mmu;
 
-       ipmmu_write(mmu, IMUCTR(utlb), 0);
+       ipmmu_imuctr_write(mmu, utlb, 0);
        mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID;
 }
 
@@ -438,7 +396,7 @@ static void ipmmu_domain_setup_context(struct ipmmu_vmsa_domain *domain)
 
        /* MAIR0 */
        ipmmu_ctx_write_root(domain, IMMAIR0,
-                            domain->cfg.arm_lpae_s1_cfg.mair[0]);
+                            domain->cfg.arm_lpae_s1_cfg.mair);
 
        /* IMBUSCR */
        if (domain->mmu->features->setup_imbuscr)
@@ -724,7 +682,7 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain,
 }
 
 static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
-                    phys_addr_t paddr, size_t size, int prot)
+                    phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
 
@@ -783,6 +741,7 @@ static int ipmmu_init_platform_device(struct device *dev,
 
 static const struct soc_device_attribute soc_rcar_gen3[] = {
        { .soc_id = "r8a774a1", },
+       { .soc_id = "r8a774b1", },
        { .soc_id = "r8a774c0", },
        { .soc_id = "r8a7795", },
        { .soc_id = "r8a7796", },
@@ -794,6 +753,7 @@ static const struct soc_device_attribute soc_rcar_gen3[] = {
 };
 
 static const struct soc_device_attribute soc_rcar_gen3_whitelist[] = {
+       { .soc_id = "r8a774b1", },
        { .soc_id = "r8a774c0", },
        { .soc_id = "r8a7795", .revision = "ES3.*" },
        { .soc_id = "r8a77965", },
@@ -985,7 +945,7 @@ static void ipmmu_device_reset(struct ipmmu_vmsa_device *mmu)
 
        /* Disable all contexts. */
        for (i = 0; i < mmu->num_ctx; ++i)
-               ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0);
+               ipmmu_ctx_write(mmu, i, IMCTR, 0);
 }
 
 static const struct ipmmu_features ipmmu_features_default = {
@@ -997,6 +957,9 @@ static const struct ipmmu_features ipmmu_features_default = {
        .twobit_imttbcr_sl0 = false,
        .reserved_context = false,
        .cache_snoop = true,
+       .ctx_offset_base = 0,
+       .ctx_offset_stride = 0x40,
+       .utlb_offset_base = 0,
 };
 
 static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
@@ -1008,6 +971,9 @@ static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
        .twobit_imttbcr_sl0 = true,
        .reserved_context = true,
        .cache_snoop = false,
+       .ctx_offset_base = 0,
+       .ctx_offset_stride = 0x40,
+       .utlb_offset_base = 0,
 };
 
 static const struct of_device_id ipmmu_of_ids[] = {
@@ -1017,6 +983,9 @@ static const struct of_device_id ipmmu_of_ids[] = {
        }, {
                .compatible = "renesas,ipmmu-r8a774a1",
                .data = &ipmmu_features_rcar_gen3,
+       }, {
+               .compatible = "renesas,ipmmu-r8a774b1",
+               .data = &ipmmu_features_rcar_gen3,
        }, {
                .compatible = "renesas,ipmmu-r8a774c0",
                .data = &ipmmu_features_rcar_gen3,
index be99d40..93f14bc 100644 (file)
@@ -504,7 +504,7 @@ fail:
 }
 
 static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova,
-                        phys_addr_t pa, size_t len, int prot)
+                        phys_addr_t pa, size_t len, int prot, gfp_t gfp)
 {
        struct msm_priv *priv = to_msm_priv(domain);
        unsigned long flags;
index 67a483c..6fc1f5e 100644 (file)
 #define MTK_M4U_TO_PORT(id)            ((id) & 0x1f)
 
 struct mtk_iommu_domain {
-       spinlock_t                      pgtlock; /* lock for page table */
-
        struct io_pgtable_cfg           cfg;
        struct io_pgtable_ops           *iop;
 
@@ -173,13 +171,16 @@ static void mtk_iommu_tlb_flush_all(void *cookie)
        }
 }
 
-static void mtk_iommu_tlb_add_flush_nosync(unsigned long iova, size_t size,
-                                          size_t granule, bool leaf,
-                                          void *cookie)
+static void mtk_iommu_tlb_flush_range_sync(unsigned long iova, size_t size,
+                                          size_t granule, void *cookie)
 {
        struct mtk_iommu_data *data = cookie;
+       unsigned long flags;
+       int ret;
+       u32 tmp;
 
        for_each_m4u(data) {
+               spin_lock_irqsave(&data->tlb_lock, flags);
                writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
                               data->base + REG_MMU_INV_SEL);
 
@@ -188,23 +189,10 @@ static void mtk_iommu_tlb_add_flush_nosync(unsigned long iova, size_t size,
                               data->base + REG_MMU_INVLD_END_A);
                writel_relaxed(F_MMU_INV_RANGE,
                               data->base + REG_MMU_INVALIDATE);
-               data->tlb_flush_active = true;
-       }
-}
-
-static void mtk_iommu_tlb_sync(void *cookie)
-{
-       struct mtk_iommu_data *data = cookie;
-       int ret;
-       u32 tmp;
-
-       for_each_m4u(data) {
-               /* Avoid timing out if there's nothing to wait for */
-               if (!data->tlb_flush_active)
-                       return;
 
+               /* tlb sync */
                ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
-                                               tmp, tmp != 0, 10, 100000);
+                                               tmp, tmp != 0, 10, 1000);
                if (ret) {
                        dev_warn(data->dev,
                                 "Partial TLB flush timed out, falling back to full flush\n");
@@ -212,35 +200,24 @@ static void mtk_iommu_tlb_sync(void *cookie)
                }
                /* Clear the CPE status */
                writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
-               data->tlb_flush_active = false;
+               spin_unlock_irqrestore(&data->tlb_lock, flags);
        }
 }
 
-static void mtk_iommu_tlb_flush_walk(unsigned long iova, size_t size,
-                                    size_t granule, void *cookie)
-{
-       mtk_iommu_tlb_add_flush_nosync(iova, size, granule, false, cookie);
-       mtk_iommu_tlb_sync(cookie);
-}
-
-static void mtk_iommu_tlb_flush_leaf(unsigned long iova, size_t size,
-                                    size_t granule, void *cookie)
-{
-       mtk_iommu_tlb_add_flush_nosync(iova, size, granule, true, cookie);
-       mtk_iommu_tlb_sync(cookie);
-}
-
 static void mtk_iommu_tlb_flush_page_nosync(struct iommu_iotlb_gather *gather,
                                            unsigned long iova, size_t granule,
                                            void *cookie)
 {
-       mtk_iommu_tlb_add_flush_nosync(iova, granule, granule, true, cookie);
+       struct mtk_iommu_data *data = cookie;
+       struct iommu_domain *domain = &data->m4u_dom->domain;
+
+       iommu_iotlb_gather_add_page(domain, gather, iova, granule);
 }
 
 static const struct iommu_flush_ops mtk_iommu_flush_ops = {
        .tlb_flush_all = mtk_iommu_tlb_flush_all,
-       .tlb_flush_walk = mtk_iommu_tlb_flush_walk,
-       .tlb_flush_leaf = mtk_iommu_tlb_flush_leaf,
+       .tlb_flush_walk = mtk_iommu_tlb_flush_range_sync,
+       .tlb_flush_leaf = mtk_iommu_tlb_flush_range_sync,
        .tlb_add_page = mtk_iommu_tlb_flush_page_nosync,
 };
 
@@ -316,8 +293,6 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom)
 {
        struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
 
-       spin_lock_init(&dom->pgtlock);
-
        dom->cfg = (struct io_pgtable_cfg) {
                .quirks = IO_PGTABLE_QUIRK_ARM_NS |
                        IO_PGTABLE_QUIRK_NO_PERMS |
@@ -412,22 +387,17 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain,
 }
 
 static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
-                        phys_addr_t paddr, size_t size, int prot)
+                        phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
        struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
-       unsigned long flags;
-       int ret;
 
        /* The "4GB mode" M4U physically can not use the lower remap of Dram. */
        if (data->enable_4GB)
                paddr |= BIT_ULL(32);
 
-       spin_lock_irqsave(&dom->pgtlock, flags);
-       ret = dom->iop->map(dom->iop, iova, paddr, size, prot);
-       spin_unlock_irqrestore(&dom->pgtlock, flags);
-
-       return ret;
+       /* Synchronize with the tlb_lock */
+       return dom->iop->map(dom->iop, iova, paddr, size, prot);
 }
 
 static size_t mtk_iommu_unmap(struct iommu_domain *domain,
@@ -435,25 +405,26 @@ static size_t mtk_iommu_unmap(struct iommu_domain *domain,
                              struct iommu_iotlb_gather *gather)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
-       unsigned long flags;
-       size_t unmapsz;
-
-       spin_lock_irqsave(&dom->pgtlock, flags);
-       unmapsz = dom->iop->unmap(dom->iop, iova, size, gather);
-       spin_unlock_irqrestore(&dom->pgtlock, flags);
 
-       return unmapsz;
+       return dom->iop->unmap(dom->iop, iova, size, gather);
 }
 
 static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
 {
-       mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data());
+       mtk_iommu_tlb_flush_all(mtk_iommu_get_m4u_data());
 }
 
 static void mtk_iommu_iotlb_sync(struct iommu_domain *domain,
                                 struct iommu_iotlb_gather *gather)
 {
-       mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data());
+       struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
+       size_t length = gather->end - gather->start;
+
+       if (gather->start == ULONG_MAX)
+               return;
+
+       mtk_iommu_tlb_flush_range_sync(gather->start, length, gather->pgsize,
+                                      data);
 }
 
 static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -461,13 +432,9 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
        struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
-       unsigned long flags;
        phys_addr_t pa;
 
-       spin_lock_irqsave(&dom->pgtlock, flags);
        pa = dom->iop->iova_to_phys(dom->iop, iova);
-       spin_unlock_irqrestore(&dom->pgtlock, flags);
-
        if (data->enable_4GB && pa >= MTK_IOMMU_4GB_MODE_REMAP_BASE)
                pa &= ~BIT_ULL(32);
 
@@ -733,6 +700,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       spin_lock_init(&data->tlb_lock);
        list_add_tail(&data->list, &m4ulist);
 
        if (!iommu_present(&platform_bus_type))
index fc0f16e..ea949a3 100644 (file)
@@ -57,7 +57,7 @@ struct mtk_iommu_data {
        struct mtk_iommu_domain         *m4u_dom;
        struct iommu_group              *m4u_group;
        bool                            enable_4GB;
-       bool                            tlb_flush_active;
+       spinlock_t                      tlb_lock; /* lock for tlb range flush */
 
        struct iommu_device             iommu;
        const struct mtk_iommu_plat_data *plat_data;
index b5efd6d..e93b94e 100644 (file)
@@ -295,7 +295,7 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain,
 }
 
 static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
-                        phys_addr_t paddr, size_t size, int prot)
+                        phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
        unsigned int page_num = size >> MT2701_IOMMU_PAGE_SHIFT;
index 614a93a..026ad2b 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/export.h>
 #include <linux/iommu.h>
 #include <linux/limits.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/of_iommu.h>
 #include <linux/of_pci.h>
index 09c6e1c..be551cc 100644 (file)
@@ -1339,7 +1339,7 @@ static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz)
 }
 
 static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
-                         phys_addr_t pa, size_t bytes, int prot)
+                         phys_addr_t pa, size_t bytes, int prot, gfp_t gfp)
 {
        struct omap_iommu_domain *omap_domain = to_omap_domain(domain);
        struct device *dev = omap_domain->dev;
index c31e7bc..52f3829 100644 (file)
@@ -284,9 +284,9 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
 
                /* MAIRs (stage-1 only) */
                iommu_writel(ctx, ARM_SMMU_CB_S1_MAIR0,
-                               pgtbl_cfg.arm_lpae_s1_cfg.mair[0]);
+                               pgtbl_cfg.arm_lpae_s1_cfg.mair);
                iommu_writel(ctx, ARM_SMMU_CB_S1_MAIR1,
-                               pgtbl_cfg.arm_lpae_s1_cfg.mair[1]);
+                               pgtbl_cfg.arm_lpae_s1_cfg.mair >> 32);
 
                /* SCTLR */
                reg = SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE |
@@ -423,7 +423,7 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de
 }
 
 static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
-                         phys_addr_t paddr, size_t size, int prot)
+                         phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        int ret;
        unsigned long flags;
@@ -539,8 +539,8 @@ static int qcom_iommu_add_device(struct device *dev)
        }
 
        group = iommu_group_get_for_dev(dev);
-       if (IS_ERR_OR_NULL(group))
-               return PTR_ERR_OR_ZERO(group);
+       if (IS_ERR(group))
+               return PTR_ERR(group);
 
        iommu_group_put(group);
        iommu_device_link(&qcom_iommu->iommu, dev);
index 4dcbf68..b33cdd5 100644 (file)
@@ -527,7 +527,7 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
        int i, err;
 
        err = pm_runtime_get_if_in_use(iommu->dev);
-       if (WARN_ON_ONCE(err <= 0))
+       if (!err || WARN_ON_ONCE(err < 0))
                return ret;
 
        if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
@@ -758,7 +758,7 @@ unwind:
 }
 
 static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
-                       phys_addr_t paddr, size_t size, int prot)
+                       phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
        unsigned long flags;
@@ -980,13 +980,13 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
        if (!dma_dev)
                return NULL;
 
-       rk_domain = devm_kzalloc(dma_dev, sizeof(*rk_domain), GFP_KERNEL);
+       rk_domain = kzalloc(sizeof(*rk_domain), GFP_KERNEL);
        if (!rk_domain)
                return NULL;
 
        if (type == IOMMU_DOMAIN_DMA &&
            iommu_get_dma_cookie(&rk_domain->domain))
-               return NULL;
+               goto err_free_domain;
 
        /*
         * rk32xx iommus use a 2 level pagetable.
@@ -1021,6 +1021,8 @@ err_free_dt:
 err_put_cookie:
        if (type == IOMMU_DOMAIN_DMA)
                iommu_put_dma_cookie(&rk_domain->domain);
+err_free_domain:
+       kfree(rk_domain);
 
        return NULL;
 }
@@ -1049,6 +1051,7 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
 
        if (domain->type == IOMMU_DOMAIN_DMA)
                iommu_put_dma_cookie(&rk_domain->domain);
+       kfree(rk_domain);
 }
 
 static int rk_iommu_add_device(struct device *dev)
index 3b0b18e..1137f3d 100644 (file)
@@ -265,7 +265,7 @@ undo_cpu_trans:
 }
 
 static int s390_iommu_map(struct iommu_domain *domain, unsigned long iova,
-                         phys_addr_t paddr, size_t size, int prot)
+                         phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct s390_domain *s390_domain = to_s390_domain(domain);
        int flags = ZPCI_PTE_VALID, rc = 0;
index 3924f7c..3fb7ba7 100644 (file)
@@ -178,7 +178,7 @@ static inline int __gart_iommu_map(struct gart_device *gart, unsigned long iova,
 }
 
 static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova,
-                         phys_addr_t pa, size_t bytes, int prot)
+                         phys_addr_t pa, size_t bytes, int prot, gfp_t gfp)
 {
        struct gart_device *gart = gart_handle;
        int ret;
index 7293fc3..63a147b 100644 (file)
@@ -159,9 +159,9 @@ static bool smmu_dma_addr_valid(struct tegra_smmu *smmu, dma_addr_t addr)
        return (addr & smmu->pfn_mask) == addr;
 }
 
-static dma_addr_t smmu_pde_to_dma(u32 pde)
+static dma_addr_t smmu_pde_to_dma(struct tegra_smmu *smmu, u32 pde)
 {
-       return pde << 12;
+       return (dma_addr_t)(pde & smmu->pfn_mask) << 12;
 }
 
 static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
@@ -240,7 +240,7 @@ static inline void smmu_flush_tlb_group(struct tegra_smmu *smmu,
 
 static inline void smmu_flush(struct tegra_smmu *smmu)
 {
-       smmu_readl(smmu, SMMU_CONFIG);
+       smmu_readl(smmu, SMMU_PTB_ASID);
 }
 
 static int tegra_smmu_alloc_asid(struct tegra_smmu *smmu, unsigned int *idp)
@@ -351,6 +351,20 @@ static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup,
        unsigned int i;
        u32 value;
 
+       group = tegra_smmu_find_swgroup(smmu, swgroup);
+       if (group) {
+               value = smmu_readl(smmu, group->reg);
+               value &= ~SMMU_ASID_MASK;
+               value |= SMMU_ASID_VALUE(asid);
+               value |= SMMU_ASID_ENABLE;
+               smmu_writel(smmu, value, group->reg);
+       } else {
+               pr_warn("%s group from swgroup %u not found\n", __func__,
+                               swgroup);
+               /* No point moving ahead if group was not found */
+               return;
+       }
+
        for (i = 0; i < smmu->soc->num_clients; i++) {
                const struct tegra_mc_client *client = &smmu->soc->clients[i];
 
@@ -361,15 +375,6 @@ static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup,
                value |= BIT(client->smmu.bit);
                smmu_writel(smmu, value, client->smmu.reg);
        }
-
-       group = tegra_smmu_find_swgroup(smmu, swgroup);
-       if (group) {
-               value = smmu_readl(smmu, group->reg);
-               value &= ~SMMU_ASID_MASK;
-               value |= SMMU_ASID_VALUE(asid);
-               value |= SMMU_ASID_ENABLE;
-               smmu_writel(smmu, value, group->reg);
-       }
 }
 
 static void tegra_smmu_disable(struct tegra_smmu *smmu, unsigned int swgroup,
@@ -549,6 +554,7 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
                                  dma_addr_t *dmap)
 {
        unsigned int pd_index = iova_pd_index(iova);
+       struct tegra_smmu *smmu = as->smmu;
        struct page *pt_page;
        u32 *pd;
 
@@ -557,7 +563,7 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
                return NULL;
 
        pd = page_address(as->pd);
-       *dmap = smmu_pde_to_dma(pd[pd_index]);
+       *dmap = smmu_pde_to_dma(smmu, pd[pd_index]);
 
        return tegra_smmu_pte_offset(pt_page, iova);
 }
@@ -599,7 +605,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
        } else {
                u32 *pd = page_address(as->pd);
 
-               *dmap = smmu_pde_to_dma(pd[pde]);
+               *dmap = smmu_pde_to_dma(smmu, pd[pde]);
        }
 
        return tegra_smmu_pte_offset(as->pts[pde], iova);
@@ -624,7 +630,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
        if (--as->count[pde] == 0) {
                struct tegra_smmu *smmu = as->smmu;
                u32 *pd = page_address(as->pd);
-               dma_addr_t pte_dma = smmu_pde_to_dma(pd[pde]);
+               dma_addr_t pte_dma = smmu_pde_to_dma(smmu, pd[pde]);
 
                tegra_smmu_set_pde(as, iova, 0);
 
@@ -650,7 +656,7 @@ static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova,
 }
 
 static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
-                         phys_addr_t paddr, size_t size, int prot)
+                         phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        struct tegra_smmu_as *as = to_smmu_as(domain);
        dma_addr_t pte_dma;
index 3ea9d76..315c7cc 100644 (file)
@@ -153,7 +153,6 @@ static off_t viommu_get_write_desc_offset(struct viommu_dev *viommu,
  */
 static int __viommu_sync_req(struct viommu_dev *viommu)
 {
-       int ret = 0;
        unsigned int len;
        size_t write_len;
        struct viommu_request *req;
@@ -182,7 +181,7 @@ static int __viommu_sync_req(struct viommu_dev *viommu)
                kfree(req);
        }
 
-       return ret;
+       return 0;
 }
 
 static int viommu_sync_req(struct viommu_dev *viommu)
@@ -713,7 +712,7 @@ static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
 }
 
 static int viommu_map(struct iommu_domain *domain, unsigned long iova,
-                     phys_addr_t paddr, size_t size, int prot)
+                     phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
        int ret;
        u32 flags;
index ccbb897..697e6a8 100644 (file)
@@ -370,6 +370,10 @@ config MVEBU_PIC
 config MVEBU_SEI
         bool
 
+config LS_EXTIRQ
+       def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
+       select MFD_SYSCON
+
 config LS_SCFG_MSI
        def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
        depends on PCI && PCI_MSI
@@ -483,8 +487,6 @@ config TI_SCI_INTA_IRQCHIP
          If you wish to use interrupt aggregator irq resources managed by the
          TI System Controller, say Y here. Otherwise, say N.
 
-endmenu
-
 config SIFIVE_PLIC
        bool "SiFive Platform-Level Interrupt Controller"
        depends on RISCV
@@ -496,3 +498,5 @@ config SIFIVE_PLIC
           interrupt sources are subordinate to the PLIC.
 
           If you don't know what to do here, say Y.
+
+endmenu
index cc7c439..e806dda 100644 (file)
@@ -84,6 +84,7 @@ obj-$(CONFIG_MVEBU_ICU)                       += irq-mvebu-icu.o
 obj-$(CONFIG_MVEBU_ODMI)               += irq-mvebu-odmi.o
 obj-$(CONFIG_MVEBU_PIC)                        += irq-mvebu-pic.o
 obj-$(CONFIG_MVEBU_SEI)                        += irq-mvebu-sei.o
+obj-$(CONFIG_LS_EXTIRQ)                        += irq-ls-extirq.o
 obj-$(CONFIG_LS_SCFG_MSI)              += irq-ls-scfg-msi.o
 obj-$(CONFIG_EZNPS_GIC)                        += irq-eznps.o
 obj-$(CONFIG_ARCH_ASPEED)              += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
index fc75c61..cbf01af 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/types.h>
 #include <linux/irqchip.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/syscore_ops.h>
 
 #define IRQS_PER_WORD          32
 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4)
@@ -39,6 +40,11 @@ struct bcm7038_l1_chip {
        unsigned int            n_words;
        struct irq_domain       *domain;
        struct bcm7038_l1_cpu   *cpus[NR_CPUS];
+#ifdef CONFIG_PM_SLEEP
+       struct list_head        list;
+       u32                     wake_mask[MAX_WORDS];
+#endif
+       u32                     irq_fwd_mask[MAX_WORDS];
        u8                      affinity[MAX_WORDS * IRQS_PER_WORD];
 };
 
@@ -249,6 +255,7 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
        resource_size_t sz;
        struct bcm7038_l1_cpu *cpu;
        unsigned int i, n_words, parent_irq;
+       int ret;
 
        if (of_address_to_resource(dn, idx, &res))
                return -EINVAL;
@@ -262,6 +269,14 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
        else if (intc->n_words != n_words)
                return -EINVAL;
 
+       ret = of_property_read_u32_array(dn , "brcm,int-fwd-mask",
+                                        intc->irq_fwd_mask, n_words);
+       if (ret != 0 && ret != -EINVAL) {
+               /* property exists but has the wrong number of words */
+               pr_err("invalid brcm,int-fwd-mask property\n");
+               return -EINVAL;
+       }
+
        cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
                                        GFP_KERNEL);
        if (!cpu)
@@ -272,8 +287,11 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
                return -ENOMEM;
 
        for (i = 0; i < n_words; i++) {
-               l1_writel(0xffffffff, cpu->map_base + reg_mask_set(intc, i));
-               cpu->mask_cache[i] = 0xffffffff;
+               l1_writel(~intc->irq_fwd_mask[i],
+                         cpu->map_base + reg_mask_set(intc, i));
+               l1_writel(intc->irq_fwd_mask[i],
+                         cpu->map_base + reg_mask_clr(intc, i));
+               cpu->mask_cache[i] = ~intc->irq_fwd_mask[i];
        }
 
        parent_irq = irq_of_parse_and_map(dn, idx);
@@ -281,12 +299,89 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
                pr_err("failed to map parent interrupt %d\n", parent_irq);
                return -EINVAL;
        }
+
+       if (of_property_read_bool(dn, "brcm,irq-can-wake"))
+               enable_irq_wake(parent_irq);
+
        irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
                                         intc);
 
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+/*
+ * We keep a list of bcm7038_l1_chip used for suspend/resume. This hack is
+ * used because the struct chip_type suspend/resume hooks are not called
+ * unless chip_type is hooked onto a generic_chip. Since this driver does
+ * not use generic_chip, we need to manually hook our resume/suspend to
+ * syscore_ops.
+ */
+static LIST_HEAD(bcm7038_l1_intcs_list);
+static DEFINE_RAW_SPINLOCK(bcm7038_l1_intcs_lock);
+
+static int bcm7038_l1_suspend(void)
+{
+       struct bcm7038_l1_chip *intc;
+       int boot_cpu, word;
+       u32 val;
+
+       /* Wakeup interrupt should only come from the boot cpu */
+       boot_cpu = cpu_logical_map(0);
+
+       list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
+               for (word = 0; word < intc->n_words; word++) {
+                       val = intc->wake_mask[word] | intc->irq_fwd_mask[word];
+                       l1_writel(~val,
+                               intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
+                       l1_writel(val,
+                               intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
+               }
+       }
+
+       return 0;
+}
+
+static void bcm7038_l1_resume(void)
+{
+       struct bcm7038_l1_chip *intc;
+       int boot_cpu, word;
+
+       boot_cpu = cpu_logical_map(0);
+
+       list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
+               for (word = 0; word < intc->n_words; word++) {
+                       l1_writel(intc->cpus[boot_cpu]->mask_cache[word],
+                               intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
+                       l1_writel(~intc->cpus[boot_cpu]->mask_cache[word],
+                               intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
+               }
+       }
+}
+
+static struct syscore_ops bcm7038_l1_syscore_ops = {
+       .suspend        = bcm7038_l1_suspend,
+       .resume         = bcm7038_l1_resume,
+};
+
+static int bcm7038_l1_set_wake(struct irq_data *d, unsigned int on)
+{
+       struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
+       u32 word = d->hwirq / IRQS_PER_WORD;
+       u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
+
+       raw_spin_lock_irqsave(&intc->lock, flags);
+       if (on)
+               intc->wake_mask[word] |= mask;
+       else
+               intc->wake_mask[word] &= ~mask;
+       raw_spin_unlock_irqrestore(&intc->lock, flags);
+
+       return 0;
+}
+#endif
+
 static struct irq_chip bcm7038_l1_irq_chip = {
        .name                   = "bcm7038-l1",
        .irq_mask               = bcm7038_l1_mask,
@@ -295,11 +390,21 @@ static struct irq_chip bcm7038_l1_irq_chip = {
 #ifdef CONFIG_SMP
        .irq_cpu_offline        = bcm7038_l1_cpu_offline,
 #endif
+#ifdef CONFIG_PM_SLEEP
+       .irq_set_wake           = bcm7038_l1_set_wake,
+#endif
 };
 
 static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
                          irq_hw_number_t hw_irq)
 {
+       struct bcm7038_l1_chip *intc = d->host_data;
+       u32 mask = BIT(hw_irq % IRQS_PER_WORD);
+       u32 word = hw_irq / IRQS_PER_WORD;
+
+       if (intc->irq_fwd_mask[word] & mask)
+               return -EPERM;
+
        irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
        irq_set_chip_data(virq, d->host_data);
        irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
@@ -340,6 +445,16 @@ int __init bcm7038_l1_of_init(struct device_node *dn,
                goto out_unmap;
        }
 
+#ifdef CONFIG_PM_SLEEP
+       /* Add bcm7038_l1_chip into a list */
+       raw_spin_lock(&bcm7038_l1_intcs_lock);
+       list_add_tail(&intc->list, &bcm7038_l1_intcs_list);
+       raw_spin_unlock(&bcm7038_l1_intcs_lock);
+
+       if (list_is_singular(&bcm7038_l1_intcs_list))
+               register_syscore_ops(&bcm7038_l1_syscore_ops);
+#endif
+
        pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
                dn, IRQS_PER_WORD * intc->n_words);
 
index e88e75c..fbec07d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
index 229d586..87711e0 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/acpi_iort.h>
+#include <linux/pci.h>
 #include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
index 787e8ee..e05673b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/acpi.h>
 #include <linux/acpi_iort.h>
+#include <linux/bitfield.h>
 #include <linux/bitmap.h>
 #include <linux/cpu.h>
 #include <linux/crash_dump.h>
@@ -102,20 +103,21 @@ struct its_node {
        struct its_collection   *collections;
        struct fwnode_handle    *fwnode_handle;
        u64                     (*get_msi_base)(struct its_device *its_dev);
+       u64                     typer;
        u64                     cbaser_save;
        u32                     ctlr_save;
        struct list_head        its_device_list;
        u64                     flags;
        unsigned long           list_nr;
-       u32                     ite_size;
-       u32                     device_ids;
        int                     numa_node;
        unsigned int            msi_domain_flags;
        u32                     pre_its_base; /* for Socionext Synquacer */
-       bool                    is_v4;
        int                     vlpi_redist_offset;
 };
 
+#define is_v4(its)             (!!((its)->typer & GITS_TYPER_VLPIS))
+#define device_ids(its)                (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)
+
 #define ITS_ITT_ALIGN          SZ_256
 
 /* The maximum number of VPEID bits supported by VLPI commands */
@@ -130,7 +132,7 @@ struct event_lpi_map {
        u16                     *col_map;
        irq_hw_number_t         lpi_base;
        int                     nr_lpis;
-       struct mutex            vlpi_lock;
+       raw_spinlock_t          vlpi_lock;
        struct its_vm           *vm;
        struct its_vlpi_map     *vlpi_maps;
        int                     nr_vlpis;
@@ -181,7 +183,7 @@ static u16 get_its_list(struct its_vm *vm)
        unsigned long its_list = 0;
 
        list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
+               if (!is_v4(its))
                        continue;
 
                if (vm->vlpi_count[its->list_nr])
@@ -191,6 +193,12 @@ static u16 get_its_list(struct its_vm *vm)
        return (u16)its_list;
 }
 
+static inline u32 its_get_event_id(struct irq_data *d)
+{
+       struct its_device *its_dev = irq_data_get_irq_chip_data(d);
+       return d->hwirq - its_dev->event_map.lpi_base;
+}
+
 static struct its_collection *dev_event_to_col(struct its_device *its_dev,
                                               u32 event)
 {
@@ -199,6 +207,22 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,
        return its->collections + its_dev->event_map.col_map[event];
 }
 
+static struct its_vlpi_map *dev_event_to_vlpi_map(struct its_device *its_dev,
+                                              u32 event)
+{
+       if (WARN_ON_ONCE(event >= its_dev->event_map.nr_lpis))
+               return NULL;
+
+       return &its_dev->event_map.vlpi_maps[event];
+}
+
+static struct its_collection *irq_to_col(struct irq_data *d)
+{
+       struct its_device *its_dev = irq_data_get_irq_chip_data(d);
+
+       return dev_event_to_col(its_dev, its_get_event_id(d));
+}
+
 static struct its_collection *valid_col(struct its_collection *col)
 {
        if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(15, 0)))
@@ -305,7 +329,10 @@ struct its_cmd_desc {
  * The ITS command block, which is what the ITS actually parses.
  */
 struct its_cmd_block {
-       u64     raw_cmd[4];
+       union {
+               u64     raw_cmd[4];
+               __le64  raw_cmd_le[4];
+       };
 };
 
 #define ITS_CMD_QUEUE_SZ               SZ_64K
@@ -414,10 +441,10 @@ static void its_encode_vpt_size(struct its_cmd_block *cmd, u8 vpt_size)
 static inline void its_fixup_cmd(struct its_cmd_block *cmd)
 {
        /* Let's fixup BE commands */
-       cmd->raw_cmd[0] = cpu_to_le64(cmd->raw_cmd[0]);
-       cmd->raw_cmd[1] = cpu_to_le64(cmd->raw_cmd[1]);
-       cmd->raw_cmd[2] = cpu_to_le64(cmd->raw_cmd[2]);
-       cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]);
+       cmd->raw_cmd_le[0] = cpu_to_le64(cmd->raw_cmd[0]);
+       cmd->raw_cmd_le[1] = cpu_to_le64(cmd->raw_cmd[1]);
+       cmd->raw_cmd_le[2] = cpu_to_le64(cmd->raw_cmd[2]);
+       cmd->raw_cmd_le[3] = cpu_to_le64(cmd->raw_cmd[3]);
 }
 
 static struct its_collection *its_build_mapd_cmd(struct its_node *its,
@@ -676,6 +703,60 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,
        return valid_vpe(its, desc->its_vmovp_cmd.vpe);
 }
 
+static struct its_vpe *its_build_vinv_cmd(struct its_node *its,
+                                         struct its_cmd_block *cmd,
+                                         struct its_cmd_desc *desc)
+{
+       struct its_vlpi_map *map;
+
+       map = dev_event_to_vlpi_map(desc->its_inv_cmd.dev,
+                                   desc->its_inv_cmd.event_id);
+
+       its_encode_cmd(cmd, GITS_CMD_INV);
+       its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
+       its_encode_event_id(cmd, desc->its_inv_cmd.event_id);
+
+       its_fixup_cmd(cmd);
+
+       return valid_vpe(its, map->vpe);
+}
+
+static struct its_vpe *its_build_vint_cmd(struct its_node *its,
+                                         struct its_cmd_block *cmd,
+                                         struct its_cmd_desc *desc)
+{
+       struct its_vlpi_map *map;
+
+       map = dev_event_to_vlpi_map(desc->its_int_cmd.dev,
+                                   desc->its_int_cmd.event_id);
+
+       its_encode_cmd(cmd, GITS_CMD_INT);
+       its_encode_devid(cmd, desc->its_int_cmd.dev->device_id);
+       its_encode_event_id(cmd, desc->its_int_cmd.event_id);
+
+       its_fixup_cmd(cmd);
+
+       return valid_vpe(its, map->vpe);
+}
+
+static struct its_vpe *its_build_vclear_cmd(struct its_node *its,
+                                           struct its_cmd_block *cmd,
+                                           struct its_cmd_desc *desc)
+{
+       struct its_vlpi_map *map;
+
+       map = dev_event_to_vlpi_map(desc->its_clear_cmd.dev,
+                                   desc->its_clear_cmd.event_id);
+
+       its_encode_cmd(cmd, GITS_CMD_CLEAR);
+       its_encode_devid(cmd, desc->its_clear_cmd.dev->device_id);
+       its_encode_event_id(cmd, desc->its_clear_cmd.event_id);
+
+       its_fixup_cmd(cmd);
+
+       return valid_vpe(its, map->vpe);
+}
+
 static u64 its_cmd_ptr_to_offset(struct its_node *its,
                                 struct its_cmd_block *ptr)
 {
@@ -953,7 +1034,7 @@ static void its_send_invall(struct its_node *its, struct its_collection *col)
 
 static void its_send_vmapti(struct its_device *dev, u32 id)
 {
-       struct its_vlpi_map *map = &dev->event_map.vlpi_maps[id];
+       struct its_vlpi_map *map = dev_event_to_vlpi_map(dev, id);
        struct its_cmd_desc desc;
 
        desc.its_vmapti_cmd.vpe = map->vpe;
@@ -967,7 +1048,7 @@ static void its_send_vmapti(struct its_device *dev, u32 id)
 
 static void its_send_vmovi(struct its_device *dev, u32 id)
 {
-       struct its_vlpi_map *map = &dev->event_map.vlpi_maps[id];
+       struct its_vlpi_map *map = dev_event_to_vlpi_map(dev, id);
        struct its_cmd_desc desc;
 
        desc.its_vmovi_cmd.vpe = map->vpe;
@@ -1021,7 +1102,7 @@ static void its_send_vmovp(struct its_vpe *vpe)
 
        /* Emit VMOVPs */
        list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
+               if (!is_v4(its))
                        continue;
 
                if (!vpe->its_vm->vlpi_count[its->list_nr])
@@ -1042,29 +1123,71 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)
        its_send_single_vcommand(its, its_build_vinvall_cmd, &desc);
 }
 
+static void its_send_vinv(struct its_device *dev, u32 event_id)
+{
+       struct its_cmd_desc desc;
+
+       /*
+        * There is no real VINV command. This is just a normal INV,
+        * with a VSYNC instead of a SYNC.
+        */
+       desc.its_inv_cmd.dev = dev;
+       desc.its_inv_cmd.event_id = event_id;
+
+       its_send_single_vcommand(dev->its, its_build_vinv_cmd, &desc);
+}
+
+static void its_send_vint(struct its_device *dev, u32 event_id)
+{
+       struct its_cmd_desc desc;
+
+       /*
+        * There is no real VINT command. This is just a normal INT,
+        * with a VSYNC instead of a SYNC.
+        */
+       desc.its_int_cmd.dev = dev;
+       desc.its_int_cmd.event_id = event_id;
+
+       its_send_single_vcommand(dev->its, its_build_vint_cmd, &desc);
+}
+
+static void its_send_vclear(struct its_device *dev, u32 event_id)
+{
+       struct its_cmd_desc desc;
+
+       /*
+        * There is no real VCLEAR command. This is just a normal CLEAR,
+        * with a VSYNC instead of a SYNC.
+        */
+       desc.its_clear_cmd.dev = dev;
+       desc.its_clear_cmd.event_id = event_id;
+
+       its_send_single_vcommand(dev->its, its_build_vclear_cmd, &desc);
+}
+
 /*
  * irqchip functions - assumes MSI, mostly.
  */
-
-static inline u32 its_get_event_id(struct irq_data *d)
+static struct its_vlpi_map *get_vlpi_map(struct irq_data *d)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
-       return d->hwirq - its_dev->event_map.lpi_base;
+       u32 event = its_get_event_id(d);
+
+       if (!irqd_is_forwarded_to_vcpu(d))
+               return NULL;
+
+       return dev_event_to_vlpi_map(its_dev, event);
 }
 
 static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
 {
+       struct its_vlpi_map *map = get_vlpi_map(d);
        irq_hw_number_t hwirq;
        void *va;
        u8 *cfg;
 
-       if (irqd_is_forwarded_to_vcpu(d)) {
-               struct its_device *its_dev = irq_data_get_irq_chip_data(d);
-               u32 event = its_get_event_id(d);
-               struct its_vlpi_map *map;
-
-               va = page_address(its_dev->event_map.vm->vprop_page);
-               map = &its_dev->event_map.vlpi_maps[event];
+       if (map) {
+               va = page_address(map->vm->vprop_page);
                hwirq = map->vintid;
 
                /* Remember the updated property */
@@ -1090,23 +1213,50 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
                dsb(ishst);
 }
 
+static void wait_for_syncr(void __iomem *rdbase)
+{
+       while (gic_read_lpir(rdbase + GICR_SYNCR) & 1)
+               cpu_relax();
+}
+
+static void direct_lpi_inv(struct irq_data *d)
+{
+       struct its_collection *col;
+       void __iomem *rdbase;
+
+       /* Target the redistributor this LPI is currently routed to */
+       col = irq_to_col(d);
+       rdbase = per_cpu_ptr(gic_rdists->rdist, col->col_id)->rd_base;
+       gic_write_lpir(d->hwirq, rdbase + GICR_INVLPIR);
+
+       wait_for_syncr(rdbase);
+}
+
 static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
 
        lpi_write_config(d, clr, set);
-       its_send_inv(its_dev, its_get_event_id(d));
+       if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu(d))
+               direct_lpi_inv(d);
+       else if (!irqd_is_forwarded_to_vcpu(d))
+               its_send_inv(its_dev, its_get_event_id(d));
+       else
+               its_send_vinv(its_dev, its_get_event_id(d));
 }
 
 static void its_vlpi_set_doorbell(struct irq_data *d, bool enable)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        u32 event = its_get_event_id(d);
+       struct its_vlpi_map *map;
 
-       if (its_dev->event_map.vlpi_maps[event].db_enabled == enable)
+       map = dev_event_to_vlpi_map(its_dev, event);
+
+       if (map->db_enabled == enable)
                return;
 
-       its_dev->event_map.vlpi_maps[event].db_enabled = enable;
+       map->db_enabled = enable;
 
        /*
         * More fun with the architecture:
@@ -1208,10 +1358,17 @@ static int its_irq_set_irqchip_state(struct irq_data *d,
        if (which != IRQCHIP_STATE_PENDING)
                return -EINVAL;
 
-       if (state)
-               its_send_int(its_dev, event);
-       else
-               its_send_clear(its_dev, event);
+       if (irqd_is_forwarded_to_vcpu(d)) {
+               if (state)
+                       its_send_vint(its_dev, event);
+               else
+                       its_send_vclear(its_dev, event);
+       } else {
+               if (state)
+                       its_send_int(its_dev, event);
+               else
+                       its_send_clear(its_dev, event);
+       }
 
        return 0;
 }
@@ -1279,13 +1436,13 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
        if (!info->map)
                return -EINVAL;
 
-       mutex_lock(&its_dev->event_map.vlpi_lock);
+       raw_spin_lock(&its_dev->event_map.vlpi_lock);
 
        if (!its_dev->event_map.vm) {
                struct its_vlpi_map *maps;
 
                maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps),
-                              GFP_KERNEL);
+                              GFP_ATOMIC);
                if (!maps) {
                        ret = -ENOMEM;
                        goto out;
@@ -1328,29 +1485,30 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
        }
 
 out:
-       mutex_unlock(&its_dev->event_map.vlpi_lock);
+       raw_spin_unlock(&its_dev->event_map.vlpi_lock);
        return ret;
 }
 
 static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
-       u32 event = its_get_event_id(d);
+       struct its_vlpi_map *map;
        int ret = 0;
 
-       mutex_lock(&its_dev->event_map.vlpi_lock);
+       raw_spin_lock(&its_dev->event_map.vlpi_lock);
+
+       map = get_vlpi_map(d);
 
-       if (!its_dev->event_map.vm ||
-           !its_dev->event_map.vlpi_maps[event].vm) {
+       if (!its_dev->event_map.vm || !map) {
                ret = -EINVAL;
                goto out;
        }
 
        /* Copy our mapping information to the incoming request */
-       *info->map = its_dev->event_map.vlpi_maps[event];
+       *info->map = *map;
 
 out:
-       mutex_unlock(&its_dev->event_map.vlpi_lock);
+       raw_spin_unlock(&its_dev->event_map.vlpi_lock);
        return ret;
 }
 
@@ -1360,7 +1518,7 @@ static int its_vlpi_unmap(struct irq_data *d)
        u32 event = its_get_event_id(d);
        int ret = 0;
 
-       mutex_lock(&its_dev->event_map.vlpi_lock);
+       raw_spin_lock(&its_dev->event_map.vlpi_lock);
 
        if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d)) {
                ret = -EINVAL;
@@ -1390,7 +1548,7 @@ static int its_vlpi_unmap(struct irq_data *d)
        }
 
 out:
-       mutex_unlock(&its_dev->event_map.vlpi_lock);
+       raw_spin_unlock(&its_dev->event_map.vlpi_lock);
        return ret;
 }
 
@@ -1416,7 +1574,7 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
        struct its_cmd_info *info = vcpu_info;
 
        /* Need a v4 ITS */
-       if (!its_dev->its->is_v4)
+       if (!is_v4(its_dev->its))
                return -EINVAL;
 
        /* Unmap request? */
@@ -1922,9 +2080,9 @@ static bool its_parse_indirect_baser(struct its_node *its,
        if (new_order >= MAX_ORDER) {
                new_order = MAX_ORDER - 1;
                ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz);
-               pr_warn("ITS@%pa: %s Table too large, reduce ids %u->%u\n",
+               pr_warn("ITS@%pa: %s Table too large, reduce ids %llu->%u\n",
                        &its->phys_base, its_base_type_string[type],
-                       its->device_ids, ids);
+                       device_ids(its), ids);
        }
 
        *order = new_order;
@@ -1970,7 +2128,7 @@ static int its_alloc_tables(struct its_node *its)
                case GITS_BASER_TYPE_DEVICE:
                        indirect = its_parse_indirect_baser(its, baser,
                                                            psz, &order,
-                                                           its->device_ids);
+                                                           device_ids(its));
                        break;
 
                case GITS_BASER_TYPE_VCPU:
@@ -2361,7 +2519,7 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id)
 
        /* Don't allow device id that exceeds ITS hardware limit */
        if (!baser)
-               return (ilog2(dev_id) < its->device_ids);
+               return (ilog2(dev_id) < device_ids(its));
 
        return its_alloc_table_entry(its, baser, dev_id);
 }
@@ -2380,7 +2538,7 @@ static bool its_alloc_vpe_table(u32 vpe_id)
        list_for_each_entry(its, &its_nodes, entry) {
                struct its_baser *baser;
 
-               if (!its->is_v4)
+               if (!is_v4(its))
                        continue;
 
                baser = its_get_baser(its, GITS_BASER_TYPE_VCPU);
@@ -2419,7 +2577,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
         * sized as a power of two (and you need at least one bit...).
         */
        nr_ites = max(2, nvecs);
-       sz = nr_ites * its->ite_size;
+       sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
        sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
        itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node);
        if (alloc_lpis) {
@@ -2450,7 +2608,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        dev->event_map.col_map = col_map;
        dev->event_map.lpi_base = lpi_base;
        dev->event_map.nr_lpis = nr_lpis;
-       mutex_init(&dev->event_map.vlpi_lock);
+       raw_spin_lock_init(&dev->event_map.vlpi_lock);
        dev->device_id = dev_id;
        INIT_LIST_HEAD(&dev->entry);
 
@@ -2471,6 +2629,7 @@ static void its_free_device(struct its_device *its_dev)
        raw_spin_lock_irqsave(&its_dev->its->lock, flags);
        list_del(&its_dev->entry);
        raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
+       kfree(its_dev->event_map.col_map);
        kfree(its_dev->itt);
        kfree(its_dev);
 }
@@ -2679,7 +2838,6 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
                its_lpi_free(its_dev->event_map.lpi_map,
                             its_dev->event_map.lpi_base,
                             its_dev->event_map.nr_lpis);
-               kfree(its_dev->event_map.col_map);
 
                /* Unmap device/itt */
                its_send_mapd(its_dev, 0);
@@ -2772,8 +2930,7 @@ static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to)
 
                rdbase = per_cpu_ptr(gic_rdists->rdist, from)->rd_base;
                gic_write_lpir(vpe->vpe_db_lpi, rdbase + GICR_CLRLPIR);
-               while (gic_read_lpir(rdbase + GICR_SYNCR) & 1)
-                       cpu_relax();
+               wait_for_syncr(rdbase);
 
                return;
        }
@@ -2869,7 +3026,7 @@ static void its_vpe_invall(struct its_vpe *vpe)
        struct its_node *its;
 
        list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
+               if (!is_v4(its))
                        continue;
 
                if (its_list_map && !vpe->its_vm->vlpi_count[its->list_nr])
@@ -2927,10 +3084,10 @@ static void its_vpe_send_inv(struct irq_data *d)
        if (gic_rdists->has_direct_lpi) {
                void __iomem *rdbase;
 
+               /* Target the redistributor this VPE is currently known on */
                rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base;
-               gic_write_lpir(vpe->vpe_db_lpi, rdbase + GICR_INVLPIR);
-               while (gic_read_lpir(rdbase + GICR_SYNCR) & 1)
-                       cpu_relax();
+               gic_write_lpir(d->parent_data->hwirq, rdbase + GICR_INVLPIR);
+               wait_for_syncr(rdbase);
        } else {
                its_vpe_send_cmd(vpe, its_send_inv);
        }
@@ -2972,8 +3129,7 @@ static int its_vpe_set_irqchip_state(struct irq_data *d,
                        gic_write_lpir(vpe->vpe_db_lpi, rdbase + GICR_SETLPIR);
                } else {
                        gic_write_lpir(vpe->vpe_db_lpi, rdbase + GICR_CLRLPIR);
-                       while (gic_read_lpir(rdbase + GICR_SYNCR) & 1)
-                               cpu_relax();
+                       wait_for_syncr(rdbase);
                }
        } else {
                if (state)
@@ -3138,7 +3294,7 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
        vpe->col_idx = cpumask_first(cpu_online_mask);
 
        list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
+               if (!is_v4(its))
                        continue;
 
                its_send_vmapp(its, vpe, true);
@@ -3164,7 +3320,7 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,
                return;
 
        list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
+               if (!is_v4(its))
                        continue;
 
                its_send_vmapp(its, vpe, false);
@@ -3215,8 +3371,9 @@ static bool __maybe_unused its_enable_quirk_cavium_22375(void *data)
 {
        struct its_node *its = data;
 
-       /* erratum 22375: only alloc 8MB table size */
-       its->device_ids = 0x14;         /* 20 bits, 8MB */
+       /* erratum 22375: only alloc 8MB table size (20 bits) */
+       its->typer &= ~GITS_TYPER_DEVBITS;
+       its->typer |= FIELD_PREP(GITS_TYPER_DEVBITS, 20 - 1);
        its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375;
 
        return true;
@@ -3236,7 +3393,8 @@ static bool __maybe_unused its_enable_quirk_qdf2400_e0065(void *data)
        struct its_node *its = data;
 
        /* On QDF2400, the size of the ITE is 16Bytes */
-       its->ite_size = 16;
+       its->typer &= ~GITS_TYPER_ITT_ENTRY_SIZE;
+       its->typer |= FIELD_PREP(GITS_TYPER_ITT_ENTRY_SIZE, 16 - 1);
 
        return true;
 }
@@ -3270,8 +3428,10 @@ static bool __maybe_unused its_enable_quirk_socionext_synquacer(void *data)
                its->get_msi_base = its_irq_get_msi_base_pre_its;
 
                ids = ilog2(pre_its_window[1]) - 2;
-               if (its->device_ids > ids)
-                       its->device_ids = ids;
+               if (device_ids(its) > ids) {
+                       its->typer &= ~GITS_TYPER_DEVBITS;
+                       its->typer |= FIELD_PREP(GITS_TYPER_DEVBITS, ids - 1);
+               }
 
                /* the pre-ITS breaks isolation, so disable MSI remapping */
                its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_MSI_REMAP;
@@ -3504,7 +3664,7 @@ static int its_init_vpe_domain(void)
        }
 
        /* Use the last possible DevID */
-       devid = GENMASK(its->device_ids - 1, 0);
+       devid = GENMASK(device_ids(its) - 1, 0);
        vpe_proxy.dev = its_create_device(its, devid, entries, false);
        if (!vpe_proxy.dev) {
                kfree(vpe_proxy.vpes);
@@ -3602,12 +3762,10 @@ static int __init its_probe_one(struct resource *res,
        INIT_LIST_HEAD(&its->entry);
        INIT_LIST_HEAD(&its->its_device_list);
        typer = gic_read_typer(its_base + GITS_TYPER);
+       its->typer = typer;
        its->base = its_base;
        its->phys_base = res->start;
-       its->ite_size = GITS_TYPER_ITT_ENTRY_SIZE(typer);
-       its->device_ids = GITS_TYPER_DEVBITS(typer);
-       its->is_v4 = !!(typer & GITS_TYPER_VLPIS);
-       if (its->is_v4) {
+       if (is_v4(its)) {
                if (!(typer & GITS_TYPER_VMOVP)) {
                        err = its_compute_its_list_map(res, its_base);
                        if (err < 0)
@@ -3674,7 +3832,7 @@ static int __init its_probe_one(struct resource *res,
        gits_write_cwriter(0, its->base + GITS_CWRITER);
        ctlr = readl_relaxed(its->base + GITS_CTLR);
        ctlr |= GITS_CTLR_ENABLE;
-       if (its->is_v4)
+       if (is_v4(its))
                ctlr |= GITS_CTLR_ImDe;
        writel_relaxed(ctlr, its->base + GITS_CTLR);
 
@@ -3999,7 +4157,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
                return err;
 
        list_for_each_entry(its, &its_nodes, entry)
-               has_v4 |= its->is_v4;
+               has_v4 |= is_v4(its);
 
        if (has_v4 & rdists->has_vlpis) {
                if (its_init_vpe_domain() ||
index 6bb1f68..d621801 100644 (file)
@@ -183,7 +183,7 @@ static void gic_do_wait_for_rwp(void __iomem *base)
                }
                cpu_relax();
                udelay(1);
-       };
+       }
 }
 
 /* Wait for completion of a distributor change */
@@ -240,7 +240,7 @@ static void gic_enable_redist(bool enable)
                        break;
                cpu_relax();
                udelay(1);
-       };
+       }
        if (!count)
                pr_err_ratelimited("redistributor failed to %s...\n",
                                   enable ? "wakeup" : "sleep");
index f126255..01d18b3 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform IRQ support
+ *  Ingenic XBurst platform IRQ support
  */
 
 #include <linux/errno.h>
@@ -10,7 +10,6 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/irqchip.h>
-#include <linux/irqchip/ingenic.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/timex.h>
@@ -22,6 +21,7 @@
 
 struct ingenic_intc_data {
        void __iomem *base;
+       struct irq_domain *domain;
        unsigned num_chips;
 };
 
@@ -35,41 +35,30 @@ struct ingenic_intc_data {
 static irqreturn_t intc_cascade(int irq, void *data)
 {
        struct ingenic_intc_data *intc = irq_get_handler_data(irq);
-       uint32_t irq_reg;
+       struct irq_domain *domain = intc->domain;
+       struct irq_chip_generic *gc;
+       uint32_t pending;
        unsigned i;
 
        for (i = 0; i < intc->num_chips; i++) {
-               irq_reg = readl(intc->base + (i * CHIP_SIZE) +
-                               JZ_REG_INTC_PENDING);
-               if (!irq_reg)
+               gc = irq_get_domain_generic_chip(domain, i * 32);
+
+               pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
+               if (!pending)
                        continue;
 
-               generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+               while (pending) {
+                       int bit = __fls(pending);
+
+                       irq = irq_find_mapping(domain, bit + (i * 32));
+                       generic_handle_irq(irq);
+                       pending &= ~BIT(bit);
+               }
        }
 
        return IRQ_HANDLED;
 }
 
-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
-{
-       struct irq_chip_regs *regs = &gc->chip_types->regs;
-
-       writel(mask, gc->reg_base + regs->enable);
-       writel(~mask, gc->reg_base + regs->disable);
-}
-
-void ingenic_intc_irq_suspend(struct irq_data *data)
-{
-       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-       intc_irq_set_mask(gc, gc->wake_active);
-}
-
-void ingenic_intc_irq_resume(struct irq_data *data)
-{
-       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-       intc_irq_set_mask(gc, gc->mask_cache);
-}
-
 static struct irqaction intc_cascade_action = {
        .handler = intc_cascade,
        .name = "SoC intc cascade interrupt",
@@ -108,17 +97,27 @@ static int __init ingenic_intc_of_init(struct device_node *node,
                goto out_unmap_irq;
        }
 
-       for (i = 0; i < num_chips; i++) {
-               /* Mask all irqs */
-               writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
-                      JZ_REG_INTC_SET_MASK);
+       domain = irq_domain_add_legacy(node, num_chips * 32,
+                                      JZ4740_IRQ_BASE, 0,
+                                      &irq_generic_chip_ops, NULL);
+       if (!domain) {
+               err = -ENOMEM;
+               goto out_unmap_base;
+       }
 
-               gc = irq_alloc_generic_chip("INTC", 1,
-                                           JZ4740_IRQ_BASE + (i * 32),
-                                           intc->base + (i * CHIP_SIZE),
-                                           handle_level_irq);
+       intc->domain = domain;
+
+       err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC",
+                                            handle_level_irq, 0,
+                                            IRQ_NOPROBE | IRQ_LEVEL, 0);
+       if (err)
+               goto out_domain_remove;
+
+       for (i = 0; i < num_chips; i++) {
+               gc = irq_get_domain_generic_chip(domain, i * 32);
 
                gc->wake_enabled = IRQ_MSK(32);
+               gc->reg_base = intc->base + (i * CHIP_SIZE);
 
                ct = gc->chip_types;
                ct->regs.enable = JZ_REG_INTC_CLEAR_MASK;
@@ -127,21 +126,19 @@ static int __init ingenic_intc_of_init(struct device_node *node,
                ct->chip.irq_mask = irq_gc_mask_disable_reg;
                ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
                ct->chip.irq_set_wake = irq_gc_set_wake;
-               ct->chip.irq_suspend = ingenic_intc_irq_suspend;
-               ct->chip.irq_resume = ingenic_intc_irq_resume;
+               ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;
 
-               irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
-                                      IRQ_NOPROBE | IRQ_LEVEL);
+               /* Mask all irqs */
+               irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
        }
 
-       domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
-                                      &irq_domain_simple_ops, NULL);
-       if (!domain)
-               pr_warn("unable to register IRQ domain\n");
-
        setup_irq(parent_irq, &intc_cascade_action);
        return 0;
 
+out_domain_remove:
+       irq_domain_remove(domain);
+out_unmap_base:
+       iounmap(intc->base);
 out_unmap_irq:
        irq_dispose_mapping(parent_irq);
 out_free:
diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
new file mode 100644 (file)
index 0000000..4d1179f
--- /dev/null
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "irq-ls-extirq: " fmt
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define MAXIRQ 12
+#define LS1021A_SCFGREVCR 0x200
+
+struct ls_extirq_data {
+       struct regmap           *syscon;
+       u32                     intpcr;
+       bool                    bit_reverse;
+       u32                     nirq;
+       struct irq_fwspec       map[MAXIRQ];
+};
+
+static int
+ls_extirq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct ls_extirq_data *priv = data->chip_data;
+       irq_hw_number_t hwirq = data->hwirq;
+       u32 value, mask;
+
+       if (priv->bit_reverse)
+               mask = 1U << (31 - hwirq);
+       else
+               mask = 1U << hwirq;
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_LOW:
+               type = IRQ_TYPE_LEVEL_HIGH;
+               value = mask;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               type = IRQ_TYPE_EDGE_RISING;
+               value = mask;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+       case IRQ_TYPE_EDGE_RISING:
+               value = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       regmap_update_bits(priv->syscon, priv->intpcr, mask, value);
+
+       return irq_chip_set_type_parent(data, type);
+}
+
+static struct irq_chip ls_extirq_chip = {
+       .name                   = "ls-extirq",
+       .irq_mask               = irq_chip_mask_parent,
+       .irq_unmask             = irq_chip_unmask_parent,
+       .irq_eoi                = irq_chip_eoi_parent,
+       .irq_set_type           = ls_extirq_set_type,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .irq_set_affinity       = irq_chip_set_affinity_parent,
+       .flags                  = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static int
+ls_extirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                      unsigned int nr_irqs, void *arg)
+{
+       struct ls_extirq_data *priv = domain->host_data;
+       struct irq_fwspec *fwspec = arg;
+       irq_hw_number_t hwirq;
+
+       if (fwspec->param_count != 2)
+               return -EINVAL;
+
+       hwirq = fwspec->param[0];
+       if (hwirq >= priv->nirq)
+               return -EINVAL;
+
+       irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &ls_extirq_chip,
+                                     priv);
+
+       return irq_domain_alloc_irqs_parent(domain, virq, 1, &priv->map[hwirq]);
+}
+
+static const struct irq_domain_ops extirq_domain_ops = {
+       .xlate          = irq_domain_xlate_twocell,
+       .alloc          = ls_extirq_domain_alloc,
+       .free           = irq_domain_free_irqs_common,
+};
+
+static int
+ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node)
+{
+       const __be32 *map;
+       u32 mapsize;
+       int ret;
+
+       map = of_get_property(node, "interrupt-map", &mapsize);
+       if (!map)
+               return -ENOENT;
+       if (mapsize % sizeof(*map))
+               return -EINVAL;
+       mapsize /= sizeof(*map);
+
+       while (mapsize) {
+               struct device_node *ipar;
+               u32 hwirq, intsize, j;
+
+               if (mapsize < 3)
+                       return -EINVAL;
+               hwirq = be32_to_cpup(map);
+               if (hwirq >= MAXIRQ)
+                       return -EINVAL;
+               priv->nirq = max(priv->nirq, hwirq + 1);
+
+               ipar = of_find_node_by_phandle(be32_to_cpup(map + 2));
+               map += 3;
+               mapsize -= 3;
+               if (!ipar)
+                       return -EINVAL;
+               priv->map[hwirq].fwnode = &ipar->fwnode;
+               ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
+               if (ret)
+                       return ret;
+
+               if (intsize > mapsize)
+                       return -EINVAL;
+
+               priv->map[hwirq].param_count = intsize;
+               for (j = 0; j < intsize; ++j)
+                       priv->map[hwirq].param[j] = be32_to_cpup(map++);
+               mapsize -= intsize;
+       }
+       return 0;
+}
+
+static int __init
+ls_extirq_of_init(struct device_node *node, struct device_node *parent)
+{
+
+       struct irq_domain *domain, *parent_domain;
+       struct ls_extirq_data *priv;
+       int ret;
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               pr_err("Cannot find parent domain\n");
+               return -ENODEV;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->syscon = syscon_node_to_regmap(node->parent);
+       if (IS_ERR(priv->syscon)) {
+               ret = PTR_ERR(priv->syscon);
+               pr_err("Failed to lookup parent regmap\n");
+               goto out;
+       }
+       ret = of_property_read_u32(node, "reg", &priv->intpcr);
+       if (ret) {
+               pr_err("Missing INTPCR offset value\n");
+               goto out;
+       }
+
+       ret = ls_extirq_parse_map(priv, node);
+       if (ret)
+               goto out;
+
+       if (of_device_is_compatible(node, "fsl,ls1021a-extirq")) {
+               u32 revcr;
+
+               ret = regmap_read(priv->syscon, LS1021A_SCFGREVCR, &revcr);
+               if (ret)
+                       goto out;
+               priv->bit_reverse = (revcr != 0);
+       }
+
+       domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node,
+                                         &extirq_domain_ops, priv);
+       if (!domain)
+               ret = -ENOMEM;
+
+out:
+       if (ret)
+               kfree(priv);
+       return ret;
+}
+
+IRQCHIP_DECLARE(ls1021a_extirq, "fsl,ls1021a-extirq", ls_extirq_of_init);
index ef4d625..8f6e6b0 100644 (file)
@@ -246,8 +246,8 @@ static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *d
        /* No free bits available. Allocate a new vint */
        vint_desc = ti_sci_inta_alloc_parent_irq(domain);
        if (IS_ERR(vint_desc)) {
-               mutex_unlock(&inta->vint_mutex);
-               return ERR_PTR(PTR_ERR(vint_desc));
+               event_desc = ERR_CAST(vint_desc);
+               goto unlock;
        }
 
        free_bit = find_first_zero_bit(vint_desc->event_map,
@@ -259,6 +259,7 @@ alloc_event:
        if (IS_ERR(event_desc))
                clear_bit(free_bit, vint_desc->event_map);
 
+unlock:
        mutex_unlock(&inta->vint_mutex);
        return event_desc;
 }
index 5a7efeb..84163f1 100644 (file)
@@ -51,7 +51,7 @@ static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
        while (readl(zevio_irq_io + IO_STATUS)) {
                irqnr = readl(zevio_irq_io + IO_CURRENT);
                handle_domain_irq(zevio_irq_domain, irqnr, regs);
-       };
+       }
 }
 
 static void __init zevio_init_irq_base(void __iomem *base)
index faa7d61..6ae9e1f 100644 (file)
@@ -1,10 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/soc/qcom/irq.h>
 #include <linux/spinlock.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#define PDC_MAX_IRQS           126
+#define PDC_MAX_IRQS           168
+#define PDC_MAX_GPIO_IRQS      256
 
 #define CLEAR_INTR(reg, intr)  (reg & ~(1 << intr))
 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
@@ -26,6 +28,8 @@
 #define IRQ_ENABLE_BANK                0x10
 #define IRQ_i_CFG              0x110
 
+#define PDC_NO_PARENT_IRQ      ~0UL
+
 struct pdc_pin_region {
        u32 pin_base;
        u32 parent_base;
@@ -47,6 +51,26 @@ static u32 pdc_reg_read(int reg, u32 i)
        return readl_relaxed(pdc_base + reg + i * sizeof(u32));
 }
 
+static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
+                                         enum irqchip_irq_state which,
+                                         bool *state)
+{
+       if (d->hwirq == GPIO_NO_WAKE_IRQ)
+               return 0;
+
+       return irq_chip_get_parent_state(d, which, state);
+}
+
+static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
+                                         enum irqchip_irq_state which,
+                                         bool value)
+{
+       if (d->hwirq == GPIO_NO_WAKE_IRQ)
+               return 0;
+
+       return irq_chip_set_parent_state(d, which, value);
+}
+
 static void pdc_enable_intr(struct irq_data *d, bool on)
 {
        int pin_out = d->hwirq;
@@ -63,15 +87,37 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
        raw_spin_unlock(&pdc_lock);
 }
 
-static void qcom_pdc_gic_mask(struct irq_data *d)
+static void qcom_pdc_gic_disable(struct irq_data *d)
 {
+       if (d->hwirq == GPIO_NO_WAKE_IRQ)
+               return;
+
        pdc_enable_intr(d, false);
+       irq_chip_disable_parent(d);
+}
+
+static void qcom_pdc_gic_enable(struct irq_data *d)
+{
+       if (d->hwirq == GPIO_NO_WAKE_IRQ)
+               return;
+
+       pdc_enable_intr(d, true);
+       irq_chip_enable_parent(d);
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
+       if (d->hwirq == GPIO_NO_WAKE_IRQ)
+               return;
+
        irq_chip_mask_parent(d);
 }
 
 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
-       pdc_enable_intr(d, true);
+       if (d->hwirq == GPIO_NO_WAKE_IRQ)
+               return;
+
        irq_chip_unmask_parent(d);
 }
 
@@ -114,6 +160,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
        int pin_out = d->hwirq;
        enum pdc_irq_config_bits pdc_type;
 
+       if (pin_out == GPIO_NO_WAKE_IRQ)
+               return 0;
+
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
                pdc_type = PDC_EDGE_RISING;
@@ -148,6 +197,10 @@ static struct irq_chip qcom_pdc_gic_chip = {
        .irq_eoi                = irq_chip_eoi_parent,
        .irq_mask               = qcom_pdc_gic_mask,
        .irq_unmask             = qcom_pdc_gic_unmask,
+       .irq_disable            = qcom_pdc_gic_disable,
+       .irq_enable             = qcom_pdc_gic_enable,
+       .irq_get_irqchip_state  = qcom_pdc_gic_get_irqchip_state,
+       .irq_set_irqchip_state  = qcom_pdc_gic_set_irqchip_state,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
        .irq_set_type           = qcom_pdc_gic_set_type,
        .flags                  = IRQCHIP_MASK_ON_SUSPEND |
@@ -169,8 +222,7 @@ static irq_hw_number_t get_parent_hwirq(int pin)
                        return (region->parent_base + pin - region->pin_base);
        }
 
-       WARN_ON(1);
-       return ~0UL;
+       return PDC_NO_PARENT_IRQ;
 }
 
 static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
@@ -199,17 +251,17 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq,
 
        ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
        if (ret)
-               return -EINVAL;
-
-       parent_hwirq = get_parent_hwirq(hwirq);
-       if (parent_hwirq == ~0UL)
-               return -EINVAL;
+               return ret;
 
        ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
                                             &qcom_pdc_gic_chip, NULL);
        if (ret)
                return ret;
 
+       parent_hwirq = get_parent_hwirq(hwirq);
+       if (parent_hwirq == PDC_NO_PARENT_IRQ)
+               return 0;
+
        if (type & IRQ_TYPE_EDGE_BOTH)
                type = IRQ_TYPE_EDGE_RISING;
 
@@ -232,6 +284,60 @@ static const struct irq_domain_ops qcom_pdc_ops = {
        .free           = irq_domain_free_irqs_common,
 };
 
+static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
+                              unsigned int nr_irqs, void *data)
+{
+       struct irq_fwspec *fwspec = data;
+       struct irq_fwspec parent_fwspec;
+       irq_hw_number_t hwirq, parent_hwirq;
+       unsigned int type;
+       int ret;
+
+       ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+                                           &qcom_pdc_gic_chip, NULL);
+       if (ret)
+               return ret;
+
+       if (hwirq == GPIO_NO_WAKE_IRQ)
+               return 0;
+
+       parent_hwirq = get_parent_hwirq(hwirq);
+       if (parent_hwirq == PDC_NO_PARENT_IRQ)
+               return 0;
+
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               type = IRQ_TYPE_EDGE_RISING;
+
+       if (type & IRQ_TYPE_LEVEL_MASK)
+               type = IRQ_TYPE_LEVEL_HIGH;
+
+       parent_fwspec.fwnode      = domain->parent->fwnode;
+       parent_fwspec.param_count = 3;
+       parent_fwspec.param[0]    = 0;
+       parent_fwspec.param[1]    = parent_hwirq;
+       parent_fwspec.param[2]    = type;
+
+       return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+                                           &parent_fwspec);
+}
+
+static int qcom_pdc_gpio_domain_select(struct irq_domain *d,
+                                      struct irq_fwspec *fwspec,
+                                      enum irq_domain_bus_token bus_token)
+{
+       return bus_token == DOMAIN_BUS_WAKEUP;
+}
+
+static const struct irq_domain_ops qcom_pdc_gpio_ops = {
+       .select         = qcom_pdc_gpio_domain_select,
+       .alloc          = qcom_pdc_gpio_alloc,
+       .free           = irq_domain_free_irqs_common,
+};
+
 static int pdc_setup_pin_mapping(struct device_node *np)
 {
        int ret, n;
@@ -270,7 +376,7 @@ static int pdc_setup_pin_mapping(struct device_node *np)
 
 static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
 {
-       struct irq_domain *parent_domain, *pdc_domain;
+       struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain;
        int ret;
 
        pdc_base = of_iomap(node, 0);
@@ -301,12 +407,27 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
                goto fail;
        }
 
+       pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain,
+                                       IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP,
+                                       PDC_MAX_GPIO_IRQS,
+                                       of_fwnode_handle(node),
+                                       &qcom_pdc_gpio_ops, NULL);
+       if (!pdc_gpio_domain) {
+               pr_err("%pOF: PDC domain add failed for GPIO domain\n", node);
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       irq_domain_update_bus_token(pdc_gpio_domain, DOMAIN_BUS_WAKEUP);
+
        return 0;
 
+remove:
+       irq_domain_remove(pdc_domain);
 fail:
        kfree(pdc_region);
        iounmap(pdc_base);
        return ret;
 }
 
-IRQCHIP_DECLARE(pdc_sdm845, "qcom,sdm845-pdc", qcom_pdc_init);
+IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);
index 0322df9..14386d0 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * EBI driver for Atmel chips
  * inspired by the fsl weim bus driver
  *
  * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/clk.h>
@@ -19,6 +16,8 @@
 #include <linux/regmap.h>
 #include <soc/at91/atmel-sfr.h>
 
+#define AT91_EBI_NUM_CS                8
+
 struct atmel_ebi_dev_config {
        int cs;
        struct atmel_smc_cs_conf smcconf;
@@ -314,7 +313,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
                if (ret)
                        return ret;
 
-               if (cs >= AT91_MATRIX_EBI_NUM_CS ||
+               if (cs >= AT91_EBI_NUM_CS ||
                    !(ebi->caps->available_cs & BIT(cs))) {
                        dev_err(dev, "invalid reg property in %pOF\n", np);
                        return -EINVAL;
@@ -344,7 +343,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
                apply = true;
 
        i = 0;
-       for_each_set_bit(cs, &cslines, AT91_MATRIX_EBI_NUM_CS) {
+       for_each_set_bit(cs, &cslines, AT91_EBI_NUM_CS) {
                ebid->configs[i].cs = cs;
 
                if (apply) {
index 6827ed4..82b415b 100644 (file)
@@ -127,7 +127,6 @@ enum dpfe_msg_fields {
        MSG_COMMAND,
        MSG_ARG_COUNT,
        MSG_ARG0,
-       MSG_CHKSUM,
        MSG_FIELD_MAX   = 16 /* Max number of arguments */
 };
 
@@ -180,7 +179,7 @@ struct dpfe_api {
 };
 
 /* Things we need for as long as we are active. */
-struct private_data {
+struct brcmstb_dpfe_priv {
        void __iomem *regs;
        void __iomem *dmem;
        void __iomem *imem;
@@ -232,9 +231,13 @@ static struct attribute *dpfe_v3_attrs[] = {
 };
 ATTRIBUTE_GROUPS(dpfe_v3);
 
-/* API v2 firmware commands */
-static const struct dpfe_api dpfe_api_v2 = {
-       .version = 2,
+/*
+ * Old API v2 firmware commands, as defined in the rev 0.61 specification, we
+ * use a version set to 1 to denote that it is not compatible with the new API
+ * v2 and onwards.
+ */
+static const struct dpfe_api dpfe_api_old_v2 = {
+       .version = 1,
        .fw_name = "dpfe.bin",
        .sysfs_attrs = dpfe_v2_groups,
        .command = {
@@ -243,21 +246,42 @@ static const struct dpfe_api dpfe_api_v2 = {
                        [MSG_COMMAND] = 1,
                        [MSG_ARG_COUNT] = 1,
                        [MSG_ARG0] = 1,
-                       [MSG_CHKSUM] = 4,
                },
                [DPFE_CMD_GET_REFRESH] = {
                        [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
                        [MSG_COMMAND] = 2,
                        [MSG_ARG_COUNT] = 1,
                        [MSG_ARG0] = 1,
-                       [MSG_CHKSUM] = 5,
                },
                [DPFE_CMD_GET_VENDOR] = {
                        [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
                        [MSG_COMMAND] = 2,
                        [MSG_ARG_COUNT] = 1,
                        [MSG_ARG0] = 2,
-                       [MSG_CHKSUM] = 6,
+               },
+       }
+};
+
+/*
+ * API v2 firmware commands, as defined in the rev 0.8 specification, named new
+ * v2 here
+ */
+static const struct dpfe_api dpfe_api_new_v2 = {
+       .version = 2,
+       .fw_name = NULL, /* We expect the firmware to have been downloaded! */
+       .sysfs_attrs = dpfe_v2_groups,
+       .command = {
+               [DPFE_CMD_GET_INFO] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 0x101,
+               },
+               [DPFE_CMD_GET_REFRESH] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 0x201,
+               },
+               [DPFE_CMD_GET_VENDOR] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 0x202,
                },
        }
 };
@@ -273,49 +297,51 @@ static const struct dpfe_api dpfe_api_v3 = {
                        [MSG_COMMAND] = 0x0101,
                        [MSG_ARG_COUNT] = 1,
                        [MSG_ARG0] = 1,
-                       [MSG_CHKSUM] = 0x104,
                },
                [DPFE_CMD_GET_REFRESH] = {
                        [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
                        [MSG_COMMAND] = 0x0202,
                        [MSG_ARG_COUNT] = 0,
-                       /*
-                        * This is a bit ugly. Without arguments, the checksum
-                        * follows right after the argument count and not at
-                        * offset MSG_CHKSUM.
-                        */
-                       [MSG_ARG0] = 0x203,
                },
                /* There's no GET_VENDOR command in API v3. */
        },
 };
 
-static bool is_dcpu_enabled(void __iomem *regs)
+static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
 {
        u32 val;
 
-       val = readl_relaxed(regs + REG_DCPU_RESET);
+       mutex_lock(&priv->lock);
+       val = readl_relaxed(priv->regs + REG_DCPU_RESET);
+       mutex_unlock(&priv->lock);
 
        return !(val & DCPU_RESET_MASK);
 }
 
-static void __disable_dcpu(void __iomem *regs)
+static void __disable_dcpu(struct brcmstb_dpfe_priv *priv)
 {
        u32 val;
 
-       if (!is_dcpu_enabled(regs))
+       if (!is_dcpu_enabled(priv))
                return;
 
+       mutex_lock(&priv->lock);
+
        /* Put DCPU in reset if it's running. */
-       val = readl_relaxed(regs + REG_DCPU_RESET);
+       val = readl_relaxed(priv->regs + REG_DCPU_RESET);
        val |= (1 << DCPU_RESET_SHIFT);
-       writel_relaxed(val, regs + REG_DCPU_RESET);
+       writel_relaxed(val, priv->regs + REG_DCPU_RESET);
+
+       mutex_unlock(&priv->lock);
 }
 
-static void __enable_dcpu(void __iomem *regs)
+static void __enable_dcpu(struct brcmstb_dpfe_priv *priv)
 {
+       void __iomem *regs = priv->regs;
        u32 val;
 
+       mutex_lock(&priv->lock);
+
        /* Clear mailbox registers. */
        writel_relaxed(0, regs + REG_TO_DCPU_MBOX);
        writel_relaxed(0, regs + REG_TO_HOST_MBOX);
@@ -329,6 +355,8 @@ static void __enable_dcpu(void __iomem *regs)
        val = readl_relaxed(regs + REG_DCPU_RESET);
        val &= ~(1 << DCPU_RESET_SHIFT);
        writel_relaxed(val, regs + REG_DCPU_RESET);
+
+       mutex_unlock(&priv->lock);
 }
 
 static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
@@ -343,7 +371,7 @@ static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
        return sum;
 }
 
-static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
+static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
                                 char *buf, ssize_t *size)
 {
        unsigned int msg_type;
@@ -382,7 +410,7 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
        return ptr;
 }
 
-static void __finalize_command(struct private_data *priv)
+static void __finalize_command(struct brcmstb_dpfe_priv *priv)
 {
        unsigned int release_mbox;
 
@@ -390,12 +418,12 @@ static void __finalize_command(struct private_data *priv)
         * It depends on the API version which MBOX register we have to write to
         * to signal we are done.
         */
-       release_mbox = (priv->dpfe_api->version < 3)
+       release_mbox = (priv->dpfe_api->version < 2)
                        ? REG_TO_HOST_MBOX : REG_TO_DCPU_MBOX;
        writel_relaxed(0, priv->regs + release_mbox);
 }
 
-static int __send_command(struct private_data *priv, unsigned int cmd,
+static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
                          u32 result[])
 {
        const u32 *msg = priv->dpfe_api->command[cmd];
@@ -421,9 +449,17 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
                return -ETIMEDOUT;
        }
 
+       /* Compute checksum over the message */
+       chksum_idx = msg[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1;
+       chksum = get_msg_chksum(msg, chksum_idx);
+
        /* Write command and arguments to message area */
-       for (i = 0; i < MSG_FIELD_MAX; i++)
-               writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
+       for (i = 0; i < MSG_FIELD_MAX; i++) {
+               if (i == chksum_idx)
+                       writel_relaxed(chksum, regs + DCPU_MSG_RAM(i));
+               else
+                       writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
+       }
 
        /* Tell DCPU there is a command waiting */
        writel_relaxed(1, regs + REG_TO_DCPU_MBOX);
@@ -517,7 +553,7 @@ static int __verify_firmware(struct init_data *init,
 
 /* Verify checksum by reading back the firmware from co-processor RAM. */
 static int __verify_fw_checksum(struct init_data *init,
-                               struct private_data *priv,
+                               struct brcmstb_dpfe_priv *priv,
                                const struct dpfe_firmware_header *header,
                                u32 checksum)
 {
@@ -571,26 +607,23 @@ static int __write_firmware(u32 __iomem *mem, const u32 *fw,
        return 0;
 }
 
-static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
-                                         struct init_data *init)
+static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
 {
        const struct dpfe_firmware_header *header;
        unsigned int dmem_size, imem_size;
-       struct device *dev = &pdev->dev;
+       struct device *dev = priv->dev;
        bool is_big_endian = false;
-       struct private_data *priv;
        const struct firmware *fw;
        const u32 *dmem, *imem;
+       struct init_data init;
        const void *fw_blob;
        int ret;
 
-       priv = platform_get_drvdata(pdev);
-
        /*
         * Skip downloading the firmware if the DCPU is already running and
         * responding to commands.
         */
-       if (is_dcpu_enabled(priv->regs)) {
+       if (is_dcpu_enabled(priv)) {
                u32 response[MSG_FIELD_MAX];
 
                ret = __send_command(priv, DPFE_CMD_GET_INFO, response);
@@ -606,20 +639,23 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
        if (!priv->dpfe_api->fw_name)
                return -ENODEV;
 
-       ret = request_firmware(&fw, priv->dpfe_api->fw_name, dev);
-       /* request_firmware() prints its own error messages. */
+       ret = firmware_request_nowarn(&fw, priv->dpfe_api->fw_name, dev);
+       /*
+        * Defer the firmware download if the firmware file couldn't be found.
+        * The root file system may not be available yet.
+        */
        if (ret)
-               return ret;
+               return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
 
-       ret = __verify_firmware(init, fw);
+       ret = __verify_firmware(&init, fw);
        if (ret)
                return -EFAULT;
 
-       __disable_dcpu(priv->regs);
+       __disable_dcpu(priv);
 
-       is_big_endian = init->is_big_endian;
-       dmem_size = init->dmem_len;
-       imem_size = init->imem_len;
+       is_big_endian = init.is_big_endian;
+       dmem_size = init.dmem_len;
+       imem_size = init.imem_len;
 
        /* At the beginning of the firmware blob is a header. */
        header = (struct dpfe_firmware_header *)fw->data;
@@ -637,17 +673,17 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
        if (ret)
                return ret;
 
-       ret = __verify_fw_checksum(init, priv, header, init->chksum);
+       ret = __verify_fw_checksum(&init, priv, header, init.chksum);
        if (ret)
                return ret;
 
-       __enable_dcpu(priv->regs);
+       __enable_dcpu(priv);
 
        return 0;
 }
 
 static ssize_t generic_show(unsigned int command, u32 response[],
-                           struct private_data *priv, char *buf)
+                           struct brcmstb_dpfe_priv *priv, char *buf)
 {
        int ret;
 
@@ -665,7 +701,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
                         char *buf)
 {
        u32 response[MSG_FIELD_MAX];
-       struct private_data *priv;
+       struct brcmstb_dpfe_priv *priv;
        unsigned int info;
        ssize_t ret;
 
@@ -688,7 +724,7 @@ static ssize_t show_refresh(struct device *dev,
 {
        u32 response[MSG_FIELD_MAX];
        void __iomem *info;
-       struct private_data *priv;
+       struct brcmstb_dpfe_priv *priv;
        u8 refresh, sr_abort, ppre, thermal_offs, tuf;
        u32 mr4;
        ssize_t ret;
@@ -721,7 +757,7 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
        u32 response[MSG_FIELD_MAX];
-       struct private_data *priv;
+       struct brcmstb_dpfe_priv *priv;
        void __iomem *info;
        unsigned long val;
        int ret;
@@ -747,7 +783,7 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
                           char *buf)
 {
        u32 response[MSG_FIELD_MAX];
-       struct private_data *priv;
+       struct brcmstb_dpfe_priv *priv;
        void __iomem *info;
        ssize_t ret;
        u32 mr5, mr6, mr7, mr8, err;
@@ -778,7 +814,7 @@ static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
                         char *buf)
 {
        u32 response[MSG_FIELD_MAX];
-       struct private_data *priv;
+       struct brcmstb_dpfe_priv *priv;
        ssize_t ret;
        u32 mr4, mr5, mr6, mr7, mr8, err;
 
@@ -800,16 +836,15 @@ static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
 
 static int brcmstb_dpfe_resume(struct platform_device *pdev)
 {
-       struct init_data init;
+       struct brcmstb_dpfe_priv *priv = platform_get_drvdata(pdev);
 
-       return brcmstb_dpfe_download_firmware(pdev, &init);
+       return brcmstb_dpfe_download_firmware(priv);
 }
 
 static int brcmstb_dpfe_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct private_data *priv;
-       struct init_data init;
+       struct brcmstb_dpfe_priv *priv;
        struct resource *res;
        int ret;
 
@@ -817,6 +852,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       priv->dev = dev;
+
        mutex_init(&priv->lock);
        platform_set_drvdata(pdev, priv);
 
@@ -851,9 +888,10 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       ret = brcmstb_dpfe_download_firmware(pdev, &init);
+       ret = brcmstb_dpfe_download_firmware(priv);
        if (ret) {
-               dev_err(dev, "Couldn't download firmware -- %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "Couldn't download firmware -- %d\n", ret);
                return ret;
        }
 
@@ -867,7 +905,7 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
 
 static int brcmstb_dpfe_remove(struct platform_device *pdev)
 {
-       struct private_data *priv = dev_get_drvdata(&pdev->dev);
+       struct brcmstb_dpfe_priv *priv = dev_get_drvdata(&pdev->dev);
 
        sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
 
@@ -876,10 +914,10 @@ static int brcmstb_dpfe_remove(struct platform_device *pdev)
 
 static const struct of_device_id brcmstb_dpfe_of_match[] = {
        /* Use legacy API v2 for a select number of chips */
-       { .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_v2 },
-       { .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_v2 },
-       { .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_v2 },
-       { .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_v2 },
+       { .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_old_v2 },
+       { .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_old_v2 },
+       { .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_old_v2 },
+       { .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_new_v2 },
        /* API v3 is the default going forward */
        { .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v3 },
        {}
index 402c6bc..9d9127b 100644 (file)
@@ -1613,7 +1613,7 @@ static void emif_shutdown(struct platform_device *pdev)
 static int get_emif_reg_values(struct emif_data *emif, u32 freq,
                struct emif_regs *regs)
 {
-       u32                             cs1_used, ip_rev, phy_type;
+       u32                             ip_rev, phy_type;
        u32                             cl, type;
        const struct lpddr2_timings     *timings;
        const struct lpddr2_min_tck     *min_tck;
@@ -1621,7 +1621,6 @@ static int get_emif_reg_values(struct emif_data *emif, u32 freq,
        const struct lpddr2_addressing  *addressing;
        struct emif_data                *emif_for_calc;
        struct device                   *dev;
-       const struct emif_custom_configs *custom_configs;
 
        dev = emif->dev;
        /*
@@ -1639,12 +1638,10 @@ static int get_emif_reg_values(struct emif_data *emif, u32 freq,
 
        device_info     = emif_for_calc->plat_data->device_info;
        type            = device_info->type;
-       cs1_used        = device_info->cs1_used;
        ip_rev          = emif_for_calc->plat_data->ip_rev;
        phy_type        = emif_for_calc->plat_data->phy_type;
 
        min_tck         = emif_for_calc->plat_data->min_tck;
-       custom_configs  = emif_for_calc->plat_data->custom_configs;
 
        set_ddr_clk_period(freq);
 
index 4a21b50..e59ccbd 100644 (file)
@@ -29,6 +29,7 @@
 #define DDR_TYPE_LPDDR2_S4     3
 #define DDR_TYPE_LPDDR2_S2     4
 #define DDR_TYPE_LPDDR2_NVM    5
+#define DDR_TYPE_LPDDR3                6
 
 /* DDR IO width */
 #define DDR_IO_WIDTH_4         1
@@ -169,4 +170,64 @@ extern const struct lpddr2_timings
        lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
 extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
 
+/*
+ * Structure for timings for LPDDR3 based on LPDDR2 plus additional fields.
+ * All parameters are in pico seconds(ps) excluding max_freq, min_freq which
+ * are in Hz.
+ */
+struct lpddr3_timings {
+       u32 max_freq;
+       u32 min_freq;
+       u32 tRFC;
+       u32 tRRD;
+       u32 tRPab;
+       u32 tRPpb;
+       u32 tRCD;
+       u32 tRC;
+       u32 tRAS;
+       u32 tWTR;
+       u32 tWR;
+       u32 tRTP;
+       u32 tW2W_C2C;
+       u32 tR2R_C2C;
+       u32 tWL;
+       u32 tDQSCK;
+       u32 tRL;
+       u32 tFAW;
+       u32 tXSR;
+       u32 tXP;
+       u32 tCKE;
+       u32 tCKESR;
+       u32 tMRD;
+};
+
+/*
+ * Min value for some parameters in terms of number of tCK cycles(nCK)
+ * Please set to zero parameters that are not valid for a given memory
+ * type
+ */
+struct lpddr3_min_tck {
+       u32 tRFC;
+       u32 tRRD;
+       u32 tRPab;
+       u32 tRPpb;
+       u32 tRCD;
+       u32 tRC;
+       u32 tRAS;
+       u32 tWTR;
+       u32 tWR;
+       u32 tRTP;
+       u32 tW2W_C2C;
+       u32 tR2R_C2C;
+       u32 tWL;
+       u32 tDQSCK;
+       u32 tRL;
+       u32 tFAW;
+       u32 tXSR;
+       u32 tXP;
+       u32 tCKE;
+       u32 tCKESR;
+       u32 tMRD;
+};
+
 #endif /* __JEDEC_DDR_H */
index 439d7d8..a113e81 100644 (file)
@@ -366,6 +366,8 @@ static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
 
 static const struct dev_pm_ops smi_larb_pm_ops = {
        SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL)
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                                    pm_runtime_force_resume)
 };
 
 static struct platform_driver mtk_smi_larb_driver = {
@@ -507,6 +509,8 @@ static int __maybe_unused mtk_smi_common_suspend(struct device *dev)
 
 static const struct dev_pm_ops smi_common_pm_ops = {
        SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL)
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                                    pm_runtime_force_resume)
 };
 
 static struct platform_driver mtk_smi_common_driver = {
index 46539b2..71f26ea 100644 (file)
@@ -3,6 +3,7 @@
  * OpenFirmware helpers for memory drivers
  *
  * Copyright (C) 2012 Texas Instruments, Inc.
+ * Copyright (C) 2019 Samsung Electronics Co., Ltd.
  */
 
 #include <linux/device.h>
@@ -149,3 +150,151 @@ default_timings:
        return lpddr2_jedec_timings;
 }
 EXPORT_SYMBOL(of_get_ddr_timings);
+
+/**
+ * of_lpddr3_get_min_tck() - extract min timing values for lpddr3
+ * @np: pointer to ddr device tree node
+ * @device: device requesting for min timing values
+ *
+ * Populates the lpddr3_min_tck structure by extracting data
+ * from device tree node. Returns a pointer to the populated
+ * structure. If any error in populating the structure, returns NULL.
+ */
+const struct lpddr3_min_tck *of_lpddr3_get_min_tck(struct device_node *np,
+                                                  struct device *dev)
+{
+       int                     ret = 0;
+       struct lpddr3_min_tck   *min;
+
+       min = devm_kzalloc(dev, sizeof(*min), GFP_KERNEL);
+       if (!min)
+               goto default_min_tck;
+
+       ret |= of_property_read_u32(np, "tRFC-min-tck", &min->tRFC);
+       ret |= of_property_read_u32(np, "tRRD-min-tck", &min->tRRD);
+       ret |= of_property_read_u32(np, "tRPab-min-tck", &min->tRPab);
+       ret |= of_property_read_u32(np, "tRPpb-min-tck", &min->tRPpb);
+       ret |= of_property_read_u32(np, "tRCD-min-tck", &min->tRCD);
+       ret |= of_property_read_u32(np, "tRC-min-tck", &min->tRC);
+       ret |= of_property_read_u32(np, "tRAS-min-tck", &min->tRAS);
+       ret |= of_property_read_u32(np, "tWTR-min-tck", &min->tWTR);
+       ret |= of_property_read_u32(np, "tWR-min-tck", &min->tWR);
+       ret |= of_property_read_u32(np, "tRTP-min-tck", &min->tRTP);
+       ret |= of_property_read_u32(np, "tW2W-C2C-min-tck", &min->tW2W_C2C);
+       ret |= of_property_read_u32(np, "tR2R-C2C-min-tck", &min->tR2R_C2C);
+       ret |= of_property_read_u32(np, "tWL-min-tck", &min->tWL);
+       ret |= of_property_read_u32(np, "tDQSCK-min-tck", &min->tDQSCK);
+       ret |= of_property_read_u32(np, "tRL-min-tck", &min->tRL);
+       ret |= of_property_read_u32(np, "tFAW-min-tck", &min->tFAW);
+       ret |= of_property_read_u32(np, "tXSR-min-tck", &min->tXSR);
+       ret |= of_property_read_u32(np, "tXP-min-tck", &min->tXP);
+       ret |= of_property_read_u32(np, "tCKE-min-tck", &min->tCKE);
+       ret |= of_property_read_u32(np, "tCKESR-min-tck", &min->tCKESR);
+       ret |= of_property_read_u32(np, "tMRD-min-tck", &min->tMRD);
+
+       if (ret) {
+               dev_warn(dev, "%s: errors while parsing min-tck values\n",
+                        __func__);
+               devm_kfree(dev, min);
+               goto default_min_tck;
+       }
+
+       return min;
+
+default_min_tck:
+       dev_warn(dev, "%s: using default min-tck values\n", __func__);
+       return NULL;
+}
+EXPORT_SYMBOL(of_lpddr3_get_min_tck);
+
+static int of_lpddr3_do_get_timings(struct device_node *np,
+                                   struct lpddr3_timings *tim)
+{
+       int ret;
+
+       /* The 'reg' param required since DT has changed, used as 'max-freq' */
+       ret = of_property_read_u32(np, "reg", &tim->max_freq);
+       ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
+       ret |= of_property_read_u32(np, "tRFC", &tim->tRFC);
+       ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
+       ret |= of_property_read_u32(np, "tRPab", &tim->tRPab);
+       ret |= of_property_read_u32(np, "tRPpb", &tim->tRPpb);
+       ret |= of_property_read_u32(np, "tRCD", &tim->tRCD);
+       ret |= of_property_read_u32(np, "tRC", &tim->tRC);
+       ret |= of_property_read_u32(np, "tRAS", &tim->tRAS);
+       ret |= of_property_read_u32(np, "tWTR", &tim->tWTR);
+       ret |= of_property_read_u32(np, "tWR", &tim->tWR);
+       ret |= of_property_read_u32(np, "tRTP", &tim->tRTP);
+       ret |= of_property_read_u32(np, "tW2W-C2C", &tim->tW2W_C2C);
+       ret |= of_property_read_u32(np, "tR2R-C2C", &tim->tR2R_C2C);
+       ret |= of_property_read_u32(np, "tFAW", &tim->tFAW);
+       ret |= of_property_read_u32(np, "tXSR", &tim->tXSR);
+       ret |= of_property_read_u32(np, "tXP", &tim->tXP);
+       ret |= of_property_read_u32(np, "tCKE", &tim->tCKE);
+       ret |= of_property_read_u32(np, "tCKESR", &tim->tCKESR);
+       ret |= of_property_read_u32(np, "tMRD", &tim->tMRD);
+
+       return ret;
+}
+
+/**
+ * of_lpddr3_get_ddr_timings() - extracts the lpddr3 timings and updates no of
+ * frequencies available.
+ * @np_ddr: Pointer to ddr device tree node
+ * @dev: Device requesting for ddr timings
+ * @device_type: Type of ddr
+ * @nr_frequencies: No of frequencies available for ddr
+ * (updated by this function)
+ *
+ * Populates lpddr3_timings structure by extracting data from device
+ * tree node. Returns pointer to populated structure. If any error
+ * while populating, returns NULL.
+ */
+const struct lpddr3_timings
+*of_lpddr3_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
+                          u32 device_type, u32 *nr_frequencies)
+{
+       struct lpddr3_timings   *timings = NULL;
+       u32                     arr_sz = 0, i = 0;
+       struct device_node      *np_tim;
+       char                    *tim_compat = NULL;
+
+       switch (device_type) {
+       case DDR_TYPE_LPDDR3:
+               tim_compat = "jedec,lpddr3-timings";
+               break;
+       default:
+               dev_warn(dev, "%s: un-supported memory type\n", __func__);
+       }
+
+       for_each_child_of_node(np_ddr, np_tim)
+               if (of_device_is_compatible(np_tim, tim_compat))
+                       arr_sz++;
+
+       if (arr_sz)
+               timings = devm_kcalloc(dev, arr_sz, sizeof(*timings),
+                                      GFP_KERNEL);
+
+       if (!timings)
+               goto default_timings;
+
+       for_each_child_of_node(np_ddr, np_tim) {
+               if (of_device_is_compatible(np_tim, tim_compat)) {
+                       if (of_lpddr3_do_get_timings(np_tim, &timings[i])) {
+                               devm_kfree(dev, timings);
+                               goto default_timings;
+                       }
+                       i++;
+               }
+       }
+
+       *nr_frequencies = arr_sz;
+
+       return timings;
+
+default_timings:
+       dev_warn(dev, "%s: failed to get timings\n", __func__);
+       *nr_frequencies = 0;
+       return NULL;
+}
+EXPORT_SYMBOL(of_lpddr3_get_ddr_timings);
index b077cc8..e39ecc4 100644 (file)
@@ -14,6 +14,11 @@ extern const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
 extern const struct lpddr2_timings
        *of_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
        u32 device_type, u32 *nr_frequencies);
+extern const struct lpddr3_min_tck
+       *of_lpddr3_get_min_tck(struct device_node *np, struct device *dev);
+extern const struct lpddr3_timings
+       *of_lpddr3_get_ddr_timings(struct device_node *np_ddr,
+       struct device *dev, u32 device_type, u32 *nr_frequencies);
 #else
 static inline const struct lpddr2_min_tck
        *of_get_min_tck(struct device_node *np, struct device *dev)
@@ -27,6 +32,19 @@ static inline const struct lpddr2_timings
 {
        return NULL;
 }
+
+static inline const struct lpddr3_min_tck
+       *of_lpddr3_get_min_tck(struct device_node *np, struct device *dev)
+{
+       return NULL;
+}
+
+static inline const struct lpddr3_timings
+       *of_lpddr3_get_ddr_timings(struct device_node *np_ddr,
+       struct device *dev, u32 device_type, u32 *nr_frequencies)
+{
+       return NULL;
+}
 #endif /* CONFIG_OF && CONFIG_DDR */
 
 #endif /* __LINUX_MEMORY_OF_REG_ */
index 79ce7ea..e9c3ce9 100644 (file)
@@ -7,6 +7,19 @@ config SAMSUNG_MC
 
 if SAMSUNG_MC
 
+config EXYNOS5422_DMC
+       tristate "EXYNOS5422 Dynamic Memory Controller driver"
+       depends on ARCH_EXYNOS || (COMPILE_TEST && HAS_IOMEM)
+       select DDR
+       depends on DEVFREQ_GOV_SIMPLE_ONDEMAND
+       depends on (PM_DEVFREQ && PM_DEVFREQ_EVENT)
+       help
+         This adds driver for Exynos5422 DMC (Dynamic Memory Controller).
+         The driver provides support for Dynamic Voltage and Frequency Scaling in
+         DMC and DRAM. It also supports changing timings of DRAM running with
+         different frequency. The timings are calculated based on DT memory
+         information.
+
 config EXYNOS_SROM
        bool "Exynos SROM controller driver" if COMPILE_TEST
        depends on (ARM && ARCH_EXYNOS) || (COMPILE_TEST && HAS_IOMEM)
index 00587be..ea071be 100644 (file)
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_EXYNOS5422_DMC)   += exynos5422-dmc.o
 obj-$(CONFIG_EXYNOS_SROM)      += exynos-srom.o
diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c
new file mode 100644 (file)
index 0000000..47dbf6d
--- /dev/null
@@ -0,0 +1,1550 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Author: Lukasz Luba <l.luba@partner.samsung.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/devfreq-event.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include "../jedec_ddr.h"
+#include "../of_memory.h"
+
+#define EXYNOS5_DREXI_TIMINGAREF               (0x0030)
+#define EXYNOS5_DREXI_TIMINGROW0               (0x0034)
+#define EXYNOS5_DREXI_TIMINGDATA0              (0x0038)
+#define EXYNOS5_DREXI_TIMINGPOWER0             (0x003C)
+#define EXYNOS5_DREXI_TIMINGROW1               (0x00E4)
+#define EXYNOS5_DREXI_TIMINGDATA1              (0x00E8)
+#define EXYNOS5_DREXI_TIMINGPOWER1             (0x00EC)
+#define CDREX_PAUSE                            (0x2091c)
+#define CDREX_LPDDR3PHY_CON3                   (0x20a20)
+#define CDREX_LPDDR3PHY_CLKM_SRC               (0x20700)
+#define EXYNOS5_TIMING_SET_SWI                 BIT(28)
+#define USE_MX_MSPLL_TIMINGS                   (1)
+#define USE_BPLL_TIMINGS                       (0)
+#define EXYNOS5_AREF_NORMAL                    (0x2e)
+
+#define DREX_PPCCLKCON         (0x0130)
+#define DREX_PEREV2CONFIG      (0x013c)
+#define DREX_PMNC_PPC          (0xE000)
+#define DREX_CNTENS_PPC                (0xE010)
+#define DREX_CNTENC_PPC                (0xE020)
+#define DREX_INTENS_PPC                (0xE030)
+#define DREX_INTENC_PPC                (0xE040)
+#define DREX_FLAG_PPC          (0xE050)
+#define DREX_PMCNT2_PPC                (0xE130)
+
+/*
+ * A value for register DREX_PMNC_PPC which should be written to reset
+ * the cycle counter CCNT (a reference wall clock). It sets zero to the
+ * CCNT counter.
+ */
+#define CC_RESET               BIT(2)
+
+/*
+ * A value for register DREX_PMNC_PPC which does the reset of all performance
+ * counters to zero.
+ */
+#define PPC_COUNTER_RESET      BIT(1)
+
+/*
+ * Enables all configured counters (including cycle counter). The value should
+ * be written to the register DREX_PMNC_PPC.
+ */
+#define PPC_ENABLE             BIT(0)
+
+/* A value for register DREX_PPCCLKCON which enables performance events clock.
+ * Must be written before first access to the performance counters register
+ * set, otherwise it could crash.
+ */
+#define PEREV_CLK_EN           BIT(0)
+
+/*
+ * Values which are used to enable counters, interrupts or configure flags of
+ * the performance counters. They configure counter 2 and cycle counter.
+ */
+#define PERF_CNT2              BIT(2)
+#define PERF_CCNT              BIT(31)
+
+/*
+ * Performance event types which are used for setting the preferred event
+ * to track in the counters.
+ * There is a set of different types, the values are from range 0 to 0x6f.
+ * These settings should be written to the configuration register which manages
+ * the type of the event (register DREX_PEREV2CONFIG).
+ */
+#define READ_TRANSFER_CH0      (0x6d)
+#define READ_TRANSFER_CH1      (0x6f)
+
+#define PERF_COUNTER_START_VALUE 0xff000000
+#define PERF_EVENT_UP_DOWN_THRESHOLD 900000000ULL
+
+/**
+ * struct dmc_opp_table - Operating level desciption
+ *
+ * Covers frequency and voltage settings of the DMC operating mode.
+ */
+struct dmc_opp_table {
+       u32 freq_hz;
+       u32 volt_uv;
+};
+
+/**
+ * struct exynos5_dmc - main structure describing DMC device
+ *
+ * The main structure for the Dynamic Memory Controller which covers clocks,
+ * memory regions, HW information, parameters and current operating mode.
+ */
+struct exynos5_dmc {
+       struct device *dev;
+       struct devfreq *df;
+       struct devfreq_simple_ondemand_data gov_data;
+       void __iomem *base_drexi0;
+       void __iomem *base_drexi1;
+       struct regmap *clk_regmap;
+       struct mutex lock;
+       unsigned long curr_rate;
+       unsigned long curr_volt;
+       unsigned long bypass_rate;
+       struct dmc_opp_table *opp;
+       struct dmc_opp_table opp_bypass;
+       int opp_count;
+       u32 timings_arr_size;
+       u32 *timing_row;
+       u32 *timing_data;
+       u32 *timing_power;
+       const struct lpddr3_timings *timings;
+       const struct lpddr3_min_tck *min_tck;
+       u32 bypass_timing_row;
+       u32 bypass_timing_data;
+       u32 bypass_timing_power;
+       struct regulator *vdd_mif;
+       struct clk *fout_spll;
+       struct clk *fout_bpll;
+       struct clk *mout_spll;
+       struct clk *mout_bpll;
+       struct clk *mout_mclk_cdrex;
+       struct clk *mout_mx_mspll_ccore;
+       struct clk *mx_mspll_ccore_phy;
+       struct clk *mout_mx_mspll_ccore_phy;
+       struct devfreq_event_dev **counter;
+       int num_counters;
+       u64 last_overflow_ts[2];
+       unsigned long load;
+       unsigned long total;
+       bool in_irq_mode;
+};
+
+#define TIMING_FIELD(t_name, t_bit_beg, t_bit_end) \
+       { .name = t_name, .bit_beg = t_bit_beg, .bit_end = t_bit_end }
+
+#define TIMING_VAL2REG(timing, t_val)                  \
+({                                                     \
+               u32 __val;                              \
+               __val = (t_val) << (timing)->bit_beg;   \
+               __val;                                  \
+})
+
+struct timing_reg {
+       char *name;
+       int bit_beg;
+       int bit_end;
+       unsigned int val;
+};
+
+static const struct timing_reg timing_row[] = {
+       TIMING_FIELD("tRFC", 24, 31),
+       TIMING_FIELD("tRRD", 20, 23),
+       TIMING_FIELD("tRP", 16, 19),
+       TIMING_FIELD("tRCD", 12, 15),
+       TIMING_FIELD("tRC", 6, 11),
+       TIMING_FIELD("tRAS", 0, 5),
+};
+
+static const struct timing_reg timing_data[] = {
+       TIMING_FIELD("tWTR", 28, 31),
+       TIMING_FIELD("tWR", 24, 27),
+       TIMING_FIELD("tRTP", 20, 23),
+       TIMING_FIELD("tW2W-C2C", 14, 14),
+       TIMING_FIELD("tR2R-C2C", 12, 12),
+       TIMING_FIELD("WL", 8, 11),
+       TIMING_FIELD("tDQSCK", 4, 7),
+       TIMING_FIELD("RL", 0, 3),
+};
+
+static const struct timing_reg timing_power[] = {
+       TIMING_FIELD("tFAW", 26, 31),
+       TIMING_FIELD("tXSR", 16, 25),
+       TIMING_FIELD("tXP", 8, 15),
+       TIMING_FIELD("tCKE", 4, 7),
+       TIMING_FIELD("tMRD", 0, 3),
+};
+
+#define TIMING_COUNT (ARRAY_SIZE(timing_row) + ARRAY_SIZE(timing_data) + \
+                     ARRAY_SIZE(timing_power))
+
+static int exynos5_counters_set_event(struct exynos5_dmc *dmc)
+{
+       int i, ret;
+
+       for (i = 0; i < dmc->num_counters; i++) {
+               if (!dmc->counter[i])
+                       continue;
+               ret = devfreq_event_set_event(dmc->counter[i]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int exynos5_counters_enable_edev(struct exynos5_dmc *dmc)
+{
+       int i, ret;
+
+       for (i = 0; i < dmc->num_counters; i++) {
+               if (!dmc->counter[i])
+                       continue;
+               ret = devfreq_event_enable_edev(dmc->counter[i]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int exynos5_counters_disable_edev(struct exynos5_dmc *dmc)
+{
+       int i, ret;
+
+       for (i = 0; i < dmc->num_counters; i++) {
+               if (!dmc->counter[i])
+                       continue;
+               ret = devfreq_event_disable_edev(dmc->counter[i]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+/**
+ * find_target_freq_id() - Finds requested frequency in local DMC configuration
+ * @dmc:       device for which the information is checked
+ * @target_rate:       requested frequency in KHz
+ *
+ * Seeks in the local DMC driver structure for the requested frequency value
+ * and returns index or error value.
+ */
+static int find_target_freq_idx(struct exynos5_dmc *dmc,
+                               unsigned long target_rate)
+{
+       int i;
+
+       for (i = dmc->opp_count - 1; i >= 0; i--)
+               if (dmc->opp[i].freq_hz <= target_rate)
+                       return i;
+
+       return -EINVAL;
+}
+
+/**
+ * exynos5_switch_timing_regs() - Changes bank register set for DRAM timings
+ * @dmc:       device for which the new settings is going to be applied
+ * @set:       boolean variable passing set value
+ *
+ * Changes the register set, which holds timing parameters.
+ * There is two register sets: 0 and 1. The register set 0
+ * is used in normal operation when the clock is provided from main PLL.
+ * The bank register set 1 is used when the main PLL frequency is going to be
+ * changed and the clock is taken from alternative, stable source.
+ * This function switches between these banks according to the
+ * currently used clock source.
+ */
+static void exynos5_switch_timing_regs(struct exynos5_dmc *dmc, bool set)
+{
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(dmc->clk_regmap, CDREX_LPDDR3PHY_CON3, &reg);
+
+       if (set)
+               reg |= EXYNOS5_TIMING_SET_SWI;
+       else
+               reg &= ~EXYNOS5_TIMING_SET_SWI;
+
+       regmap_write(dmc->clk_regmap, CDREX_LPDDR3PHY_CON3, reg);
+}
+
+/**
+ * exynos5_init_freq_table() - Initialized PM OPP framework
+ * @dmc:       DMC device for which the frequencies are used for OPP init
+ * @profile:   devfreq device's profile
+ *
+ * Populate the devfreq device's OPP table based on current frequency, voltage.
+ */
+static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
+                                  struct devfreq_dev_profile *profile)
+{
+       int i, ret;
+       int idx;
+       unsigned long freq;
+
+       ret = dev_pm_opp_of_add_table(dmc->dev);
+       if (ret < 0) {
+               dev_err(dmc->dev, "Failed to get OPP table\n");
+               return ret;
+       }
+
+       dmc->opp_count = dev_pm_opp_get_opp_count(dmc->dev);
+
+       dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count,
+                                     sizeof(struct dmc_opp_table), GFP_KERNEL);
+       if (!dmc->opp)
+               goto err_opp;
+
+       idx = dmc->opp_count - 1;
+       for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) {
+               struct dev_pm_opp *opp;
+
+               opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq);
+               if (IS_ERR(opp))
+                       goto err_opp;
+
+               dmc->opp[idx - i].freq_hz = freq;
+               dmc->opp[idx - i].volt_uv = dev_pm_opp_get_voltage(opp);
+
+               dev_pm_opp_put(opp);
+       }
+
+       return 0;
+
+err_opp:
+       dev_pm_opp_of_remove_table(dmc->dev);
+
+       return -EINVAL;
+}
+
+/**
+ * exynos5_set_bypass_dram_timings() - Low-level changes of the DRAM timings
+ * @dmc:       device for which the new settings is going to be applied
+ * @param:     DRAM parameters which passes timing data
+ *
+ * Low-level function for changing timings for DRAM memory clocking from
+ * 'bypass' clock source (fixed frequency @400MHz).
+ * It uses timing bank registers set 1.
+ */
+static void exynos5_set_bypass_dram_timings(struct exynos5_dmc *dmc)
+{
+       writel(EXYNOS5_AREF_NORMAL,
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGAREF);
+
+       writel(dmc->bypass_timing_row,
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGROW1);
+       writel(dmc->bypass_timing_row,
+              dmc->base_drexi1 + EXYNOS5_DREXI_TIMINGROW1);
+       writel(dmc->bypass_timing_data,
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGDATA1);
+       writel(dmc->bypass_timing_data,
+              dmc->base_drexi1 + EXYNOS5_DREXI_TIMINGDATA1);
+       writel(dmc->bypass_timing_power,
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGPOWER1);
+       writel(dmc->bypass_timing_power,
+              dmc->base_drexi1 + EXYNOS5_DREXI_TIMINGPOWER1);
+}
+
+/**
+ * exynos5_dram_change_timings() - Low-level changes of the DRAM final timings
+ * @dmc:       device for which the new settings is going to be applied
+ * @target_rate:       target frequency of the DMC
+ *
+ * Low-level function for changing timings for DRAM memory operating from main
+ * clock source (BPLL), which can have different frequencies. Thus, each
+ * frequency must have corresponding timings register values in order to keep
+ * the needed delays.
+ * It uses timing bank registers set 0.
+ */
+static int exynos5_dram_change_timings(struct exynos5_dmc *dmc,
+                                      unsigned long target_rate)
+{
+       int idx;
+
+       for (idx = dmc->opp_count - 1; idx >= 0; idx--)
+               if (dmc->opp[idx].freq_hz <= target_rate)
+                       break;
+
+       if (idx < 0)
+               return -EINVAL;
+
+       writel(EXYNOS5_AREF_NORMAL,
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGAREF);
+
+       writel(dmc->timing_row[idx],
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGROW0);
+       writel(dmc->timing_row[idx],
+              dmc->base_drexi1 + EXYNOS5_DREXI_TIMINGROW0);
+       writel(dmc->timing_data[idx],
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGDATA0);
+       writel(dmc->timing_data[idx],
+              dmc->base_drexi1 + EXYNOS5_DREXI_TIMINGDATA0);
+       writel(dmc->timing_power[idx],
+              dmc->base_drexi0 + EXYNOS5_DREXI_TIMINGPOWER0);
+       writel(dmc->timing_power[idx],
+              dmc->base_drexi1 + EXYNOS5_DREXI_TIMINGPOWER0);
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_align_target_voltage() - Sets the final voltage for the DMC
+ * @dmc:       device for which it is going to be set
+ * @target_volt:       new voltage which is chosen to be final
+ *
+ * Function tries to align voltage to the safe level for 'normal' mode.
+ * It checks the need of higher voltage and changes the value. The target
+ * voltage might be lower that currently set and still the system will be
+ * stable.
+ */
+static int exynos5_dmc_align_target_voltage(struct exynos5_dmc *dmc,
+                                           unsigned long target_volt)
+{
+       int ret = 0;
+
+       if (dmc->curr_volt <= target_volt)
+               return 0;
+
+       ret = regulator_set_voltage(dmc->vdd_mif, target_volt,
+                                   target_volt);
+       if (!ret)
+               dmc->curr_volt = target_volt;
+
+       return ret;
+}
+
+/**
+ * exynos5_dmc_align_bypass_voltage() - Sets the voltage for the DMC
+ * @dmc:       device for which it is going to be set
+ * @target_volt:       new voltage which is chosen to be final
+ *
+ * Function tries to align voltage to the safe level for the 'bypass' mode.
+ * It checks the need of higher voltage and changes the value.
+ * The target voltage must not be less than currently needed, because
+ * for current frequency the device might become unstable.
+ */
+static int exynos5_dmc_align_bypass_voltage(struct exynos5_dmc *dmc,
+                                           unsigned long target_volt)
+{
+       int ret = 0;
+       unsigned long bypass_volt = dmc->opp_bypass.volt_uv;
+
+       target_volt = max(bypass_volt, target_volt);
+
+       if (dmc->curr_volt >= target_volt)
+               return 0;
+
+       ret = regulator_set_voltage(dmc->vdd_mif, target_volt,
+                                   target_volt);
+       if (!ret)
+               dmc->curr_volt = target_volt;
+
+       return ret;
+}
+
+/**
+ * exynos5_dmc_align_bypass_dram_timings() - Chooses and sets DRAM timings
+ * @dmc:       device for which it is going to be set
+ * @target_rate:       new frequency which is chosen to be final
+ *
+ * Function changes the DRAM timings for the temporary 'bypass' mode.
+ */
+static int exynos5_dmc_align_bypass_dram_timings(struct exynos5_dmc *dmc,
+                                                unsigned long target_rate)
+{
+       int idx = find_target_freq_idx(dmc, target_rate);
+
+       if (idx < 0)
+               return -EINVAL;
+
+       exynos5_set_bypass_dram_timings(dmc);
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_switch_to_bypass_configuration() - Switching to temporary clock
+ * @dmc:       DMC device for which the switching is going to happen
+ * @target_rate:       new frequency which is going to be set as a final
+ * @target_volt:       new voltage which is going to be set as a final
+ *
+ * Function configures DMC and clocks for operating in temporary 'bypass' mode.
+ * This mode is used only temporary but if required, changes voltage and timings
+ * for DRAM chips. It switches the main clock to stable clock source for the
+ * period of the main PLL reconfiguration.
+ */
+static int
+exynos5_dmc_switch_to_bypass_configuration(struct exynos5_dmc *dmc,
+                                          unsigned long target_rate,
+                                          unsigned long target_volt)
+{
+       int ret;
+
+       /*
+        * Having higher voltage for a particular frequency does not harm
+        * the chip. Use it for the temporary frequency change when one
+        * voltage manipulation might be avoided.
+        */
+       ret = exynos5_dmc_align_bypass_voltage(dmc, target_volt);
+       if (ret)
+               return ret;
+
+       /*
+        * Longer delays for DRAM does not cause crash, the opposite does.
+        */
+       ret = exynos5_dmc_align_bypass_dram_timings(dmc, target_rate);
+       if (ret)
+               return ret;
+
+       /*
+        * Delays are long enough, so use them for the new coming clock.
+        */
+       exynos5_switch_timing_regs(dmc, USE_MX_MSPLL_TIMINGS);
+
+       return ret;
+}
+
+/**
+ * exynos5_dmc_change_freq_and_volt() - Changes voltage and frequency of the DMC
+ * using safe procedure
+ * @dmc:       device for which the frequency is going to be changed
+ * @target_rate:       requested new frequency
+ * @target_volt:       requested voltage which corresponds to the new frequency
+ *
+ * The DMC frequency change procedure requires a few steps.
+ * The main requirement is to change the clock source in the clk mux
+ * for the time of main clock PLL locking. The assumption is that the
+ * alternative clock source set as parent is stable.
+ * The second parent's clock frequency is fixed to 400MHz, it is named 'bypass'
+ * clock. This requires alignment in DRAM timing parameters for the new
+ * T-period. There is two bank sets for keeping DRAM
+ * timings: set 0 and set 1. The set 0 is used when main clock source is
+ * chosen. The 2nd set of regs is used for 'bypass' clock. Switching between
+ * the two bank sets is part of the process.
+ * The voltage must also be aligned to the minimum required level. There is
+ * this intermediate step with switching to 'bypass' parent clock source.
+ * if the old voltage is lower, it requires an increase of the voltage level.
+ * The complexity of the voltage manipulation is hidden in low level function.
+ * In this function there is last alignment of the voltage level at the end.
+ */
+static int
+exynos5_dmc_change_freq_and_volt(struct exynos5_dmc *dmc,
+                                unsigned long target_rate,
+                                unsigned long target_volt)
+{
+       int ret;
+
+       ret = exynos5_dmc_switch_to_bypass_configuration(dmc, target_rate,
+                                                        target_volt);
+       if (ret)
+               return ret;
+
+       /*
+        * Voltage is set at least to a level needed for this frequency,
+        * so switching clock source is safe now.
+        */
+       clk_prepare_enable(dmc->fout_spll);
+       clk_prepare_enable(dmc->mout_spll);
+       clk_prepare_enable(dmc->mout_mx_mspll_ccore);
+
+       ret = clk_set_parent(dmc->mout_mclk_cdrex, dmc->mout_mx_mspll_ccore);
+       if (ret)
+               goto disable_clocks;
+
+       /*
+        * We are safe to increase the timings for current bypass frequency.
+        * Thanks to this the settings will be ready for the upcoming clock
+        * source change.
+        */
+       exynos5_dram_change_timings(dmc, target_rate);
+
+       clk_set_rate(dmc->fout_bpll, target_rate);
+
+       exynos5_switch_timing_regs(dmc, USE_BPLL_TIMINGS);
+
+       ret = clk_set_parent(dmc->mout_mclk_cdrex, dmc->mout_bpll);
+       if (ret)
+               goto disable_clocks;
+
+       /*
+        * Make sure if the voltage is not from 'bypass' settings and align to
+        * the right level for power efficiency.
+        */
+       ret = exynos5_dmc_align_target_voltage(dmc, target_volt);
+
+disable_clocks:
+       clk_disable_unprepare(dmc->mout_mx_mspll_ccore);
+       clk_disable_unprepare(dmc->mout_spll);
+       clk_disable_unprepare(dmc->fout_spll);
+
+       return ret;
+}
+
+/**
+ * exynos5_dmc_get_volt_freq() - Gets the frequency and voltage from the OPP
+ * table.
+ * @dmc:       device for which the frequency is going to be changed
+ * @freq:       requested frequency in KHz
+ * @target_rate:       returned frequency which is the same or lower than
+ *                     requested
+ * @target_volt:       returned voltage which corresponds to the returned
+ *                     frequency
+ *
+ * Function gets requested frequency and checks OPP framework for needed
+ * frequency and voltage. It populates the values 'target_rate' and
+ * 'target_volt' or returns error value when OPP framework fails.
+ */
+static int exynos5_dmc_get_volt_freq(struct exynos5_dmc *dmc,
+                                    unsigned long *freq,
+                                    unsigned long *target_rate,
+                                    unsigned long *target_volt, u32 flags)
+{
+       struct dev_pm_opp *opp;
+
+       opp = devfreq_recommended_opp(dmc->dev, freq, flags);
+       if (IS_ERR(opp))
+               return PTR_ERR(opp);
+
+       *target_rate = dev_pm_opp_get_freq(opp);
+       *target_volt = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_target() - Function responsible for changing frequency of DMC
+ * @dev:       device for which the frequency is going to be changed
+ * @freq:      requested frequency in KHz
+ * @flags:     flags provided for this frequency change request
+ *
+ * An entry function provided to the devfreq framework which provides frequency
+ * change of the DMC. The function gets the possible rate from OPP table based
+ * on requested frequency. It calls the next function responsible for the
+ * frequency and voltage change. In case of failure, does not set 'curr_rate'
+ * and returns error value to the framework.
+ */
+static int exynos5_dmc_target(struct device *dev, unsigned long *freq,
+                             u32 flags)
+{
+       struct exynos5_dmc *dmc = dev_get_drvdata(dev);
+       unsigned long target_rate = 0;
+       unsigned long target_volt = 0;
+       int ret;
+
+       ret = exynos5_dmc_get_volt_freq(dmc, freq, &target_rate, &target_volt,
+                                       flags);
+
+       if (ret)
+               return ret;
+
+       if (target_rate == dmc->curr_rate)
+               return 0;
+
+       mutex_lock(&dmc->lock);
+
+       ret = exynos5_dmc_change_freq_and_volt(dmc, target_rate, target_volt);
+
+       if (ret) {
+               mutex_unlock(&dmc->lock);
+               return ret;
+       }
+
+       dmc->curr_rate = target_rate;
+
+       mutex_unlock(&dmc->lock);
+       return 0;
+}
+
+/**
+ * exynos5_counters_get() - Gets the performance counters values.
+ * @dmc:       device for which the counters are going to be checked
+ * @load_count:        variable which is populated with counter value
+ * @total_count:       variable which is used as 'wall clock' reference
+ *
+ * Function which provides performance counters values. It sums up counters for
+ * two DMC channels. The 'total_count' is used as a reference and max value.
+ * The ratio 'load_count/total_count' shows the busy percentage [0%, 100%].
+ */
+static int exynos5_counters_get(struct exynos5_dmc *dmc,
+                               unsigned long *load_count,
+                               unsigned long *total_count)
+{
+       unsigned long total = 0;
+       struct devfreq_event_data event;
+       int ret, i;
+
+       *load_count = 0;
+
+       /* Take into account only read+write counters, but stop all */
+       for (i = 0; i < dmc->num_counters; i++) {
+               if (!dmc->counter[i])
+                       continue;
+
+               ret = devfreq_event_get_event(dmc->counter[i], &event);
+               if (ret < 0)
+                       return ret;
+
+               *load_count += event.load_count;
+
+               if (total < event.total_count)
+                       total = event.total_count;
+       }
+
+       *total_count = total;
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_start_perf_events() - Setup and start performance event counters
+ * @dmc:       device for which the counters are going to be checked
+ * @beg_value: initial value for the counter
+ *
+ * Function which enables needed counters, interrupts and sets initial values
+ * then starts the counters.
+ */
+static void exynos5_dmc_start_perf_events(struct exynos5_dmc *dmc,
+                                         u32 beg_value)
+{
+       /* Enable interrupts for counter 2 */
+       writel(PERF_CNT2, dmc->base_drexi0 + DREX_INTENS_PPC);
+       writel(PERF_CNT2, dmc->base_drexi1 + DREX_INTENS_PPC);
+
+       /* Enable counter 2 and CCNT  */
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi0 + DREX_CNTENS_PPC);
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi1 + DREX_CNTENS_PPC);
+
+       /* Clear overflow flag for all counters */
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi0 + DREX_FLAG_PPC);
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi1 + DREX_FLAG_PPC);
+
+       /* Reset all counters */
+       writel(CC_RESET | PPC_COUNTER_RESET, dmc->base_drexi0 + DREX_PMNC_PPC);
+       writel(CC_RESET | PPC_COUNTER_RESET, dmc->base_drexi1 + DREX_PMNC_PPC);
+
+       /*
+        * Set start value for the counters, the number of samples that
+        * will be gathered is calculated as: 0xffffffff - beg_value
+        */
+       writel(beg_value, dmc->base_drexi0 + DREX_PMCNT2_PPC);
+       writel(beg_value, dmc->base_drexi1 + DREX_PMCNT2_PPC);
+
+       /* Start all counters */
+       writel(PPC_ENABLE, dmc->base_drexi0 + DREX_PMNC_PPC);
+       writel(PPC_ENABLE, dmc->base_drexi1 + DREX_PMNC_PPC);
+}
+
+/**
+ * exynos5_dmc_perf_events_calc() - Calculate utilization
+ * @dmc:       device for which the counters are going to be checked
+ * @diff_ts:   time between last interrupt and current one
+ *
+ * Function which calculates needed utilization for the devfreq governor.
+ * It prepares values for 'busy_time' and 'total_time' based on elapsed time
+ * between interrupts, which approximates utilization.
+ */
+static void exynos5_dmc_perf_events_calc(struct exynos5_dmc *dmc, u64 diff_ts)
+{
+       /*
+        * This is a simple algorithm for managing traffic on DMC.
+        * When there is almost no load the counters overflow every 4s,
+        * no mater the DMC frequency.
+        * The high load might be approximated using linear function.
+        * Knowing that, simple calculation can provide 'busy_time' and
+        * 'total_time' to the devfreq governor which picks up target
+        * frequency.
+        * We want a fast ramp up and slow decay in frequency change function.
+        */
+       if (diff_ts < PERF_EVENT_UP_DOWN_THRESHOLD) {
+               /*
+                * Set higher utilization for the simple_ondemand governor.
+                * The governor should increase the frequency of the DMC.
+                */
+               dmc->load = 70;
+               dmc->total = 100;
+       } else {
+               /*
+                * Set low utilization for the simple_ondemand governor.
+                * The governor should decrease the frequency of the DMC.
+                */
+               dmc->load = 35;
+               dmc->total = 100;
+       }
+
+       dev_dbg(dmc->dev, "diff_ts=%llu\n", diff_ts);
+}
+
+/**
+ * exynos5_dmc_perf_events_check() - Checks the status of the counters
+ * @dmc:       device for which the counters are going to be checked
+ *
+ * Function which is called from threaded IRQ to check the counters state
+ * and to call approximation for the needed utilization.
+ */
+static void exynos5_dmc_perf_events_check(struct exynos5_dmc *dmc)
+{
+       u32 val;
+       u64 diff_ts, ts;
+
+       ts = ktime_get_ns();
+
+       /* Stop all counters */
+       writel(0, dmc->base_drexi0 + DREX_PMNC_PPC);
+       writel(0, dmc->base_drexi1 + DREX_PMNC_PPC);
+
+       /* Check the source in interrupt flag registers (which channel) */
+       val = readl(dmc->base_drexi0 + DREX_FLAG_PPC);
+       if (val) {
+               diff_ts = ts - dmc->last_overflow_ts[0];
+               dmc->last_overflow_ts[0] = ts;
+               dev_dbg(dmc->dev, "drex0 0xE050 val= 0x%08x\n",  val);
+       } else {
+               val = readl(dmc->base_drexi1 + DREX_FLAG_PPC);
+               diff_ts = ts - dmc->last_overflow_ts[1];
+               dmc->last_overflow_ts[1] = ts;
+               dev_dbg(dmc->dev, "drex1 0xE050 val= 0x%08x\n",  val);
+       }
+
+       exynos5_dmc_perf_events_calc(dmc, diff_ts);
+
+       exynos5_dmc_start_perf_events(dmc, PERF_COUNTER_START_VALUE);
+}
+
+/**
+ * exynos5_dmc_enable_perf_events() - Enable performance events
+ * @dmc:       device for which the counters are going to be checked
+ *
+ * Function which is setup needed environment and enables counters.
+ */
+static void exynos5_dmc_enable_perf_events(struct exynos5_dmc *dmc)
+{
+       u64 ts;
+
+       /* Enable Performance Event Clock */
+       writel(PEREV_CLK_EN, dmc->base_drexi0 + DREX_PPCCLKCON);
+       writel(PEREV_CLK_EN, dmc->base_drexi1 + DREX_PPCCLKCON);
+
+       /* Select read transfers as performance event2 */
+       writel(READ_TRANSFER_CH0, dmc->base_drexi0 + DREX_PEREV2CONFIG);
+       writel(READ_TRANSFER_CH1, dmc->base_drexi1 + DREX_PEREV2CONFIG);
+
+       ts = ktime_get_ns();
+       dmc->last_overflow_ts[0] = ts;
+       dmc->last_overflow_ts[1] = ts;
+
+       /* Devfreq shouldn't be faster than initialization, play safe though. */
+       dmc->load = 99;
+       dmc->total = 100;
+}
+
+/**
+ * exynos5_dmc_disable_perf_events() - Disable performance events
+ * @dmc:       device for which the counters are going to be checked
+ *
+ * Function which stops, disables performance event counters and interrupts.
+ */
+static void exynos5_dmc_disable_perf_events(struct exynos5_dmc *dmc)
+{
+       /* Stop all counters */
+       writel(0, dmc->base_drexi0 + DREX_PMNC_PPC);
+       writel(0, dmc->base_drexi1 + DREX_PMNC_PPC);
+
+       /* Disable interrupts for counter 2 */
+       writel(PERF_CNT2, dmc->base_drexi0 + DREX_INTENC_PPC);
+       writel(PERF_CNT2, dmc->base_drexi1 + DREX_INTENC_PPC);
+
+       /* Disable counter 2 and CCNT  */
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi0 + DREX_CNTENC_PPC);
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi1 + DREX_CNTENC_PPC);
+
+       /* Clear overflow flag for all counters */
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi0 + DREX_FLAG_PPC);
+       writel(PERF_CNT2 | PERF_CCNT, dmc->base_drexi1 + DREX_FLAG_PPC);
+}
+
+/**
+ * exynos5_dmc_get_status() - Read current DMC performance statistics.
+ * @dev:       device for which the statistics are requested
+ * @stat:      structure which has statistic fields
+ *
+ * Function reads the DMC performance counters and calculates 'busy_time'
+ * and 'total_time'. To protect from overflow, the values are shifted right
+ * by 10. After read out the counters are setup to count again.
+ */
+static int exynos5_dmc_get_status(struct device *dev,
+                                 struct devfreq_dev_status *stat)
+{
+       struct exynos5_dmc *dmc = dev_get_drvdata(dev);
+       unsigned long load, total;
+       int ret;
+
+       if (dmc->in_irq_mode) {
+               stat->current_frequency = dmc->curr_rate;
+               stat->busy_time = dmc->load;
+               stat->total_time = dmc->total;
+       } else {
+               ret = exynos5_counters_get(dmc, &load, &total);
+               if (ret < 0)
+                       return -EINVAL;
+
+               /* To protect from overflow, divide by 1024 */
+               stat->busy_time = load >> 10;
+               stat->total_time = total >> 10;
+
+               ret = exynos5_counters_set_event(dmc);
+               if (ret < 0) {
+                       dev_err(dev, "could not set event counter\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_get_cur_freq() - Function returns current DMC frequency
+ * @dev:       device for which the framework checks operating frequency
+ * @freq:      returned frequency value
+ *
+ * It returns the currently used frequency of the DMC. The real operating
+ * frequency might be lower when the clock source value could not be divided
+ * to the requested value.
+ */
+static int exynos5_dmc_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+       struct exynos5_dmc *dmc = dev_get_drvdata(dev);
+
+       mutex_lock(&dmc->lock);
+       *freq = dmc->curr_rate;
+       mutex_unlock(&dmc->lock);
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_df_profile - Devfreq governor's profile structure
+ *
+ * It provides to the devfreq framework needed functions and polling period.
+ */
+static struct devfreq_dev_profile exynos5_dmc_df_profile = {
+       .target = exynos5_dmc_target,
+       .get_dev_status = exynos5_dmc_get_status,
+       .get_cur_freq = exynos5_dmc_get_cur_freq,
+};
+
+/**
+ * exynos5_dmc_align_initial_frequency() - Align initial frequency value
+ * @dmc:       device for which the frequency is going to be set
+ * @bootloader_init_freq:      initial frequency set by the bootloader in KHz
+ *
+ * The initial bootloader frequency, which is present during boot, might be
+ * different that supported frequency values in the driver. It is possible
+ * due to different PLL settings or used PLL as a source.
+ * This function provides the 'initial_freq' for the devfreq framework
+ * statistics engine which supports only registered values. Thus, some alignment
+ * must be made.
+ */
+static unsigned long
+exynos5_dmc_align_init_freq(struct exynos5_dmc *dmc,
+                           unsigned long bootloader_init_freq)
+{
+       unsigned long aligned_freq;
+       int idx;
+
+       idx = find_target_freq_idx(dmc, bootloader_init_freq);
+       if (idx >= 0)
+               aligned_freq = dmc->opp[idx].freq_hz;
+       else
+               aligned_freq = dmc->opp[dmc->opp_count - 1].freq_hz;
+
+       return aligned_freq;
+}
+
+/**
+ * create_timings_aligned() - Create register values and align with standard
+ * @dmc:       device for which the frequency is going to be set
+ * @idx:       speed bin in the OPP table
+ * @clk_period_ps:     the period of the clock, known as tCK
+ *
+ * The function calculates timings and creates a register value ready for
+ * a frequency transition. The register contains a few timings. They are
+ * shifted by a known offset. The timing value is calculated based on memory
+ * specyfication: minimal time required and minimal cycles required.
+ */
+static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row,
+                                 u32 *reg_timing_data, u32 *reg_timing_power,
+                                 u32 clk_period_ps)
+{
+       u32 val;
+       const struct timing_reg *reg;
+
+       if (clk_period_ps == 0)
+               return -EINVAL;
+
+       *reg_timing_row = 0;
+       *reg_timing_data = 0;
+       *reg_timing_power = 0;
+
+       val = dmc->timings->tRFC / clk_period_ps;
+       val += dmc->timings->tRFC % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRFC);
+       reg = &timing_row[0];
+       *reg_timing_row |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRRD / clk_period_ps;
+       val += dmc->timings->tRRD % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRRD);
+       reg = &timing_row[1];
+       *reg_timing_row |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRPab / clk_period_ps;
+       val += dmc->timings->tRPab % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRPab);
+       reg = &timing_row[2];
+       *reg_timing_row |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRCD / clk_period_ps;
+       val += dmc->timings->tRCD % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRCD);
+       reg = &timing_row[3];
+       *reg_timing_row |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRC / clk_period_ps;
+       val += dmc->timings->tRC % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRC);
+       reg = &timing_row[4];
+       *reg_timing_row |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRAS / clk_period_ps;
+       val += dmc->timings->tRAS % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRAS);
+       reg = &timing_row[5];
+       *reg_timing_row |= TIMING_VAL2REG(reg, val);
+
+       /* data related timings */
+       val = dmc->timings->tWTR / clk_period_ps;
+       val += dmc->timings->tWTR % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tWTR);
+       reg = &timing_data[0];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tWR / clk_period_ps;
+       val += dmc->timings->tWR % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tWR);
+       reg = &timing_data[1];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRTP / clk_period_ps;
+       val += dmc->timings->tRTP % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRTP);
+       reg = &timing_data[2];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tW2W_C2C / clk_period_ps;
+       val += dmc->timings->tW2W_C2C % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tW2W_C2C);
+       reg = &timing_data[3];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tR2R_C2C / clk_period_ps;
+       val += dmc->timings->tR2R_C2C % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tR2R_C2C);
+       reg = &timing_data[4];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tWL / clk_period_ps;
+       val += dmc->timings->tWL % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tWL);
+       reg = &timing_data[5];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tDQSCK / clk_period_ps;
+       val += dmc->timings->tDQSCK % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tDQSCK);
+       reg = &timing_data[6];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tRL / clk_period_ps;
+       val += dmc->timings->tRL % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tRL);
+       reg = &timing_data[7];
+       *reg_timing_data |= TIMING_VAL2REG(reg, val);
+
+       /* power related timings */
+       val = dmc->timings->tFAW / clk_period_ps;
+       val += dmc->timings->tFAW % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tXP);
+       reg = &timing_power[0];
+       *reg_timing_power |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tXSR / clk_period_ps;
+       val += dmc->timings->tXSR % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tXSR);
+       reg = &timing_power[1];
+       *reg_timing_power |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tXP / clk_period_ps;
+       val += dmc->timings->tXP % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tXP);
+       reg = &timing_power[2];
+       *reg_timing_power |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tCKE / clk_period_ps;
+       val += dmc->timings->tCKE % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tCKE);
+       reg = &timing_power[3];
+       *reg_timing_power |= TIMING_VAL2REG(reg, val);
+
+       val = dmc->timings->tMRD / clk_period_ps;
+       val += dmc->timings->tMRD % clk_period_ps ? 1 : 0;
+       val = max(val, dmc->min_tck->tMRD);
+       reg = &timing_power[4];
+       *reg_timing_power |= TIMING_VAL2REG(reg, val);
+
+       return 0;
+}
+
+/**
+ * of_get_dram_timings() - helper function for parsing DT settings for DRAM
+ * @dmc:        device for which the frequency is going to be set
+ *
+ * The function parses DT entries with DRAM information.
+ */
+static int of_get_dram_timings(struct exynos5_dmc *dmc)
+{
+       int ret = 0;
+       int idx;
+       struct device_node *np_ddr;
+       u32 freq_mhz, clk_period_ps;
+
+       np_ddr = of_parse_phandle(dmc->dev->of_node, "device-handle", 0);
+       if (!np_ddr) {
+               dev_warn(dmc->dev, "could not find 'device-handle' in DT\n");
+               return -EINVAL;
+       }
+
+       dmc->timing_row = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
+                                            sizeof(u32), GFP_KERNEL);
+       if (!dmc->timing_row)
+               return -ENOMEM;
+
+       dmc->timing_data = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
+                                             sizeof(u32), GFP_KERNEL);
+       if (!dmc->timing_data)
+               return -ENOMEM;
+
+       dmc->timing_power = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
+                                              sizeof(u32), GFP_KERNEL);
+       if (!dmc->timing_power)
+               return -ENOMEM;
+
+       dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dmc->dev,
+                                                DDR_TYPE_LPDDR3,
+                                                &dmc->timings_arr_size);
+       if (!dmc->timings) {
+               of_node_put(np_ddr);
+               dev_warn(dmc->dev, "could not get timings from DT\n");
+               return -EINVAL;
+       }
+
+       dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dmc->dev);
+       if (!dmc->min_tck) {
+               of_node_put(np_ddr);
+               dev_warn(dmc->dev, "could not get tck from DT\n");
+               return -EINVAL;
+       }
+
+       /* Sorted array of OPPs with frequency ascending */
+       for (idx = 0; idx < dmc->opp_count; idx++) {
+               freq_mhz = dmc->opp[idx].freq_hz / 1000000;
+               clk_period_ps = 1000000 / freq_mhz;
+
+               ret = create_timings_aligned(dmc, &dmc->timing_row[idx],
+                                            &dmc->timing_data[idx],
+                                            &dmc->timing_power[idx],
+                                            clk_period_ps);
+       }
+
+       of_node_put(np_ddr);
+
+       /* Take the highest frequency's timings as 'bypass' */
+       dmc->bypass_timing_row = dmc->timing_row[idx - 1];
+       dmc->bypass_timing_data = dmc->timing_data[idx - 1];
+       dmc->bypass_timing_power = dmc->timing_power[idx - 1];
+
+       return ret;
+}
+
+/**
+ * exynos5_dmc_init_clks() - Initialize clocks needed for DMC operation.
+ * @dmc:       DMC structure containing needed fields
+ *
+ * Get the needed clocks defined in DT device, enable and set the right parents.
+ * Read current frequency and initialize the initial rate for governor.
+ */
+static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
+{
+       int ret;
+       unsigned long target_volt = 0;
+       unsigned long target_rate = 0;
+       unsigned int tmp;
+
+       dmc->fout_spll = devm_clk_get(dmc->dev, "fout_spll");
+       if (IS_ERR(dmc->fout_spll))
+               return PTR_ERR(dmc->fout_spll);
+
+       dmc->fout_bpll = devm_clk_get(dmc->dev, "fout_bpll");
+       if (IS_ERR(dmc->fout_bpll))
+               return PTR_ERR(dmc->fout_bpll);
+
+       dmc->mout_mclk_cdrex = devm_clk_get(dmc->dev, "mout_mclk_cdrex");
+       if (IS_ERR(dmc->mout_mclk_cdrex))
+               return PTR_ERR(dmc->mout_mclk_cdrex);
+
+       dmc->mout_bpll = devm_clk_get(dmc->dev, "mout_bpll");
+       if (IS_ERR(dmc->mout_bpll))
+               return PTR_ERR(dmc->mout_bpll);
+
+       dmc->mout_mx_mspll_ccore = devm_clk_get(dmc->dev,
+                                               "mout_mx_mspll_ccore");
+       if (IS_ERR(dmc->mout_mx_mspll_ccore))
+               return PTR_ERR(dmc->mout_mx_mspll_ccore);
+
+       dmc->mout_spll = devm_clk_get(dmc->dev, "ff_dout_spll2");
+       if (IS_ERR(dmc->mout_spll)) {
+               dmc->mout_spll = devm_clk_get(dmc->dev, "mout_sclk_spll");
+               if (IS_ERR(dmc->mout_spll))
+                       return PTR_ERR(dmc->mout_spll);
+       }
+
+       /*
+        * Convert frequency to KHz values and set it for the governor.
+        */
+       dmc->curr_rate = clk_get_rate(dmc->mout_mclk_cdrex);
+       dmc->curr_rate = exynos5_dmc_align_init_freq(dmc, dmc->curr_rate);
+       exynos5_dmc_df_profile.initial_freq = dmc->curr_rate;
+
+       ret = exynos5_dmc_get_volt_freq(dmc, &dmc->curr_rate, &target_rate,
+                                       &target_volt, 0);
+       if (ret)
+               return ret;
+
+       dmc->curr_volt = target_volt;
+
+       clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll);
+
+       dmc->bypass_rate = clk_get_rate(dmc->mout_mx_mspll_ccore);
+
+       clk_prepare_enable(dmc->fout_bpll);
+       clk_prepare_enable(dmc->mout_bpll);
+
+       /*
+        * Some bootloaders do not set clock routes correctly.
+        * Stop one path in clocks to PHY.
+        */
+       regmap_read(dmc->clk_regmap, CDREX_LPDDR3PHY_CLKM_SRC, &tmp);
+       tmp &= ~(BIT(1) | BIT(0));
+       regmap_write(dmc->clk_regmap, CDREX_LPDDR3PHY_CLKM_SRC, tmp);
+
+       return 0;
+}
+
+/**
+ * exynos5_performance_counters_init() - Initializes performance DMC's counters
+ * @dmc:       DMC for which it does the setup
+ *
+ * Initialization of performance counters in DMC for estimating usage.
+ * The counter's values are used for calculation of a memory bandwidth and based
+ * on that the governor changes the frequency.
+ * The counters are not used when the governor is GOVERNOR_USERSPACE.
+ */
+static int exynos5_performance_counters_init(struct exynos5_dmc *dmc)
+{
+       int counters_size;
+       int ret, i;
+
+       dmc->num_counters = devfreq_event_get_edev_count(dmc->dev);
+       if (dmc->num_counters < 0) {
+               dev_err(dmc->dev, "could not get devfreq-event counters\n");
+               return dmc->num_counters;
+       }
+
+       counters_size = sizeof(struct devfreq_event_dev) * dmc->num_counters;
+       dmc->counter = devm_kzalloc(dmc->dev, counters_size, GFP_KERNEL);
+       if (!dmc->counter)
+               return -ENOMEM;
+
+       for (i = 0; i < dmc->num_counters; i++) {
+               dmc->counter[i] =
+                       devfreq_event_get_edev_by_phandle(dmc->dev, i);
+               if (IS_ERR_OR_NULL(dmc->counter[i]))
+                       return -EPROBE_DEFER;
+       }
+
+       ret = exynos5_counters_enable_edev(dmc);
+       if (ret < 0) {
+               dev_err(dmc->dev, "could not enable event counter\n");
+               return ret;
+       }
+
+       ret = exynos5_counters_set_event(dmc);
+       if (ret < 0) {
+               exynos5_counters_disable_edev(dmc);
+               dev_err(dmc->dev, "could not set event counter\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * exynos5_dmc_set_pause_on_switching() - Controls a pause feature in DMC
+ * @dmc:       device which is used for changing this feature
+ * @set:       a boolean state passing enable/disable request
+ *
+ * There is a need of pausing DREX DMC when divider or MUX in clock tree
+ * changes its configuration. In such situation access to the memory is blocked
+ * in DMC automatically. This feature is used when clock frequency change
+ * request appears and touches clock tree.
+ */
+static inline int exynos5_dmc_set_pause_on_switching(struct exynos5_dmc *dmc)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(dmc->clk_regmap, CDREX_PAUSE, &val);
+       if (ret)
+               return ret;
+
+       val |= 1UL;
+       regmap_write(dmc->clk_regmap, CDREX_PAUSE, val);
+
+       return 0;
+}
+
+static irqreturn_t dmc_irq_thread(int irq, void *priv)
+{
+       int res;
+       struct exynos5_dmc *dmc = priv;
+
+       mutex_lock(&dmc->df->lock);
+
+       exynos5_dmc_perf_events_check(dmc);
+
+       res = update_devfreq(dmc->df);
+       if (res)
+               dev_warn(dmc->dev, "devfreq failed with %d\n", res);
+
+       mutex_unlock(&dmc->df->lock);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * exynos5_dmc_probe() - Probe function for the DMC driver
+ * @pdev:      platform device for which the driver is going to be initialized
+ *
+ * Initialize basic components: clocks, regulators, performance counters, etc.
+ * Read out product version and based on the information setup
+ * internal structures for the controller (frequency and voltage) and for DRAM
+ * memory parameters: timings for each operating frequency.
+ * Register new devfreq device for controlling DVFS of the DMC.
+ */
+static int exynos5_dmc_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct exynos5_dmc *dmc;
+       struct resource *res;
+       int irq[2];
+
+       dmc = devm_kzalloc(dev, sizeof(*dmc), GFP_KERNEL);
+       if (!dmc)
+               return -ENOMEM;
+
+       mutex_init(&dmc->lock);
+
+       dmc->dev = dev;
+       platform_set_drvdata(pdev, dmc);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dmc->base_drexi0 = devm_ioremap_resource(dev, res);
+       if (IS_ERR(dmc->base_drexi0))
+               return PTR_ERR(dmc->base_drexi0);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       dmc->base_drexi1 = devm_ioremap_resource(dev, res);
+       if (IS_ERR(dmc->base_drexi1))
+               return PTR_ERR(dmc->base_drexi1);
+
+       dmc->clk_regmap = syscon_regmap_lookup_by_phandle(np,
+                               "samsung,syscon-clk");
+       if (IS_ERR(dmc->clk_regmap))
+               return PTR_ERR(dmc->clk_regmap);
+
+       ret = exynos5_init_freq_table(dmc, &exynos5_dmc_df_profile);
+       if (ret) {
+               dev_warn(dev, "couldn't initialize frequency settings\n");
+               return ret;
+       }
+
+       dmc->vdd_mif = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(dmc->vdd_mif)) {
+               ret = PTR_ERR(dmc->vdd_mif);
+               return ret;
+       }
+
+       ret = exynos5_dmc_init_clks(dmc);
+       if (ret)
+               return ret;
+
+       ret = of_get_dram_timings(dmc);
+       if (ret) {
+               dev_warn(dev, "couldn't initialize timings settings\n");
+               goto remove_clocks;
+       }
+
+       ret = exynos5_dmc_set_pause_on_switching(dmc);
+       if (ret) {
+               dev_warn(dev, "couldn't get access to PAUSE register\n");
+               goto remove_clocks;
+       }
+
+       /* There is two modes in which the driver works: polling or IRQ */
+       irq[0] = platform_get_irq_byname(pdev, "drex_0");
+       irq[1] = platform_get_irq_byname(pdev, "drex_1");
+       if (irq[0] > 0 && irq[1] > 0) {
+               ret = devm_request_threaded_irq(dev, irq[0], NULL,
+                                               dmc_irq_thread, IRQF_ONESHOT,
+                                               dev_name(dev), dmc);
+               if (ret) {
+                       dev_err(dev, "couldn't grab IRQ\n");
+                       goto remove_clocks;
+               }
+
+               ret = devm_request_threaded_irq(dev, irq[1], NULL,
+                                               dmc_irq_thread, IRQF_ONESHOT,
+                                               dev_name(dev), dmc);
+               if (ret) {
+                       dev_err(dev, "couldn't grab IRQ\n");
+                       goto remove_clocks;
+               }
+
+               /*
+                * Setup default thresholds for the devfreq governor.
+                * The values are chosen based on experiments.
+                */
+               dmc->gov_data.upthreshold = 55;
+               dmc->gov_data.downdifferential = 5;
+
+               exynos5_dmc_enable_perf_events(dmc);
+
+               dmc->in_irq_mode = 1;
+       } else {
+               ret = exynos5_performance_counters_init(dmc);
+               if (ret) {
+                       dev_warn(dev, "couldn't probe performance counters\n");
+                       goto remove_clocks;
+               }
+
+               /*
+                * Setup default thresholds for the devfreq governor.
+                * The values are chosen based on experiments.
+                */
+               dmc->gov_data.upthreshold = 30;
+               dmc->gov_data.downdifferential = 5;
+
+               exynos5_dmc_df_profile.polling_ms = 500;
+       }
+
+
+       dmc->df = devm_devfreq_add_device(dev, &exynos5_dmc_df_profile,
+                                         DEVFREQ_GOV_SIMPLE_ONDEMAND,
+                                         &dmc->gov_data);
+
+       if (IS_ERR(dmc->df)) {
+               ret = PTR_ERR(dmc->df);
+               goto err_devfreq_add;
+       }
+
+       if (dmc->in_irq_mode)
+               exynos5_dmc_start_perf_events(dmc, PERF_COUNTER_START_VALUE);
+
+       dev_info(dev, "DMC initialized\n");
+
+       return 0;
+
+err_devfreq_add:
+       if (dmc->in_irq_mode)
+               exynos5_dmc_disable_perf_events(dmc);
+       else
+               exynos5_counters_disable_edev(dmc);
+remove_clocks:
+       clk_disable_unprepare(dmc->mout_bpll);
+       clk_disable_unprepare(dmc->fout_bpll);
+
+       return ret;
+}
+
+/**
+ * exynos5_dmc_remove() - Remove function for the platform device
+ * @pdev:      platform device which is going to be removed
+ *
+ * The function relies on 'devm' framework function which automatically
+ * clean the device's resources. It just calls explicitly disable function for
+ * the performance counters.
+ */
+static int exynos5_dmc_remove(struct platform_device *pdev)
+{
+       struct exynos5_dmc *dmc = dev_get_drvdata(&pdev->dev);
+
+       if (dmc->in_irq_mode)
+               exynos5_dmc_disable_perf_events(dmc);
+       else
+               exynos5_counters_disable_edev(dmc);
+
+       clk_disable_unprepare(dmc->mout_bpll);
+       clk_disable_unprepare(dmc->fout_bpll);
+
+       dev_pm_opp_remove_table(dmc->dev);
+
+       return 0;
+}
+
+static const struct of_device_id exynos5_dmc_of_match[] = {
+       { .compatible = "samsung,exynos5422-dmc", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, exynos5_dmc_of_match);
+
+static struct platform_driver exynos5_dmc_platdrv = {
+       .probe  = exynos5_dmc_probe,
+       .remove = exynos5_dmc_remove,
+       .driver = {
+               .name   = "exynos5-dmc",
+               .of_match_table = exynos5_dmc_of_match,
+       },
+};
+module_platform_driver(exynos5_dmc_platdrv);
+MODULE_DESCRIPTION("Driver for Exynos5422 Dynamic Memory Controller dynamic frequency and voltage change");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lukasz Luba");
index 4680124..fbfbaad 100644 (file)
@@ -17,6 +17,16 @@ config TEGRA20_EMC
          This driver is required to change memory timings / clock rate for
          external memory.
 
+config TEGRA30_EMC
+       bool "NVIDIA Tegra30 External Memory Controller driver"
+       default y
+       depends on TEGRA_MC && ARCH_TEGRA_3x_SOC
+       help
+         This driver is for the External Memory Controller (EMC) found on
+         Tegra30 chips. The EMC controls the external DRAM on the board.
+         This driver is required to change memory timings / clock rate for
+         external memory.
+
 config TEGRA124_EMC
        bool "NVIDIA Tegra124 External Memory Controller driver"
        default y
index 3971a6b..3d23c42 100644 (file)
@@ -11,5 +11,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
 obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
 
 obj-$(CONFIG_TEGRA20_EMC)  += tegra20-emc.o
+obj-$(CONFIG_TEGRA30_EMC)  += tegra30-emc.o
 obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
 obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
index 3d8d322..ec84035 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
 #include "mc.h"
 
-#define MC_INTSTATUS 0x000
-
-#define MC_INTMASK 0x004
-
-#define MC_ERR_STATUS 0x08
-#define  MC_ERR_STATUS_TYPE_SHIFT 28
-#define  MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT)
-#define  MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT)
-#define  MC_ERR_STATUS_READABLE (1 << 27)
-#define  MC_ERR_STATUS_WRITABLE (1 << 26)
-#define  MC_ERR_STATUS_NONSECURE (1 << 25)
-#define  MC_ERR_STATUS_ADR_HI_SHIFT 20
-#define  MC_ERR_STATUS_ADR_HI_MASK 0x3
-#define  MC_ERR_STATUS_SECURITY (1 << 17)
-#define  MC_ERR_STATUS_RW (1 << 16)
-
-#define MC_ERR_ADR 0x0c
-
-#define MC_GART_ERROR_REQ              0x30
-#define MC_DECERR_EMEM_OTHERS_STATUS   0x58
-#define MC_SECURITY_VIOLATION_STATUS   0x74
-
-#define MC_EMEM_ARB_CFG 0x90
-#define  MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x)  (((x) & 0x1ff) << 0)
-#define  MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK        0x1ff
-#define MC_EMEM_ARB_MISC0 0xd8
-
-#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 },
@@ -307,7 +275,7 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
        return 0;
 }
 
-void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
+int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
 {
        unsigned int i;
        struct tegra_mc_timing *timing = NULL;
@@ -322,11 +290,13 @@ void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
        if (!timing) {
                dev_err(mc->dev, "no memory timing registered for rate %lu\n",
                        rate);
-               return;
+               return -EINVAL;
        }
 
        for (i = 0; i < mc->soc->num_emem_regs; ++i)
                mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]);
+
+       return 0;
 }
 
 unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
@@ -626,6 +596,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
        struct resource *res;
        struct tegra_mc *mc;
        void *isr;
+       u64 mask;
        int err;
 
        mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
@@ -637,6 +608,14 @@ static int tegra_mc_probe(struct platform_device *pdev)
        mc->soc = of_device_get_match_data(&pdev->dev);
        mc->dev = &pdev->dev;
 
+       mask = DMA_BIT_MASK(mc->soc->num_address_bits);
+
+       err = dma_coerce_mask_and_coherent(&pdev->dev, mask);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
+               return err;
+       }
+
        /* length of MC tick in nanoseconds */
        mc->tick = 30;
 
@@ -658,6 +637,9 @@ static int tegra_mc_probe(struct platform_device *pdev)
        } else
 #endif
        {
+               /* ensure that debug features are disabled */
+               mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
+
                err = tegra_mc_setup_latency_allowance(mc);
                if (err < 0) {
                        dev_err(&pdev->dev,
index f935349..957c6eb 100644 (file)
@@ -6,20 +6,76 @@
 #ifndef MEMORY_TEGRA_MC_H
 #define MEMORY_TEGRA_MC_H
 
+#include <linux/bits.h>
 #include <linux/io.h>
 #include <linux/types.h>
 
 #include <soc/tegra/mc.h>
 
-#define MC_INT_DECERR_MTS (1 << 16)
-#define MC_INT_SECERR_SEC (1 << 13)
-#define MC_INT_DECERR_VPR (1 << 12)
-#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
-#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
-#define MC_INT_ARBITRATION_EMEM (1 << 9)
-#define MC_INT_SECURITY_VIOLATION (1 << 8)
-#define MC_INT_INVALID_GART_PAGE (1 << 7)
-#define MC_INT_DECERR_EMEM (1 << 6)
+#define MC_INTSTATUS                                   0x00
+#define MC_INTMASK                                     0x04
+#define MC_ERR_STATUS                                  0x08
+#define MC_ERR_ADR                                     0x0c
+#define MC_GART_ERROR_REQ                              0x30
+#define MC_EMEM_ADR_CFG                                        0x54
+#define MC_DECERR_EMEM_OTHERS_STATUS                   0x58
+#define MC_SECURITY_VIOLATION_STATUS                   0x74
+#define MC_EMEM_ARB_CFG                                        0x90
+#define MC_EMEM_ARB_OUTSTANDING_REQ                    0x94
+#define MC_EMEM_ARB_TIMING_RCD                         0x98
+#define MC_EMEM_ARB_TIMING_RP                          0x9c
+#define MC_EMEM_ARB_TIMING_RC                          0xa0
+#define MC_EMEM_ARB_TIMING_RAS                         0xa4
+#define MC_EMEM_ARB_TIMING_FAW                         0xa8
+#define MC_EMEM_ARB_TIMING_RRD                         0xac
+#define MC_EMEM_ARB_TIMING_RAP2PRE                     0xb0
+#define MC_EMEM_ARB_TIMING_WAP2PRE                     0xb4
+#define MC_EMEM_ARB_TIMING_R2R                         0xb8
+#define MC_EMEM_ARB_TIMING_W2W                         0xbc
+#define MC_EMEM_ARB_TIMING_R2W                         0xc0
+#define MC_EMEM_ARB_TIMING_W2R                         0xc4
+#define MC_EMEM_ARB_DA_TURNS                           0xd0
+#define MC_EMEM_ARB_DA_COVERS                          0xd4
+#define MC_EMEM_ARB_MISC0                              0xd8
+#define MC_EMEM_ARB_MISC1                              0xdc
+#define MC_EMEM_ARB_RING1_THROTTLE                     0xe0
+#define MC_EMEM_ARB_OVERRIDE                           0xe8
+#define MC_TIMING_CONTROL_DBG                          0xf8
+#define MC_TIMING_CONTROL                              0xfc
+
+#define MC_INT_DECERR_MTS                              BIT(16)
+#define MC_INT_SECERR_SEC                              BIT(13)
+#define MC_INT_DECERR_VPR                              BIT(12)
+#define MC_INT_INVALID_APB_ASID_UPDATE                 BIT(11)
+#define MC_INT_INVALID_SMMU_PAGE                       BIT(10)
+#define MC_INT_ARBITRATION_EMEM                                BIT(9)
+#define MC_INT_SECURITY_VIOLATION                      BIT(8)
+#define MC_INT_INVALID_GART_PAGE                       BIT(7)
+#define MC_INT_DECERR_EMEM                             BIT(6)
+
+#define MC_ERR_STATUS_TYPE_SHIFT                       28
+#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE           (0x6 << 28)
+#define MC_ERR_STATUS_TYPE_MASK                                (0x7 << 28)
+#define MC_ERR_STATUS_READABLE                         BIT(27)
+#define MC_ERR_STATUS_WRITABLE                         BIT(26)
+#define MC_ERR_STATUS_NONSECURE                                BIT(25)
+#define MC_ERR_STATUS_ADR_HI_SHIFT                     20
+#define MC_ERR_STATUS_ADR_HI_MASK                      0x3
+#define MC_ERR_STATUS_SECURITY                         BIT(17)
+#define MC_ERR_STATUS_RW                               BIT(16)
+
+#define MC_EMEM_ADR_CFG_EMEM_NUMDEV                    BIT(0)
+
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x)           ((x) & 0x1ff)
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK         0x1ff
+
+#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK           0x1ff
+#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE   BIT(30)
+#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE       BIT(31)
+
+#define MC_EMEM_ARB_OVERRIDE_EACK_MASK                 0x3
+
+#define MC_TIMING_UPDATE                               BIT(0)
 
 static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
 {
index ac8351b..48ef01c 100644 (file)
@@ -909,16 +909,18 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
        { .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
 };
 
-static const unsigned int tegra114_group_display[] = {
+static const unsigned int tegra114_group_drm[] = {
        TEGRA_SWGROUP_DC,
        TEGRA_SWGROUP_DCB,
+       TEGRA_SWGROUP_G2,
+       TEGRA_SWGROUP_NV,
 };
 
 static const struct tegra_smmu_group_soc tegra114_groups[] = {
        {
-               .name = "display",
-               .swgroups = tegra114_group_display,
-               .num_swgroups = ARRAY_SIZE(tegra114_group_display),
+               .name = "drm",
+               .swgroups = tegra114_group_drm,
+               .num_swgroups = ARRAY_SIZE(tegra114_group_drm),
        },
 };
 
index 5d0ccb2..493b5dc 100644 (file)
 
 #include "mc.h"
 
-#define MC_EMEM_ARB_CFG                                0x90
-#define MC_EMEM_ARB_OUTSTANDING_REQ            0x94
-#define MC_EMEM_ARB_TIMING_RCD                 0x98
-#define MC_EMEM_ARB_TIMING_RP                  0x9c
-#define MC_EMEM_ARB_TIMING_RC                  0xa0
-#define MC_EMEM_ARB_TIMING_RAS                 0xa4
-#define MC_EMEM_ARB_TIMING_FAW                 0xa8
-#define MC_EMEM_ARB_TIMING_RRD                 0xac
-#define MC_EMEM_ARB_TIMING_RAP2PRE             0xb0
-#define MC_EMEM_ARB_TIMING_WAP2PRE             0xb4
-#define MC_EMEM_ARB_TIMING_R2R                 0xb8
-#define MC_EMEM_ARB_TIMING_W2W                 0xbc
-#define MC_EMEM_ARB_TIMING_R2W                 0xc0
-#define MC_EMEM_ARB_TIMING_W2R                 0xc4
-#define MC_EMEM_ARB_DA_TURNS                   0xd0
-#define MC_EMEM_ARB_DA_COVERS                  0xd4
-#define MC_EMEM_ARB_MISC0                      0xd8
-#define MC_EMEM_ARB_MISC1                      0xdc
-#define MC_EMEM_ARB_RING1_THROTTLE             0xe0
-
 static const struct tegra_mc_client tegra124_mc_clients[] = {
        {
                .id = 0x00,
@@ -974,16 +954,18 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
        { .name = "vi",        .swgroup = TEGRA_SWGROUP_VI,        .reg = 0x280 },
 };
 
-static const unsigned int tegra124_group_display[] = {
+static const unsigned int tegra124_group_drm[] = {
        TEGRA_SWGROUP_DC,
        TEGRA_SWGROUP_DCB,
+       TEGRA_SWGROUP_GPU,
+       TEGRA_SWGROUP_VIC,
 };
 
 static const struct tegra_smmu_group_soc tegra124_groups[] = {
        {
-               .name = "display",
-               .swgroups = tegra124_group_display,
-               .num_swgroups = ARRAY_SIZE(tegra124_group_display),
+               .name = "drm",
+               .swgroups = tegra124_group_drm,
+               .num_swgroups = ARRAY_SIZE(tegra124_group_drm),
        },
 };
 
index 9ee5bef..1b23b1c 100644 (file)
@@ -6,10 +6,11 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk/tegra.h>
 #include <linux/completion.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
-#include <linux/iopoll.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -21,6 +22,7 @@
 
 #define EMC_INTSTATUS                          0x000
 #define EMC_INTMASK                            0x004
+#define EMC_DBG                                        0x008
 #define EMC_TIMING_CONTROL                     0x028
 #define EMC_RC                                 0x02c
 #define EMC_RFC                                        0x030
 #define EMC_REFRESH_OVERFLOW_INT               BIT(3)
 #define EMC_CLKCHANGE_COMPLETE_INT             BIT(4)
 
+#define EMC_DBG_READ_MUX_ASSEMBLY              BIT(0)
+#define EMC_DBG_WRITE_MUX_ACTIVE               BIT(1)
+#define EMC_DBG_FORCE_UPDATE                   BIT(2)
+#define EMC_DBG_READ_DQM_CTRL                  BIT(9)
+#define EMC_DBG_CFG_PRIORITY                   BIT(24)
+
 static const u16 emc_timing_registers[] = {
        EMC_RC,
        EMC_RFC,
@@ -137,9 +145,6 @@ struct tegra_emc {
        struct device *dev;
        struct completion clk_handshake_complete;
        struct notifier_block clk_nb;
-       struct clk *backup_clk;
-       struct clk *emc_mux;
-       struct clk *pll_m;
        struct clk *clk;
        void __iomem *regs;
 
@@ -219,7 +224,7 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
 
 static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
 {
-       long timeout;
+       unsigned long timeout;
 
        dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush);
 
@@ -231,14 +236,10 @@ static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
        }
 
        timeout = wait_for_completion_timeout(&emc->clk_handshake_complete,
-                                             usecs_to_jiffies(100));
+                                             msecs_to_jiffies(100));
        if (timeout == 0) {
                dev_err(emc->dev, "EMC-CAR handshake failed\n");
                return -EIO;
-       } else if (timeout < 0) {
-               dev_err(emc->dev, "failed to wait for EMC-CAR handshake: %ld\n",
-                       timeout);
-               return timeout;
        }
 
        return 0;
@@ -363,6 +364,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
        sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
             NULL);
 
+       dev_info(emc->dev,
+                "got %u timings for RAM code %u (min %luMHz max %luMHz)\n",
+                emc->num_timings,
+                tegra_read_ram_code(),
+                emc->timings[0].rate / 1000000,
+                emc->timings[emc->num_timings - 1].rate / 1000000);
+
        return 0;
 }
 
@@ -398,7 +406,7 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
 static int emc_setup_hw(struct tegra_emc *emc)
 {
        u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
-       u32 emc_cfg;
+       u32 emc_cfg, emc_dbg;
 
        emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
 
@@ -421,42 +429,53 @@ static int emc_setup_hw(struct tegra_emc *emc)
        writel_relaxed(intmask, emc->regs + EMC_INTMASK);
        writel_relaxed(intmask, emc->regs + EMC_INTSTATUS);
 
+       /* ensure that unwanted debug features are disabled */
+       emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
+       emc_dbg |= EMC_DBG_CFG_PRIORITY;
+       emc_dbg &= ~EMC_DBG_READ_MUX_ASSEMBLY;
+       emc_dbg &= ~EMC_DBG_WRITE_MUX_ACTIVE;
+       emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
+       writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
+
        return 0;
 }
 
-static int emc_init(struct tegra_emc *emc, unsigned long rate)
+static long emc_round_rate(unsigned long rate,
+                          unsigned long min_rate,
+                          unsigned long max_rate,
+                          void *arg)
 {
-       int err;
+       struct emc_timing *timing = NULL;
+       struct tegra_emc *emc = arg;
+       unsigned int i;
 
-       err = clk_set_parent(emc->emc_mux, emc->backup_clk);
-       if (err) {
-               dev_err(emc->dev,
-                       "failed to reparent to backup source: %d\n", err);
-               return err;
-       }
+       min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
 
-       err = clk_set_rate(emc->pll_m, rate);
-       if (err) {
-               dev_err(emc->dev,
-                       "failed to change pll_m rate: %d\n", err);
-               return err;
-       }
+       for (i = 0; i < emc->num_timings; i++) {
+               if (emc->timings[i].rate < rate && i != emc->num_timings - 1)
+                       continue;
 
-       err = clk_set_parent(emc->emc_mux, emc->pll_m);
-       if (err) {
-               dev_err(emc->dev,
-                       "failed to reparent to pll_m: %d\n", err);
-               return err;
+               if (emc->timings[i].rate > max_rate) {
+                       i = max(i, 1u) - 1;
+
+                       if (emc->timings[i].rate < min_rate)
+                               break;
+               }
+
+               if (emc->timings[i].rate < min_rate)
+                       continue;
+
+               timing = &emc->timings[i];
+               break;
        }
 
-       err = clk_set_rate(emc->clk, rate);
-       if (err) {
-               dev_err(emc->dev,
-                       "failed to change emc rate: %d\n", err);
-               return err;
+       if (!timing) {
+               dev_err(emc->dev, "no timing for rate %lu min %lu max %lu\n",
+                       rate, min_rate, max_rate);
+               return -EINVAL;
        }
 
-       return 0;
+       return timing->rate;
 }
 
 static int tegra_emc_probe(struct platform_device *pdev)
@@ -515,57 +534,26 @@ static int tegra_emc_probe(struct platform_device *pdev)
                return err;
        }
 
+       tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
+
        emc->clk = devm_clk_get(&pdev->dev, "emc");
        if (IS_ERR(emc->clk)) {
                err = PTR_ERR(emc->clk);
                dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
-               return err;
-       }
-
-       emc->pll_m = clk_get_sys(NULL, "pll_m");
-       if (IS_ERR(emc->pll_m)) {
-               err = PTR_ERR(emc->pll_m);
-               dev_err(&pdev->dev, "failed to get pll_m clock: %d\n", err);
-               return err;
-       }
-
-       emc->backup_clk = clk_get_sys(NULL, "pll_p");
-       if (IS_ERR(emc->backup_clk)) {
-               err = PTR_ERR(emc->backup_clk);
-               dev_err(&pdev->dev, "failed to get pll_p clock: %d\n", err);
-               goto put_pll_m;
-       }
-
-       emc->emc_mux = clk_get_parent(emc->clk);
-       if (IS_ERR(emc->emc_mux)) {
-               err = PTR_ERR(emc->emc_mux);
-               dev_err(&pdev->dev, "failed to get emc_mux clock: %d\n", err);
-               goto put_backup;
+               goto unset_cb;
        }
 
        err = clk_notifier_register(emc->clk, &emc->clk_nb);
        if (err) {
                dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
                        err);
-               goto put_backup;
-       }
-
-       /* set DRAM clock rate to maximum */
-       err = emc_init(emc, emc->timings[emc->num_timings - 1].rate);
-       if (err) {
-               dev_err(&pdev->dev, "failed to initialize EMC clock rate: %d\n",
-                       err);
-               goto unreg_notifier;
+               goto unset_cb;
        }
 
        return 0;
 
-unreg_notifier:
-       clk_notifier_unregister(emc->clk, &emc->clk_nb);
-put_backup:
-       clk_put(emc->backup_clk);
-put_pll_m:
-       clk_put(emc->pll_m);
+unset_cb:
+       tegra20_clk_set_emc_round_callback(NULL, NULL);
 
        return err;
 }
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
new file mode 100644 (file)
index 0000000..6929980
--- /dev/null
@@ -0,0 +1,1232 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tegra30 External Memory Controller driver
+ *
+ * Based on downstream driver from NVIDIA and tegra124-emc.c
+ * Copyright (C) 2011-2014 NVIDIA Corporation
+ *
+ * Author: Dmitry Osipenko <digetx@gmail.com>
+ * Copyright (C) 2019 GRATE-DRIVER project
+ */
+
+#include <linux/clk.h>
+#include <linux/clk/tegra.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sort.h>
+#include <linux/types.h>
+
+#include <soc/tegra/fuse.h>
+
+#include "mc.h"
+
+#define EMC_INTSTATUS                          0x000
+#define EMC_INTMASK                            0x004
+#define EMC_DBG                                        0x008
+#define EMC_CFG                                        0x00c
+#define EMC_REFCTRL                            0x020
+#define EMC_TIMING_CONTROL                     0x028
+#define EMC_RC                                 0x02c
+#define EMC_RFC                                        0x030
+#define EMC_RAS                                        0x034
+#define EMC_RP                                 0x038
+#define EMC_R2W                                        0x03c
+#define EMC_W2R                                        0x040
+#define EMC_R2P                                        0x044
+#define EMC_W2P                                        0x048
+#define EMC_RD_RCD                             0x04c
+#define EMC_WR_RCD                             0x050
+#define EMC_RRD                                        0x054
+#define EMC_REXT                               0x058
+#define EMC_WDV                                        0x05c
+#define EMC_QUSE                               0x060
+#define EMC_QRST                               0x064
+#define EMC_QSAFE                              0x068
+#define EMC_RDV                                        0x06c
+#define EMC_REFRESH                            0x070
+#define EMC_BURST_REFRESH_NUM                  0x074
+#define EMC_PDEX2WR                            0x078
+#define EMC_PDEX2RD                            0x07c
+#define EMC_PCHG2PDEN                          0x080
+#define EMC_ACT2PDEN                           0x084
+#define EMC_AR2PDEN                            0x088
+#define EMC_RW2PDEN                            0x08c
+#define EMC_TXSR                               0x090
+#define EMC_TCKE                               0x094
+#define EMC_TFAW                               0x098
+#define EMC_TRPAB                              0x09c
+#define EMC_TCLKSTABLE                         0x0a0
+#define EMC_TCLKSTOP                           0x0a4
+#define EMC_TREFBW                             0x0a8
+#define EMC_QUSE_EXTRA                         0x0ac
+#define EMC_ODT_WRITE                          0x0b0
+#define EMC_ODT_READ                           0x0b4
+#define EMC_WEXT                               0x0b8
+#define EMC_CTT                                        0x0bc
+#define EMC_MRS_WAIT_CNT                       0x0c8
+#define EMC_MRS                                        0x0cc
+#define EMC_EMRS                               0x0d0
+#define EMC_SELF_REF                           0x0e0
+#define EMC_MRW                                        0x0e8
+#define EMC_XM2DQSPADCTRL3                     0x0f8
+#define EMC_FBIO_SPARE                         0x100
+#define EMC_FBIO_CFG5                          0x104
+#define EMC_FBIO_CFG6                          0x114
+#define EMC_CFG_RSV                            0x120
+#define EMC_AUTO_CAL_CONFIG                    0x2a4
+#define EMC_AUTO_CAL_INTERVAL                  0x2a8
+#define EMC_AUTO_CAL_STATUS                    0x2ac
+#define EMC_STATUS                             0x2b4
+#define EMC_CFG_2                              0x2b8
+#define EMC_CFG_DIG_DLL                                0x2bc
+#define EMC_CFG_DIG_DLL_PERIOD                 0x2c0
+#define EMC_CTT_DURATION                       0x2d8
+#define EMC_CTT_TERM_CTRL                      0x2dc
+#define EMC_ZCAL_INTERVAL                      0x2e0
+#define EMC_ZCAL_WAIT_CNT                      0x2e4
+#define EMC_ZQ_CAL                             0x2ec
+#define EMC_XM2CMDPADCTRL                      0x2f0
+#define EMC_XM2DQSPADCTRL2                     0x2fc
+#define EMC_XM2DQPADCTRL2                      0x304
+#define EMC_XM2CLKPADCTRL                      0x308
+#define EMC_XM2COMPPADCTRL                     0x30c
+#define EMC_XM2VTTGENPADCTRL                   0x310
+#define EMC_XM2VTTGENPADCTRL2                  0x314
+#define EMC_XM2QUSEPADCTRL                     0x318
+#define EMC_DLL_XFORM_DQS0                     0x328
+#define EMC_DLL_XFORM_DQS1                     0x32c
+#define EMC_DLL_XFORM_DQS2                     0x330
+#define EMC_DLL_XFORM_DQS3                     0x334
+#define EMC_DLL_XFORM_DQS4                     0x338
+#define EMC_DLL_XFORM_DQS5                     0x33c
+#define EMC_DLL_XFORM_DQS6                     0x340
+#define EMC_DLL_XFORM_DQS7                     0x344
+#define EMC_DLL_XFORM_QUSE0                    0x348
+#define EMC_DLL_XFORM_QUSE1                    0x34c
+#define EMC_DLL_XFORM_QUSE2                    0x350
+#define EMC_DLL_XFORM_QUSE3                    0x354
+#define EMC_DLL_XFORM_QUSE4                    0x358
+#define EMC_DLL_XFORM_QUSE5                    0x35c
+#define EMC_DLL_XFORM_QUSE6                    0x360
+#define EMC_DLL_XFORM_QUSE7                    0x364
+#define EMC_DLL_XFORM_DQ0                      0x368
+#define EMC_DLL_XFORM_DQ1                      0x36c
+#define EMC_DLL_XFORM_DQ2                      0x370
+#define EMC_DLL_XFORM_DQ3                      0x374
+#define EMC_DLI_TRIM_TXDQS0                    0x3a8
+#define EMC_DLI_TRIM_TXDQS1                    0x3ac
+#define EMC_DLI_TRIM_TXDQS2                    0x3b0
+#define EMC_DLI_TRIM_TXDQS3                    0x3b4
+#define EMC_DLI_TRIM_TXDQS4                    0x3b8
+#define EMC_DLI_TRIM_TXDQS5                    0x3bc
+#define EMC_DLI_TRIM_TXDQS6                    0x3c0
+#define EMC_DLI_TRIM_TXDQS7                    0x3c4
+#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE    0x3c8
+#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE     0x3cc
+#define EMC_UNSTALL_RW_AFTER_CLKCHANGE         0x3d0
+#define EMC_SEL_DPD_CTRL                       0x3d8
+#define EMC_PRE_REFRESH_REQ_CNT                        0x3dc
+#define EMC_DYN_SELF_REF_CONTROL               0x3e0
+#define EMC_TXSRDLL                            0x3e4
+
+#define EMC_STATUS_TIMING_UPDATE_STALLED       BIT(23)
+
+#define EMC_MODE_SET_DLL_RESET                 BIT(8)
+#define EMC_MODE_SET_LONG_CNT                  BIT(26)
+
+#define EMC_SELF_REF_CMD_ENABLED               BIT(0)
+
+#define DRAM_DEV_SEL_ALL                       (0 << 30)
+#define DRAM_DEV_SEL_0                         (2 << 30)
+#define DRAM_DEV_SEL_1                         (1 << 30)
+#define DRAM_BROADCAST(num) \
+       ((num) > 1 ? DRAM_DEV_SEL_ALL : DRAM_DEV_SEL_0)
+
+#define EMC_ZQ_CAL_CMD                         BIT(0)
+#define EMC_ZQ_CAL_LONG                                BIT(4)
+#define EMC_ZQ_CAL_LONG_CMD_DEV0 \
+       (DRAM_DEV_SEL_0 | EMC_ZQ_CAL_LONG | EMC_ZQ_CAL_CMD)
+#define EMC_ZQ_CAL_LONG_CMD_DEV1 \
+       (DRAM_DEV_SEL_1 | EMC_ZQ_CAL_LONG | EMC_ZQ_CAL_CMD)
+
+#define EMC_DBG_READ_MUX_ASSEMBLY              BIT(0)
+#define EMC_DBG_WRITE_MUX_ACTIVE               BIT(1)
+#define EMC_DBG_FORCE_UPDATE                   BIT(2)
+#define EMC_DBG_CFG_PRIORITY                   BIT(24)
+
+#define EMC_CFG5_QUSE_MODE_SHIFT               13
+#define EMC_CFG5_QUSE_MODE_MASK                        (7 << EMC_CFG5_QUSE_MODE_SHIFT)
+
+#define EMC_CFG5_QUSE_MODE_INTERNAL_LPBK       2
+#define EMC_CFG5_QUSE_MODE_PULSE_INTERN                3
+
+#define EMC_SEL_DPD_CTRL_QUSE_DPD_ENABLE       BIT(9)
+
+#define EMC_XM2COMPPADCTRL_VREF_CAL_ENABLE     BIT(10)
+
+#define EMC_XM2QUSEPADCTRL_IVREF_ENABLE                BIT(4)
+
+#define EMC_XM2DQSPADCTRL2_VREF_ENABLE         BIT(5)
+#define EMC_XM2DQSPADCTRL3_VREF_ENABLE         BIT(5)
+
+#define EMC_AUTO_CAL_STATUS_ACTIVE             BIT(31)
+
+#define        EMC_FBIO_CFG5_DRAM_TYPE_MASK            0x3
+
+#define EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK       0x3ff
+#define EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT       16
+#define EMC_MRS_WAIT_CNT_LONG_WAIT_MASK \
+       (0x3ff << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT)
+
+#define EMC_REFCTRL_DEV_SEL_MASK               0x3
+#define EMC_REFCTRL_ENABLE                     BIT(31)
+#define EMC_REFCTRL_ENABLE_ALL(num) \
+       (((num) > 1 ? 0 : 2) | EMC_REFCTRL_ENABLE)
+#define EMC_REFCTRL_DISABLE_ALL(num)           ((num) > 1 ? 0 : 2)
+
+#define EMC_CFG_PERIODIC_QRST                  BIT(21)
+#define EMC_CFG_DYN_SREF_ENABLE                        BIT(28)
+
+#define EMC_CLKCHANGE_REQ_ENABLE               BIT(0)
+#define EMC_CLKCHANGE_PD_ENABLE                        BIT(1)
+#define EMC_CLKCHANGE_SR_ENABLE                        BIT(2)
+
+#define EMC_TIMING_UPDATE                      BIT(0)
+
+#define EMC_REFRESH_OVERFLOW_INT               BIT(3)
+#define EMC_CLKCHANGE_COMPLETE_INT             BIT(4)
+
+enum emc_dram_type {
+       DRAM_TYPE_DDR3,
+       DRAM_TYPE_DDR1,
+       DRAM_TYPE_LPDDR2,
+       DRAM_TYPE_DDR2,
+};
+
+enum emc_dll_change {
+       DLL_CHANGE_NONE,
+       DLL_CHANGE_ON,
+       DLL_CHANGE_OFF
+};
+
+static const u16 emc_timing_registers[] = {
+       [0] = EMC_RC,
+       [1] = EMC_RFC,
+       [2] = EMC_RAS,
+       [3] = EMC_RP,
+       [4] = EMC_R2W,
+       [5] = EMC_W2R,
+       [6] = EMC_R2P,
+       [7] = EMC_W2P,
+       [8] = EMC_RD_RCD,
+       [9] = EMC_WR_RCD,
+       [10] = EMC_RRD,
+       [11] = EMC_REXT,
+       [12] = EMC_WEXT,
+       [13] = EMC_WDV,
+       [14] = EMC_QUSE,
+       [15] = EMC_QRST,
+       [16] = EMC_QSAFE,
+       [17] = EMC_RDV,
+       [18] = EMC_REFRESH,
+       [19] = EMC_BURST_REFRESH_NUM,
+       [20] = EMC_PRE_REFRESH_REQ_CNT,
+       [21] = EMC_PDEX2WR,
+       [22] = EMC_PDEX2RD,
+       [23] = EMC_PCHG2PDEN,
+       [24] = EMC_ACT2PDEN,
+       [25] = EMC_AR2PDEN,
+       [26] = EMC_RW2PDEN,
+       [27] = EMC_TXSR,
+       [28] = EMC_TXSRDLL,
+       [29] = EMC_TCKE,
+       [30] = EMC_TFAW,
+       [31] = EMC_TRPAB,
+       [32] = EMC_TCLKSTABLE,
+       [33] = EMC_TCLKSTOP,
+       [34] = EMC_TREFBW,
+       [35] = EMC_QUSE_EXTRA,
+       [36] = EMC_FBIO_CFG6,
+       [37] = EMC_ODT_WRITE,
+       [38] = EMC_ODT_READ,
+       [39] = EMC_FBIO_CFG5,
+       [40] = EMC_CFG_DIG_DLL,
+       [41] = EMC_CFG_DIG_DLL_PERIOD,
+       [42] = EMC_DLL_XFORM_DQS0,
+       [43] = EMC_DLL_XFORM_DQS1,
+       [44] = EMC_DLL_XFORM_DQS2,
+       [45] = EMC_DLL_XFORM_DQS3,
+       [46] = EMC_DLL_XFORM_DQS4,
+       [47] = EMC_DLL_XFORM_DQS5,
+       [48] = EMC_DLL_XFORM_DQS6,
+       [49] = EMC_DLL_XFORM_DQS7,
+       [50] = EMC_DLL_XFORM_QUSE0,
+       [51] = EMC_DLL_XFORM_QUSE1,
+       [52] = EMC_DLL_XFORM_QUSE2,
+       [53] = EMC_DLL_XFORM_QUSE3,
+       [54] = EMC_DLL_XFORM_QUSE4,
+       [55] = EMC_DLL_XFORM_QUSE5,
+       [56] = EMC_DLL_XFORM_QUSE6,
+       [57] = EMC_DLL_XFORM_QUSE7,
+       [58] = EMC_DLI_TRIM_TXDQS0,
+       [59] = EMC_DLI_TRIM_TXDQS1,
+       [60] = EMC_DLI_TRIM_TXDQS2,
+       [61] = EMC_DLI_TRIM_TXDQS3,
+       [62] = EMC_DLI_TRIM_TXDQS4,
+       [63] = EMC_DLI_TRIM_TXDQS5,
+       [64] = EMC_DLI_TRIM_TXDQS6,
+       [65] = EMC_DLI_TRIM_TXDQS7,
+       [66] = EMC_DLL_XFORM_DQ0,
+       [67] = EMC_DLL_XFORM_DQ1,
+       [68] = EMC_DLL_XFORM_DQ2,
+       [69] = EMC_DLL_XFORM_DQ3,
+       [70] = EMC_XM2CMDPADCTRL,
+       [71] = EMC_XM2DQSPADCTRL2,
+       [72] = EMC_XM2DQPADCTRL2,
+       [73] = EMC_XM2CLKPADCTRL,
+       [74] = EMC_XM2COMPPADCTRL,
+       [75] = EMC_XM2VTTGENPADCTRL,
+       [76] = EMC_XM2VTTGENPADCTRL2,
+       [77] = EMC_XM2QUSEPADCTRL,
+       [78] = EMC_XM2DQSPADCTRL3,
+       [79] = EMC_CTT_TERM_CTRL,
+       [80] = EMC_ZCAL_INTERVAL,
+       [81] = EMC_ZCAL_WAIT_CNT,
+       [82] = EMC_MRS_WAIT_CNT,
+       [83] = EMC_AUTO_CAL_CONFIG,
+       [84] = EMC_CTT,
+       [85] = EMC_CTT_DURATION,
+       [86] = EMC_DYN_SELF_REF_CONTROL,
+       [87] = EMC_FBIO_SPARE,
+       [88] = EMC_CFG_RSV,
+};
+
+struct emc_timing {
+       unsigned long rate;
+
+       u32 data[ARRAY_SIZE(emc_timing_registers)];
+
+       u32 emc_auto_cal_interval;
+       u32 emc_mode_1;
+       u32 emc_mode_2;
+       u32 emc_mode_reset;
+       u32 emc_zcal_cnt_long;
+       bool emc_cfg_periodic_qrst;
+       bool emc_cfg_dyn_self_ref;
+};
+
+struct tegra_emc {
+       struct device *dev;
+       struct tegra_mc *mc;
+       struct completion clk_handshake_complete;
+       struct notifier_block clk_nb;
+       struct clk *clk;
+       void __iomem *regs;
+       unsigned int irq;
+
+       struct emc_timing *timings;
+       unsigned int num_timings;
+
+       u32 mc_override;
+       u32 emc_cfg;
+
+       u32 emc_mode_1;
+       u32 emc_mode_2;
+       u32 emc_mode_reset;
+
+       bool vref_cal_toggle : 1;
+       bool zcal_long : 1;
+       bool dll_on : 1;
+       bool prepared : 1;
+       bool bad_state : 1;
+};
+
+static irqreturn_t tegra_emc_isr(int irq, void *data)
+{
+       struct tegra_emc *emc = data;
+       u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
+       u32 status;
+
+       status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask;
+       if (!status)
+               return IRQ_NONE;
+
+       /* notify about EMC-CAR handshake completion */
+       if (status & EMC_CLKCHANGE_COMPLETE_INT)
+               complete(&emc->clk_handshake_complete);
+
+       /* notify about HW problem */
+       if (status & EMC_REFRESH_OVERFLOW_INT)
+               dev_err_ratelimited(emc->dev,
+                                   "refresh request overflow timeout\n");
+
+       /* clear interrupts */
+       writel_relaxed(status, emc->regs + EMC_INTSTATUS);
+
+       return IRQ_HANDLED;
+}
+
+static struct emc_timing *emc_find_timing(struct tegra_emc *emc,
+                                         unsigned long rate)
+{
+       struct emc_timing *timing = NULL;
+       unsigned int i;
+
+       for (i = 0; i < emc->num_timings; i++) {
+               if (emc->timings[i].rate >= rate) {
+                       timing = &emc->timings[i];
+                       break;
+               }
+       }
+
+       if (!timing) {
+               dev_err(emc->dev, "no timing for rate %lu\n", rate);
+               return NULL;
+       }
+
+       return timing;
+}
+
+static bool emc_dqs_preset(struct tegra_emc *emc, struct emc_timing *timing,
+                          bool *schmitt_to_vref)
+{
+       bool preset = false;
+       u32 val;
+
+       if (timing->data[71] & EMC_XM2DQSPADCTRL2_VREF_ENABLE) {
+               val = readl_relaxed(emc->regs + EMC_XM2DQSPADCTRL2);
+
+               if (!(val & EMC_XM2DQSPADCTRL2_VREF_ENABLE)) {
+                       val |= EMC_XM2DQSPADCTRL2_VREF_ENABLE;
+                       writel_relaxed(val, emc->regs + EMC_XM2DQSPADCTRL2);
+
+                       preset = true;
+               }
+       }
+
+       if (timing->data[78] & EMC_XM2DQSPADCTRL3_VREF_ENABLE) {
+               val = readl_relaxed(emc->regs + EMC_XM2DQSPADCTRL3);
+
+               if (!(val & EMC_XM2DQSPADCTRL3_VREF_ENABLE)) {
+                       val |= EMC_XM2DQSPADCTRL3_VREF_ENABLE;
+                       writel_relaxed(val, emc->regs + EMC_XM2DQSPADCTRL3);
+
+                       preset = true;
+               }
+       }
+
+       if (timing->data[77] & EMC_XM2QUSEPADCTRL_IVREF_ENABLE) {
+               val = readl_relaxed(emc->regs + EMC_XM2QUSEPADCTRL);
+
+               if (!(val & EMC_XM2QUSEPADCTRL_IVREF_ENABLE)) {
+                       val |= EMC_XM2QUSEPADCTRL_IVREF_ENABLE;
+                       writel_relaxed(val, emc->regs + EMC_XM2QUSEPADCTRL);
+
+                       *schmitt_to_vref = true;
+                       preset = true;
+               }
+       }
+
+       return preset;
+}
+
+static int emc_seq_update_timing(struct tegra_emc *emc)
+{
+       u32 val;
+       int err;
+
+       writel_relaxed(EMC_TIMING_UPDATE, emc->regs + EMC_TIMING_CONTROL);
+
+       err = readl_relaxed_poll_timeout_atomic(emc->regs + EMC_STATUS, val,
+                               !(val & EMC_STATUS_TIMING_UPDATE_STALLED),
+                               1, 200);
+       if (err) {
+               dev_err(emc->dev, "failed to update timing: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int emc_prepare_mc_clk_cfg(struct tegra_emc *emc, unsigned long rate)
+{
+       struct tegra_mc *mc = emc->mc;
+       unsigned int misc0_index = 16;
+       unsigned int i;
+       bool same;
+
+       for (i = 0; i < mc->num_timings; i++) {
+               if (mc->timings[i].rate != rate)
+                       continue;
+
+               if (mc->timings[i].emem_data[misc0_index] & BIT(27))
+                       same = true;
+               else
+                       same = false;
+
+               return tegra20_clk_prepare_emc_mc_same_freq(emc->clk, same);
+       }
+
+       return -EINVAL;
+}
+
+static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
+{
+       struct emc_timing *timing = emc_find_timing(emc, rate);
+       enum emc_dll_change dll_change;
+       enum emc_dram_type dram_type;
+       bool schmitt_to_vref = false;
+       unsigned int pre_wait = 0;
+       bool qrst_used = false;
+       unsigned int dram_num;
+       unsigned int i;
+       u32 fbio_cfg5;
+       u32 emc_dbg;
+       u32 val;
+       int err;
+
+       if (!timing || emc->bad_state)
+               return -EINVAL;
+
+       dev_dbg(emc->dev, "%s: using timing rate %lu for requested rate %lu\n",
+               __func__, timing->rate, rate);
+
+       emc->bad_state = true;
+
+       err = emc_prepare_mc_clk_cfg(emc, rate);
+       if (err) {
+               dev_err(emc->dev, "mc clock preparation failed: %d\n", err);
+               return err;
+       }
+
+       emc->vref_cal_toggle = false;
+       emc->mc_override = mc_readl(emc->mc, MC_EMEM_ARB_OVERRIDE);
+       emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG);
+       emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
+
+       if (emc->dll_on == !!(timing->emc_mode_1 & 0x1))
+               dll_change = DLL_CHANGE_NONE;
+       else if (timing->emc_mode_1 & 0x1)
+               dll_change = DLL_CHANGE_ON;
+       else
+               dll_change = DLL_CHANGE_OFF;
+
+       emc->dll_on = !!(timing->emc_mode_1 & 0x1);
+
+       if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL))
+               emc->zcal_long = true;
+       else
+               emc->zcal_long = false;
+
+       fbio_cfg5 = readl_relaxed(emc->regs + EMC_FBIO_CFG5);
+       dram_type = fbio_cfg5 & EMC_FBIO_CFG5_DRAM_TYPE_MASK;
+
+       dram_num = tegra_mc_get_emem_device_count(emc->mc);
+
+       /* disable dynamic self-refresh */
+       if (emc->emc_cfg & EMC_CFG_DYN_SREF_ENABLE) {
+               emc->emc_cfg &= ~EMC_CFG_DYN_SREF_ENABLE;
+               writel_relaxed(emc->emc_cfg, emc->regs + EMC_CFG);
+
+               pre_wait = 5;
+       }
+
+       /* update MC arbiter settings */
+       val = mc_readl(emc->mc, MC_EMEM_ARB_OUTSTANDING_REQ);
+       if (!(val & MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE) ||
+           ((val & MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK) > 0x50)) {
+
+               val = MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE |
+                     MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE | 0x50;
+               mc_writel(emc->mc, val, MC_EMEM_ARB_OUTSTANDING_REQ);
+               mc_writel(emc->mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
+       }
+
+       if (emc->mc_override & MC_EMEM_ARB_OVERRIDE_EACK_MASK)
+               mc_writel(emc->mc,
+                         emc->mc_override & ~MC_EMEM_ARB_OVERRIDE_EACK_MASK,
+                         MC_EMEM_ARB_OVERRIDE);
+
+       /* check DQ/DQS VREF delay */
+       if (emc_dqs_preset(emc, timing, &schmitt_to_vref)) {
+               if (pre_wait < 3)
+                       pre_wait = 3;
+       }
+
+       if (pre_wait) {
+               err = emc_seq_update_timing(emc);
+               if (err)
+                       return err;
+
+               udelay(pre_wait);
+       }
+
+       /* disable auto-calibration if VREF mode is switching */
+       if (timing->emc_auto_cal_interval) {
+               val = readl_relaxed(emc->regs + EMC_XM2COMPPADCTRL);
+               val ^= timing->data[74];
+
+               if (val & EMC_XM2COMPPADCTRL_VREF_CAL_ENABLE) {
+                       writel_relaxed(0, emc->regs + EMC_AUTO_CAL_INTERVAL);
+
+                       err = readl_relaxed_poll_timeout_atomic(
+                               emc->regs + EMC_AUTO_CAL_STATUS, val,
+                               !(val & EMC_AUTO_CAL_STATUS_ACTIVE), 1, 300);
+                       if (err) {
+                               dev_err(emc->dev,
+                                       "failed to disable auto-cal: %d\n",
+                                       err);
+                               return err;
+                       }
+
+                       emc->vref_cal_toggle = true;
+               }
+       }
+
+       /* program shadow registers */
+       for (i = 0; i < ARRAY_SIZE(timing->data); i++) {
+               /* EMC_XM2CLKPADCTRL should be programmed separately */
+               if (i != 73)
+                       writel_relaxed(timing->data[i],
+                                      emc->regs + emc_timing_registers[i]);
+       }
+
+       err = tegra_mc_write_emem_configuration(emc->mc, timing->rate);
+       if (err)
+               return err;
+
+       /* DDR3: predict MRS long wait count */
+       if (dram_type == DRAM_TYPE_DDR3 && dll_change == DLL_CHANGE_ON) {
+               u32 cnt = 512;
+
+               if (emc->zcal_long)
+                       cnt -= dram_num * 256;
+
+               val = timing->data[82] & EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK;
+               if (cnt < val)
+                       cnt = val;
+
+               val = timing->data[82] & ~EMC_MRS_WAIT_CNT_LONG_WAIT_MASK;
+               val |= (cnt << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT) &
+                       EMC_MRS_WAIT_CNT_LONG_WAIT_MASK;
+
+               writel_relaxed(val, emc->regs + EMC_MRS_WAIT_CNT);
+       }
+
+       /* disable interrupt since read access is prohibited after stalling */
+       disable_irq(emc->irq);
+
+       /* this read also completes the writes */
+       val = readl_relaxed(emc->regs + EMC_SEL_DPD_CTRL);
+
+       if (!(val & EMC_SEL_DPD_CTRL_QUSE_DPD_ENABLE) && schmitt_to_vref) {
+               u32 cur_mode, new_mode;
+
+               cur_mode = fbio_cfg5 & EMC_CFG5_QUSE_MODE_MASK;
+               cur_mode >>= EMC_CFG5_QUSE_MODE_SHIFT;
+
+               new_mode = timing->data[39] & EMC_CFG5_QUSE_MODE_MASK;
+               new_mode >>= EMC_CFG5_QUSE_MODE_SHIFT;
+
+               if ((cur_mode != EMC_CFG5_QUSE_MODE_PULSE_INTERN &&
+                    cur_mode != EMC_CFG5_QUSE_MODE_INTERNAL_LPBK) ||
+                   (new_mode != EMC_CFG5_QUSE_MODE_PULSE_INTERN &&
+                    new_mode != EMC_CFG5_QUSE_MODE_INTERNAL_LPBK))
+                       qrst_used = true;
+       }
+
+       /* flow control marker 1 */
+       writel_relaxed(0x1, emc->regs + EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE);
+
+       /* enable periodic reset */
+       if (qrst_used) {
+               writel_relaxed(emc_dbg | EMC_DBG_WRITE_MUX_ACTIVE,
+                              emc->regs + EMC_DBG);
+               writel_relaxed(emc->emc_cfg | EMC_CFG_PERIODIC_QRST,
+                              emc->regs + EMC_CFG);
+               writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
+       }
+
+       /* disable auto-refresh to save time after clock change */
+       writel_relaxed(EMC_REFCTRL_DISABLE_ALL(dram_num),
+                      emc->regs + EMC_REFCTRL);
+
+       /* turn off DLL and enter self-refresh on DDR3 */
+       if (dram_type == DRAM_TYPE_DDR3) {
+               if (dll_change == DLL_CHANGE_OFF)
+                       writel_relaxed(timing->emc_mode_1,
+                                      emc->regs + EMC_EMRS);
+
+               writel_relaxed(DRAM_BROADCAST(dram_num) |
+                              EMC_SELF_REF_CMD_ENABLED,
+                              emc->regs + EMC_SELF_REF);
+       }
+
+       /* flow control marker 2 */
+       writel_relaxed(0x1, emc->regs + EMC_STALL_THEN_EXE_AFTER_CLKCHANGE);
+
+       /* enable write-active MUX, update unshadowed pad control */
+       writel_relaxed(emc_dbg | EMC_DBG_WRITE_MUX_ACTIVE, emc->regs + EMC_DBG);
+       writel_relaxed(timing->data[73], emc->regs + EMC_XM2CLKPADCTRL);
+
+       /* restore periodic QRST and disable write-active MUX */
+       val = !!(emc->emc_cfg & EMC_CFG_PERIODIC_QRST);
+       if (qrst_used || timing->emc_cfg_periodic_qrst != val) {
+               if (timing->emc_cfg_periodic_qrst)
+                       emc->emc_cfg |= EMC_CFG_PERIODIC_QRST;
+               else
+                       emc->emc_cfg &= ~EMC_CFG_PERIODIC_QRST;
+
+               writel_relaxed(emc->emc_cfg, emc->regs + EMC_CFG);
+       }
+       writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
+
+       /* exit self-refresh on DDR3 */
+       if (dram_type == DRAM_TYPE_DDR3)
+               writel_relaxed(DRAM_BROADCAST(dram_num),
+                              emc->regs + EMC_SELF_REF);
+
+       /* set DRAM-mode registers */
+       if (dram_type == DRAM_TYPE_DDR3) {
+               if (timing->emc_mode_1 != emc->emc_mode_1)
+                       writel_relaxed(timing->emc_mode_1,
+                                      emc->regs + EMC_EMRS);
+
+               if (timing->emc_mode_2 != emc->emc_mode_2)
+                       writel_relaxed(timing->emc_mode_2,
+                                      emc->regs + EMC_EMRS);
+
+               if (timing->emc_mode_reset != emc->emc_mode_reset ||
+                   dll_change == DLL_CHANGE_ON) {
+                       val = timing->emc_mode_reset;
+                       if (dll_change == DLL_CHANGE_ON) {
+                               val |= EMC_MODE_SET_DLL_RESET;
+                               val |= EMC_MODE_SET_LONG_CNT;
+                       } else {
+                               val &= ~EMC_MODE_SET_DLL_RESET;
+                       }
+                       writel_relaxed(val, emc->regs + EMC_MRS);
+               }
+       } else {
+               if (timing->emc_mode_2 != emc->emc_mode_2)
+                       writel_relaxed(timing->emc_mode_2,
+                                      emc->regs + EMC_MRW);
+
+               if (timing->emc_mode_1 != emc->emc_mode_1)
+                       writel_relaxed(timing->emc_mode_1,
+                                      emc->regs + EMC_MRW);
+       }
+
+       emc->emc_mode_1 = timing->emc_mode_1;
+       emc->emc_mode_2 = timing->emc_mode_2;
+       emc->emc_mode_reset = timing->emc_mode_reset;
+
+       /* issue ZCAL command if turning ZCAL on */
+       if (emc->zcal_long) {
+               writel_relaxed(EMC_ZQ_CAL_LONG_CMD_DEV0,
+                              emc->regs + EMC_ZQ_CAL);
+
+               if (dram_num > 1)
+                       writel_relaxed(EMC_ZQ_CAL_LONG_CMD_DEV1,
+                                      emc->regs + EMC_ZQ_CAL);
+       }
+
+       /* re-enable auto-refresh */
+       writel_relaxed(EMC_REFCTRL_ENABLE_ALL(dram_num),
+                      emc->regs + EMC_REFCTRL);
+
+       /* flow control marker 3 */
+       writel_relaxed(0x1, emc->regs + EMC_UNSTALL_RW_AFTER_CLKCHANGE);
+
+       reinit_completion(&emc->clk_handshake_complete);
+
+       /* interrupt can be re-enabled now */
+       enable_irq(emc->irq);
+
+       emc->bad_state = false;
+       emc->prepared = true;
+
+       return 0;
+}
+
+static int emc_complete_timing_change(struct tegra_emc *emc,
+                                     unsigned long rate)
+{
+       struct emc_timing *timing = emc_find_timing(emc, rate);
+       unsigned long timeout;
+       int ret;
+
+       timeout = wait_for_completion_timeout(&emc->clk_handshake_complete,
+                                             msecs_to_jiffies(100));
+       if (timeout == 0) {
+               dev_err(emc->dev, "emc-car handshake failed\n");
+               emc->bad_state = true;
+               return -EIO;
+       }
+
+       /* restore auto-calibration */
+       if (emc->vref_cal_toggle)
+               writel_relaxed(timing->emc_auto_cal_interval,
+                              emc->regs + EMC_AUTO_CAL_INTERVAL);
+
+       /* restore dynamic self-refresh */
+       if (timing->emc_cfg_dyn_self_ref) {
+               emc->emc_cfg |= EMC_CFG_DYN_SREF_ENABLE;
+               writel_relaxed(emc->emc_cfg, emc->regs + EMC_CFG);
+       }
+
+       /* set number of clocks to wait after each ZQ command */
+       if (emc->zcal_long)
+               writel_relaxed(timing->emc_zcal_cnt_long,
+                              emc->regs + EMC_ZCAL_WAIT_CNT);
+
+       udelay(2);
+       /* update restored timing */
+       ret = emc_seq_update_timing(emc);
+       if (ret)
+               emc->bad_state = true;
+
+       /* restore early ACK */
+       mc_writel(emc->mc, emc->mc_override, MC_EMEM_ARB_OVERRIDE);
+
+       emc->prepared = false;
+
+       return ret;
+}
+
+static int emc_unprepare_timing_change(struct tegra_emc *emc,
+                                      unsigned long rate)
+{
+       if (emc->prepared && !emc->bad_state) {
+               /* shouldn't ever happen in practice */
+               dev_err(emc->dev, "timing configuration can't be reverted\n");
+               emc->bad_state = true;
+       }
+
+       return 0;
+}
+
+static int emc_clk_change_notify(struct notifier_block *nb,
+                                unsigned long msg, void *data)
+{
+       struct tegra_emc *emc = container_of(nb, struct tegra_emc, clk_nb);
+       struct clk_notifier_data *cnd = data;
+       int err;
+
+       switch (msg) {
+       case PRE_RATE_CHANGE:
+               err = emc_prepare_timing_change(emc, cnd->new_rate);
+               break;
+
+       case ABORT_RATE_CHANGE:
+               err = emc_unprepare_timing_change(emc, cnd->old_rate);
+               break;
+
+       case POST_RATE_CHANGE:
+               err = emc_complete_timing_change(emc, cnd->new_rate);
+               break;
+
+       default:
+               return NOTIFY_DONE;
+       }
+
+       return notifier_from_errno(err);
+}
+
+static int load_one_timing_from_dt(struct tegra_emc *emc,
+                                  struct emc_timing *timing,
+                                  struct device_node *node)
+{
+       u32 value;
+       int err;
+
+       err = of_property_read_u32(node, "clock-frequency", &value);
+       if (err) {
+               dev_err(emc->dev, "timing %pOF: failed to read rate: %d\n",
+                       node, err);
+               return err;
+       }
+
+       timing->rate = value;
+
+       err = of_property_read_u32_array(node, "nvidia,emc-configuration",
+                                        timing->data,
+                                        ARRAY_SIZE(emc_timing_registers));
+       if (err) {
+               dev_err(emc->dev,
+                       "timing %pOF: failed to read emc timing data: %d\n",
+                       node, err);
+               return err;
+       }
+
+#define EMC_READ_BOOL(prop, dtprop) \
+       timing->prop = of_property_read_bool(node, dtprop);
+
+#define EMC_READ_U32(prop, dtprop) \
+       err = of_property_read_u32(node, dtprop, &timing->prop); \
+       if (err) { \
+               dev_err(emc->dev, \
+                       "timing %pOFn: failed to read " #prop ": %d\n", \
+                       node, err); \
+               return err; \
+       }
+
+       EMC_READ_U32(emc_auto_cal_interval, "nvidia,emc-auto-cal-interval")
+       EMC_READ_U32(emc_mode_1, "nvidia,emc-mode-1")
+       EMC_READ_U32(emc_mode_2, "nvidia,emc-mode-2")
+       EMC_READ_U32(emc_mode_reset, "nvidia,emc-mode-reset")
+       EMC_READ_U32(emc_zcal_cnt_long, "nvidia,emc-zcal-cnt-long")
+       EMC_READ_BOOL(emc_cfg_dyn_self_ref, "nvidia,emc-cfg-dyn-self-ref")
+       EMC_READ_BOOL(emc_cfg_periodic_qrst, "nvidia,emc-cfg-periodic-qrst")
+
+#undef EMC_READ_U32
+#undef EMC_READ_BOOL
+
+       dev_dbg(emc->dev, "%s: %pOF: rate %lu\n", __func__, node, timing->rate);
+
+       return 0;
+}
+
+static int cmp_timings(const void *_a, const void *_b)
+{
+       const struct emc_timing *a = _a;
+       const struct emc_timing *b = _b;
+
+       if (a->rate < b->rate)
+               return -1;
+
+       if (a->rate > b->rate)
+               return 1;
+
+       return 0;
+}
+
+static int emc_check_mc_timings(struct tegra_emc *emc)
+{
+       struct tegra_mc *mc = emc->mc;
+       unsigned int i;
+
+       if (emc->num_timings != mc->num_timings) {
+               dev_err(emc->dev, "emc/mc timings number mismatch: %u %u\n",
+                       emc->num_timings, mc->num_timings);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < mc->num_timings; i++) {
+               if (emc->timings[i].rate != mc->timings[i].rate) {
+                       dev_err(emc->dev,
+                               "emc/mc timing rate mismatch: %lu %lu\n",
+                               emc->timings[i].rate, mc->timings[i].rate);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int emc_load_timings_from_dt(struct tegra_emc *emc,
+                                   struct device_node *node)
+{
+       struct device_node *child;
+       struct emc_timing *timing;
+       int child_count;
+       int err;
+
+       child_count = of_get_child_count(node);
+       if (!child_count) {
+               dev_err(emc->dev, "no memory timings in: %pOF\n", node);
+               return -EINVAL;
+       }
+
+       emc->timings = devm_kcalloc(emc->dev, child_count, sizeof(*timing),
+                                   GFP_KERNEL);
+       if (!emc->timings)
+               return -ENOMEM;
+
+       emc->num_timings = child_count;
+       timing = emc->timings;
+
+       for_each_child_of_node(node, child) {
+               err = load_one_timing_from_dt(emc, timing++, child);
+               if (err) {
+                       of_node_put(child);
+                       return err;
+               }
+       }
+
+       sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
+            NULL);
+
+       err = emc_check_mc_timings(emc);
+       if (err)
+               return err;
+
+       dev_info(emc->dev,
+                "got %u timings for RAM code %u (min %luMHz max %luMHz)\n",
+                emc->num_timings,
+                tegra_read_ram_code(),
+                emc->timings[0].rate / 1000000,
+                emc->timings[emc->num_timings - 1].rate / 1000000);
+
+       return 0;
+}
+
+static struct device_node *emc_find_node_by_ram_code(struct device *dev)
+{
+       struct device_node *np;
+       u32 value, ram_code;
+       int err;
+
+       ram_code = tegra_read_ram_code();
+
+       for_each_child_of_node(dev->of_node, np) {
+               err = of_property_read_u32(np, "nvidia,ram-code", &value);
+               if (err || value != ram_code)
+                       continue;
+
+               return np;
+       }
+
+       dev_err(dev, "no memory timings for RAM code %u found in device-tree\n",
+               ram_code);
+
+       return NULL;
+}
+
+static int emc_setup_hw(struct tegra_emc *emc)
+{
+       u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
+       u32 fbio_cfg5, emc_cfg, emc_dbg;
+       enum emc_dram_type dram_type;
+
+       fbio_cfg5 = readl_relaxed(emc->regs + EMC_FBIO_CFG5);
+       dram_type = fbio_cfg5 & EMC_FBIO_CFG5_DRAM_TYPE_MASK;
+
+       emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
+
+       /* enable EMC and CAR to handshake on PLL divider/source changes */
+       emc_cfg |= EMC_CLKCHANGE_REQ_ENABLE;
+
+       /* configure clock change mode accordingly to DRAM type */
+       switch (dram_type) {
+       case DRAM_TYPE_LPDDR2:
+               emc_cfg |= EMC_CLKCHANGE_PD_ENABLE;
+               emc_cfg &= ~EMC_CLKCHANGE_SR_ENABLE;
+               break;
+
+       default:
+               emc_cfg &= ~EMC_CLKCHANGE_SR_ENABLE;
+               emc_cfg &= ~EMC_CLKCHANGE_PD_ENABLE;
+               break;
+       }
+
+       writel_relaxed(emc_cfg, emc->regs + EMC_CFG_2);
+
+       /* initialize interrupt */
+       writel_relaxed(intmask, emc->regs + EMC_INTMASK);
+       writel_relaxed(0xffffffff, emc->regs + EMC_INTSTATUS);
+
+       /* ensure that unwanted debug features are disabled */
+       emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
+       emc_dbg |= EMC_DBG_CFG_PRIORITY;
+       emc_dbg &= ~EMC_DBG_READ_MUX_ASSEMBLY;
+       emc_dbg &= ~EMC_DBG_WRITE_MUX_ACTIVE;
+       emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
+       writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
+
+       return 0;
+}
+
+static long emc_round_rate(unsigned long rate,
+                          unsigned long min_rate,
+                          unsigned long max_rate,
+                          void *arg)
+{
+       struct emc_timing *timing = NULL;
+       struct tegra_emc *emc = arg;
+       unsigned int i;
+
+       min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
+
+       for (i = 0; i < emc->num_timings; i++) {
+               if (emc->timings[i].rate < rate && i != emc->num_timings - 1)
+                       continue;
+
+               if (emc->timings[i].rate > max_rate) {
+                       i = max(i, 1u) - 1;
+
+                       if (emc->timings[i].rate < min_rate)
+                               break;
+               }
+
+               if (emc->timings[i].rate < min_rate)
+                       continue;
+
+               timing = &emc->timings[i];
+               break;
+       }
+
+       if (!timing) {
+               dev_err(emc->dev, "no timing for rate %lu min %lu max %lu\n",
+                       rate, min_rate, max_rate);
+               return -EINVAL;
+       }
+
+       return timing->rate;
+}
+
+static int tegra_emc_probe(struct platform_device *pdev)
+{
+       struct platform_device *mc;
+       struct device_node *np;
+       struct tegra_emc *emc;
+       int err;
+
+       if (of_get_child_count(pdev->dev.of_node) == 0) {
+               dev_info(&pdev->dev,
+                        "device-tree node doesn't have memory timings\n");
+               return 0;
+       }
+
+       np = of_parse_phandle(pdev->dev.of_node, "nvidia,memory-controller", 0);
+       if (!np) {
+               dev_err(&pdev->dev, "could not get memory controller node\n");
+               return -ENOENT;
+       }
+
+       mc = of_find_device_by_node(np);
+       of_node_put(np);
+       if (!mc)
+               return -ENOENT;
+
+       np = emc_find_node_by_ram_code(&pdev->dev);
+       if (!np)
+               return -EINVAL;
+
+       emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
+       if (!emc) {
+               of_node_put(np);
+               return -ENOMEM;
+       }
+
+       emc->mc = platform_get_drvdata(mc);
+       if (!emc->mc)
+               return -EPROBE_DEFER;
+
+       init_completion(&emc->clk_handshake_complete);
+       emc->clk_nb.notifier_call = emc_clk_change_notify;
+       emc->dev = &pdev->dev;
+
+       err = emc_load_timings_from_dt(emc, np);
+       of_node_put(np);
+       if (err)
+               return err;
+
+       emc->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(emc->regs))
+               return PTR_ERR(emc->regs);
+
+       err = emc_setup_hw(emc);
+       if (err)
+               return err;
+
+       err = platform_get_irq(pdev, 0);
+       if (err < 0) {
+               dev_err(&pdev->dev, "interrupt not specified: %d\n", err);
+               return err;
+       }
+       emc->irq = err;
+
+       err = devm_request_irq(&pdev->dev, emc->irq, tegra_emc_isr, 0,
+                              dev_name(&pdev->dev), emc);
+       if (err) {
+               dev_err(&pdev->dev, "failed to request irq: %d\n", err);
+               return err;
+       }
+
+       tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
+
+       emc->clk = devm_clk_get(&pdev->dev, "emc");
+       if (IS_ERR(emc->clk)) {
+               err = PTR_ERR(emc->clk);
+               dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
+               goto unset_cb;
+       }
+
+       err = clk_notifier_register(emc->clk, &emc->clk_nb);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
+                       err);
+               goto unset_cb;
+       }
+
+       platform_set_drvdata(pdev, emc);
+
+       return 0;
+
+unset_cb:
+       tegra20_clk_set_emc_round_callback(NULL, NULL);
+
+       return err;
+}
+
+static int tegra_emc_suspend(struct device *dev)
+{
+       struct tegra_emc *emc = dev_get_drvdata(dev);
+
+       /*
+        * Suspending in a bad state will hang machine. The "prepared" var
+        * shall be always false here unless it's a kernel bug that caused
+        * suspending in a wrong order.
+        */
+       if (WARN_ON(emc->prepared) || emc->bad_state)
+               return -EINVAL;
+
+       emc->bad_state = true;
+
+       return 0;
+}
+
+static int tegra_emc_resume(struct device *dev)
+{
+       struct tegra_emc *emc = dev_get_drvdata(dev);
+
+       emc_setup_hw(emc);
+       emc->bad_state = false;
+
+       return 0;
+}
+
+static const struct dev_pm_ops tegra_emc_pm_ops = {
+       .suspend = tegra_emc_suspend,
+       .resume = tegra_emc_resume,
+};
+
+static const struct of_device_id tegra_emc_of_match[] = {
+       { .compatible = "nvidia,tegra30-emc", },
+       {},
+};
+
+static struct platform_driver tegra_emc_driver = {
+       .probe = tegra_emc_probe,
+       .driver = {
+               .name = "tegra30-emc",
+               .of_match_table = tegra_emc_of_match,
+               .pm = &tegra_emc_pm_ops,
+               .suppress_bind_attrs = true,
+       },
+};
+
+static int __init tegra_emc_init(void)
+{
+       return platform_driver_register(&tegra_emc_driver);
+}
+subsys_initcall(tegra_emc_init);
index 14788fc..fcdd812 100644 (file)
 
 #include "mc.h"
 
+static const unsigned long tegra30_mc_emem_regs[] = {
+       MC_EMEM_ARB_CFG,
+       MC_EMEM_ARB_OUTSTANDING_REQ,
+       MC_EMEM_ARB_TIMING_RCD,
+       MC_EMEM_ARB_TIMING_RP,
+       MC_EMEM_ARB_TIMING_RC,
+       MC_EMEM_ARB_TIMING_RAS,
+       MC_EMEM_ARB_TIMING_FAW,
+       MC_EMEM_ARB_TIMING_RRD,
+       MC_EMEM_ARB_TIMING_RAP2PRE,
+       MC_EMEM_ARB_TIMING_WAP2PRE,
+       MC_EMEM_ARB_TIMING_R2R,
+       MC_EMEM_ARB_TIMING_W2W,
+       MC_EMEM_ARB_TIMING_R2W,
+       MC_EMEM_ARB_TIMING_W2R,
+       MC_EMEM_ARB_DA_TURNS,
+       MC_EMEM_ARB_DA_COVERS,
+       MC_EMEM_ARB_MISC0,
+       MC_EMEM_ARB_RING1_THROTTLE,
+};
+
 static const struct tegra_mc_client tegra30_mc_clients[] = {
        {
                .id = 0x00,
@@ -931,16 +952,19 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
        { .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
 };
 
-static const unsigned int tegra30_group_display[] = {
+static const unsigned int tegra30_group_drm[] = {
        TEGRA_SWGROUP_DC,
        TEGRA_SWGROUP_DCB,
+       TEGRA_SWGROUP_G2,
+       TEGRA_SWGROUP_NV,
+       TEGRA_SWGROUP_NV2,
 };
 
 static const struct tegra_smmu_group_soc tegra30_groups[] = {
        {
-               .name = "display",
-               .swgroups = tegra30_group_display,
-               .num_swgroups = ARRAY_SIZE(tegra30_group_display),
+               .name = "drm",
+               .swgroups = tegra30_group_drm,
+               .num_swgroups = ARRAY_SIZE(tegra30_group_drm),
        },
 };
 
@@ -994,6 +1018,8 @@ const struct tegra_mc_soc tegra30_mc_soc = {
        .atom_size = 16,
        .client_id_mask = 0x7f,
        .smmu = &tegra30_smmu_soc,
+       .emem_regs = tegra30_mc_emem_regs,
+       .num_emem_regs = ARRAY_SIZE(tegra30_mc_emem_regs),
        .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
                   MC_INT_DECERR_EMEM,
        .reset_ops = &tegra_mc_reset_ops_common,
index b36142d..0a9c5dd 100644 (file)
@@ -848,7 +848,7 @@ static int jmb38x_ms_count_slots(struct pci_dev *pdev)
 {
        int cnt, rc = 0;
 
-       for (cnt = 0; cnt < PCI_ROM_RESOURCE; ++cnt) {
+       for (cnt = 0; cnt < PCI_STD_NUM_BARS; ++cnt) {
                if (!(IORESOURCE_MEM & pci_resource_flags(pdev, cnt)))
                        break;
 
index 6e6dfd6..c4b977a 100644 (file)
@@ -78,6 +78,10 @@ static const struct mfd_cell cros_ec_rtc_cells[] = {
        { .name = "cros-ec-rtc", },
 };
 
+static const struct mfd_cell cros_ec_sensorhub_cells[] = {
+       { .name = "cros-ec-sensorhub", },
+};
+
 static const struct mfd_cell cros_usbpd_charger_cells[] = {
        { .name = "cros-usbpd-charger", },
        { .name = "cros-usbpd-logger", },
@@ -112,229 +116,11 @@ static const struct mfd_cell cros_ec_vbc_cells[] = {
        { .name = "cros-ec-vbc", }
 };
 
-static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
-{
-       struct cros_ec_command *msg;
-       int ret;
-
-       if (ec->features[0] == -1U && ec->features[1] == -1U) {
-               /* features bitmap not read yet */
-               msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
-               if (!msg)
-                       return -ENOMEM;
-
-               msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
-               msg->insize = sizeof(ec->features);
-
-               ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
-               if (ret < 0) {
-                       dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
-                                ret, msg->result);
-                       memset(ec->features, 0, sizeof(ec->features));
-               } else {
-                       memcpy(ec->features, msg->data, sizeof(ec->features));
-               }
-
-               dev_dbg(ec->dev, "EC features %08x %08x\n",
-                       ec->features[0], ec->features[1]);
-
-               kfree(msg);
-       }
-
-       return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
-}
-
 static void cros_ec_class_release(struct device *dev)
 {
        kfree(to_cros_ec_dev(dev));
 }
 
-static void cros_ec_sensors_register(struct cros_ec_dev *ec)
-{
-       /*
-        * Issue a command to get the number of sensor reported.
-        * Build an array of sensors driver and register them all.
-        */
-       int ret, i, id, sensor_num;
-       struct mfd_cell *sensor_cells;
-       struct cros_ec_sensor_platform *sensor_platforms;
-       int sensor_type[MOTIONSENSE_TYPE_MAX];
-       struct ec_params_motion_sense *params;
-       struct ec_response_motion_sense *resp;
-       struct cros_ec_command *msg;
-
-       msg = kzalloc(sizeof(struct cros_ec_command) +
-                     max(sizeof(*params), sizeof(*resp)), GFP_KERNEL);
-       if (msg == NULL)
-               return;
-
-       msg->version = 2;
-       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
-       msg->outsize = sizeof(*params);
-       msg->insize = sizeof(*resp);
-
-       params = (struct ec_params_motion_sense *)msg->data;
-       params->cmd = MOTIONSENSE_CMD_DUMP;
-
-       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
-       if (ret < 0) {
-               dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n",
-                        ret, msg->result);
-               goto error;
-       }
-
-       resp = (struct ec_response_motion_sense *)msg->data;
-       sensor_num = resp->dump.sensor_count;
-       /*
-        * Allocate 2 extra sensors if lid angle sensor and/or FIFO are needed.
-        */
-       sensor_cells = kcalloc(sensor_num + 2, sizeof(struct mfd_cell),
-                              GFP_KERNEL);
-       if (sensor_cells == NULL)
-               goto error;
-
-       sensor_platforms = kcalloc(sensor_num,
-                                  sizeof(struct cros_ec_sensor_platform),
-                                  GFP_KERNEL);
-       if (sensor_platforms == NULL)
-               goto error_platforms;
-
-       memset(sensor_type, 0, sizeof(sensor_type));
-       id = 0;
-       for (i = 0; i < sensor_num; i++) {
-               params->cmd = MOTIONSENSE_CMD_INFO;
-               params->info.sensor_num = i;
-               ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
-               if (ret < 0) {
-                       dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n",
-                                i, ret, msg->result);
-                       continue;
-               }
-               switch (resp->info.type) {
-               case MOTIONSENSE_TYPE_ACCEL:
-                       sensor_cells[id].name = "cros-ec-accel";
-                       break;
-               case MOTIONSENSE_TYPE_BARO:
-                       sensor_cells[id].name = "cros-ec-baro";
-                       break;
-               case MOTIONSENSE_TYPE_GYRO:
-                       sensor_cells[id].name = "cros-ec-gyro";
-                       break;
-               case MOTIONSENSE_TYPE_MAG:
-                       sensor_cells[id].name = "cros-ec-mag";
-                       break;
-               case MOTIONSENSE_TYPE_PROX:
-                       sensor_cells[id].name = "cros-ec-prox";
-                       break;
-               case MOTIONSENSE_TYPE_LIGHT:
-                       sensor_cells[id].name = "cros-ec-light";
-                       break;
-               case MOTIONSENSE_TYPE_ACTIVITY:
-                       sensor_cells[id].name = "cros-ec-activity";
-                       break;
-               default:
-                       dev_warn(ec->dev, "unknown type %d\n", resp->info.type);
-                       continue;
-               }
-               sensor_platforms[id].sensor_num = i;
-               sensor_cells[id].id = sensor_type[resp->info.type];
-               sensor_cells[id].platform_data = &sensor_platforms[id];
-               sensor_cells[id].pdata_size =
-                       sizeof(struct cros_ec_sensor_platform);
-
-               sensor_type[resp->info.type]++;
-               id++;
-       }
-
-       if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
-               ec->has_kb_wake_angle = true;
-
-       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
-               sensor_cells[id].name = "cros-ec-ring";
-               id++;
-       }
-       if (cros_ec_check_features(ec,
-                               EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
-               sensor_cells[id].name = "cros-ec-lid-angle";
-               id++;
-       }
-
-       ret = mfd_add_devices(ec->dev, 0, sensor_cells, id,
-                             NULL, 0, NULL);
-       if (ret)
-               dev_err(ec->dev, "failed to add EC sensors\n");
-
-       kfree(sensor_platforms);
-error_platforms:
-       kfree(sensor_cells);
-error:
-       kfree(msg);
-}
-
-static struct cros_ec_sensor_platform sensor_platforms[] = {
-       { .sensor_num = 0 },
-       { .sensor_num = 1 }
-};
-
-static const struct mfd_cell cros_ec_accel_legacy_cells[] = {
-       {
-               .name = "cros-ec-accel-legacy",
-               .platform_data = &sensor_platforms[0],
-               .pdata_size = sizeof(struct cros_ec_sensor_platform),
-       },
-       {
-               .name = "cros-ec-accel-legacy",
-               .platform_data = &sensor_platforms[1],
-               .pdata_size = sizeof(struct cros_ec_sensor_platform),
-       }
-};
-
-static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec)
-{
-       struct cros_ec_device *ec_dev = ec->ec_dev;
-       u8 status;
-       int ret;
-
-       /*
-        * ECs that need legacy support are the main EC, directly connected to
-        * the AP.
-        */
-       if (ec->cmd_offset != 0)
-               return;
-
-       /*
-        * Check if EC supports direct memory reads and if EC has
-        * accelerometers.
-        */
-       if (ec_dev->cmd_readmem) {
-               ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS, 1,
-                                         &status);
-               if (ret < 0) {
-                       dev_warn(ec->dev, "EC direct read error.\n");
-                       return;
-               }
-
-               /* Check if EC has accelerometers. */
-               if (!(status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
-                       dev_info(ec->dev, "EC does not have accelerometers.\n");
-                       return;
-               }
-       }
-
-       /*
-        * The device may still support accelerometers:
-        * it would be an older ARM based device that do not suppor the
-        * EC_CMD_GET_FEATURES command.
-        *
-        * Register 2 accelerometers, we will fail in the IIO driver if there
-        * are no sensors.
-        */
-       ret = mfd_add_hotplug_devices(ec->dev, cros_ec_accel_legacy_cells,
-                                     ARRAY_SIZE(cros_ec_accel_legacy_cells));
-       if (ret)
-               dev_err(ec_dev->dev, "failed to add EC sensors\n");
-}
-
 static int ec_device_probe(struct platform_device *pdev)
 {
        int retval = -ENOMEM;
@@ -390,11 +176,14 @@ static int ec_device_probe(struct platform_device *pdev)
                goto failed;
 
        /* check whether this EC is a sensor hub. */
-       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
-               cros_ec_sensors_register(ec);
-       else
-               /* Workaroud for older EC firmware */
-               cros_ec_accel_legacy_register(ec);
+       if (cros_ec_get_sensor_count(ec) > 0) {
+               retval = mfd_add_hotplug_devices(ec->dev,
+                               cros_ec_sensorhub_cells,
+                               ARRAY_SIZE(cros_ec_sensorhub_cells));
+               if (retval)
+                       dev_err(ec->dev, "failed to add %s subdevice: %d\n",
+                               cros_ec_sensorhub_cells->name, retval);
+       }
 
        /*
         * The following subdevices can be detected by sending the
index 7284a22..a4fdad0 100644 (file)
 #include <linux/sched/task_stack.h>
 #include <linux/uaccess.h>
 
+#ifdef CONFIG_X86_32
+#include <asm/desc.h>
+#endif
+
 struct lkdtm_list {
        struct list_head node;
 };
@@ -337,3 +341,38 @@ void lkdtm_UNSET_SMEP(void)
        pr_err("FAIL: this test is x86_64-only\n");
 #endif
 }
+
+#ifdef CONFIG_X86_32
+void lkdtm_DOUBLE_FAULT(void)
+{
+       /*
+        * Trigger #DF by setting the stack limit to zero.  This clobbers
+        * a GDT TLS slot, which is okay because the current task will die
+        * anyway due to the double fault.
+        */
+       struct desc_struct d = {
+               .type = 3,      /* expand-up, writable, accessed data */
+               .p = 1,         /* present */
+               .d = 1,         /* 32-bit */
+               .g = 0,         /* limit in bytes */
+               .s = 1,         /* not system */
+       };
+
+       local_irq_disable();
+       write_gdt_entry(get_cpu_gdt_rw(smp_processor_id()),
+                       GDT_ENTRY_TLS_MIN, &d, DESCTYPE_S);
+
+       /*
+        * Put our zero-limit segment in SS and then trigger a fault.  The
+        * 4-byte access to (%esp) will fault with #SS, and the attempt to
+        * deliver the fault will recursively cause #SS and result in #DF.
+        * This whole process happens while NMIs and MCEs are blocked by the
+        * MOV SS window.  This is nice because an NMI with an invalid SS
+        * would also double-fault, resulting in the NMI or MCE being lost.
+        */
+       asm volatile ("movw %0, %%ss; addl $0, (%%esp)" ::
+                     "r" ((unsigned short)(GDT_ENTRY_TLS_MIN << 3)));
+
+       panic("tried to double fault but didn't die\n");
+}
+#endif
index cbc4c90..ee0d6e7 100644 (file)
@@ -171,6 +171,9 @@ static const struct crashtype crashtypes[] = {
        CRASHTYPE(USERCOPY_KERNEL_DS),
        CRASHTYPE(STACKLEAK_ERASING),
        CRASHTYPE(CFI_FORWARD_PROTO),
+#ifdef CONFIG_X86_32
+       CRASHTYPE(DOUBLE_FAULT),
+#endif
 };
 
 
index ab446e0..c56d23e 100644 (file)
@@ -28,6 +28,9 @@ void lkdtm_CORRUPT_USER_DS(void);
 void lkdtm_STACK_GUARD_PAGE_LEADING(void);
 void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
 void lkdtm_UNSET_SMEP(void);
+#ifdef CONFIG_X86_32
+void lkdtm_DOUBLE_FAULT(void);
+#endif
 
 /* lkdtm_heap.c */
 void __init lkdtm_heap_init(void);
index 6e208a0..a5e3170 100644 (file)
@@ -94,7 +94,7 @@ enum pci_barno {
 struct pci_endpoint_test {
        struct pci_dev  *pdev;
        void __iomem    *base;
-       void __iomem    *bar[6];
+       void __iomem    *bar[PCI_STD_NUM_BARS];
        struct completion irq_raised;
        int             last_irq;
        int             num_irqs;
@@ -687,7 +687,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
        if (!pci_endpoint_test_request_irq(test))
                goto err_disable_irq;
 
-       for (bar = BAR_0; bar <= BAR_5; bar++) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
                        base = pci_ioremap_bar(pdev, bar);
                        if (!base) {
@@ -740,7 +740,7 @@ err_ida_remove:
        ida_simple_remove(&pci_endpoint_test_ida, id);
 
 err_iounmap:
-       for (bar = BAR_0; bar <= BAR_5; bar++) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (test->bar[bar])
                        pci_iounmap(pdev, test->bar[bar]);
        }
@@ -771,7 +771,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
        misc_deregister(&test->miscdev);
        kfree(misc_device->name);
        ida_simple_remove(&pci_endpoint_test_ida, id);
-       for (bar = BAR_0; bar <= BAR_5; bar++) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (test->bar[bar])
                        pci_iounmap(pdev, test->bar[bar]);
        }
index 426ad91..d054e28 100644 (file)
@@ -96,7 +96,7 @@ void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src,
        if (!part)
                return NULL;
 
-       if (!addr_in_gen_pool(pool, (unsigned long)dst, size))
+       if (!gen_pool_has_addr(pool, (unsigned long)dst, size))
                return NULL;
 
        base = (unsigned long)part->base;
index f8b624a..a27b635 100644 (file)
@@ -9,6 +9,6 @@ obj-$(CONFIG_MTD_ONENAND)               += onenand.o
 # Board specific.
 obj-$(CONFIG_MTD_ONENAND_GENERIC)      += generic.o
 obj-$(CONFIG_MTD_ONENAND_OMAP2)                += omap2.o
-obj-$(CONFIG_MTD_ONENAND_SAMSUNG)       += samsung.o
+obj-$(CONFIG_MTD_ONENAND_SAMSUNG)       += samsung_mtd.o
 
 onenand-objs = onenand_base.o onenand_bbt.o
diff --git a/drivers/mtd/nand/onenand/samsung.c b/drivers/mtd/nand/onenand/samsung.c
deleted file mode 100644 (file)
index 55e5536..0000000
+++ /dev/null
@@ -1,1006 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Samsung S3C64XX/S5PC1XX OneNAND driver
- *
- *  Copyright © 2008-2010 Samsung Electronics
- *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Marek Szyprowski <m.szyprowski@samsung.com>
- *
- * Implementation:
- *     S3C64XX: emulate the pseudo BufferRAM
- *     S5PC110: use DMA
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/onenand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include "samsung.h"
-
-enum soc_type {
-       TYPE_S3C6400,
-       TYPE_S3C6410,
-       TYPE_S5PC110,
-};
-
-#define ONENAND_ERASE_STATUS           0x00
-#define ONENAND_MULTI_ERASE_SET                0x01
-#define ONENAND_ERASE_START            0x03
-#define ONENAND_UNLOCK_START           0x08
-#define ONENAND_UNLOCK_END             0x09
-#define ONENAND_LOCK_START             0x0A
-#define ONENAND_LOCK_END               0x0B
-#define ONENAND_LOCK_TIGHT_START       0x0C
-#define ONENAND_LOCK_TIGHT_END         0x0D
-#define ONENAND_UNLOCK_ALL             0x0E
-#define ONENAND_OTP_ACCESS             0x12
-#define ONENAND_SPARE_ACCESS_ONLY      0x13
-#define ONENAND_MAIN_ACCESS_ONLY       0x14
-#define ONENAND_ERASE_VERIFY           0x15
-#define ONENAND_MAIN_SPARE_ACCESS      0x16
-#define ONENAND_PIPELINE_READ          0x4000
-
-#define MAP_00                         (0x0)
-#define MAP_01                         (0x1)
-#define MAP_10                         (0x2)
-#define MAP_11                         (0x3)
-
-#define S3C64XX_CMD_MAP_SHIFT          24
-
-#define S3C6400_FBA_SHIFT              10
-#define S3C6400_FPA_SHIFT              4
-#define S3C6400_FSA_SHIFT              2
-
-#define S3C6410_FBA_SHIFT              12
-#define S3C6410_FPA_SHIFT              6
-#define S3C6410_FSA_SHIFT              4
-
-/* S5PC110 specific definitions */
-#define S5PC110_DMA_SRC_ADDR           0x400
-#define S5PC110_DMA_SRC_CFG            0x404
-#define S5PC110_DMA_DST_ADDR           0x408
-#define S5PC110_DMA_DST_CFG            0x40C
-#define S5PC110_DMA_TRANS_SIZE         0x414
-#define S5PC110_DMA_TRANS_CMD          0x418
-#define S5PC110_DMA_TRANS_STATUS       0x41C
-#define S5PC110_DMA_TRANS_DIR          0x420
-#define S5PC110_INTC_DMA_CLR           0x1004
-#define S5PC110_INTC_ONENAND_CLR       0x1008
-#define S5PC110_INTC_DMA_MASK          0x1024
-#define S5PC110_INTC_ONENAND_MASK      0x1028
-#define S5PC110_INTC_DMA_PEND          0x1044
-#define S5PC110_INTC_ONENAND_PEND      0x1048
-#define S5PC110_INTC_DMA_STATUS                0x1064
-#define S5PC110_INTC_ONENAND_STATUS    0x1068
-
-#define S5PC110_INTC_DMA_TD            (1 << 24)
-#define S5PC110_INTC_DMA_TE            (1 << 16)
-
-#define S5PC110_DMA_CFG_SINGLE         (0x0 << 16)
-#define S5PC110_DMA_CFG_4BURST         (0x2 << 16)
-#define S5PC110_DMA_CFG_8BURST         (0x3 << 16)
-#define S5PC110_DMA_CFG_16BURST                (0x4 << 16)
-
-#define S5PC110_DMA_CFG_INC            (0x0 << 8)
-#define S5PC110_DMA_CFG_CNT            (0x1 << 8)
-
-#define S5PC110_DMA_CFG_8BIT           (0x0 << 0)
-#define S5PC110_DMA_CFG_16BIT          (0x1 << 0)
-#define S5PC110_DMA_CFG_32BIT          (0x2 << 0)
-
-#define S5PC110_DMA_SRC_CFG_READ       (S5PC110_DMA_CFG_16BURST | \
-                                       S5PC110_DMA_CFG_INC | \
-                                       S5PC110_DMA_CFG_16BIT)
-#define S5PC110_DMA_DST_CFG_READ       (S5PC110_DMA_CFG_16BURST | \
-                                       S5PC110_DMA_CFG_INC | \
-                                       S5PC110_DMA_CFG_32BIT)
-#define S5PC110_DMA_SRC_CFG_WRITE      (S5PC110_DMA_CFG_16BURST | \
-                                       S5PC110_DMA_CFG_INC | \
-                                       S5PC110_DMA_CFG_32BIT)
-#define S5PC110_DMA_DST_CFG_WRITE      (S5PC110_DMA_CFG_16BURST | \
-                                       S5PC110_DMA_CFG_INC | \
-                                       S5PC110_DMA_CFG_16BIT)
-
-#define S5PC110_DMA_TRANS_CMD_TDC      (0x1 << 18)
-#define S5PC110_DMA_TRANS_CMD_TEC      (0x1 << 16)
-#define S5PC110_DMA_TRANS_CMD_TR       (0x1 << 0)
-
-#define S5PC110_DMA_TRANS_STATUS_TD    (0x1 << 18)
-#define S5PC110_DMA_TRANS_STATUS_TB    (0x1 << 17)
-#define S5PC110_DMA_TRANS_STATUS_TE    (0x1 << 16)
-
-#define S5PC110_DMA_DIR_READ           0x0
-#define S5PC110_DMA_DIR_WRITE          0x1
-
-struct s3c_onenand {
-       struct mtd_info *mtd;
-       struct platform_device  *pdev;
-       enum soc_type   type;
-       void __iomem    *base;
-       void __iomem    *ahb_addr;
-       int             bootram_command;
-       void            *page_buf;
-       void            *oob_buf;
-       unsigned int    (*mem_addr)(int fba, int fpa, int fsa);
-       unsigned int    (*cmd_map)(unsigned int type, unsigned int val);
-       void __iomem    *dma_addr;
-       unsigned long   phys_base;
-       struct completion       complete;
-};
-
-#define CMD_MAP_00(dev, addr)          (dev->cmd_map(MAP_00, ((addr) << 1)))
-#define CMD_MAP_01(dev, mem_addr)      (dev->cmd_map(MAP_01, (mem_addr)))
-#define CMD_MAP_10(dev, mem_addr)      (dev->cmd_map(MAP_10, (mem_addr)))
-#define CMD_MAP_11(dev, addr)          (dev->cmd_map(MAP_11, ((addr) << 2)))
-
-static struct s3c_onenand *onenand;
-
-static inline int s3c_read_reg(int offset)
-{
-       return readl(onenand->base + offset);
-}
-
-static inline void s3c_write_reg(int value, int offset)
-{
-       writel(value, onenand->base + offset);
-}
-
-static inline int s3c_read_cmd(unsigned int cmd)
-{
-       return readl(onenand->ahb_addr + cmd);
-}
-
-static inline void s3c_write_cmd(int value, unsigned int cmd)
-{
-       writel(value, onenand->ahb_addr + cmd);
-}
-
-#ifdef SAMSUNG_DEBUG
-static void s3c_dump_reg(void)
-{
-       int i;
-
-       for (i = 0; i < 0x400; i += 0x40) {
-               printk(KERN_INFO "0x%08X: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                       (unsigned int) onenand->base + i,
-                       s3c_read_reg(i), s3c_read_reg(i + 0x10),
-                       s3c_read_reg(i + 0x20), s3c_read_reg(i + 0x30));
-       }
-}
-#endif
-
-static unsigned int s3c64xx_cmd_map(unsigned type, unsigned val)
-{
-       return (type << S3C64XX_CMD_MAP_SHIFT) | val;
-}
-
-static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa)
-{
-       return (fba << S3C6400_FBA_SHIFT) | (fpa << S3C6400_FPA_SHIFT) |
-               (fsa << S3C6400_FSA_SHIFT);
-}
-
-static unsigned int s3c6410_mem_addr(int fba, int fpa, int fsa)
-{
-       return (fba << S3C6410_FBA_SHIFT) | (fpa << S3C6410_FPA_SHIFT) |
-               (fsa << S3C6410_FSA_SHIFT);
-}
-
-static void s3c_onenand_reset(void)
-{
-       unsigned long timeout = 0x10000;
-       int stat;
-
-       s3c_write_reg(ONENAND_MEM_RESET_COLD, MEM_RESET_OFFSET);
-       while (1 && timeout--) {
-               stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
-               if (stat & RST_CMP)
-                       break;
-       }
-       stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
-       s3c_write_reg(stat, INT_ERR_ACK_OFFSET);
-
-       /* Clear interrupt */
-       s3c_write_reg(0x0, INT_ERR_ACK_OFFSET);
-       /* Clear the ECC status */
-       s3c_write_reg(0x0, ECC_ERR_STAT_OFFSET);
-}
-
-static unsigned short s3c_onenand_readw(void __iomem *addr)
-{
-       struct onenand_chip *this = onenand->mtd->priv;
-       struct device *dev = &onenand->pdev->dev;
-       int reg = addr - this->base;
-       int word_addr = reg >> 1;
-       int value;
-
-       /* It's used for probing time */
-       switch (reg) {
-       case ONENAND_REG_MANUFACTURER_ID:
-               return s3c_read_reg(MANUFACT_ID_OFFSET);
-       case ONENAND_REG_DEVICE_ID:
-               return s3c_read_reg(DEVICE_ID_OFFSET);
-       case ONENAND_REG_VERSION_ID:
-               return s3c_read_reg(FLASH_VER_ID_OFFSET);
-       case ONENAND_REG_DATA_BUFFER_SIZE:
-               return s3c_read_reg(DATA_BUF_SIZE_OFFSET);
-       case ONENAND_REG_TECHNOLOGY:
-               return s3c_read_reg(TECH_OFFSET);
-       case ONENAND_REG_SYS_CFG1:
-               return s3c_read_reg(MEM_CFG_OFFSET);
-
-       /* Used at unlock all status */
-       case ONENAND_REG_CTRL_STATUS:
-               return 0;
-
-       case ONENAND_REG_WP_STATUS:
-               return ONENAND_WP_US;
-
-       default:
-               break;
-       }
-
-       /* BootRAM access control */
-       if ((unsigned int) addr < ONENAND_DATARAM && onenand->bootram_command) {
-               if (word_addr == 0)
-                       return s3c_read_reg(MANUFACT_ID_OFFSET);
-               if (word_addr == 1)
-                       return s3c_read_reg(DEVICE_ID_OFFSET);
-               if (word_addr == 2)
-                       return s3c_read_reg(FLASH_VER_ID_OFFSET);
-       }
-
-       value = s3c_read_cmd(CMD_MAP_11(onenand, word_addr)) & 0xffff;
-       dev_info(dev, "%s: Illegal access at reg 0x%x, value 0x%x\n", __func__,
-                word_addr, value);
-       return value;
-}
-
-static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
-{
-       struct onenand_chip *this = onenand->mtd->priv;
-       struct device *dev = &onenand->pdev->dev;
-       unsigned int reg = addr - this->base;
-       unsigned int word_addr = reg >> 1;
-
-       /* It's used for probing time */
-       switch (reg) {
-       case ONENAND_REG_SYS_CFG1:
-               s3c_write_reg(value, MEM_CFG_OFFSET);
-               return;
-
-       case ONENAND_REG_START_ADDRESS1:
-       case ONENAND_REG_START_ADDRESS2:
-               return;
-
-       /* Lock/lock-tight/unlock/unlock_all */
-       case ONENAND_REG_START_BLOCK_ADDRESS:
-               return;
-
-       default:
-               break;
-       }
-
-       /* BootRAM access control */
-       if ((unsigned int)addr < ONENAND_DATARAM) {
-               if (value == ONENAND_CMD_READID) {
-                       onenand->bootram_command = 1;
-                       return;
-               }
-               if (value == ONENAND_CMD_RESET) {
-                       s3c_write_reg(ONENAND_MEM_RESET_COLD, MEM_RESET_OFFSET);
-                       onenand->bootram_command = 0;
-                       return;
-               }
-       }
-
-       dev_info(dev, "%s: Illegal access at reg 0x%x, value 0x%x\n", __func__,
-                word_addr, value);
-
-       s3c_write_cmd(value, CMD_MAP_11(onenand, word_addr));
-}
-
-static int s3c_onenand_wait(struct mtd_info *mtd, int state)
-{
-       struct device *dev = &onenand->pdev->dev;
-       unsigned int flags = INT_ACT;
-       unsigned int stat, ecc;
-       unsigned long timeout;
-
-       switch (state) {
-       case FL_READING:
-               flags |= BLK_RW_CMP | LOAD_CMP;
-               break;
-       case FL_WRITING:
-               flags |= BLK_RW_CMP | PGM_CMP;
-               break;
-       case FL_ERASING:
-               flags |= BLK_RW_CMP | ERS_CMP;
-               break;
-       case FL_LOCKING:
-               flags |= BLK_RW_CMP;
-               break;
-       default:
-               break;
-       }
-
-       /* The 20 msec is enough */
-       timeout = jiffies + msecs_to_jiffies(20);
-       while (time_before(jiffies, timeout)) {
-               stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
-               if (stat & flags)
-                       break;
-
-               if (state != FL_READING)
-                       cond_resched();
-       }
-       /* To get correct interrupt status in timeout case */
-       stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
-       s3c_write_reg(stat, INT_ERR_ACK_OFFSET);
-
-       /*
-        * In the Spec. it checks the controller status first
-        * However if you get the correct information in case of
-        * power off recovery (POR) test, it should read ECC status first
-        */
-       if (stat & LOAD_CMP) {
-               ecc = s3c_read_reg(ECC_ERR_STAT_OFFSET);
-               if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
-                       dev_info(dev, "%s: ECC error = 0x%04x\n", __func__,
-                                ecc);
-                       mtd->ecc_stats.failed++;
-                       return -EBADMSG;
-               }
-       }
-
-       if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) {
-               dev_info(dev, "%s: controller error = 0x%04x\n", __func__,
-                        stat);
-               if (stat & LOCKED_BLK)
-                       dev_info(dev, "%s: it's locked error = 0x%04x\n",
-                                __func__, stat);
-
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int s3c_onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
-                              size_t len)
-{
-       struct onenand_chip *this = mtd->priv;
-       unsigned int *m, *s;
-       int fba, fpa, fsa = 0;
-       unsigned int mem_addr, cmd_map_01, cmd_map_10;
-       int i, mcount, scount;
-       int index;
-
-       fba = (int) (addr >> this->erase_shift);
-       fpa = (int) (addr >> this->page_shift);
-       fpa &= this->page_mask;
-
-       mem_addr = onenand->mem_addr(fba, fpa, fsa);
-       cmd_map_01 = CMD_MAP_01(onenand, mem_addr);
-       cmd_map_10 = CMD_MAP_10(onenand, mem_addr);
-
-       switch (cmd) {
-       case ONENAND_CMD_READ:
-       case ONENAND_CMD_READOOB:
-       case ONENAND_CMD_BUFFERRAM:
-               ONENAND_SET_NEXT_BUFFERRAM(this);
-       default:
-               break;
-       }
-
-       index = ONENAND_CURRENT_BUFFERRAM(this);
-
-       /*
-        * Emulate Two BufferRAMs and access with 4 bytes pointer
-        */
-       m = onenand->page_buf;
-       s = onenand->oob_buf;
-
-       if (index) {
-               m += (this->writesize >> 2);
-               s += (mtd->oobsize >> 2);
-       }
-
-       mcount = mtd->writesize >> 2;
-       scount = mtd->oobsize >> 2;
-
-       switch (cmd) {
-       case ONENAND_CMD_READ:
-               /* Main */
-               for (i = 0; i < mcount; i++)
-                       *m++ = s3c_read_cmd(cmd_map_01);
-               return 0;
-
-       case ONENAND_CMD_READOOB:
-               s3c_write_reg(TSRF, TRANS_SPARE_OFFSET);
-               /* Main */
-               for (i = 0; i < mcount; i++)
-                       *m++ = s3c_read_cmd(cmd_map_01);
-
-               /* Spare */
-               for (i = 0; i < scount; i++)
-                       *s++ = s3c_read_cmd(cmd_map_01);
-
-               s3c_write_reg(0, TRANS_SPARE_OFFSET);
-               return 0;
-
-       case ONENAND_CMD_PROG:
-               /* Main */
-               for (i = 0; i < mcount; i++)
-                       s3c_write_cmd(*m++, cmd_map_01);
-               return 0;
-
-       case ONENAND_CMD_PROGOOB:
-               s3c_write_reg(TSRF, TRANS_SPARE_OFFSET);
-
-               /* Main - dummy write */
-               for (i = 0; i < mcount; i++)
-                       s3c_write_cmd(0xffffffff, cmd_map_01);
-
-               /* Spare */
-               for (i = 0; i < scount; i++)
-                       s3c_write_cmd(*s++, cmd_map_01);
-
-               s3c_write_reg(0, TRANS_SPARE_OFFSET);
-               return 0;
-
-       case ONENAND_CMD_UNLOCK_ALL:
-               s3c_write_cmd(ONENAND_UNLOCK_ALL, cmd_map_10);
-               return 0;
-
-       case ONENAND_CMD_ERASE:
-               s3c_write_cmd(ONENAND_ERASE_START, cmd_map_10);
-               return 0;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area)
-{
-       struct onenand_chip *this = mtd->priv;
-       int index = ONENAND_CURRENT_BUFFERRAM(this);
-       unsigned char *p;
-
-       if (area == ONENAND_DATARAM) {
-               p = onenand->page_buf;
-               if (index == 1)
-                       p += this->writesize;
-       } else {
-               p = onenand->oob_buf;
-               if (index == 1)
-                       p += mtd->oobsize;
-       }
-
-       return p;
-}
-
-static int onenand_read_bufferram(struct mtd_info *mtd, int area,
-                                 unsigned char *buffer, int offset,
-                                 size_t count)
-{
-       unsigned char *p;
-
-       p = s3c_get_bufferram(mtd, area);
-       memcpy(buffer, p + offset, count);
-       return 0;
-}
-
-static int onenand_write_bufferram(struct mtd_info *mtd, int area,
-                                  const unsigned char *buffer, int offset,
-                                  size_t count)
-{
-       unsigned char *p;
-
-       p = s3c_get_bufferram(mtd, area);
-       memcpy(p + offset, buffer, count);
-       return 0;
-}
-
-static int (*s5pc110_dma_ops)(dma_addr_t dst, dma_addr_t src, size_t count, int direction);
-
-static int s5pc110_dma_poll(dma_addr_t dst, dma_addr_t src, size_t count, int direction)
-{
-       void __iomem *base = onenand->dma_addr;
-       int status;
-       unsigned long timeout;
-
-       writel(src, base + S5PC110_DMA_SRC_ADDR);
-       writel(dst, base + S5PC110_DMA_DST_ADDR);
-
-       if (direction == S5PC110_DMA_DIR_READ) {
-               writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG);
-               writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG);
-       } else {
-               writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG);
-               writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG);
-       }
-
-       writel(count, base + S5PC110_DMA_TRANS_SIZE);
-       writel(direction, base + S5PC110_DMA_TRANS_DIR);
-
-       writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
-
-       /*
-        * There's no exact timeout values at Spec.
-        * In real case it takes under 1 msec.
-        * So 20 msecs are enough.
-        */
-       timeout = jiffies + msecs_to_jiffies(20);
-
-       do {
-               status = readl(base + S5PC110_DMA_TRANS_STATUS);
-               if (status & S5PC110_DMA_TRANS_STATUS_TE) {
-                       writel(S5PC110_DMA_TRANS_CMD_TEC,
-                                       base + S5PC110_DMA_TRANS_CMD);
-                       return -EIO;
-               }
-       } while (!(status & S5PC110_DMA_TRANS_STATUS_TD) &&
-               time_before(jiffies, timeout));
-
-       writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD);
-
-       return 0;
-}
-
-static irqreturn_t s5pc110_onenand_irq(int irq, void *data)
-{
-       void __iomem *base = onenand->dma_addr;
-       int status, cmd = 0;
-
-       status = readl(base + S5PC110_INTC_DMA_STATUS);
-
-       if (likely(status & S5PC110_INTC_DMA_TD))
-               cmd = S5PC110_DMA_TRANS_CMD_TDC;
-
-       if (unlikely(status & S5PC110_INTC_DMA_TE))
-               cmd = S5PC110_DMA_TRANS_CMD_TEC;
-
-       writel(cmd, base + S5PC110_DMA_TRANS_CMD);
-       writel(status, base + S5PC110_INTC_DMA_CLR);
-
-       if (!onenand->complete.done)
-               complete(&onenand->complete);
-
-       return IRQ_HANDLED;
-}
-
-static int s5pc110_dma_irq(dma_addr_t dst, dma_addr_t src, size_t count, int direction)
-{
-       void __iomem *base = onenand->dma_addr;
-       int status;
-
-       status = readl(base + S5PC110_INTC_DMA_MASK);
-       if (status) {
-               status &= ~(S5PC110_INTC_DMA_TD | S5PC110_INTC_DMA_TE);
-               writel(status, base + S5PC110_INTC_DMA_MASK);
-       }
-
-       writel(src, base + S5PC110_DMA_SRC_ADDR);
-       writel(dst, base + S5PC110_DMA_DST_ADDR);
-
-       if (direction == S5PC110_DMA_DIR_READ) {
-               writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG);
-               writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG);
-       } else {
-               writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG);
-               writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG);
-       }
-
-       writel(count, base + S5PC110_DMA_TRANS_SIZE);
-       writel(direction, base + S5PC110_DMA_TRANS_DIR);
-
-       writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
-
-       wait_for_completion_timeout(&onenand->complete, msecs_to_jiffies(20));
-
-       return 0;
-}
-
-static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
-               unsigned char *buffer, int offset, size_t count)
-{
-       struct onenand_chip *this = mtd->priv;
-       void __iomem *p;
-       void *buf = (void *) buffer;
-       dma_addr_t dma_src, dma_dst;
-       int err, ofs, page_dma = 0;
-       struct device *dev = &onenand->pdev->dev;
-
-       p = this->base + area;
-       if (ONENAND_CURRENT_BUFFERRAM(this)) {
-               if (area == ONENAND_DATARAM)
-                       p += this->writesize;
-               else
-                       p += mtd->oobsize;
-       }
-
-       if (offset & 3 || (size_t) buf & 3 ||
-               !onenand->dma_addr || count != mtd->writesize)
-               goto normal;
-
-       /* Handle vmalloc address */
-       if (buf >= high_memory) {
-               struct page *page;
-
-               if (((size_t) buf & PAGE_MASK) !=
-                   ((size_t) (buf + count - 1) & PAGE_MASK))
-                       goto normal;
-               page = vmalloc_to_page(buf);
-               if (!page)
-                       goto normal;
-
-               /* Page offset */
-               ofs = ((size_t) buf & ~PAGE_MASK);
-               page_dma = 1;
-
-               /* DMA routine */
-               dma_src = onenand->phys_base + (p - this->base);
-               dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE);
-       } else {
-               /* DMA routine */
-               dma_src = onenand->phys_base + (p - this->base);
-               dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
-       }
-       if (dma_mapping_error(dev, dma_dst)) {
-               dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count);
-               goto normal;
-       }
-       err = s5pc110_dma_ops(dma_dst, dma_src,
-                       count, S5PC110_DMA_DIR_READ);
-
-       if (page_dma)
-               dma_unmap_page(dev, dma_dst, count, DMA_FROM_DEVICE);
-       else
-               dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE);
-
-       if (!err)
-               return 0;
-
-normal:
-       if (count != mtd->writesize) {
-               /* Copy the bufferram to memory to prevent unaligned access */
-               memcpy(this->page_buf, p, mtd->writesize);
-               p = this->page_buf + offset;
-       }
-
-       memcpy(buffer, p, count);
-
-       return 0;
-}
-
-static int s5pc110_chip_probe(struct mtd_info *mtd)
-{
-       /* Now just return 0 */
-       return 0;
-}
-
-static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state)
-{
-       unsigned int flags = INT_ACT | LOAD_CMP;
-       unsigned int stat;
-       unsigned long timeout;
-
-       /* The 20 msec is enough */
-       timeout = jiffies + msecs_to_jiffies(20);
-       while (time_before(jiffies, timeout)) {
-               stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
-               if (stat & flags)
-                       break;
-       }
-       /* To get correct interrupt status in timeout case */
-       stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
-       s3c_write_reg(stat, INT_ERR_ACK_OFFSET);
-
-       if (stat & LD_FAIL_ECC_ERR) {
-               s3c_onenand_reset();
-               return ONENAND_BBT_READ_ERROR;
-       }
-
-       if (stat & LOAD_CMP) {
-               int ecc = s3c_read_reg(ECC_ERR_STAT_OFFSET);
-               if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
-                       s3c_onenand_reset();
-                       return ONENAND_BBT_READ_ERROR;
-               }
-       }
-
-       return 0;
-}
-
-static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
-{
-       struct onenand_chip *this = mtd->priv;
-       struct device *dev = &onenand->pdev->dev;
-       unsigned int block, end;
-       int tmp;
-
-       end = this->chipsize >> this->erase_shift;
-
-       for (block = 0; block < end; block++) {
-               unsigned int mem_addr = onenand->mem_addr(block, 0, 0);
-               tmp = s3c_read_cmd(CMD_MAP_01(onenand, mem_addr));
-
-               if (s3c_read_reg(INT_ERR_STAT_OFFSET) & LOCKED_BLK) {
-                       dev_err(dev, "block %d is write-protected!\n", block);
-                       s3c_write_reg(LOCKED_BLK, INT_ERR_ACK_OFFSET);
-               }
-       }
-}
-
-static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
-                                   size_t len, int cmd)
-{
-       struct onenand_chip *this = mtd->priv;
-       int start, end, start_mem_addr, end_mem_addr;
-
-       start = ofs >> this->erase_shift;
-       start_mem_addr = onenand->mem_addr(start, 0, 0);
-       end = start + (len >> this->erase_shift) - 1;
-       end_mem_addr = onenand->mem_addr(end, 0, 0);
-
-       if (cmd == ONENAND_CMD_LOCK) {
-               s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(onenand,
-                                                            start_mem_addr));
-               s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(onenand,
-                                                          end_mem_addr));
-       } else {
-               s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(onenand,
-                                                              start_mem_addr));
-               s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(onenand,
-                                                            end_mem_addr));
-       }
-
-       this->wait(mtd, FL_LOCKING);
-}
-
-static void s3c_unlock_all(struct mtd_info *mtd)
-{
-       struct onenand_chip *this = mtd->priv;
-       loff_t ofs = 0;
-       size_t len = this->chipsize;
-
-       if (this->options & ONENAND_HAS_UNLOCK_ALL) {
-               /* Write unlock command */
-               this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
-
-               /* No need to check return value */
-               this->wait(mtd, FL_LOCKING);
-
-               /* Workaround for all block unlock in DDP */
-               if (!ONENAND_IS_DDP(this)) {
-                       s3c_onenand_check_lock_status(mtd);
-                       return;
-               }
-
-               /* All blocks on another chip */
-               ofs = this->chipsize >> 1;
-               len = this->chipsize >> 1;
-       }
-
-       s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
-
-       s3c_onenand_check_lock_status(mtd);
-}
-
-static void s3c_onenand_setup(struct mtd_info *mtd)
-{
-       struct onenand_chip *this = mtd->priv;
-
-       onenand->mtd = mtd;
-
-       if (onenand->type == TYPE_S3C6400) {
-               onenand->mem_addr = s3c6400_mem_addr;
-               onenand->cmd_map = s3c64xx_cmd_map;
-       } else if (onenand->type == TYPE_S3C6410) {
-               onenand->mem_addr = s3c6410_mem_addr;
-               onenand->cmd_map = s3c64xx_cmd_map;
-       } else if (onenand->type == TYPE_S5PC110) {
-               /* Use generic onenand functions */
-               this->read_bufferram = s5pc110_read_bufferram;
-               this->chip_probe = s5pc110_chip_probe;
-               return;
-       } else {
-               BUG();
-       }
-
-       this->read_word = s3c_onenand_readw;
-       this->write_word = s3c_onenand_writew;
-
-       this->wait = s3c_onenand_wait;
-       this->bbt_wait = s3c_onenand_bbt_wait;
-       this->unlock_all = s3c_unlock_all;
-       this->command = s3c_onenand_command;
-
-       this->read_bufferram = onenand_read_bufferram;
-       this->write_bufferram = onenand_write_bufferram;
-}
-
-static int s3c_onenand_probe(struct platform_device *pdev)
-{
-       struct onenand_platform_data *pdata;
-       struct onenand_chip *this;
-       struct mtd_info *mtd;
-       struct resource *r;
-       int size, err;
-
-       pdata = dev_get_platdata(&pdev->dev);
-       /* No need to check pdata. the platform data is optional */
-
-       size = sizeof(struct mtd_info) + sizeof(struct onenand_chip);
-       mtd = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!mtd)
-               return -ENOMEM;
-
-       onenand = devm_kzalloc(&pdev->dev, sizeof(struct s3c_onenand),
-                              GFP_KERNEL);
-       if (!onenand)
-               return -ENOMEM;
-
-       this = (struct onenand_chip *) &mtd[1];
-       mtd->priv = this;
-       mtd->dev.parent = &pdev->dev;
-       onenand->pdev = pdev;
-       onenand->type = platform_get_device_id(pdev)->driver_data;
-
-       s3c_onenand_setup(mtd);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       onenand->base = devm_ioremap_resource(&pdev->dev, r);
-       if (IS_ERR(onenand->base))
-               return PTR_ERR(onenand->base);
-
-       onenand->phys_base = r->start;
-
-       /* Set onenand_chip also */
-       this->base = onenand->base;
-
-       /* Use runtime badblock check */
-       this->options |= ONENAND_SKIP_UNLOCK_CHECK;
-
-       if (onenand->type != TYPE_S5PC110) {
-               r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               onenand->ahb_addr = devm_ioremap_resource(&pdev->dev, r);
-               if (IS_ERR(onenand->ahb_addr))
-                       return PTR_ERR(onenand->ahb_addr);
-
-               /* Allocate 4KiB BufferRAM */
-               onenand->page_buf = devm_kzalloc(&pdev->dev, SZ_4K,
-                                                GFP_KERNEL);
-               if (!onenand->page_buf)
-                       return -ENOMEM;
-
-               /* Allocate 128 SpareRAM */
-               onenand->oob_buf = devm_kzalloc(&pdev->dev, 128, GFP_KERNEL);
-               if (!onenand->oob_buf)
-                       return -ENOMEM;
-
-               /* S3C doesn't handle subpage write */
-               mtd->subpage_sft = 0;
-               this->subpagesize = mtd->writesize;
-
-       } else { /* S5PC110 */
-               r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               onenand->dma_addr = devm_ioremap_resource(&pdev->dev, r);
-               if (IS_ERR(onenand->dma_addr))
-                       return PTR_ERR(onenand->dma_addr);
-
-               s5pc110_dma_ops = s5pc110_dma_poll;
-               /* Interrupt support */
-               r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-               if (r) {
-                       init_completion(&onenand->complete);
-                       s5pc110_dma_ops = s5pc110_dma_irq;
-                       err = devm_request_irq(&pdev->dev, r->start,
-                                              s5pc110_onenand_irq,
-                                              IRQF_SHARED, "onenand",
-                                              &onenand);
-                       if (err) {
-                               dev_err(&pdev->dev, "failed to get irq\n");
-                               return err;
-                       }
-               }
-       }
-
-       err = onenand_scan(mtd, 1);
-       if (err)
-               return err;
-
-       if (onenand->type != TYPE_S5PC110) {
-               /* S3C doesn't handle subpage write */
-               mtd->subpage_sft = 0;
-               this->subpagesize = mtd->writesize;
-       }
-
-       if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
-               dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
-
-       err = mtd_device_register(mtd, pdata ? pdata->parts : NULL,
-                                 pdata ? pdata->nr_parts : 0);
-       if (err) {
-               dev_err(&pdev->dev, "failed to parse partitions and register the MTD device\n");
-               onenand_release(mtd);
-               return err;
-       }
-
-       platform_set_drvdata(pdev, mtd);
-
-       return 0;
-}
-
-static int s3c_onenand_remove(struct platform_device *pdev)
-{
-       struct mtd_info *mtd = platform_get_drvdata(pdev);
-
-       onenand_release(mtd);
-
-       return 0;
-}
-
-static int s3c_pm_ops_suspend(struct device *dev)
-{
-       struct mtd_info *mtd = dev_get_drvdata(dev);
-       struct onenand_chip *this = mtd->priv;
-
-       this->wait(mtd, FL_PM_SUSPENDED);
-       return 0;
-}
-
-static  int s3c_pm_ops_resume(struct device *dev)
-{
-       struct mtd_info *mtd = dev_get_drvdata(dev);
-       struct onenand_chip *this = mtd->priv;
-
-       this->unlock_all(mtd);
-       return 0;
-}
-
-static const struct dev_pm_ops s3c_pm_ops = {
-       .suspend        = s3c_pm_ops_suspend,
-       .resume         = s3c_pm_ops_resume,
-};
-
-static const struct platform_device_id s3c_onenand_driver_ids[] = {
-       {
-               .name           = "s3c6400-onenand",
-               .driver_data    = TYPE_S3C6400,
-       }, {
-               .name           = "s3c6410-onenand",
-               .driver_data    = TYPE_S3C6410,
-       }, {
-               .name           = "s5pc110-onenand",
-               .driver_data    = TYPE_S5PC110,
-       }, { },
-};
-MODULE_DEVICE_TABLE(platform, s3c_onenand_driver_ids);
-
-static struct platform_driver s3c_onenand_driver = {
-       .driver         = {
-               .name   = "samsung-onenand",
-               .pm     = &s3c_pm_ops,
-       },
-       .id_table       = s3c_onenand_driver_ids,
-       .probe          = s3c_onenand_probe,
-       .remove         = s3c_onenand_remove,
-};
-
-module_platform_driver(s3c_onenand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
-MODULE_DESCRIPTION("Samsung OneNAND controller support");
diff --git a/drivers/mtd/nand/onenand/samsung_mtd.c b/drivers/mtd/nand/onenand/samsung_mtd.c
new file mode 100644 (file)
index 0000000..55e5536
--- /dev/null
@@ -0,0 +1,1006 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Samsung S3C64XX/S5PC1XX OneNAND driver
+ *
+ *  Copyright © 2008-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Implementation:
+ *     S3C64XX: emulate the pseudo BufferRAM
+ *     S5PC110: use DMA
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include "samsung.h"
+
+enum soc_type {
+       TYPE_S3C6400,
+       TYPE_S3C6410,
+       TYPE_S5PC110,
+};
+
+#define ONENAND_ERASE_STATUS           0x00
+#define ONENAND_MULTI_ERASE_SET                0x01
+#define ONENAND_ERASE_START            0x03
+#define ONENAND_UNLOCK_START           0x08
+#define ONENAND_UNLOCK_END             0x09
+#define ONENAND_LOCK_START             0x0A
+#define ONENAND_LOCK_END               0x0B
+#define ONENAND_LOCK_TIGHT_START       0x0C
+#define ONENAND_LOCK_TIGHT_END         0x0D
+#define ONENAND_UNLOCK_ALL             0x0E
+#define ONENAND_OTP_ACCESS             0x12
+#define ONENAND_SPARE_ACCESS_ONLY      0x13
+#define ONENAND_MAIN_ACCESS_ONLY       0x14
+#define ONENAND_ERASE_VERIFY           0x15
+#define ONENAND_MAIN_SPARE_ACCESS      0x16
+#define ONENAND_PIPELINE_READ          0x4000
+
+#define MAP_00                         (0x0)
+#define MAP_01                         (0x1)
+#define MAP_10                         (0x2)
+#define MAP_11                         (0x3)
+
+#define S3C64XX_CMD_MAP_SHIFT          24
+
+#define S3C6400_FBA_SHIFT              10
+#define S3C6400_FPA_SHIFT              4
+#define S3C6400_FSA_SHIFT              2
+
+#define S3C6410_FBA_SHIFT              12
+#define S3C6410_FPA_SHIFT              6
+#define S3C6410_FSA_SHIFT              4
+
+/* S5PC110 specific definitions */
+#define S5PC110_DMA_SRC_ADDR           0x400
+#define S5PC110_DMA_SRC_CFG            0x404
+#define S5PC110_DMA_DST_ADDR           0x408
+#define S5PC110_DMA_DST_CFG            0x40C
+#define S5PC110_DMA_TRANS_SIZE         0x414
+#define S5PC110_DMA_TRANS_CMD          0x418
+#define S5PC110_DMA_TRANS_STATUS       0x41C
+#define S5PC110_DMA_TRANS_DIR          0x420
+#define S5PC110_INTC_DMA_CLR           0x1004
+#define S5PC110_INTC_ONENAND_CLR       0x1008
+#define S5PC110_INTC_DMA_MASK          0x1024
+#define S5PC110_INTC_ONENAND_MASK      0x1028
+#define S5PC110_INTC_DMA_PEND          0x1044
+#define S5PC110_INTC_ONENAND_PEND      0x1048
+#define S5PC110_INTC_DMA_STATUS                0x1064
+#define S5PC110_INTC_ONENAND_STATUS    0x1068
+
+#define S5PC110_INTC_DMA_TD            (1 << 24)
+#define S5PC110_INTC_DMA_TE            (1 << 16)
+
+#define S5PC110_DMA_CFG_SINGLE         (0x0 << 16)
+#define S5PC110_DMA_CFG_4BURST         (0x2 << 16)
+#define S5PC110_DMA_CFG_8BURST         (0x3 << 16)
+#define S5PC110_DMA_CFG_16BURST                (0x4 << 16)
+
+#define S5PC110_DMA_CFG_INC            (0x0 << 8)
+#define S5PC110_DMA_CFG_CNT            (0x1 << 8)
+
+#define S5PC110_DMA_CFG_8BIT           (0x0 << 0)
+#define S5PC110_DMA_CFG_16BIT          (0x1 << 0)
+#define S5PC110_DMA_CFG_32BIT          (0x2 << 0)
+
+#define S5PC110_DMA_SRC_CFG_READ       (S5PC110_DMA_CFG_16BURST | \
+                                       S5PC110_DMA_CFG_INC | \
+                                       S5PC110_DMA_CFG_16BIT)
+#define S5PC110_DMA_DST_CFG_READ       (S5PC110_DMA_CFG_16BURST | \
+                                       S5PC110_DMA_CFG_INC | \
+                                       S5PC110_DMA_CFG_32BIT)
+#define S5PC110_DMA_SRC_CFG_WRITE      (S5PC110_DMA_CFG_16BURST | \
+                                       S5PC110_DMA_CFG_INC | \
+                                       S5PC110_DMA_CFG_32BIT)
+#define S5PC110_DMA_DST_CFG_WRITE      (S5PC110_DMA_CFG_16BURST | \
+                                       S5PC110_DMA_CFG_INC | \
+                                       S5PC110_DMA_CFG_16BIT)
+
+#define S5PC110_DMA_TRANS_CMD_TDC      (0x1 << 18)
+#define S5PC110_DMA_TRANS_CMD_TEC      (0x1 << 16)
+#define S5PC110_DMA_TRANS_CMD_TR       (0x1 << 0)
+
+#define S5PC110_DMA_TRANS_STATUS_TD    (0x1 << 18)
+#define S5PC110_DMA_TRANS_STATUS_TB    (0x1 << 17)
+#define S5PC110_DMA_TRANS_STATUS_TE    (0x1 << 16)
+
+#define S5PC110_DMA_DIR_READ           0x0
+#define S5PC110_DMA_DIR_WRITE          0x1
+
+struct s3c_onenand {
+       struct mtd_info *mtd;
+       struct platform_device  *pdev;
+       enum soc_type   type;
+       void __iomem    *base;
+       void __iomem    *ahb_addr;
+       int             bootram_command;
+       void            *page_buf;
+       void            *oob_buf;
+       unsigned int    (*mem_addr)(int fba, int fpa, int fsa);
+       unsigned int    (*cmd_map)(unsigned int type, unsigned int val);
+       void __iomem    *dma_addr;
+       unsigned long   phys_base;
+       struct completion       complete;
+};
+
+#define CMD_MAP_00(dev, addr)          (dev->cmd_map(MAP_00, ((addr) << 1)))
+#define CMD_MAP_01(dev, mem_addr)      (dev->cmd_map(MAP_01, (mem_addr)))
+#define CMD_MAP_10(dev, mem_addr)      (dev->cmd_map(MAP_10, (mem_addr)))
+#define CMD_MAP_11(dev, addr)          (dev->cmd_map(MAP_11, ((addr) << 2)))
+
+static struct s3c_onenand *onenand;
+
+static inline int s3c_read_reg(int offset)
+{
+       return readl(onenand->base + offset);
+}
+
+static inline void s3c_write_reg(int value, int offset)
+{
+       writel(value, onenand->base + offset);
+}
+
+static inline int s3c_read_cmd(unsigned int cmd)
+{
+       return readl(onenand->ahb_addr + cmd);
+}
+
+static inline void s3c_write_cmd(int value, unsigned int cmd)
+{
+       writel(value, onenand->ahb_addr + cmd);
+}
+
+#ifdef SAMSUNG_DEBUG
+static void s3c_dump_reg(void)
+{
+       int i;
+
+       for (i = 0; i < 0x400; i += 0x40) {
+               printk(KERN_INFO "0x%08X: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       (unsigned int) onenand->base + i,
+                       s3c_read_reg(i), s3c_read_reg(i + 0x10),
+                       s3c_read_reg(i + 0x20), s3c_read_reg(i + 0x30));
+       }
+}
+#endif
+
+static unsigned int s3c64xx_cmd_map(unsigned type, unsigned val)
+{
+       return (type << S3C64XX_CMD_MAP_SHIFT) | val;
+}
+
+static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa)
+{
+       return (fba << S3C6400_FBA_SHIFT) | (fpa << S3C6400_FPA_SHIFT) |
+               (fsa << S3C6400_FSA_SHIFT);
+}
+
+static unsigned int s3c6410_mem_addr(int fba, int fpa, int fsa)
+{
+       return (fba << S3C6410_FBA_SHIFT) | (fpa << S3C6410_FPA_SHIFT) |
+               (fsa << S3C6410_FSA_SHIFT);
+}
+
+static void s3c_onenand_reset(void)
+{
+       unsigned long timeout = 0x10000;
+       int stat;
+
+       s3c_write_reg(ONENAND_MEM_RESET_COLD, MEM_RESET_OFFSET);
+       while (1 && timeout--) {
+               stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
+               if (stat & RST_CMP)
+                       break;
+       }
+       stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
+       s3c_write_reg(stat, INT_ERR_ACK_OFFSET);
+
+       /* Clear interrupt */
+       s3c_write_reg(0x0, INT_ERR_ACK_OFFSET);
+       /* Clear the ECC status */
+       s3c_write_reg(0x0, ECC_ERR_STAT_OFFSET);
+}
+
+static unsigned short s3c_onenand_readw(void __iomem *addr)
+{
+       struct onenand_chip *this = onenand->mtd->priv;
+       struct device *dev = &onenand->pdev->dev;
+       int reg = addr - this->base;
+       int word_addr = reg >> 1;
+       int value;
+
+       /* It's used for probing time */
+       switch (reg) {
+       case ONENAND_REG_MANUFACTURER_ID:
+               return s3c_read_reg(MANUFACT_ID_OFFSET);
+       case ONENAND_REG_DEVICE_ID:
+               return s3c_read_reg(DEVICE_ID_OFFSET);
+       case ONENAND_REG_VERSION_ID:
+               return s3c_read_reg(FLASH_VER_ID_OFFSET);
+       case ONENAND_REG_DATA_BUFFER_SIZE:
+               return s3c_read_reg(DATA_BUF_SIZE_OFFSET);
+       case ONENAND_REG_TECHNOLOGY:
+               return s3c_read_reg(TECH_OFFSET);
+       case ONENAND_REG_SYS_CFG1:
+               return s3c_read_reg(MEM_CFG_OFFSET);
+
+       /* Used at unlock all status */
+       case ONENAND_REG_CTRL_STATUS:
+               return 0;
+
+       case ONENAND_REG_WP_STATUS:
+               return ONENAND_WP_US;
+
+       default:
+               break;
+       }
+
+       /* BootRAM access control */
+       if ((unsigned int) addr < ONENAND_DATARAM && onenand->bootram_command) {
+               if (word_addr == 0)
+                       return s3c_read_reg(MANUFACT_ID_OFFSET);
+               if (word_addr == 1)
+                       return s3c_read_reg(DEVICE_ID_OFFSET);
+               if (word_addr == 2)
+                       return s3c_read_reg(FLASH_VER_ID_OFFSET);
+       }
+
+       value = s3c_read_cmd(CMD_MAP_11(onenand, word_addr)) & 0xffff;
+       dev_info(dev, "%s: Illegal access at reg 0x%x, value 0x%x\n", __func__,
+                word_addr, value);
+       return value;
+}
+
+static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
+{
+       struct onenand_chip *this = onenand->mtd->priv;
+       struct device *dev = &onenand->pdev->dev;
+       unsigned int reg = addr - this->base;
+       unsigned int word_addr = reg >> 1;
+
+       /* It's used for probing time */
+       switch (reg) {
+       case ONENAND_REG_SYS_CFG1:
+               s3c_write_reg(value, MEM_CFG_OFFSET);
+               return;
+
+       case ONENAND_REG_START_ADDRESS1:
+       case ONENAND_REG_START_ADDRESS2:
+               return;
+
+       /* Lock/lock-tight/unlock/unlock_all */
+       case ONENAND_REG_START_BLOCK_ADDRESS:
+               return;
+
+       default:
+               break;
+       }
+
+       /* BootRAM access control */
+       if ((unsigned int)addr < ONENAND_DATARAM) {
+               if (value == ONENAND_CMD_READID) {
+                       onenand->bootram_command = 1;
+                       return;
+               }
+               if (value == ONENAND_CMD_RESET) {
+                       s3c_write_reg(ONENAND_MEM_RESET_COLD, MEM_RESET_OFFSET);
+                       onenand->bootram_command = 0;
+                       return;
+               }
+       }
+
+       dev_info(dev, "%s: Illegal access at reg 0x%x, value 0x%x\n", __func__,
+                word_addr, value);
+
+       s3c_write_cmd(value, CMD_MAP_11(onenand, word_addr));
+}
+
+static int s3c_onenand_wait(struct mtd_info *mtd, int state)
+{
+       struct device *dev = &onenand->pdev->dev;
+       unsigned int flags = INT_ACT;
+       unsigned int stat, ecc;
+       unsigned long timeout;
+
+       switch (state) {
+       case FL_READING:
+               flags |= BLK_RW_CMP | LOAD_CMP;
+               break;
+       case FL_WRITING:
+               flags |= BLK_RW_CMP | PGM_CMP;
+               break;
+       case FL_ERASING:
+               flags |= BLK_RW_CMP | ERS_CMP;
+               break;
+       case FL_LOCKING:
+               flags |= BLK_RW_CMP;
+               break;
+       default:
+               break;
+       }
+
+       /* The 20 msec is enough */
+       timeout = jiffies + msecs_to_jiffies(20);
+       while (time_before(jiffies, timeout)) {
+               stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
+               if (stat & flags)
+                       break;
+
+               if (state != FL_READING)
+                       cond_resched();
+       }
+       /* To get correct interrupt status in timeout case */
+       stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
+       s3c_write_reg(stat, INT_ERR_ACK_OFFSET);
+
+       /*
+        * In the Spec. it checks the controller status first
+        * However if you get the correct information in case of
+        * power off recovery (POR) test, it should read ECC status first
+        */
+       if (stat & LOAD_CMP) {
+               ecc = s3c_read_reg(ECC_ERR_STAT_OFFSET);
+               if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
+                       dev_info(dev, "%s: ECC error = 0x%04x\n", __func__,
+                                ecc);
+                       mtd->ecc_stats.failed++;
+                       return -EBADMSG;
+               }
+       }
+
+       if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) {
+               dev_info(dev, "%s: controller error = 0x%04x\n", __func__,
+                        stat);
+               if (stat & LOCKED_BLK)
+                       dev_info(dev, "%s: it's locked error = 0x%04x\n",
+                                __func__, stat);
+
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int s3c_onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
+                              size_t len)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned int *m, *s;
+       int fba, fpa, fsa = 0;
+       unsigned int mem_addr, cmd_map_01, cmd_map_10;
+       int i, mcount, scount;
+       int index;
+
+       fba = (int) (addr >> this->erase_shift);
+       fpa = (int) (addr >> this->page_shift);
+       fpa &= this->page_mask;
+
+       mem_addr = onenand->mem_addr(fba, fpa, fsa);
+       cmd_map_01 = CMD_MAP_01(onenand, mem_addr);
+       cmd_map_10 = CMD_MAP_10(onenand, mem_addr);
+
+       switch (cmd) {
+       case ONENAND_CMD_READ:
+       case ONENAND_CMD_READOOB:
+       case ONENAND_CMD_BUFFERRAM:
+               ONENAND_SET_NEXT_BUFFERRAM(this);
+       default:
+               break;
+       }
+
+       index = ONENAND_CURRENT_BUFFERRAM(this);
+
+       /*
+        * Emulate Two BufferRAMs and access with 4 bytes pointer
+        */
+       m = onenand->page_buf;
+       s = onenand->oob_buf;
+
+       if (index) {
+               m += (this->writesize >> 2);
+               s += (mtd->oobsize >> 2);
+       }
+
+       mcount = mtd->writesize >> 2;
+       scount = mtd->oobsize >> 2;
+
+       switch (cmd) {
+       case ONENAND_CMD_READ:
+               /* Main */
+               for (i = 0; i < mcount; i++)
+                       *m++ = s3c_read_cmd(cmd_map_01);
+               return 0;
+
+       case ONENAND_CMD_READOOB:
+               s3c_write_reg(TSRF, TRANS_SPARE_OFFSET);
+               /* Main */
+               for (i = 0; i < mcount; i++)
+                       *m++ = s3c_read_cmd(cmd_map_01);
+
+               /* Spare */
+               for (i = 0; i < scount; i++)
+                       *s++ = s3c_read_cmd(cmd_map_01);
+
+               s3c_write_reg(0, TRANS_SPARE_OFFSET);
+               return 0;
+
+       case ONENAND_CMD_PROG:
+               /* Main */
+               for (i = 0; i < mcount; i++)
+                       s3c_write_cmd(*m++, cmd_map_01);
+               return 0;
+
+       case ONENAND_CMD_PROGOOB:
+               s3c_write_reg(TSRF, TRANS_SPARE_OFFSET);
+
+               /* Main - dummy write */
+               for (i = 0; i < mcount; i++)
+                       s3c_write_cmd(0xffffffff, cmd_map_01);
+
+               /* Spare */
+               for (i = 0; i < scount; i++)
+                       s3c_write_cmd(*s++, cmd_map_01);
+
+               s3c_write_reg(0, TRANS_SPARE_OFFSET);
+               return 0;
+
+       case ONENAND_CMD_UNLOCK_ALL:
+               s3c_write_cmd(ONENAND_UNLOCK_ALL, cmd_map_10);
+               return 0;
+
+       case ONENAND_CMD_ERASE:
+               s3c_write_cmd(ONENAND_ERASE_START, cmd_map_10);
+               return 0;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area)
+{
+       struct onenand_chip *this = mtd->priv;
+       int index = ONENAND_CURRENT_BUFFERRAM(this);
+       unsigned char *p;
+
+       if (area == ONENAND_DATARAM) {
+               p = onenand->page_buf;
+               if (index == 1)
+                       p += this->writesize;
+       } else {
+               p = onenand->oob_buf;
+               if (index == 1)
+                       p += mtd->oobsize;
+       }
+
+       return p;
+}
+
+static int onenand_read_bufferram(struct mtd_info *mtd, int area,
+                                 unsigned char *buffer, int offset,
+                                 size_t count)
+{
+       unsigned char *p;
+
+       p = s3c_get_bufferram(mtd, area);
+       memcpy(buffer, p + offset, count);
+       return 0;
+}
+
+static int onenand_write_bufferram(struct mtd_info *mtd, int area,
+                                  const unsigned char *buffer, int offset,
+                                  size_t count)
+{
+       unsigned char *p;
+
+       p = s3c_get_bufferram(mtd, area);
+       memcpy(p + offset, buffer, count);
+       return 0;
+}
+
+static int (*s5pc110_dma_ops)(dma_addr_t dst, dma_addr_t src, size_t count, int direction);
+
+static int s5pc110_dma_poll(dma_addr_t dst, dma_addr_t src, size_t count, int direction)
+{
+       void __iomem *base = onenand->dma_addr;
+       int status;
+       unsigned long timeout;
+
+       writel(src, base + S5PC110_DMA_SRC_ADDR);
+       writel(dst, base + S5PC110_DMA_DST_ADDR);
+
+       if (direction == S5PC110_DMA_DIR_READ) {
+               writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG);
+               writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG);
+       } else {
+               writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG);
+               writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG);
+       }
+
+       writel(count, base + S5PC110_DMA_TRANS_SIZE);
+       writel(direction, base + S5PC110_DMA_TRANS_DIR);
+
+       writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
+
+       /*
+        * There's no exact timeout values at Spec.
+        * In real case it takes under 1 msec.
+        * So 20 msecs are enough.
+        */
+       timeout = jiffies + msecs_to_jiffies(20);
+
+       do {
+               status = readl(base + S5PC110_DMA_TRANS_STATUS);
+               if (status & S5PC110_DMA_TRANS_STATUS_TE) {
+                       writel(S5PC110_DMA_TRANS_CMD_TEC,
+                                       base + S5PC110_DMA_TRANS_CMD);
+                       return -EIO;
+               }
+       } while (!(status & S5PC110_DMA_TRANS_STATUS_TD) &&
+               time_before(jiffies, timeout));
+
+       writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD);
+
+       return 0;
+}
+
+static irqreturn_t s5pc110_onenand_irq(int irq, void *data)
+{
+       void __iomem *base = onenand->dma_addr;
+       int status, cmd = 0;
+
+       status = readl(base + S5PC110_INTC_DMA_STATUS);
+
+       if (likely(status & S5PC110_INTC_DMA_TD))
+               cmd = S5PC110_DMA_TRANS_CMD_TDC;
+
+       if (unlikely(status & S5PC110_INTC_DMA_TE))
+               cmd = S5PC110_DMA_TRANS_CMD_TEC;
+
+       writel(cmd, base + S5PC110_DMA_TRANS_CMD);
+       writel(status, base + S5PC110_INTC_DMA_CLR);
+
+       if (!onenand->complete.done)
+               complete(&onenand->complete);
+
+       return IRQ_HANDLED;
+}
+
+static int s5pc110_dma_irq(dma_addr_t dst, dma_addr_t src, size_t count, int direction)
+{
+       void __iomem *base = onenand->dma_addr;
+       int status;
+
+       status = readl(base + S5PC110_INTC_DMA_MASK);
+       if (status) {
+               status &= ~(S5PC110_INTC_DMA_TD | S5PC110_INTC_DMA_TE);
+               writel(status, base + S5PC110_INTC_DMA_MASK);
+       }
+
+       writel(src, base + S5PC110_DMA_SRC_ADDR);
+       writel(dst, base + S5PC110_DMA_DST_ADDR);
+
+       if (direction == S5PC110_DMA_DIR_READ) {
+               writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG);
+               writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG);
+       } else {
+               writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG);
+               writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG);
+       }
+
+       writel(count, base + S5PC110_DMA_TRANS_SIZE);
+       writel(direction, base + S5PC110_DMA_TRANS_DIR);
+
+       writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
+
+       wait_for_completion_timeout(&onenand->complete, msecs_to_jiffies(20));
+
+       return 0;
+}
+
+static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
+               unsigned char *buffer, int offset, size_t count)
+{
+       struct onenand_chip *this = mtd->priv;
+       void __iomem *p;
+       void *buf = (void *) buffer;
+       dma_addr_t dma_src, dma_dst;
+       int err, ofs, page_dma = 0;
+       struct device *dev = &onenand->pdev->dev;
+
+       p = this->base + area;
+       if (ONENAND_CURRENT_BUFFERRAM(this)) {
+               if (area == ONENAND_DATARAM)
+                       p += this->writesize;
+               else
+                       p += mtd->oobsize;
+       }
+
+       if (offset & 3 || (size_t) buf & 3 ||
+               !onenand->dma_addr || count != mtd->writesize)
+               goto normal;
+
+       /* Handle vmalloc address */
+       if (buf >= high_memory) {
+               struct page *page;
+
+               if (((size_t) buf & PAGE_MASK) !=
+                   ((size_t) (buf + count - 1) & PAGE_MASK))
+                       goto normal;
+               page = vmalloc_to_page(buf);
+               if (!page)
+                       goto normal;
+
+               /* Page offset */
+               ofs = ((size_t) buf & ~PAGE_MASK);
+               page_dma = 1;
+
+               /* DMA routine */
+               dma_src = onenand->phys_base + (p - this->base);
+               dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE);
+       } else {
+               /* DMA routine */
+               dma_src = onenand->phys_base + (p - this->base);
+               dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
+       }
+       if (dma_mapping_error(dev, dma_dst)) {
+               dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count);
+               goto normal;
+       }
+       err = s5pc110_dma_ops(dma_dst, dma_src,
+                       count, S5PC110_DMA_DIR_READ);
+
+       if (page_dma)
+               dma_unmap_page(dev, dma_dst, count, DMA_FROM_DEVICE);
+       else
+               dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE);
+
+       if (!err)
+               return 0;
+
+normal:
+       if (count != mtd->writesize) {
+               /* Copy the bufferram to memory to prevent unaligned access */
+               memcpy(this->page_buf, p, mtd->writesize);
+               p = this->page_buf + offset;
+       }
+
+       memcpy(buffer, p, count);
+
+       return 0;
+}
+
+static int s5pc110_chip_probe(struct mtd_info *mtd)
+{
+       /* Now just return 0 */
+       return 0;
+}
+
+static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state)
+{
+       unsigned int flags = INT_ACT | LOAD_CMP;
+       unsigned int stat;
+       unsigned long timeout;
+
+       /* The 20 msec is enough */
+       timeout = jiffies + msecs_to_jiffies(20);
+       while (time_before(jiffies, timeout)) {
+               stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
+               if (stat & flags)
+                       break;
+       }
+       /* To get correct interrupt status in timeout case */
+       stat = s3c_read_reg(INT_ERR_STAT_OFFSET);
+       s3c_write_reg(stat, INT_ERR_ACK_OFFSET);
+
+       if (stat & LD_FAIL_ECC_ERR) {
+               s3c_onenand_reset();
+               return ONENAND_BBT_READ_ERROR;
+       }
+
+       if (stat & LOAD_CMP) {
+               int ecc = s3c_read_reg(ECC_ERR_STAT_OFFSET);
+               if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
+                       s3c_onenand_reset();
+                       return ONENAND_BBT_READ_ERROR;
+               }
+       }
+
+       return 0;
+}
+
+static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct device *dev = &onenand->pdev->dev;
+       unsigned int block, end;
+       int tmp;
+
+       end = this->chipsize >> this->erase_shift;
+
+       for (block = 0; block < end; block++) {
+               unsigned int mem_addr = onenand->mem_addr(block, 0, 0);
+               tmp = s3c_read_cmd(CMD_MAP_01(onenand, mem_addr));
+
+               if (s3c_read_reg(INT_ERR_STAT_OFFSET) & LOCKED_BLK) {
+                       dev_err(dev, "block %d is write-protected!\n", block);
+                       s3c_write_reg(LOCKED_BLK, INT_ERR_ACK_OFFSET);
+               }
+       }
+}
+
+static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
+                                   size_t len, int cmd)
+{
+       struct onenand_chip *this = mtd->priv;
+       int start, end, start_mem_addr, end_mem_addr;
+
+       start = ofs >> this->erase_shift;
+       start_mem_addr = onenand->mem_addr(start, 0, 0);
+       end = start + (len >> this->erase_shift) - 1;
+       end_mem_addr = onenand->mem_addr(end, 0, 0);
+
+       if (cmd == ONENAND_CMD_LOCK) {
+               s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(onenand,
+                                                            start_mem_addr));
+               s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(onenand,
+                                                          end_mem_addr));
+       } else {
+               s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(onenand,
+                                                              start_mem_addr));
+               s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(onenand,
+                                                            end_mem_addr));
+       }
+
+       this->wait(mtd, FL_LOCKING);
+}
+
+static void s3c_unlock_all(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+       loff_t ofs = 0;
+       size_t len = this->chipsize;
+
+       if (this->options & ONENAND_HAS_UNLOCK_ALL) {
+               /* Write unlock command */
+               this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
+
+               /* No need to check return value */
+               this->wait(mtd, FL_LOCKING);
+
+               /* Workaround for all block unlock in DDP */
+               if (!ONENAND_IS_DDP(this)) {
+                       s3c_onenand_check_lock_status(mtd);
+                       return;
+               }
+
+               /* All blocks on another chip */
+               ofs = this->chipsize >> 1;
+               len = this->chipsize >> 1;
+       }
+
+       s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+
+       s3c_onenand_check_lock_status(mtd);
+}
+
+static void s3c_onenand_setup(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       onenand->mtd = mtd;
+
+       if (onenand->type == TYPE_S3C6400) {
+               onenand->mem_addr = s3c6400_mem_addr;
+               onenand->cmd_map = s3c64xx_cmd_map;
+       } else if (onenand->type == TYPE_S3C6410) {
+               onenand->mem_addr = s3c6410_mem_addr;
+               onenand->cmd_map = s3c64xx_cmd_map;
+       } else if (onenand->type == TYPE_S5PC110) {
+               /* Use generic onenand functions */
+               this->read_bufferram = s5pc110_read_bufferram;
+               this->chip_probe = s5pc110_chip_probe;
+               return;
+       } else {
+               BUG();
+       }
+
+       this->read_word = s3c_onenand_readw;
+       this->write_word = s3c_onenand_writew;
+
+       this->wait = s3c_onenand_wait;
+       this->bbt_wait = s3c_onenand_bbt_wait;
+       this->unlock_all = s3c_unlock_all;
+       this->command = s3c_onenand_command;
+
+       this->read_bufferram = onenand_read_bufferram;
+       this->write_bufferram = onenand_write_bufferram;
+}
+
+static int s3c_onenand_probe(struct platform_device *pdev)
+{
+       struct onenand_platform_data *pdata;
+       struct onenand_chip *this;
+       struct mtd_info *mtd;
+       struct resource *r;
+       int size, err;
+
+       pdata = dev_get_platdata(&pdev->dev);
+       /* No need to check pdata. the platform data is optional */
+
+       size = sizeof(struct mtd_info) + sizeof(struct onenand_chip);
+       mtd = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!mtd)
+               return -ENOMEM;
+
+       onenand = devm_kzalloc(&pdev->dev, sizeof(struct s3c_onenand),
+                              GFP_KERNEL);
+       if (!onenand)
+               return -ENOMEM;
+
+       this = (struct onenand_chip *) &mtd[1];
+       mtd->priv = this;
+       mtd->dev.parent = &pdev->dev;
+       onenand->pdev = pdev;
+       onenand->type = platform_get_device_id(pdev)->driver_data;
+
+       s3c_onenand_setup(mtd);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       onenand->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(onenand->base))
+               return PTR_ERR(onenand->base);
+
+       onenand->phys_base = r->start;
+
+       /* Set onenand_chip also */
+       this->base = onenand->base;
+
+       /* Use runtime badblock check */
+       this->options |= ONENAND_SKIP_UNLOCK_CHECK;
+
+       if (onenand->type != TYPE_S5PC110) {
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               onenand->ahb_addr = devm_ioremap_resource(&pdev->dev, r);
+               if (IS_ERR(onenand->ahb_addr))
+                       return PTR_ERR(onenand->ahb_addr);
+
+               /* Allocate 4KiB BufferRAM */
+               onenand->page_buf = devm_kzalloc(&pdev->dev, SZ_4K,
+                                                GFP_KERNEL);
+               if (!onenand->page_buf)
+                       return -ENOMEM;
+
+               /* Allocate 128 SpareRAM */
+               onenand->oob_buf = devm_kzalloc(&pdev->dev, 128, GFP_KERNEL);
+               if (!onenand->oob_buf)
+                       return -ENOMEM;
+
+               /* S3C doesn't handle subpage write */
+               mtd->subpage_sft = 0;
+               this->subpagesize = mtd->writesize;
+
+       } else { /* S5PC110 */
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               onenand->dma_addr = devm_ioremap_resource(&pdev->dev, r);
+               if (IS_ERR(onenand->dma_addr))
+                       return PTR_ERR(onenand->dma_addr);
+
+               s5pc110_dma_ops = s5pc110_dma_poll;
+               /* Interrupt support */
+               r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+               if (r) {
+                       init_completion(&onenand->complete);
+                       s5pc110_dma_ops = s5pc110_dma_irq;
+                       err = devm_request_irq(&pdev->dev, r->start,
+                                              s5pc110_onenand_irq,
+                                              IRQF_SHARED, "onenand",
+                                              &onenand);
+                       if (err) {
+                               dev_err(&pdev->dev, "failed to get irq\n");
+                               return err;
+                       }
+               }
+       }
+
+       err = onenand_scan(mtd, 1);
+       if (err)
+               return err;
+
+       if (onenand->type != TYPE_S5PC110) {
+               /* S3C doesn't handle subpage write */
+               mtd->subpage_sft = 0;
+               this->subpagesize = mtd->writesize;
+       }
+
+       if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
+               dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
+
+       err = mtd_device_register(mtd, pdata ? pdata->parts : NULL,
+                                 pdata ? pdata->nr_parts : 0);
+       if (err) {
+               dev_err(&pdev->dev, "failed to parse partitions and register the MTD device\n");
+               onenand_release(mtd);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, mtd);
+
+       return 0;
+}
+
+static int s3c_onenand_remove(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+
+       onenand_release(mtd);
+
+       return 0;
+}
+
+static int s3c_pm_ops_suspend(struct device *dev)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       struct onenand_chip *this = mtd->priv;
+
+       this->wait(mtd, FL_PM_SUSPENDED);
+       return 0;
+}
+
+static  int s3c_pm_ops_resume(struct device *dev)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       struct onenand_chip *this = mtd->priv;
+
+       this->unlock_all(mtd);
+       return 0;
+}
+
+static const struct dev_pm_ops s3c_pm_ops = {
+       .suspend        = s3c_pm_ops_suspend,
+       .resume         = s3c_pm_ops_resume,
+};
+
+static const struct platform_device_id s3c_onenand_driver_ids[] = {
+       {
+               .name           = "s3c6400-onenand",
+               .driver_data    = TYPE_S3C6400,
+       }, {
+               .name           = "s3c6410-onenand",
+               .driver_data    = TYPE_S3C6410,
+       }, {
+               .name           = "s5pc110-onenand",
+               .driver_data    = TYPE_S5PC110,
+       }, { },
+};
+MODULE_DEVICE_TABLE(platform, s3c_onenand_driver_ids);
+
+static struct platform_driver s3c_onenand_driver = {
+       .driver         = {
+               .name   = "samsung-onenand",
+               .pm     = &s3c_pm_ops,
+       },
+       .id_table       = s3c_onenand_driver_ids,
+       .probe          = s3c_onenand_probe,
+       .remove         = s3c_onenand_remove,
+};
+
+module_platform_driver(s3c_onenand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("Samsung OneNAND controller support");
index 0f847d5..54646c2 100644 (file)
@@ -107,6 +107,7 @@ void ubi_dump_vol_info(const struct ubi_volume *vol)
        pr_err("\tlast_eb_bytes   %d\n", vol->last_eb_bytes);
        pr_err("\tcorrupted       %d\n", vol->corrupted);
        pr_err("\tupd_marker      %d\n", vol->upd_marker);
+       pr_err("\tskip_check      %d\n", vol->skip_check);
 
        if (vol->name_len <= UBI_VOL_NAME_MAX &&
            strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
index c44c847..426820a 100644 (file)
@@ -57,18 +57,6 @@ static void return_unused_pool_pebs(struct ubi_device *ubi,
        }
 }
 
-static int anchor_pebs_available(struct rb_root *root)
-{
-       struct rb_node *p;
-       struct ubi_wl_entry *e;
-
-       ubi_rb_for_each_entry(p, e, root, u.rb)
-               if (e->pnum < UBI_FM_MAX_START)
-                       return 1;
-
-       return 0;
-}
-
 /**
  * ubi_wl_get_fm_peb - find a physical erase block with a given maximal number.
  * @ubi: UBI device description object
@@ -277,8 +265,26 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
 int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
 {
        struct ubi_work *wrk;
+       struct ubi_wl_entry *anchor;
 
        spin_lock(&ubi->wl_lock);
+
+       /* Do we already have an anchor? */
+       if (ubi->fm_anchor) {
+               spin_unlock(&ubi->wl_lock);
+               return 0;
+       }
+
+       /* See if we can find an anchor PEB on the list of free PEBs */
+       anchor = ubi_wl_get_fm_peb(ubi, 1);
+       if (anchor) {
+               ubi->fm_anchor = anchor;
+               spin_unlock(&ubi->wl_lock);
+               return 0;
+       }
+
+       /* No luck, trigger wear leveling to produce a new anchor PEB */
+       ubi->fm_do_produce_anchor = 1;
        if (ubi->wl_scheduled) {
                spin_unlock(&ubi->wl_lock);
                return 0;
@@ -294,7 +300,6 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
                return -ENOMEM;
        }
 
-       wrk->anchor = 1;
        wrk->func = &wear_leveling_worker;
        __schedule_ubi_work(ubi, wrk);
        return 0;
index 30621c6..1c7be4e 100644 (file)
@@ -1540,14 +1540,6 @@ int ubi_update_fastmap(struct ubi_device *ubi)
                return 0;
        }
 
-       ret = ubi_ensure_anchor_pebs(ubi);
-       if (ret) {
-               up_write(&ubi->fm_eba_sem);
-               up_write(&ubi->work_sem);
-               up_write(&ubi->fm_protect);
-               return ret;
-       }
-
        new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL);
        if (!new_fm) {
                up_write(&ubi->fm_eba_sem);
@@ -1618,7 +1610,8 @@ int ubi_update_fastmap(struct ubi_device *ubi)
        }
 
        spin_lock(&ubi->wl_lock);
-       tmp_e = ubi_wl_get_fm_peb(ubi, 1);
+       tmp_e = ubi->fm_anchor;
+       ubi->fm_anchor = NULL;
        spin_unlock(&ubi->wl_lock);
 
        if (old_fm) {
@@ -1670,6 +1663,9 @@ out_unlock:
        up_write(&ubi->work_sem);
        up_write(&ubi->fm_protect);
        kfree(old_fm);
+
+       ubi_ensure_anchor_pebs(ubi);
+
        return ret;
 
 err:
index 721b6aa..9688b41 100644 (file)
@@ -491,6 +491,8 @@ struct ubi_debug_info {
  * @fm_work: fastmap work queue
  * @fm_work_scheduled: non-zero if fastmap work was scheduled
  * @fast_attach: non-zero if UBI was attached by fastmap
+ * @fm_anchor: The next anchor PEB to use for fastmap
+ * @fm_do_produce_anchor: If true produce an anchor PEB in wl
  *
  * @used: RB-tree of used physical eraseblocks
  * @erroneous: RB-tree of erroneous used physical eraseblocks
@@ -599,6 +601,8 @@ struct ubi_device {
        struct work_struct fm_work;
        int fm_work_scheduled;
        int fast_attach;
+       struct ubi_wl_entry *fm_anchor;
+       int fm_do_produce_anchor;
 
        /* Wear-leveling sub-system's stuff */
        struct rb_root used;
@@ -789,7 +793,6 @@ struct ubi_attach_info {
  * @vol_id: the volume ID on which this erasure is being performed
  * @lnum: the logical eraseblock number
  * @torture: if the physical eraseblock has to be tortured
- * @anchor: produce a anchor PEB to by used by fastmap
  *
  * The @func pointer points to the worker function. If the @shutdown argument is
  * not zero, the worker has to free the resources and exit immediately as the
@@ -805,7 +808,6 @@ struct ubi_work {
        int vol_id;
        int lnum;
        int torture;
-       int anchor;
 };
 
 #include "debug.h"
@@ -968,7 +970,7 @@ int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count);
 void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol);
 #else
 static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
-int static inline ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) { return 0; }
+static inline int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) { return 0; }
 static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {}
 #endif
 
index 3fcdefe..5d77a38 100644 (file)
@@ -339,13 +339,6 @@ static struct ubi_wl_entry *find_wl_entry(struct ubi_device *ubi,
                }
        }
 
-       /* If no fastmap has been written and this WL entry can be used
-        * as anchor PEB, hold it back and return the second best WL entry
-        * such that fastmap can use the anchor PEB later. */
-       if (prev_e && !ubi->fm_disabled &&
-           !ubi->fm && e->pnum < UBI_FM_MAX_START)
-               return prev_e;
-
        return e;
 }
 
@@ -656,9 +649,6 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
 {
        int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
        int erase = 0, keep = 0, vol_id = -1, lnum = -1;
-#ifdef CONFIG_MTD_UBI_FASTMAP
-       int anchor = wrk->anchor;
-#endif
        struct ubi_wl_entry *e1, *e2;
        struct ubi_vid_io_buf *vidb;
        struct ubi_vid_hdr *vid_hdr;
@@ -698,11 +688,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
        }
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
-       /* Check whether we need to produce an anchor PEB */
-       if (!anchor)
-               anchor = !anchor_pebs_available(&ubi->free);
-
-       if (anchor) {
+       if (ubi->fm_do_produce_anchor) {
                e1 = find_anchor_wl_entry(&ubi->used);
                if (!e1)
                        goto out_cancel;
@@ -719,6 +705,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                self_check_in_wl_tree(ubi, e1, &ubi->used);
                rb_erase(&e1->u.rb, &ubi->used);
                dbg_wl("anchor-move PEB %d to PEB %d", e1->pnum, e2->pnum);
+               ubi->fm_do_produce_anchor = 0;
        } else if (!ubi->scrub.rb_node) {
 #else
        if (!ubi->scrub.rb_node) {
@@ -1051,7 +1038,6 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
                goto out_cancel;
        }
 
-       wrk->anchor = 0;
        wrk->func = &wear_leveling_worker;
        if (nested)
                __schedule_ubi_work(ubi, wrk);
@@ -1093,8 +1079,15 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
        err = sync_erase(ubi, e, wl_wrk->torture);
        if (!err) {
                spin_lock(&ubi->wl_lock);
-               wl_tree_add(e, &ubi->free);
-               ubi->free_count++;
+
+               if (!ubi->fm_anchor && e->pnum < UBI_FM_MAX_START) {
+                       ubi->fm_anchor = e;
+                       ubi->fm_do_produce_anchor = 0;
+               } else {
+                       wl_tree_add(e, &ubi->free);
+                       ubi->free_count++;
+               }
+
                spin_unlock(&ubi->wl_lock);
 
                /*
@@ -1882,6 +1875,9 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
        if (err)
                goto out_free;
 
+#ifdef CONFIG_MTD_UBI_FASTMAP
+       ubi_ensure_anchor_pebs(ubi);
+#endif
        return 0;
 
 out_free:
index a9e2d66..c93a532 100644 (file)
@@ -2,7 +2,6 @@
 #ifndef UBI_WL_H
 #define UBI_WL_H
 #ifdef CONFIG_MTD_UBI_FASTMAP
-static int anchor_pebs_available(struct rb_root *root);
 static void update_fastmap_work_fn(struct work_struct *wrk);
 static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root);
 static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi);
index d5ae2e1..9c767ee 100644 (file)
@@ -4422,6 +4422,7 @@ static int macb_remove(struct platform_device *pdev)
                mdiobus_free(bp->mii_bus);
 
                unregister_netdev(dev);
+               tasklet_kill(&bp->hresp_err_tasklet);
                pm_runtime_disable(&pdev->dev);
                pm_runtime_dont_use_autosuspend(&pdev->dev);
                if (!pm_runtime_suspended(&pdev->dev)) {
index 17d300e..f51dca1 100644 (file)
@@ -49,4 +49,4 @@ config BE2NET_SKYHAWK
 
 comment "WARNING: be2net is useless without any enabled chip"
        depends on BE2NET_BE2=n && BE2NET_BE3=n && BE2NET_LANCER=n && \
-       BE2NET_SKYHAWK=n && BE2NET
+               BE2NET_SKYHAWK=n && BE2NET
index a6f2063..8ed8503 100644 (file)
@@ -1858,7 +1858,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
                }
 
                /* Indicate that we support PAUSE frames (see comment in
-                * Documentation/networking/phy.txt)
+                * Documentation/networking/phy.rst)
                 */
                phy_support_asym_pause(phy);
 
index c40729b..7fad2f2 100644 (file)
@@ -45,7 +45,6 @@
 
 #define BAR_0          0
 #define BAR_1          1
-#define BAR_5          5
 
 #define INTEL_E1000_ETHERNET_DEVICE(device_id) {\
        PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
index 416da96..aca97b0 100644 (file)
@@ -977,7 +977,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_ioremap;
 
        if (adapter->need_ioport) {
-               for (i = BAR_1; i <= BAR_5; i++) {
+               for (i = BAR_1; i < PCI_STD_NUM_BARS; i++) {
                        if (pci_resource_len(pdev, i) == 0)
                                continue;
                        if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
index e85271b..681d44c 100644 (file)
@@ -42,7 +42,6 @@
 
 #define BAR_0          0
 #define BAR_1          1
-#define BAR_5          5
 
 struct ixgb_adapter;
 #include "ixgb_hw.h"
index 0940a0d..3d8c051 100644 (file)
@@ -412,7 +412,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_ioremap;
        }
 
-       for (i = BAR_1; i <= BAR_5; i++) {
+       for (i = BAR_1; i < PCI_STD_NUM_BARS; i++) {
                if (pci_resource_len(pdev, i) == 0)
                        continue;
                if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
index 784b1e2..6ed8753 100644 (file)
@@ -130,42 +130,6 @@ static const char *mlx5e_netdev_kind(struct net_device *dev)
                return "unknown";
 }
 
-static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
-                                  struct net_device *mirred_dev,
-                                  struct net_device **out_dev,
-                                  struct net_device **route_dev,
-                                  struct flowi6 *fl6,
-                                  struct neighbour **out_n,
-                                  u8 *out_ttl)
-{
-       struct dst_entry *dst;
-       struct neighbour *n;
-
-       int ret;
-
-       ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst,
-                                        fl6);
-       if (ret < 0)
-               return ret;
-
-       if (!(*out_ttl))
-               *out_ttl = ip6_dst_hoplimit(dst);
-
-       ret = get_route_and_out_devs(priv, dst->dev, route_dev, out_dev);
-       if (ret < 0) {
-               dst_release(dst);
-               return ret;
-       }
-
-       n = dst_neigh_lookup(dst, &fl6->daddr);
-       dst_release(dst);
-       if (!n)
-               return -ENOMEM;
-
-       *out_n = n;
-       return 0;
-}
-
 static int mlx5e_gen_ip_tunnel_header(char buf[], __u8 *ip_proto,
                                      struct mlx5e_encap_entry *e)
 {
@@ -319,6 +283,43 @@ release_neigh:
        return err;
 }
 
+#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
+static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
+                                  struct net_device *mirred_dev,
+                                  struct net_device **out_dev,
+                                  struct net_device **route_dev,
+                                  struct flowi6 *fl6,
+                                  struct neighbour **out_n,
+                                  u8 *out_ttl)
+{
+       struct dst_entry *dst;
+       struct neighbour *n;
+
+       int ret;
+
+       ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst,
+                                        fl6);
+       if (ret < 0)
+               return ret;
+
+       if (!(*out_ttl))
+               *out_ttl = ip6_dst_hoplimit(dst);
+
+       ret = get_route_and_out_devs(priv, dst->dev, route_dev, out_dev);
+       if (ret < 0) {
+               dst_release(dst);
+               return ret;
+       }
+
+       n = dst_neigh_lookup(dst, &fl6->daddr);
+       dst_release(dst);
+       if (!n)
+               return -ENOMEM;
+
+       *out_n = n;
+       return 0;
+}
+
 int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
                                    struct net_device *mirred_dev,
                                    struct mlx5e_encap_entry *e)
@@ -436,6 +437,7 @@ release_neigh:
        neigh_release(n);
        return err;
 }
+#endif
 
 bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
                                    struct net_device *netdev)
index dbdb7c5..39317cd 100644 (file)
@@ -596,8 +596,8 @@ enum ionic_txq_desc_opcode {
  *                      the @encap is set, the device will
  *                      offload the outer header checksums using
  *                      LCO (local checksum offload) (see
- *                      Documentation/networking/checksum-
- *                      offloads.txt for more info).
+ *                      Documentation/networking/checksum-offloads.rst
+ *                      for more info).
  *
  *                   IONIC_TXQ_DESC_OPCODE_CSUM_HW:
  *
index d47a038..38d2126 100644 (file)
@@ -1542,6 +1542,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
        rtl_lock_config_regs(tp);
 
        device_set_wakeup_enable(tp_to_dev(tp), wolopts);
+       tp->dev->wol_enabled = wolopts ? 1 : 0;
 }
 
 static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -3872,7 +3873,7 @@ static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
                r8168dp_hw_jumbo_enable(tp);
                break;
-       case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_34:
+       case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:
                r8168e_hw_jumbo_enable(tp);
                break;
        default:
index 292045f..8237dbc 100644 (file)
@@ -489,7 +489,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
        }
 
        /* Get the base address of device */
-       for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (pci_resource_len(pdev, i) == 0)
                        continue;
                ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
@@ -532,7 +532,7 @@ static void stmmac_pci_remove(struct pci_dev *pdev)
        if (priv->plat->stmmac_clk)
                clk_unregister_fixed_rate(priv->plat->stmmac_clk);
 
-       for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (pci_resource_len(pdev, i) == 0)
                        continue;
                pcim_iounmap_regions(pdev, BIT(i));
index 386bafe..fa8604d 100644 (file)
@@ -34,7 +34,7 @@ static int xlgmac_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
                return ret;
        }
 
-       for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (pci_resource_len(pcidev, i) == 0)
                        continue;
                ret = pcim_iomap_regions(pcidev, BIT(i), XLGMAC_DRV_NAME);
index 929f3d3..ecdbde5 100644 (file)
@@ -384,7 +384,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
                       int flags, u16 vid)
 {
        u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
-       int mcast_members;
+       int mcast_members = 0;
        int idx;
 
        idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
@@ -397,11 +397,13 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
                mcast_members = cpsw_ale_get_port_mask(ale_entry,
                                                       ale->port_mask_bits);
                mcast_members &= ~port_mask;
+       }
+
+       if (mcast_members)
                cpsw_ale_set_port_mask(ale_entry, mcast_members,
                                       ale->port_mask_bits);
-       } else {
+       else
                cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
-       }
 
        cpsw_ale_write(ale, idx, ale_entry);
        return 0;
@@ -478,6 +480,10 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry,
        members = cpsw_ale_get_vlan_member_list(ale_entry,
                                                ale->vlan_field_bits);
        members &= ~port_mask;
+       if (!members) {
+               cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+               return;
+       }
 
        untag = cpsw_ale_get_vlan_untag_force(ale_entry,
                                              ale->vlan_field_bits);
index 677c459..476db53 100644 (file)
@@ -439,6 +439,15 @@ static struct phy_driver realtek_drvs[] = {
                .resume         = genphy_resume,
                .read_page      = rtl821x_read_page,
                .write_page     = rtl821x_write_page,
+       }, {
+               PHY_ID_MATCH_MODEL(0x001cc880),
+               .name           = "RTL8208 Fast Ethernet",
+               .read_mmd       = genphy_read_mmd_unsupported,
+               .write_mmd      = genphy_write_mmd_unsupported,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+               .read_page      = rtl821x_read_page,
+               .write_page     = rtl821x_write_page,
        }, {
                PHY_ID_MATCH_EXACT(0x001cc910),
                .name           = "RTL8211 Gigabit Ethernet",
index 32ae710..1081d17 100644 (file)
@@ -421,8 +421,6 @@ extern struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
  *     Asynchronous Interfacing
  */
 
-#define SERIAL_MAGIC 0x5301
-
 /*
  * The size of the serial xmit buffer is 1 page, or 4096 bytes
  */
index 6ec5892..dfe37a5 100644 (file)
@@ -2412,16 +2412,6 @@ static const struct nvme_core_quirk_entry core_quirks[] = {
                .vid = 0x14a4,
                .fr = "22301111",
                .quirks = NVME_QUIRK_SIMPLE_SUSPEND,
-       },
-       {
-               /*
-                * This Kingston E8FK11.T firmware version has no interrupt
-                * after resume with actions related to suspend to idle
-                * https://bugzilla.kernel.org/show_bug.cgi?id=204887
-                */
-               .vid = 0x2646,
-               .fr = "E8FK11.T",
-               .quirks = NVME_QUIRK_SIMPLE_SUSPEND,
        }
 };
 
index 39bd763..d6b5334 100644 (file)
 static int meson_efuse_read(void *context, unsigned int offset,
                            void *val, size_t bytes)
 {
-       return meson_sm_call_read((u8 *)val, bytes, SM_EFUSE_READ, offset,
+       struct meson_sm_firmware *fw = context;
+
+       return meson_sm_call_read(fw, (u8 *)val, bytes, SM_EFUSE_READ, offset,
                                  bytes, 0, 0, 0);
 }
 
 static int meson_efuse_write(void *context, unsigned int offset,
                             void *val, size_t bytes)
 {
-       return meson_sm_call_write((u8 *)val, bytes, SM_EFUSE_WRITE, offset,
+       struct meson_sm_firmware *fw = context;
+
+       return meson_sm_call_write(fw, (u8 *)val, bytes, SM_EFUSE_WRITE, offset,
                                   bytes, 0, 0, 0);
 }
 
@@ -37,12 +41,25 @@ MODULE_DEVICE_TABLE(of, meson_efuse_match);
 static int meson_efuse_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct meson_sm_firmware *fw;
+       struct device_node *sm_np;
        struct nvmem_device *nvmem;
        struct nvmem_config *econfig;
        struct clk *clk;
        unsigned int size;
        int ret;
 
+       sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
+       if (!sm_np) {
+               dev_err(&pdev->dev, "no secure-monitor node\n");
+               return -ENODEV;
+       }
+
+       fw = meson_sm_get(sm_np);
+       of_node_put(sm_np);
+       if (!fw)
+               return -EPROBE_DEFER;
+
        clk = devm_clk_get(dev, NULL);
        if (IS_ERR(clk)) {
                ret = PTR_ERR(clk);
@@ -65,7 +82,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
                return ret;
        }
 
-       if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
+       if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
                dev_err(dev, "failed to get max user");
                return -EINVAL;
        }
@@ -81,6 +98,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
        econfig->reg_read = meson_efuse_read;
        econfig->reg_write = meson_efuse_write;
        econfig->size = size;
+       econfig->priv = fw;
 
        nvmem = devm_nvmem_register(&pdev->dev, econfig);
 
index 978427a..99c1b80 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
+#include "of_private.h"
+
 /* Max address size we deal with */
 #define OF_MAX_ADDR_CELLS      4
 #define OF_CHECK_ADDR_COUNT(na)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
@@ -241,6 +243,7 @@ static int parser_init(struct of_pci_range_parser *parser,
        parser->node = node;
        parser->pna = of_n_addr_cells(node);
        parser->np = parser->pna + na + ns;
+       parser->dma = !strcmp(name, "dma-ranges");
 
        parser->range = of_get_property(node, name, &rlen);
        if (parser->range == NULL)
@@ -279,7 +282,11 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
        range->pci_space = be32_to_cpup(parser->range);
        range->flags = of_bus_pci_get_flags(parser->range);
        range->pci_addr = of_read_number(parser->range + 1, ns);
-       range->cpu_addr = of_translate_address(parser->node,
+       if (parser->dma)
+               range->cpu_addr = of_translate_dma_address(parser->node,
+                               parser->range + na);
+       else
+               range->cpu_addr = of_translate_address(parser->node,
                                parser->range + na);
        range->size = of_read_number(parser->range + parser->pna + na, ns);
 
@@ -292,8 +299,12 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
 
                flags = of_bus_pci_get_flags(parser->range);
                pci_addr = of_read_number(parser->range + 1, ns);
-               cpu_addr = of_translate_address(parser->node,
-                               parser->range + na);
+               if (parser->dma)
+                       cpu_addr = of_translate_dma_address(parser->node,
+                                       parser->range + na);
+               else
+                       cpu_addr = of_translate_address(parser->node,
+                                       parser->range + na);
                size = of_read_number(parser->range + parser->pna + na, ns);
 
                if (flags != range->flags)
@@ -517,9 +528,13 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
         *
         * As far as we know, this damage only exists on Apple machines, so
         * This code is only enabled on powerpc. --gcl
+        *
+        * This quirk also applies for 'dma-ranges' which frequently exist in
+        * child nodes without 'dma-ranges' in the parent nodes. --RobH
         */
        ranges = of_get_property(parent, rprop, &rlen);
-       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
+       if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
+           strcmp(rprop, "dma-ranges")) {
                pr_debug("no ranges; cannot translate\n");
                return 1;
        }
@@ -695,6 +710,16 @@ static struct device_node *__of_get_dma_parent(const struct device_node *np)
        return of_node_get(args.np);
 }
 
+static struct device_node *of_get_next_dma_parent(struct device_node *np)
+{
+       struct device_node *parent;
+
+       parent = __of_get_dma_parent(np);
+       of_node_put(np);
+
+       return parent;
+}
+
 u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
        struct device_node *host;
@@ -826,25 +851,6 @@ int of_address_to_resource(struct device_node *dev, int index,
 }
 EXPORT_SYMBOL_GPL(of_address_to_resource);
 
-struct device_node *of_find_matching_node_by_address(struct device_node *from,
-                                       const struct of_device_id *matches,
-                                       u64 base_address)
-{
-       struct device_node *dn = of_find_matching_node(from, matches);
-       struct resource res;
-
-       while (dn) {
-               if (!of_address_to_resource(dn, 0, &res) &&
-                   res.start == base_address)
-                       return dn;
-
-               dn = of_find_matching_node(dn, matches);
-       }
-
-       return NULL;
-}
-
-
 /**
  * of_iomap - Maps the memory mapped IO for a given device_node
  * @device:    the device whose io range will be mapped
@@ -924,47 +930,39 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
        const __be32 *ranges = NULL;
        int len, naddr, nsize, pna;
        int ret = 0;
+       bool found_dma_ranges = false;
        u64 dmaaddr;
 
-       if (!node)
-               return -EINVAL;
-
-       while (1) {
-               struct device_node *parent;
-
-               naddr = of_n_addr_cells(node);
-               nsize = of_n_size_cells(node);
-
-               parent = __of_get_dma_parent(node);
-               of_node_put(node);
-
-               node = parent;
-               if (!node)
-                       break;
-
+       while (node) {
                ranges = of_get_property(node, "dma-ranges", &len);
 
                /* Ignore empty ranges, they imply no translation required */
                if (ranges && len > 0)
                        break;
 
-               /*
-                * At least empty ranges has to be defined for parent node if
-                * DMA is supported
-                */
-               if (!ranges)
-                       break;
+               /* Once we find 'dma-ranges', then a missing one is an error */
+               if (found_dma_ranges && !ranges) {
+                       ret = -ENODEV;
+                       goto out;
+               }
+               found_dma_ranges = true;
+
+               node = of_get_next_dma_parent(node);
        }
 
-       if (!ranges) {
+       if (!node || !ranges) {
                pr_debug("no dma-ranges found for node(%pOF)\n", np);
                ret = -ENODEV;
                goto out;
        }
 
-       len /= sizeof(u32);
-
+       naddr = of_bus_n_addr_cells(node);
+       nsize = of_bus_n_size_cells(node);
        pna = of_n_addr_cells(node);
+       if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* dma-ranges format:
         * DMA addr     : naddr cells
@@ -972,10 +970,10 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
         * size         : nsize cells
         */
        dmaaddr = of_read_number(ranges, naddr);
-       *paddr = of_translate_dma_address(np, ranges);
+       *paddr = of_translate_dma_address(node, ranges + naddr);
        if (*paddr == OF_BAD_ADDR) {
-               pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
-                      dma_addr, np);
+               pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
+                      dmaaddr, np);
                ret = -EINVAL;
                goto out;
        }
@@ -991,7 +989,6 @@ out:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(of_dma_get_range);
 
 /**
  * of_dma_is_coherent - Check if device is coherent
@@ -1009,7 +1006,7 @@ bool of_dma_is_coherent(struct device_node *np)
                        of_node_put(node);
                        return true;
                }
-               node = of_get_next_parent(node);
+               node = of_get_next_dma_parent(node);
        }
        of_node_put(node);
        return false;
index 1d667eb..db7fbc0 100644 (file)
@@ -86,34 +86,46 @@ static bool __of_node_is_type(const struct device_node *np, const char *type)
        return np && match && type && !strcmp(match, type);
 }
 
-int of_n_addr_cells(struct device_node *np)
+int of_bus_n_addr_cells(struct device_node *np)
 {
        u32 cells;
 
-       do {
-               if (np->parent)
-                       np = np->parent;
+       for (; np; np = np->parent)
                if (!of_property_read_u32(np, "#address-cells", &cells))
                        return cells;
-       } while (np->parent);
+
        /* No #address-cells property for the root node */
        return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
 }
+
+int of_n_addr_cells(struct device_node *np)
+{
+       if (np->parent)
+               np = np->parent;
+
+       return of_bus_n_addr_cells(np);
+}
 EXPORT_SYMBOL(of_n_addr_cells);
 
-int of_n_size_cells(struct device_node *np)
+int of_bus_n_size_cells(struct device_node *np)
 {
        u32 cells;
 
-       do {
-               if (np->parent)
-                       np = np->parent;
+       for (; np; np = np->parent)
                if (!of_property_read_u32(np, "#size-cells", &cells))
                        return cells;
-       } while (np->parent);
+
        /* No #size-cells property for the root node */
        return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
 }
+
+int of_n_size_cells(struct device_node *np)
+{
+       if (np->parent)
+               np = np->parent;
+
+       return of_bus_n_size_cells(np);
+}
 EXPORT_SYMBOL(of_n_size_cells);
 
 #ifdef CONFIG_NUMA
index f1c23aa..2cdf64d 100644 (file)
@@ -947,8 +947,8 @@ int __init early_init_dt_scan_chosen_stdout(void)
                if (fdt_node_check_compatible(fdt, offset, match->compatible))
                        continue;
 
-               of_setup_earlycon(match, offset, options);
-               return 0;
+               if (of_setup_earlycon(match, offset, options) == 0)
+                       return 0;
        }
        return -ENODEV;
 }
index 2478681..66294d2 100644 (file)
@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np,
 #define for_each_transaction_entry_reverse(_oft, _te) \
        list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
 
+extern int of_bus_n_addr_cells(struct device_node *np);
+extern int of_bus_n_size_cells(struct device_node *np);
+
+#ifdef CONFIG_OF_ADDRESS
+extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+                           u64 *paddr, u64 *size);
+#else
+static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+                                  u64 *paddr, u64 *size)
+{
+       return -ENODEV;
+}
+#endif
+
 #endif /* _LINUX_OF_PRIVATE_H */
index c423e94..9617b7d 100644 (file)
@@ -305,7 +305,6 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
 {
        struct property *new_prop = NULL, *prop;
        int ret = 0;
-       bool check_for_non_overlay_node = false;
 
        if (target->in_livetree)
                if (!of_prop_cmp(overlay_prop->name, "name") ||
@@ -318,6 +317,25 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
        else
                prop = NULL;
 
+       if (prop) {
+               if (!of_prop_cmp(prop->name, "#address-cells")) {
+                       if (!of_prop_val_eq(prop, overlay_prop)) {
+                               pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n",
+                                      target->np);
+                               ret = -EINVAL;
+                       }
+                       return ret;
+
+               } else if (!of_prop_cmp(prop->name, "#size-cells")) {
+                       if (!of_prop_val_eq(prop, overlay_prop)) {
+                               pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n",
+                                      target->np);
+                               ret = -EINVAL;
+                       }
+                       return ret;
+               }
+       }
+
        if (is_symbols_prop) {
                if (prop)
                        return -EINVAL;
@@ -330,33 +348,18 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
                return -ENOMEM;
 
        if (!prop) {
-               check_for_non_overlay_node = true;
                if (!target->in_livetree) {
                        new_prop->next = target->np->deadprops;
                        target->np->deadprops = new_prop;
                }
                ret = of_changeset_add_property(&ovcs->cset, target->np,
                                                new_prop);
-       } else if (!of_prop_cmp(prop->name, "#address-cells")) {
-               if (!of_prop_val_eq(prop, new_prop)) {
-                       pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n",
-                              target->np);
-                       ret = -EINVAL;
-               }
-       } else if (!of_prop_cmp(prop->name, "#size-cells")) {
-               if (!of_prop_val_eq(prop, new_prop)) {
-                       pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n",
-                              target->np);
-                       ret = -EINVAL;
-               }
        } else {
-               check_for_non_overlay_node = true;
                ret = of_changeset_update_property(&ovcs->cset, target->np,
                                                   new_prop);
        }
 
-       if (check_for_non_overlay_node &&
-           !of_node_check_flag(target->np, OF_OVERLAY))
+       if (!of_node_check_flag(target->np, OF_OVERLAY))
                pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n",
                       target->np, new_prop->name);
 
index 477966d..e851c57 100644 (file)
@@ -165,7 +165,7 @@ EXPORT_SYMBOL_GPL(of_property_read_u64_index);
  *
  * @np:                device node from which the property value is to be read.
  * @propname:  name of the property to be searched.
- * @out_values:        pointer to return value, modified only if return value is 0.
+ * @out_values:        pointer to found values.
  * @sz_min:    minimum number of array elements to read
  * @sz_max:    maximum number of array elements to read, if zero there is no
  *             upper limit on the number of elements in the dts entry but only
@@ -213,7 +213,7 @@ EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
  *
  * @np:                device node from which the property value is to be read.
  * @propname:  name of the property to be searched.
- * @out_values:        pointer to return value, modified only if return value is 0.
+ * @out_values:        pointer to found values.
  * @sz_min:    minimum number of array elements to read
  * @sz_max:    maximum number of array elements to read, if zero there is no
  *             upper limit on the number of elements in the dts entry but only
@@ -261,7 +261,7 @@ EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
  *
  * @np:                device node from which the property value is to be read.
  * @propname:  name of the property to be searched.
- * @out_values:        pointer to return value, modified only if return value is 0.
+ * @out_values:        pointer to return found values.
  * @sz_min:    minimum number of array elements to read
  * @sz_max:    maximum number of array elements to read, if zero there is no
  *             upper limit on the number of elements in the dts entry but only
@@ -335,7 +335,7 @@ EXPORT_SYMBOL_GPL(of_property_read_u64);
  *
  * @np:                device node from which the property value is to be read.
  * @propname:  name of the property to be searched.
- * @out_values:        pointer to return value, modified only if return value is 0.
+ * @out_values:        pointer to found values.
  * @sz_min:    minimum number of array elements to read
  * @sz_max:    maximum number of array elements to read, if zero there is no
  *             upper limit on the number of elements in the dts entry but only
index 55fe0ee..a85b5e1 100644 (file)
@@ -15,5 +15,6 @@
 #include "tests-phandle.dtsi"
 #include "tests-interrupts.dtsi"
 #include "tests-match.dtsi"
+#include "tests-address.dtsi"
 #include "tests-platform.dtsi"
 #include "tests-overlay.dtsi"
diff --git a/drivers/of/unittest-data/tests-address.dtsi b/drivers/of/unittest-data/tests-address.dtsi
new file mode 100644 (file)
index 0000000..3fe5d39
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       testcase-data {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               address-tests {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       /* ranges here is to make sure we don't use it for
+                        * dma-ranges translation */
+                       ranges = <0x70000000 0x70000000 0x40000000>,
+                                <0x00000000 0xd0000000 0x20000000>;
+                       dma-ranges = <0x0 0x20000000 0x40000000>;
+
+                       device@70000000 {
+                               reg = <0x70000000 0x1000>;
+                       };
+
+                       bus@80000000 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges = <0x0 0x80000000 0x100000>;
+                               dma-ranges = <0x10000000 0x0 0x40000000>;
+
+                               device@1000 {
+                                       reg = <0x1000 0x1000>;
+                               };
+                       };
+
+                       pci@90000000 {
+                               device_type = "pci";
+                               #address-cells = <3>;
+                               #size-cells = <2>;
+                               reg = <0x90000000 0x1000>;
+                               ranges = <0x42000000 0x0 0x40000000 0x40000000 0x0 0x10000000>;
+                               dma-ranges = <0x42000000 0x0 0x80000000 0x00000000 0x0 0x10000000>,
+                                            <0x42000000 0x0 0xc0000000 0x20000000 0x0 0x10000000>;
+                       };
+
+               };
+       };
+};
index 92e895d..68b8758 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/hashtable.h>
 #include <linux/libfdt.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_fdt.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
@@ -779,6 +780,95 @@ static void __init of_unittest_changeset(void)
 #endif
 }
 
+static void __init of_unittest_dma_ranges_one(const char *path,
+               u64 expect_dma_addr, u64 expect_paddr, u64 expect_size)
+{
+       struct device_node *np;
+       u64 dma_addr, paddr, size;
+       int rc;
+
+       np = of_find_node_by_path(path);
+       if (!np) {
+               pr_err("missing testcase data\n");
+               return;
+       }
+
+       rc = of_dma_get_range(np, &dma_addr, &paddr, &size);
+
+       unittest(!rc, "of_dma_get_range failed on node %pOF rc=%i\n", np, rc);
+       if (!rc) {
+               unittest(size == expect_size,
+                        "of_dma_get_range wrong size on node %pOF size=%llx\n", np, size);
+               unittest(paddr == expect_paddr,
+                        "of_dma_get_range wrong phys addr (%llx) on node %pOF", paddr, np);
+               unittest(dma_addr == expect_dma_addr,
+                        "of_dma_get_range wrong DMA addr (%llx) on node %pOF", dma_addr, np);
+       }
+       of_node_put(np);
+}
+
+static void __init of_unittest_parse_dma_ranges(void)
+{
+       of_unittest_dma_ranges_one("/testcase-data/address-tests/device@70000000",
+               0x0, 0x20000000, 0x40000000);
+       of_unittest_dma_ranges_one("/testcase-data/address-tests/bus@80000000/device@1000",
+               0x10000000, 0x20000000, 0x40000000);
+       of_unittest_dma_ranges_one("/testcase-data/address-tests/pci@90000000",
+               0x80000000, 0x20000000, 0x10000000);
+}
+
+static void __init of_unittest_pci_dma_ranges(void)
+{
+       struct device_node *np;
+       struct of_pci_range range;
+       struct of_pci_range_parser parser;
+       int i = 0;
+
+       if (!IS_ENABLED(CONFIG_PCI))
+               return;
+
+       np = of_find_node_by_path("/testcase-data/address-tests/pci@90000000");
+       if (!np) {
+               pr_err("missing testcase data\n");
+               return;
+       }
+
+       if (of_pci_dma_range_parser_init(&parser, np)) {
+               pr_err("missing dma-ranges property\n");
+               return;
+       }
+
+       /*
+        * Get the dma-ranges from the device tree
+        */
+       for_each_of_pci_range(&parser, &range) {
+               if (!i) {
+                       unittest(range.size == 0x10000000,
+                                "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
+                                np, range.size);
+                       unittest(range.cpu_addr == 0x20000000,
+                                "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
+                                range.cpu_addr, np);
+                       unittest(range.pci_addr == 0x80000000,
+                                "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
+                                range.pci_addr, np);
+               } else {
+                       unittest(range.size == 0x10000000,
+                                "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
+                                np, range.size);
+                       unittest(range.cpu_addr == 0x40000000,
+                                "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
+                                range.cpu_addr, np);
+                       unittest(range.pci_addr == 0xc0000000,
+                                "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
+                                range.pci_addr, np);
+               }
+               i++;
+       }
+
+       of_node_put(np);
+}
+
 static void __init of_unittest_parse_interrupts(void)
 {
        struct device_node *np;
@@ -1146,8 +1236,10 @@ static void attach_node_and_children(struct device_node *np)
        full_name = kasprintf(GFP_KERNEL, "%pOF", np);
 
        if (!strcmp(full_name, "/__local_fixups__") ||
-           !strcmp(full_name, "/__fixups__"))
+           !strcmp(full_name, "/__fixups__")) {
+               kfree(full_name);
                return;
+       }
 
        dup = of_find_node_by_path(full_name);
        kfree(full_name);
@@ -2555,6 +2647,8 @@ static int __init of_unittest(void)
        of_unittest_changeset();
        of_unittest_parse_interrupts();
        of_unittest_parse_interrupts_extended();
+       of_unittest_parse_dma_ranges();
+       of_unittest_pci_dma_ranges();
        of_unittest_match_node();
        of_unittest_platform_populate();
        of_unittest_overlay();
index a304f5e..4bef5c2 100644 (file)
@@ -52,7 +52,7 @@ config PCI_MSI
           If you don't know what to do here, say Y.
 
 config PCI_MSI_IRQ_DOMAIN
-       def_bool ARC || ARM || ARM64 || X86 || RISCV
+       def_bool y
        depends on PCI_MSI
        select GENERIC_MSI_IRQ_DOMAIN
 
@@ -106,14 +106,14 @@ config PCI_PF_STUB
          When in doubt, say N.
 
 config XEN_PCIDEV_FRONTEND
-        tristate "Xen PCI Frontend"
-        depends on X86 && XEN
-        select PCI_XEN
+       tristate "Xen PCI Frontend"
+       depends on X86 && XEN
+       select PCI_XEN
        select XEN_XENBUS_FRONTEND
-        default y
-        help
-          The PCI device frontend driver allows the kernel to import arbitrary
-          PCI devices from a PCI backend to support PCI driver domains.
+       default y
+       help
+         The PCI device frontend driver allows the kernel to import arbitrary
+         PCI devices from a PCI backend to support PCI driver domains.
 
 config PCI_ATS
        bool
@@ -180,12 +180,12 @@ config PCI_LABEL
        select NLS
 
 config PCI_HYPERV
-        tristate "Hyper-V PCI Frontend"
-        depends on X86_64 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS
+       tristate "Hyper-V PCI Frontend"
+       depends on X86_64 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS
        select PCI_HYPERV_INTERFACE
-        help
-          The PCI device frontend driver allows the kernel to import arbitrary
-          PCI devices from a PCI backend to support PCI driver domains.
+       help
+         The PCI device frontend driver allows the kernel to import arbitrary
+         PCI devices from a PCI backend to support PCI driver domains.
 
 source "drivers/pci/hotplug/Kconfig"
 source "drivers/pci/controller/Kconfig"
index 28cdd8c..522d2b9 100644 (file)
@@ -7,6 +7,8 @@ obj-$(CONFIG_PCI)               += access.o bus.o probe.o host-bridge.o \
                                   pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
                                   setup-bus.o vc.o mmap.o setup-irq.o
 
+obj-$(CONFIG_PCI)              += pcie/
+
 ifdef CONFIG_PCI
 obj-$(CONFIG_PROC_FS)          += proc.o
 obj-$(CONFIG_SYSFS)            += slot.o
@@ -15,7 +17,6 @@ endif
 
 obj-$(CONFIG_OF)               += of.o
 obj-$(CONFIG_PCI_QUIRKS)       += quirks.o
-obj-$(CONFIG_PCIEPORTBUS)      += pcie/
 obj-$(CONFIG_HOTPLUG_PCI)      += hotplug/
 obj-$(CONFIG_PCI_MSI)          += msi.o
 obj-$(CONFIG_PCI_ATS)          += ats.o
index 2fccb57..79c4a2e 100644 (file)
@@ -355,7 +355,7 @@ static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
               pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
 }
 
-static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
+bool pcie_cap_has_rtctl(const struct pci_dev *dev)
 {
        int type = pci_pcie_type(dev);
 
index e184992..982b46f 100644 (file)
@@ -60,8 +60,6 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
                pdev = pci_physfn(dev);
                if (pdev->ats_stu != ps)
                        return -EINVAL;
-
-               atomic_inc(&pdev->ats_ref_cnt);  /* count enabled VFs */
        } else {
                dev->ats_stu = ps;
                ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
@@ -71,7 +69,6 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
        dev->ats_enabled = 1;
        return 0;
 }
-EXPORT_SYMBOL_GPL(pci_enable_ats);
 
 /**
  * pci_disable_ats - disable the ATS capability
@@ -79,27 +76,17 @@ EXPORT_SYMBOL_GPL(pci_enable_ats);
  */
 void pci_disable_ats(struct pci_dev *dev)
 {
-       struct pci_dev *pdev;
        u16 ctrl;
 
        if (WARN_ON(!dev->ats_enabled))
                return;
 
-       if (atomic_read(&dev->ats_ref_cnt))
-               return;         /* VFs still enabled */
-
-       if (dev->is_virtfn) {
-               pdev = pci_physfn(dev);
-               atomic_dec(&pdev->ats_ref_cnt);
-       }
-
        pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
        ctrl &= ~PCI_ATS_CTRL_ENABLE;
        pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
 
        dev->ats_enabled = 0;
 }
-EXPORT_SYMBOL_GPL(pci_disable_ats);
 
 void pci_restore_ats_state(struct pci_dev *dev)
 {
@@ -113,7 +100,6 @@ void pci_restore_ats_state(struct pci_dev *dev)
                ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
        pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
 }
-EXPORT_SYMBOL_GPL(pci_restore_ats_state);
 
 /**
  * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
@@ -140,7 +126,6 @@ int pci_ats_queue_depth(struct pci_dev *dev)
        pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
        return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
 }
-EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
 
 /**
  * pci_ats_page_aligned - Return Page Aligned Request bit status.
@@ -167,9 +152,22 @@ int pci_ats_page_aligned(struct pci_dev *pdev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(pci_ats_page_aligned);
 
 #ifdef CONFIG_PCI_PRI
+void pci_pri_init(struct pci_dev *pdev)
+{
+       u16 status;
+
+       pdev->pri_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
+
+       if (!pdev->pri_cap)
+               return;
+
+       pci_read_config_word(pdev, pdev->pri_cap + PCI_PRI_STATUS, &status);
+       if (status & PCI_PRI_STATUS_PASID)
+               pdev->pasid_required = 1;
+}
+
 /**
  * pci_enable_pri - Enable PRI capability
  * @ pdev: PCI device structure
@@ -180,32 +178,41 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
 {
        u16 control, status;
        u32 max_requests;
-       int pos;
+       int pri = pdev->pri_cap;
+
+       /*
+        * VFs must not implement the PRI Capability.  If their PF
+        * implements PRI, it is shared by the VFs, so if the PF PRI is
+        * enabled, it is also enabled for the VF.
+        */
+       if (pdev->is_virtfn) {
+               if (pci_physfn(pdev)->pri_enabled)
+                       return 0;
+               return -EINVAL;
+       }
 
        if (WARN_ON(pdev->pri_enabled))
                return -EBUSY;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
-       if (!pos)
+       if (!pri)
                return -EINVAL;
 
-       pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
+       pci_read_config_word(pdev, pri + PCI_PRI_STATUS, &status);
        if (!(status & PCI_PRI_STATUS_STOPPED))
                return -EBUSY;
 
-       pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
+       pci_read_config_dword(pdev, pri + PCI_PRI_MAX_REQ, &max_requests);
        reqs = min(max_requests, reqs);
        pdev->pri_reqs_alloc = reqs;
-       pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
+       pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
 
        control = PCI_PRI_CTRL_ENABLE;
-       pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+       pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
 
        pdev->pri_enabled = 1;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(pci_enable_pri);
 
 /**
  * pci_disable_pri - Disable PRI capability
@@ -216,18 +223,21 @@ EXPORT_SYMBOL_GPL(pci_enable_pri);
 void pci_disable_pri(struct pci_dev *pdev)
 {
        u16 control;
-       int pos;
+       int pri = pdev->pri_cap;
+
+       /* VFs share the PF PRI */
+       if (pdev->is_virtfn)
+               return;
 
        if (WARN_ON(!pdev->pri_enabled))
                return;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
-       if (!pos)
+       if (!pri)
                return;
 
-       pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
+       pci_read_config_word(pdev, pri + PCI_PRI_CTRL, &control);
        control &= ~PCI_PRI_CTRL_ENABLE;
-       pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+       pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
 
        pdev->pri_enabled = 0;
 }
@@ -241,19 +251,20 @@ void pci_restore_pri_state(struct pci_dev *pdev)
 {
        u16 control = PCI_PRI_CTRL_ENABLE;
        u32 reqs = pdev->pri_reqs_alloc;
-       int pos;
+       int pri = pdev->pri_cap;
+
+       if (pdev->is_virtfn)
+               return;
 
        if (!pdev->pri_enabled)
                return;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
-       if (!pos)
+       if (!pri)
                return;
 
-       pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
-       pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+       pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
+       pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
 }
-EXPORT_SYMBOL_GPL(pci_restore_pri_state);
 
 /**
  * pci_reset_pri - Resets device's PRI state
@@ -265,24 +276,45 @@ EXPORT_SYMBOL_GPL(pci_restore_pri_state);
 int pci_reset_pri(struct pci_dev *pdev)
 {
        u16 control;
-       int pos;
+       int pri = pdev->pri_cap;
+
+       if (pdev->is_virtfn)
+               return 0;
 
        if (WARN_ON(pdev->pri_enabled))
                return -EBUSY;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
-       if (!pos)
+       if (!pri)
                return -EINVAL;
 
        control = PCI_PRI_CTRL_RESET;
-       pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+       pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(pci_reset_pri);
+
+/**
+ * pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
+ *                              status.
+ * @pdev: PCI device structure
+ *
+ * Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
+ */
+int pci_prg_resp_pasid_required(struct pci_dev *pdev)
+{
+       if (pdev->is_virtfn)
+               pdev = pci_physfn(pdev);
+
+       return pdev->pasid_required;
+}
 #endif /* CONFIG_PCI_PRI */
 
 #ifdef CONFIG_PCI_PASID
+void pci_pasid_init(struct pci_dev *pdev)
+{
+       pdev->pasid_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
+}
+
 /**
  * pci_enable_pasid - Enable the PASID capability
  * @pdev: PCI device structure
@@ -295,7 +327,17 @@ EXPORT_SYMBOL_GPL(pci_reset_pri);
 int pci_enable_pasid(struct pci_dev *pdev, int features)
 {
        u16 control, supported;
-       int pos;
+       int pasid = pdev->pasid_cap;
+
+       /*
+        * VFs must not implement the PASID Capability, but if a PF
+        * supports PASID, its VFs share the PF PASID configuration.
+        */
+       if (pdev->is_virtfn) {
+               if (pci_physfn(pdev)->pasid_enabled)
+                       return 0;
+               return -EINVAL;
+       }
 
        if (WARN_ON(pdev->pasid_enabled))
                return -EBUSY;
@@ -303,11 +345,10 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
        if (!pdev->eetlp_prefix_path)
                return -EINVAL;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
-       if (!pos)
+       if (!pasid)
                return -EINVAL;
 
-       pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
+       pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
        supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
 
        /* User wants to enable anything unsupported? */
@@ -317,13 +358,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
        control = PCI_PASID_CTRL_ENABLE | features;
        pdev->pasid_features = features;
 
-       pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
+       pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
 
        pdev->pasid_enabled = 1;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(pci_enable_pasid);
 
 /**
  * pci_disable_pasid - Disable the PASID capability
@@ -332,20 +372,22 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid);
 void pci_disable_pasid(struct pci_dev *pdev)
 {
        u16 control = 0;
-       int pos;
+       int pasid = pdev->pasid_cap;
+
+       /* VFs share the PF PASID configuration */
+       if (pdev->is_virtfn)
+               return;
 
        if (WARN_ON(!pdev->pasid_enabled))
                return;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
-       if (!pos)
+       if (!pasid)
                return;
 
-       pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
+       pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
 
        pdev->pasid_enabled = 0;
 }
-EXPORT_SYMBOL_GPL(pci_disable_pasid);
 
 /**
  * pci_restore_pasid_state - Restore PASID capabilities
@@ -354,19 +396,20 @@ EXPORT_SYMBOL_GPL(pci_disable_pasid);
 void pci_restore_pasid_state(struct pci_dev *pdev)
 {
        u16 control;
-       int pos;
+       int pasid = pdev->pasid_cap;
+
+       if (pdev->is_virtfn)
+               return;
 
        if (!pdev->pasid_enabled)
                return;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
-       if (!pos)
+       if (!pasid)
                return;
 
        control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
-       pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
+       pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
 }
-EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
 
 /**
  * pci_pasid_features - Check which PASID features are supported
@@ -381,49 +424,20 @@ EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
 int pci_pasid_features(struct pci_dev *pdev)
 {
        u16 supported;
-       int pos;
+       int pasid = pdev->pasid_cap;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
-       if (!pos)
+       if (pdev->is_virtfn)
+               pdev = pci_physfn(pdev);
+
+       if (!pasid)
                return -EINVAL;
 
-       pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
+       pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
 
        supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
 
        return supported;
 }
-EXPORT_SYMBOL_GPL(pci_pasid_features);
-
-/**
- * pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
- *                              status.
- * @pdev: PCI device structure
- *
- * Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
- *
- * Even though the PRG response PASID status is read from PRI Status
- * Register, since this API will mainly be used by PASID users, this
- * function is defined within #ifdef CONFIG_PCI_PASID instead of
- * CONFIG_PCI_PRI.
- */
-int pci_prg_resp_pasid_required(struct pci_dev *pdev)
-{
-       u16 status;
-       int pos;
-
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
-       if (!pos)
-               return 0;
-
-       pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
-
-       if (status & PCI_PRI_STATUS_PASID)
-               return 1;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);
 
 #define PASID_NUMBER_SHIFT     8
 #define PASID_NUMBER_MASK      (0x1f << PASID_NUMBER_SHIFT)
@@ -437,17 +451,18 @@ EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);
 int pci_max_pasids(struct pci_dev *pdev)
 {
        u16 supported;
-       int pos;
+       int pasid = pdev->pasid_cap;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
-       if (!pos)
+       if (pdev->is_virtfn)
+               pdev = pci_physfn(pdev);
+
+       if (!pasid)
                return -EINVAL;
 
-       pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
+       pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
 
        supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
 
        return (1 << supported);
 }
-EXPORT_SYMBOL_GPL(pci_max_pasids);
 #endif /* CONFIG_PCI_PASID */
index 70e0782..c77069c 100644 (file)
@@ -22,34 +22,6 @@ config PCI_AARDVARK
         controller is part of the South Bridge of the Marvel Armada
         3700 SoC.
 
-menu "Cadence PCIe controllers support"
-
-config PCIE_CADENCE
-       bool
-
-config PCIE_CADENCE_HOST
-       bool "Cadence PCIe host controller"
-       depends on OF
-       depends on PCI
-       select IRQ_DOMAIN
-       select PCIE_CADENCE
-       help
-         Say Y here if you want to support the Cadence PCIe controller in host
-         mode. This PCIe controller may be embedded into many different vendors
-         SoCs.
-
-config PCIE_CADENCE_EP
-       bool "Cadence PCIe endpoint controller"
-       depends on OF
-       depends on PCI_ENDPOINT
-       select PCIE_CADENCE
-       help
-         Say Y here if you want to support the Cadence PCIe  controller in
-         endpoint mode. This PCIe controller may be embedded into many
-         different vendors SoCs.
-
-endmenu
-
 config PCIE_XILINX_NWL
        bool "NWL PCIe Core"
        depends on ARCH_ZYNQMP || COMPILE_TEST
@@ -135,7 +107,7 @@ config PCI_V3_SEMI
 
 config PCI_VERSATILE
        bool "ARM Versatile PB PCI controller"
-       depends on ARCH_VERSATILE
+       depends on ARCH_VERSATILE || COMPILE_TEST
 
 config PCIE_IPROC
        tristate
@@ -289,4 +261,5 @@ config PCI_HYPERV_INTERFACE
          have a common interface with the Hyper-V PCI frontend driver.
 
 source "drivers/pci/controller/dwc/Kconfig"
+source "drivers/pci/controller/cadence/Kconfig"
 endmenu
index a2a22c9..3d4f597 100644 (file)
@@ -1,7 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
-obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
-obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
+obj-$(CONFIG_PCIE_CADENCE) += cadence/
 obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o
 obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
 obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
new file mode 100644 (file)
index 0000000..b76b3cf
--- /dev/null
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "Cadence PCIe controllers support"
+       depends on PCI
+
+config PCIE_CADENCE
+       bool
+
+config PCIE_CADENCE_HOST
+       bool
+       depends on OF
+       select IRQ_DOMAIN
+       select PCIE_CADENCE
+
+config PCIE_CADENCE_EP
+       bool
+       depends on OF
+       depends on PCI_ENDPOINT
+       select PCIE_CADENCE
+
+config PCIE_CADENCE_PLAT
+       bool
+
+config PCIE_CADENCE_PLAT_HOST
+       bool "Cadence PCIe platform host controller"
+       depends on OF
+       select PCIE_CADENCE_HOST
+       select PCIE_CADENCE_PLAT
+       help
+         Say Y here if you want to support the Cadence PCIe platform controller in
+         host mode. This PCIe controller may be embedded into many different
+         vendors SoCs.
+
+config PCIE_CADENCE_PLAT_EP
+       bool "Cadence PCIe platform endpoint controller"
+       depends on OF
+       depends on PCI_ENDPOINT
+       select PCIE_CADENCE_EP
+       select PCIE_CADENCE_PLAT
+       help
+         Say Y here if you want to support the Cadence PCIe  platform controller in
+         endpoint mode. This PCIe controller may be embedded into many
+         different vendors SoCs.
+
+endmenu
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
new file mode 100644 (file)
index 0000000..232a3f2
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
+obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
+obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
+obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
new file mode 100644 (file)
index 0000000..1c173da
--- /dev/null
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe endpoint controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/pci-epc.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+
+#include "pcie-cadence.h"
+
+#define CDNS_PCIE_EP_MIN_APERTURE              128     /* 128 bytes */
+#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE         0x1
+#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY       0x3
+
+static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn,
+                                    struct pci_epf_header *hdr)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+
+       cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid);
+       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid);
+       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code);
+       cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE,
+                              hdr->subclass_code | hdr->baseclass_code << 8);
+       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE,
+                              hdr->cache_line_size);
+       cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id);
+       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin);
+
+       /*
+        * Vendor ID can only be modified from function 0, all other functions
+        * use the same vendor ID as function 0.
+        */
+       if (fn == 0) {
+               /* Update the vendor IDs. */
+               u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) |
+                        CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id);
+
+               cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+       }
+
+       return 0;
+}
+
+static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
+                               struct pci_epf_bar *epf_bar)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       dma_addr_t bar_phys = epf_bar->phys_addr;
+       enum pci_barno bar = epf_bar->barno;
+       int flags = epf_bar->flags;
+       u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
+       u64 sz;
+
+       /* BAR size is 2^(aperture + 7) */
+       sz = max_t(size_t, epf_bar->size, CDNS_PCIE_EP_MIN_APERTURE);
+       /*
+        * roundup_pow_of_two() returns an unsigned long, which is not suited
+        * for 64bit values.
+        */
+       sz = 1ULL << fls64(sz - 1);
+       aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
+
+       if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+               ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS;
+       } else {
+               bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
+               bool is_64bits = sz > SZ_2G;
+
+               if (is_64bits && (bar & 1))
+                       return -EINVAL;
+
+               if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))
+                       epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+               if (is_64bits && is_prefetch)
+                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
+               else if (is_prefetch)
+                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
+               else if (is_64bits)
+                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS;
+               else
+                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS;
+       }
+
+       addr0 = lower_32_bits(bar_phys);
+       addr1 = upper_32_bits(bar_phys);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar),
+                        addr0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar),
+                        addr1);
+
+       if (bar < BAR_4) {
+               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
+               b = bar;
+       } else {
+               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
+               b = bar - BAR_4;
+       }
+
+       cfg = cdns_pcie_readl(pcie, reg);
+       cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
+                CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
+       cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
+               CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
+       cdns_pcie_writel(pcie, reg, cfg);
+
+       return 0;
+}
+
+static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
+                                  struct pci_epf_bar *epf_bar)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       enum pci_barno bar = epf_bar->barno;
+       u32 reg, cfg, b, ctrl;
+
+       if (bar < BAR_4) {
+               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
+               b = bar;
+       } else {
+               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
+               b = bar - BAR_4;
+       }
+
+       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
+       cfg = cdns_pcie_readl(pcie, reg);
+       cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
+                CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
+       cfg |= CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
+       cdns_pcie_writel(pcie, reg, cfg);
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+}
+
+static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
+                                u64 pci_addr, size_t size)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       u32 r;
+
+       r = find_first_zero_bit(&ep->ob_region_map,
+                               sizeof(ep->ob_region_map) * BITS_PER_LONG);
+       if (r >= ep->max_regions - 1) {
+               dev_err(&epc->dev, "no free outbound region\n");
+               return -EINVAL;
+       }
+
+       cdns_pcie_set_outbound_region(pcie, fn, r, false, addr, pci_addr, size);
+
+       set_bit(r, &ep->ob_region_map);
+       ep->ob_addr[r] = addr;
+
+       return 0;
+}
+
+static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn,
+                                   phys_addr_t addr)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       u32 r;
+
+       for (r = 0; r < ep->max_regions - 1; r++)
+               if (ep->ob_addr[r] == addr)
+                       break;
+
+       if (r == ep->max_regions - 1)
+               return;
+
+       cdns_pcie_reset_outbound_region(pcie, r);
+
+       ep->ob_addr[r] = 0;
+       clear_bit(r, &ep->ob_region_map);
+}
+
+static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 mmc)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+       u16 flags;
+
+       /*
+        * Set the Multiple Message Capable bitfield into the Message Control
+        * register.
+        */
+       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+       flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
+       flags |= PCI_MSI_FLAGS_64BIT;
+       flags &= ~PCI_MSI_FLAGS_MASKBIT;
+       cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
+
+       return 0;
+}
+
+static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+       u16 flags, mme;
+
+       /* Validate that the MSI feature is actually enabled. */
+       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+       if (!(flags & PCI_MSI_FLAGS_ENABLE))
+               return -EINVAL;
+
+       /*
+        * Get the Multiple Message Enable bitfield from the Message Control
+        * register.
+        */
+       mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
+
+       return mme;
+}
+
+static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
+                                    u8 intx, bool is_asserted)
+{
+       struct cdns_pcie *pcie = &ep->pcie;
+       u32 offset;
+       u16 status;
+       u8 msg_code;
+
+       intx &= 3;
+
+       /* Set the outbound region if needed. */
+       if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
+                    ep->irq_pci_fn != fn)) {
+               /* First region was reserved for IRQ writes. */
+               cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0,
+                                                            ep->irq_phys_addr);
+               ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
+               ep->irq_pci_fn = fn;
+       }
+
+       if (is_asserted) {
+               ep->irq_pending |= BIT(intx);
+               msg_code = MSG_CODE_ASSERT_INTA + intx;
+       } else {
+               ep->irq_pending &= ~BIT(intx);
+               msg_code = MSG_CODE_DEASSERT_INTA + intx;
+       }
+
+       status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
+       if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
+               status ^= PCI_STATUS_INTERRUPT;
+               cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
+       }
+
+       offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
+                CDNS_PCIE_NORMAL_MSG_CODE(msg_code) |
+                CDNS_PCIE_MSG_NO_DATA;
+       writel(0, ep->irq_cpu_addr + offset);
+}
+
+static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx)
+{
+       u16 cmd;
+
+       cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND);
+       if (cmd & PCI_COMMAND_INTX_DISABLE)
+               return -EINVAL;
+
+       cdns_pcie_ep_assert_intx(ep, fn, intx, true);
+       /*
+        * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq()
+        * from drivers/pci/dwc/pci-dra7xx.c
+        */
+       mdelay(1);
+       cdns_pcie_ep_assert_intx(ep, fn, intx, false);
+       return 0;
+}
+
+static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
+                                    u8 interrupt_num)
+{
+       struct cdns_pcie *pcie = &ep->pcie;
+       u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+       u16 flags, mme, data, data_mask;
+       u8 msi_count;
+       u64 pci_addr, pci_addr_mask = 0xff;
+
+       /* Check whether the MSI feature has been enabled by the PCI host. */
+       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+       if (!(flags & PCI_MSI_FLAGS_ENABLE))
+               return -EINVAL;
+
+       /* Get the number of enabled MSIs */
+       mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
+       msi_count = 1 << mme;
+       if (!interrupt_num || interrupt_num > msi_count)
+               return -EINVAL;
+
+       /* Compute the data value to be written. */
+       data_mask = msi_count - 1;
+       data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
+       data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
+
+       /* Get the PCI address where to write the data into. */
+       pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
+       pci_addr <<= 32;
+       pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
+       pci_addr &= GENMASK_ULL(63, 2);
+
+       /* Set the outbound region if needed. */
+       if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
+                    ep->irq_pci_fn != fn)) {
+               /* First region was reserved for IRQ writes. */
+               cdns_pcie_set_outbound_region(pcie, fn, 0,
+                                             false,
+                                             ep->irq_phys_addr,
+                                             pci_addr & ~pci_addr_mask,
+                                             pci_addr_mask + 1);
+               ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
+               ep->irq_pci_fn = fn;
+       }
+       writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
+
+       return 0;
+}
+
+static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
+                                 enum pci_epc_irq_type type,
+                                 u16 interrupt_num)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+
+       switch (type) {
+       case PCI_EPC_IRQ_LEGACY:
+               return cdns_pcie_ep_send_legacy_irq(ep, fn, 0);
+
+       case PCI_EPC_IRQ_MSI:
+               return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static int cdns_pcie_ep_start(struct pci_epc *epc)
+{
+       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+       struct cdns_pcie *pcie = &ep->pcie;
+       struct pci_epf *epf;
+       u32 cfg;
+
+       /*
+        * BIT(0) is hardwired to 1, hence function 0 is always enabled
+        * and can't be disabled anyway.
+        */
+       cfg = BIT(0);
+       list_for_each_entry(epf, &epc->pci_epf, list)
+               cfg |= BIT(epf->func_no);
+       cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
+
+       return 0;
+}
+
+static const struct pci_epc_features cdns_pcie_epc_features = {
+       .linkup_notifier = false,
+       .msi_capable = true,
+       .msix_capable = false,
+};
+
+static const struct pci_epc_features*
+cdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
+{
+       return &cdns_pcie_epc_features;
+}
+
+static const struct pci_epc_ops cdns_pcie_epc_ops = {
+       .write_header   = cdns_pcie_ep_write_header,
+       .set_bar        = cdns_pcie_ep_set_bar,
+       .clear_bar      = cdns_pcie_ep_clear_bar,
+       .map_addr       = cdns_pcie_ep_map_addr,
+       .unmap_addr     = cdns_pcie_ep_unmap_addr,
+       .set_msi        = cdns_pcie_ep_set_msi,
+       .get_msi        = cdns_pcie_ep_get_msi,
+       .raise_irq      = cdns_pcie_ep_raise_irq,
+       .start          = cdns_pcie_ep_start,
+       .get_features   = cdns_pcie_ep_get_features,
+};
+
+
+int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
+{
+       struct device *dev = ep->pcie.dev;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct device_node *np = dev->of_node;
+       struct cdns_pcie *pcie = &ep->pcie;
+       struct resource *res;
+       struct pci_epc *epc;
+       int ret;
+
+       pcie->is_rc = false;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+       pcie->reg_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pcie->reg_base)) {
+               dev_err(dev, "missing \"reg\"\n");
+               return PTR_ERR(pcie->reg_base);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+       if (!res) {
+               dev_err(dev, "missing \"mem\"\n");
+               return -EINVAL;
+       }
+       pcie->mem_res = res;
+
+       ret = of_property_read_u32(np, "cdns,max-outbound-regions",
+                                  &ep->max_regions);
+       if (ret < 0) {
+               dev_err(dev, "missing \"cdns,max-outbound-regions\"\n");
+               return ret;
+       }
+       ep->ob_addr = devm_kcalloc(dev,
+                                  ep->max_regions, sizeof(*ep->ob_addr),
+                                  GFP_KERNEL);
+       if (!ep->ob_addr)
+               return -ENOMEM;
+
+       /* Disable all but function 0 (anyway BIT(0) is hardwired to 1). */
+       cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0));
+
+       epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
+       if (IS_ERR(epc)) {
+               dev_err(dev, "failed to create epc device\n");
+               ret = PTR_ERR(epc);
+               goto err_init;
+       }
+
+       epc_set_drvdata(epc, ep);
+
+       if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
+               epc->max_functions = 1;
+
+       ret = pci_epc_mem_init(epc, pcie->mem_res->start,
+                              resource_size(pcie->mem_res));
+       if (ret < 0) {
+               dev_err(dev, "failed to initialize the memory space\n");
+               goto err_init;
+       }
+
+       ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
+                                                 SZ_128K);
+       if (!ep->irq_cpu_addr) {
+               dev_err(dev, "failed to reserve memory space for MSI\n");
+               ret = -ENOMEM;
+               goto free_epc_mem;
+       }
+       ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
+       /* Reserve region 0 for IRQs */
+       set_bit(0, &ep->ob_region_map);
+
+       return 0;
+
+ free_epc_mem:
+       pci_epc_mem_exit(epc);
+
+ err_init:
+       pm_runtime_put_sync(dev);
+
+       return ret;
+}
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
new file mode 100644 (file)
index 0000000..9b1c396
--- /dev/null
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe host controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "pcie-cadence.h"
+
+static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+                                     int where)
+{
+       struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+       struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+       struct cdns_pcie *pcie = &rc->pcie;
+       unsigned int busn = bus->number;
+       u32 addr0, desc0;
+
+       if (busn == rc->bus_range->start) {
+               /*
+                * Only the root port (devfn == 0) is connected to this bus.
+                * All other PCI devices are behind some bridge hence on another
+                * bus.
+                */
+               if (devfn)
+                       return NULL;
+
+               return pcie->reg_base + (where & 0xfff);
+       }
+       /* Check that the link is up */
+       if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1))
+               return NULL;
+       /* Clear AXI link-down status */
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0);
+
+       /* Update Output registers for AXI region 0. */
+       addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
+               CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
+               CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
+
+       /* Configuration Type 0 or Type 1 access. */
+       desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+               CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+       /*
+        * The bus number was already set once for all in desc1 by
+        * cdns_pcie_host_init_address_translation().
+        */
+       if (busn == rc->bus_range->start + 1)
+               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
+       else
+               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
+
+       return rc->cfg_base + (where & 0xfff);
+}
+
+static struct pci_ops cdns_pcie_host_ops = {
+       .map_bus        = cdns_pci_map_bus,
+       .read           = pci_generic_config_read,
+       .write          = pci_generic_config_write,
+};
+
+
+static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
+{
+       struct cdns_pcie *pcie = &rc->pcie;
+       u32 value, ctrl;
+
+       /*
+        * Set the root complex BAR configuration register:
+        * - disable both BAR0 and BAR1.
+        * - enable Prefetchable Memory Base and Limit registers in type 1
+        *   config space (64 bits).
+        * - enable IO Base and Limit registers in type 1 config
+        *   space (32 bits).
+        */
+       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
+       value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
+               CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
+               CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
+               CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
+               CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
+               CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
+       cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
+
+       /* Set root port configuration space */
+       if (rc->vendor_id != 0xffff)
+               cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
+       if (rc->device_id != 0xffff)
+               cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
+
+       cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
+       cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
+       cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
+
+       return 0;
+}
+
+static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
+{
+       struct cdns_pcie *pcie = &rc->pcie;
+       struct resource *mem_res = pcie->mem_res;
+       struct resource *bus_range = rc->bus_range;
+       struct resource *cfg_res = rc->cfg_res;
+       struct device *dev = pcie->dev;
+       struct device_node *np = dev->of_node;
+       struct of_pci_range_parser parser;
+       struct of_pci_range range;
+       u32 addr0, addr1, desc1;
+       u64 cpu_addr;
+       int r, err;
+
+       /*
+        * Reserve region 0 for PCI configure space accesses:
+        * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
+        * cdns_pci_map_bus(), other region registers are set here once for all.
+        */
+       addr1 = 0; /* Should be programmed to zero. */
+       desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
+
+       cpu_addr = cfg_res->start - mem_res->start;
+       addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
+               (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+       addr1 = upper_32_bits(cpu_addr);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
+
+       err = of_pci_range_parser_init(&parser, np);
+       if (err)
+               return err;
+
+       r = 1;
+       for_each_of_pci_range(&parser, &range) {
+               bool is_io;
+
+               if (r >= rc->max_regions)
+                       break;
+
+               if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
+                       is_io = false;
+               else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
+                       is_io = true;
+               else
+                       continue;
+
+               cdns_pcie_set_outbound_region(pcie, 0, r, is_io,
+                                             range.cpu_addr,
+                                             range.pci_addr,
+                                             range.size);
+               r++;
+       }
+
+       /*
+        * Set Root Port no BAR match Inbound Translation registers:
+        * needed for MSI and DMA.
+        * Root Port BAR0 and BAR1 are disabled, hence no need to set their
+        * inbound translation registers.
+        */
+       addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
+       addr1 = 0;
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
+
+       return 0;
+}
+
+static int cdns_pcie_host_init(struct device *dev,
+                              struct list_head *resources,
+                              struct cdns_pcie_rc *rc)
+{
+       struct resource *bus_range = NULL;
+       int err;
+
+       /* Parse our PCI ranges and request their resources */
+       err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+       if (err)
+               return err;
+
+       rc->bus_range = bus_range;
+       rc->pcie.bus = bus_range->start;
+
+       err = cdns_pcie_host_init_root_port(rc);
+       if (err)
+               goto err_out;
+
+       err = cdns_pcie_host_init_address_translation(rc);
+       if (err)
+               goto err_out;
+
+       return 0;
+
+ err_out:
+       pci_free_resource_list(resources);
+       return err;
+}
+
+int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
+{
+       struct device *dev = rc->pcie.dev;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct device_node *np = dev->of_node;
+       struct pci_host_bridge *bridge;
+       struct list_head resources;
+       struct cdns_pcie *pcie;
+       struct resource *res;
+       int ret;
+
+       bridge = pci_host_bridge_from_priv(rc);
+       if (!bridge)
+               return -ENOMEM;
+
+       pcie = &rc->pcie;
+       pcie->is_rc = true;
+
+       rc->max_regions = 32;
+       of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
+
+       rc->no_bar_nbits = 32;
+       of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
+
+       rc->vendor_id = 0xffff;
+       of_property_read_u16(np, "vendor-id", &rc->vendor_id);
+
+       rc->device_id = 0xffff;
+       of_property_read_u16(np, "device-id", &rc->device_id);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+       pcie->reg_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pcie->reg_base)) {
+               dev_err(dev, "missing \"reg\"\n");
+               return PTR_ERR(pcie->reg_base);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+       rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
+       if (IS_ERR(rc->cfg_base)) {
+               dev_err(dev, "missing \"cfg\"\n");
+               return PTR_ERR(rc->cfg_base);
+       }
+       rc->cfg_res = res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+       if (!res) {
+               dev_err(dev, "missing \"mem\"\n");
+               return -EINVAL;
+       }
+
+       pcie->mem_res = res;
+
+       ret = cdns_pcie_host_init(dev, &resources, rc);
+       if (ret)
+               goto err_init;
+
+       list_splice_init(&resources, &bridge->windows);
+       bridge->dev.parent = dev;
+       bridge->busnr = pcie->bus;
+       bridge->ops = &cdns_pcie_host_ops;
+       bridge->map_irq = of_irq_parse_and_map_pci;
+       bridge->swizzle_irq = pci_common_swizzle;
+
+       ret = pci_host_probe(bridge);
+       if (ret < 0)
+               goto err_host_probe;
+
+       return 0;
+
+ err_host_probe:
+       pci_free_resource_list(&resources);
+
+ err_init:
+       pm_runtime_put_sync(dev);
+
+       return ret;
+}
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
new file mode 100644 (file)
index 0000000..f5c6bf6
--- /dev/null
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cadence PCIe platform  driver.
+ *
+ * Copyright (c) 2019, Cadence Design Systems
+ * Author: Tom Joseph <tjoseph@cadence.com>
+ */
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include "pcie-cadence.h"
+
+/**
+ * struct cdns_plat_pcie - private data for this PCIe platform driver
+ * @pcie: Cadence PCIe controller
+ * @is_rc: Set to 1 indicates the PCIe controller mode is Root Complex,
+ *         if 0 it is in Endpoint mode.
+ */
+struct cdns_plat_pcie {
+       struct cdns_pcie        *pcie;
+       bool is_rc;
+};
+
+struct cdns_plat_pcie_of_data {
+       bool is_rc;
+};
+
+static const struct of_device_id cdns_plat_pcie_of_match[];
+
+static int cdns_plat_pcie_probe(struct platform_device *pdev)
+{
+       const struct cdns_plat_pcie_of_data *data;
+       struct cdns_plat_pcie *cdns_plat_pcie;
+       const struct of_device_id *match;
+       struct device *dev = &pdev->dev;
+       struct pci_host_bridge *bridge;
+       struct cdns_pcie_ep *ep;
+       struct cdns_pcie_rc *rc;
+       int phy_count;
+       bool is_rc;
+       int ret;
+
+       match = of_match_device(cdns_plat_pcie_of_match, dev);
+       if (!match)
+               return -EINVAL;
+
+       data = (struct cdns_plat_pcie_of_data *)match->data;
+       is_rc = data->is_rc;
+
+       pr_debug(" Started %s with is_rc: %d\n", __func__, is_rc);
+       cdns_plat_pcie = devm_kzalloc(dev, sizeof(*cdns_plat_pcie), GFP_KERNEL);
+       if (!cdns_plat_pcie)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, cdns_plat_pcie);
+       if (is_rc) {
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_PLAT_HOST))
+                       return -ENODEV;
+
+               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+               if (!bridge)
+                       return -ENOMEM;
+
+               rc = pci_host_bridge_priv(bridge);
+               rc->pcie.dev = dev;
+               cdns_plat_pcie->pcie = &rc->pcie;
+               cdns_plat_pcie->is_rc = is_rc;
+
+               ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
+               if (ret) {
+                       dev_err(dev, "failed to init phy\n");
+                       return ret;
+               }
+               pm_runtime_enable(dev);
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "pm_runtime_get_sync() failed\n");
+                       goto err_get_sync;
+               }
+
+               ret = cdns_pcie_host_setup(rc);
+               if (ret)
+                       goto err_init;
+       } else {
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_PLAT_EP))
+                       return -ENODEV;
+
+               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+               if (!ep)
+                       return -ENOMEM;
+
+               ep->pcie.dev = dev;
+               cdns_plat_pcie->pcie = &ep->pcie;
+               cdns_plat_pcie->is_rc = is_rc;
+
+               ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
+               if (ret) {
+                       dev_err(dev, "failed to init phy\n");
+                       return ret;
+               }
+
+               pm_runtime_enable(dev);
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "pm_runtime_get_sync() failed\n");
+                       goto err_get_sync;
+               }
+
+               ret = cdns_pcie_ep_setup(ep);
+               if (ret)
+                       goto err_init;
+       }
+
+ err_init:
+       pm_runtime_put_sync(dev);
+
+ err_get_sync:
+       pm_runtime_disable(dev);
+       cdns_pcie_disable_phy(cdns_plat_pcie->pcie);
+       phy_count = cdns_plat_pcie->pcie->phy_count;
+       while (phy_count--)
+               device_link_del(cdns_plat_pcie->pcie->link[phy_count]);
+
+       return 0;
+}
+
+static void cdns_plat_pcie_shutdown(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct cdns_pcie *pcie = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_put_sync(dev);
+       if (ret < 0)
+               dev_dbg(dev, "pm_runtime_put_sync failed\n");
+
+       pm_runtime_disable(dev);
+
+       cdns_pcie_disable_phy(pcie);
+}
+
+static const struct cdns_plat_pcie_of_data cdns_plat_pcie_host_of_data = {
+       .is_rc = true,
+};
+
+static const struct cdns_plat_pcie_of_data cdns_plat_pcie_ep_of_data = {
+       .is_rc = false,
+};
+
+static const struct of_device_id cdns_plat_pcie_of_match[] = {
+       {
+               .compatible = "cdns,cdns-pcie-host",
+               .data = &cdns_plat_pcie_host_of_data,
+       },
+       {
+               .compatible = "cdns,cdns-pcie-ep",
+               .data = &cdns_plat_pcie_ep_of_data,
+       },
+       {},
+};
+
+static struct platform_driver cdns_plat_pcie_driver = {
+       .driver = {
+               .name = "cdns-pcie",
+               .of_match_table = cdns_plat_pcie_of_match,
+               .pm     = &cdns_pcie_pm_ops,
+       },
+       .probe = cdns_plat_pcie_probe,
+       .shutdown = cdns_plat_pcie_shutdown,
+};
+builtin_platform_driver(cdns_plat_pcie_driver);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
new file mode 100644 (file)
index 0000000..cd795f6
--- /dev/null
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#include <linux/kernel.h>
+
+#include "pcie-cadence.h"
+
+void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
+                                  u32 r, bool is_io,
+                                  u64 cpu_addr, u64 pci_addr, size_t size)
+{
+       /*
+        * roundup_pow_of_two() returns an unsigned long, which is not suited
+        * for 64bit values.
+        */
+       u64 sz = 1ULL << fls64(size - 1);
+       int nbits = ilog2(sz);
+       u32 addr0, addr1, desc0, desc1;
+
+       if (nbits < 8)
+               nbits = 8;
+
+       /* Set the PCI address */
+       addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
+               (lower_32_bits(pci_addr) & GENMASK(31, 8));
+       addr1 = upper_32_bits(pci_addr);
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1);
+
+       /* Set the PCIe header descriptor */
+       if (is_io)
+               desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO;
+       else
+               desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM;
+       desc1 = 0;
+
+       /*
+        * Whatever Bit [23] is set or not inside DESC0 register of the outbound
+        * PCIe descriptor, the PCI function number must be set into
+        * Bits [26:24] of DESC0 anyway.
+        *
+        * In Root Complex mode, the function number is always 0 but in Endpoint
+        * mode, the PCIe controller may support more than one function. This
+        * function number needs to be set properly into the outbound PCIe
+        * descriptor.
+        *
+        * Besides, setting Bit [23] is mandatory when in Root Complex mode:
+        * then the driver must provide the bus, resp. device, number in
+        * Bits [7:0] of DESC1, resp. Bits[31:27] of DESC0. Like the function
+        * number, the device number is always 0 in Root Complex mode.
+        *
+        * However when in Endpoint mode, we can clear Bit [23] of DESC0, hence
+        * the PCIe controller will use the captured values for the bus and
+        * device numbers.
+        */
+       if (pcie->is_rc) {
+               /* The device and function numbers are always 0. */
+               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+                        CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+               desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
+       } else {
+               /*
+                * Use captured values for bus and device numbers but still
+                * need to set the function number.
+                */
+               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
+       }
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
+
+       /* Set the CPU address */
+       cpu_addr -= pcie->mem_res->start;
+       addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
+               (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+       addr1 = upper_32_bits(cpu_addr);
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
+}
+
+void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
+                                                 u32 r, u64 cpu_addr)
+{
+       u32 addr0, addr1, desc0, desc1;
+
+       desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
+       desc1 = 0;
+
+       /* See cdns_pcie_set_outbound_region() comments above. */
+       if (pcie->is_rc) {
+               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+                        CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+               desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
+       } else {
+               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
+       }
+
+       /* Set the CPU address */
+       cpu_addr -= pcie->mem_res->start;
+       addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
+               (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+       addr1 = upper_32_bits(cpu_addr);
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
+}
+
+void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
+{
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
+
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
+       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
+}
+
+void cdns_pcie_disable_phy(struct cdns_pcie *pcie)
+{
+       int i = pcie->phy_count;
+
+       while (i--) {
+               phy_power_off(pcie->phy[i]);
+               phy_exit(pcie->phy[i]);
+       }
+}
+
+int cdns_pcie_enable_phy(struct cdns_pcie *pcie)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < pcie->phy_count; i++) {
+               ret = phy_init(pcie->phy[i]);
+               if (ret < 0)
+                       goto err_phy;
+
+               ret = phy_power_on(pcie->phy[i]);
+               if (ret < 0) {
+                       phy_exit(pcie->phy[i]);
+                       goto err_phy;
+               }
+       }
+
+       return 0;
+
+err_phy:
+       while (--i >= 0) {
+               phy_power_off(pcie->phy[i]);
+               phy_exit(pcie->phy[i]);
+       }
+
+       return ret;
+}
+
+int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
+{
+       struct device_node *np = dev->of_node;
+       int phy_count;
+       struct phy **phy;
+       struct device_link **link;
+       int i;
+       int ret;
+       const char *name;
+
+       phy_count = of_property_count_strings(np, "phy-names");
+       if (phy_count < 1) {
+               dev_err(dev, "no phy-names.  PHY will not be initialized\n");
+               pcie->phy_count = 0;
+               return 0;
+       }
+
+       phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return -ENOMEM;
+
+       link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
+       if (!link)
+               return -ENOMEM;
+
+       for (i = 0; i < phy_count; i++) {
+               of_property_read_string_index(np, "phy-names", i, &name);
+               phy[i] = devm_phy_get(dev, name);
+               if (IS_ERR(phy[i])) {
+                       ret = PTR_ERR(phy[i]);
+                       goto err_phy;
+               }
+               link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
+               if (!link[i]) {
+                       devm_phy_put(dev, phy[i]);
+                       ret = -EINVAL;
+                       goto err_phy;
+               }
+       }
+
+       pcie->phy_count = phy_count;
+       pcie->phy = phy;
+       pcie->link = link;
+
+       ret =  cdns_pcie_enable_phy(pcie);
+       if (ret)
+               goto err_phy;
+
+       return 0;
+
+err_phy:
+       while (--i >= 0) {
+               device_link_del(link[i]);
+               devm_phy_put(dev, phy[i]);
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cdns_pcie_suspend_noirq(struct device *dev)
+{
+       struct cdns_pcie *pcie = dev_get_drvdata(dev);
+
+       cdns_pcie_disable_phy(pcie);
+
+       return 0;
+}
+
+static int cdns_pcie_resume_noirq(struct device *dev)
+{
+       struct cdns_pcie *pcie = dev_get_drvdata(dev);
+       int ret;
+
+       ret = cdns_pcie_enable_phy(pcie);
+       if (ret) {
+               dev_err(dev, "failed to enable phy\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops cdns_pcie_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
+                                     cdns_pcie_resume_noirq)
+};
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
new file mode 100644 (file)
index 0000000..a2b28b9
--- /dev/null
@@ -0,0 +1,399 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#ifndef _PCIE_CADENCE_H
+#define _PCIE_CADENCE_H
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+
+/*
+ * Local Management Registers
+ */
+#define CDNS_PCIE_LM_BASE      0x00100000
+
+/* Vendor ID Register */
+#define CDNS_PCIE_LM_ID                (CDNS_PCIE_LM_BASE + 0x0044)
+#define  CDNS_PCIE_LM_ID_VENDOR_MASK   GENMASK(15, 0)
+#define  CDNS_PCIE_LM_ID_VENDOR_SHIFT  0
+#define  CDNS_PCIE_LM_ID_VENDOR(vid) \
+       (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
+#define  CDNS_PCIE_LM_ID_SUBSYS_MASK   GENMASK(31, 16)
+#define  CDNS_PCIE_LM_ID_SUBSYS_SHIFT  16
+#define  CDNS_PCIE_LM_ID_SUBSYS(sub) \
+       (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
+
+/* Root Port Requestor ID Register */
+#define CDNS_PCIE_LM_RP_RID    (CDNS_PCIE_LM_BASE + 0x0228)
+#define  CDNS_PCIE_LM_RP_RID_MASK      GENMASK(15, 0)
+#define  CDNS_PCIE_LM_RP_RID_SHIFT     0
+#define  CDNS_PCIE_LM_RP_RID_(rid) \
+       (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
+
+/* Endpoint Bus and Device Number Register */
+#define CDNS_PCIE_LM_EP_ID     (CDNS_PCIE_LM_BASE + 0x022c)
+#define  CDNS_PCIE_LM_EP_ID_DEV_MASK   GENMASK(4, 0)
+#define  CDNS_PCIE_LM_EP_ID_DEV_SHIFT  0
+#define  CDNS_PCIE_LM_EP_ID_BUS_MASK   GENMASK(15, 8)
+#define  CDNS_PCIE_LM_EP_ID_BUS_SHIFT  8
+
+/* Endpoint Function f BAR b Configuration Registers */
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
+       (CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
+       (CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
+#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
+       (GENMASK(4, 0) << ((b) * 8))
+#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
+       (((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
+#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
+       (GENMASK(7, 5) << ((b) * 8))
+#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
+       (((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
+
+/* Endpoint Function Configuration Register */
+#define CDNS_PCIE_LM_EP_FUNC_CFG       (CDNS_PCIE_LM_BASE + 0x02c0)
+
+/* Root Complex BAR Configuration Register */
+#define CDNS_PCIE_LM_RC_BAR_CFG        (CDNS_PCIE_LM_BASE + 0x0300)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK    GENMASK(5, 0)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
+       (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK                GENMASK(8, 6)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
+       (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK    GENMASK(13, 9)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
+       (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK                GENMASK(16, 14)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
+       (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE   BIT(17)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS   0
+#define  CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS   BIT(18)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE             BIT(19)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS             0
+#define  CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS             BIT(20)
+#define  CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE          BIT(31)
+
+/* BAR control values applicable to both Endpoint Function and Root Complex */
+#define  CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED            0x0
+#define  CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS           0x1
+#define  CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS          0x4
+#define  CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
+#define  CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS          0x6
+#define  CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
+
+
+/*
+ * Endpoint Function Registers (PCI configuration space for endpoint functions)
+ */
+#define CDNS_PCIE_EP_FUNC_BASE(fn)     (((fn) << 12) & GENMASK(19, 12))
+
+#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET       0x90
+
+/*
+ * Root Port Registers (PCI configuration space for the root port function)
+ */
+#define CDNS_PCIE_RP_BASE      0x00200000
+
+
+/*
+ * Address Translation Registers
+ */
+#define CDNS_PCIE_AT_BASE      0x00400000
+
+/* Region r Outbound AXI to PCIe Address Translation Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+       (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
+#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK   GENMASK(5, 0)
+#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
+       (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
+#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK   GENMASK(19, 12)
+#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+       (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
+#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK     GENMASK(27, 20)
+#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+       (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
+
+/* Region r Outbound AXI to PCIe Address Translation Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+       (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
+
+/* Region r Outbound PCIe Descriptor Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
+       (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK                GENMASK(3, 0)
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM         0x2
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO          0x6
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0  0xa
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1  0xb
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG  0xc
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG  0xd
+/* Bit 23 MUST be set in RC mode. */
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID    BIT(23)
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK       GENMASK(31, 24)
+#define  CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+       (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+
+/* Region r Outbound PCIe Descriptor Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_DESC1(r)        \
+       (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
+#define  CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
+#define  CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
+       ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
+
+/* Region r AXI Region Base Address Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+       (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
+#define  CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK   GENMASK(5, 0)
+#define  CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
+       (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
+
+/* Region r AXI Region Base Address Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+       (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
+
+/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
+       (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
+#define  CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK       GENMASK(5, 0)
+#define  CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
+       (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
+       (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
+
+/* AXI link down register */
+#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
+
+enum cdns_pcie_rp_bar {
+       RP_BAR0,
+       RP_BAR1,
+       RP_NO_BAR
+};
+
+/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
+       (CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
+#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
+       (CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
+
+/* Normal/Vendor specific message access: offset inside some outbound region */
+#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK      GENMASK(7, 5)
+#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
+       (((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
+#define CDNS_PCIE_NORMAL_MSG_CODE_MASK         GENMASK(15, 8)
+#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
+       (((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
+#define CDNS_PCIE_MSG_NO_DATA                  BIT(16)
+
+struct cdns_pcie;
+
+enum cdns_pcie_msg_code {
+       MSG_CODE_ASSERT_INTA    = 0x20,
+       MSG_CODE_ASSERT_INTB    = 0x21,
+       MSG_CODE_ASSERT_INTC    = 0x22,
+       MSG_CODE_ASSERT_INTD    = 0x23,
+       MSG_CODE_DEASSERT_INTA  = 0x24,
+       MSG_CODE_DEASSERT_INTB  = 0x25,
+       MSG_CODE_DEASSERT_INTC  = 0x26,
+       MSG_CODE_DEASSERT_INTD  = 0x27,
+};
+
+enum cdns_pcie_msg_routing {
+       /* Route to Root Complex */
+       MSG_ROUTING_TO_RC,
+
+       /* Use Address Routing */
+       MSG_ROUTING_BY_ADDR,
+
+       /* Use ID Routing */
+       MSG_ROUTING_BY_ID,
+
+       /* Route as Broadcast Message from Root Complex */
+       MSG_ROUTING_BCAST,
+
+       /* Local message; terminate at receiver (INTx messages) */
+       MSG_ROUTING_LOCAL,
+
+       /* Gather & route to Root Complex (PME_TO_Ack message) */
+       MSG_ROUTING_GATHER,
+};
+
+/**
+ * struct cdns_pcie - private data for Cadence PCIe controller drivers
+ * @reg_base: IO mapped register base
+ * @mem_res: start/end offsets in the physical system memory to map PCI accesses
+ * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
+ * @bus: In Root Complex mode, the bus number
+ */
+struct cdns_pcie {
+       void __iomem            *reg_base;
+       struct resource         *mem_res;
+       struct device           *dev;
+       bool                    is_rc;
+       u8                      bus;
+       int                     phy_count;
+       struct phy              **phy;
+       struct device_link      **link;
+       const struct cdns_pcie_common_ops *ops;
+};
+
+/**
+ * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
+ * @pcie: Cadence PCIe controller
+ * @dev: pointer to PCIe device
+ * @cfg_res: start/end offsets in the physical system memory to map PCI
+ *           configuration space accesses
+ * @bus_range: first/last buses behind the PCIe host controller
+ * @cfg_base: IO mapped window to access the PCI configuration space of a
+ *            single function at a time
+ * @max_regions: maximum number of regions supported by the hardware
+ * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
+ *                translation (nbits sets into the "no BAR match" register)
+ * @vendor_id: PCI vendor ID
+ * @device_id: PCI device ID
+ */
+struct cdns_pcie_rc {
+       struct cdns_pcie        pcie;
+       struct resource         *cfg_res;
+       struct resource         *bus_range;
+       void __iomem            *cfg_base;
+       u32                     max_regions;
+       u32                     no_bar_nbits;
+       u16                     vendor_id;
+       u16                     device_id;
+};
+
+/**
+ * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
+ * @pcie: Cadence PCIe controller
+ * @max_regions: maximum number of regions supported by hardware
+ * @ob_region_map: bitmask of mapped outbound regions
+ * @ob_addr: base addresses in the AXI bus where the outbound regions start
+ * @irq_phys_addr: base address on the AXI bus where the MSI/legacy IRQ
+ *                dedicated outbound regions is mapped.
+ * @irq_cpu_addr: base address in the CPU space where a write access triggers
+ *               the sending of a memory write (MSI) / normal message (legacy
+ *               IRQ) TLP through the PCIe bus.
+ * @irq_pci_addr: used to save the current mapping of the MSI/legacy IRQ
+ *               dedicated outbound region.
+ * @irq_pci_fn: the latest PCI function that has updated the mapping of
+ *             the MSI/legacy IRQ dedicated outbound region.
+ * @irq_pending: bitmask of asserted legacy IRQs.
+ */
+struct cdns_pcie_ep {
+       struct cdns_pcie        pcie;
+       u32                     max_regions;
+       unsigned long           ob_region_map;
+       phys_addr_t             *ob_addr;
+       phys_addr_t             irq_phys_addr;
+       void __iomem            *irq_cpu_addr;
+       u64                     irq_pci_addr;
+       u8                      irq_pci_fn;
+       u8                      irq_pending;
+};
+
+
+/* Register access */
+static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
+{
+       writeb(value, pcie->reg_base + reg);
+}
+
+static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
+{
+       writew(value, pcie->reg_base + reg);
+}
+
+static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
+{
+       writel(value, pcie->reg_base + reg);
+}
+
+static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
+{
+       return readl(pcie->reg_base + reg);
+}
+
+/* Root Port register access */
+static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
+                                      u32 reg, u8 value)
+{
+       writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
+                                      u32 reg, u16 value)
+{
+       writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+/* Endpoint Function register access */
+static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
+                                         u32 reg, u8 value)
+{
+       writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
+                                         u32 reg, u16 value)
+{
+       writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
+                                         u32 reg, u32 value)
+{
+       writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
+{
+       return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
+{
+       return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
+{
+       return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+#ifdef CONFIG_PCIE_CADENCE_HOST
+int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
+#else
+static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
+{
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PCIE_CADENCE_EP
+int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep);
+#else
+static inline int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
+{
+       return 0;
+}
+#endif
+void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
+                                  u32 r, bool is_io,
+                                  u64 cpu_addr, u64 pci_addr, size_t size);
+
+void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
+                                                 u32 r, u64 cpu_addr);
+
+void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
+void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
+int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
+int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
+extern const struct dev_pm_ops cdns_pcie_pm_ops;
+
+#endif /* _PCIE_CADENCE_H */
index 0ba988b..625a031 100644 (file)
@@ -7,9 +7,9 @@ config PCIE_DW
        bool
 
 config PCIE_DW_HOST
-        bool
+       bool
        depends on PCI_MSI_IRQ_DOMAIN
-        select PCIE_DW
+       select PCIE_DW
 
 config PCIE_DW_EP
        bool
@@ -224,7 +224,7 @@ config PCIE_HISI_STB
        depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW_HOST
        help
-          Say Y here if you want PCIe controller support on HiSilicon STB SoCs
+         Say Y here if you want PCIe controller support on HiSilicon STB SoCs
 
 config PCI_MESON
        bool "MESON PCIe controller"
index 4234ddb..b20651c 100644 (file)
@@ -353,7 +353,7 @@ static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
        struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
        enum pci_barno bar;
 
-       for (bar = BAR_0; bar <= BAR_5; bar++)
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                dw_pcie_ep_reset_bar(pci, bar);
 
        dra7xx_pcie_enable_wrapper_interrupts(dra7xx);
index ca9aa45..0d151ce 100644 (file)
@@ -58,7 +58,7 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        enum pci_barno bar;
 
-       for (bar = BAR_0; bar <= BAR_5; bar++)
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                dw_pcie_ep_reset_bar(pci, bar);
 }
 
index 3a5fa26..f24f79a 100644 (file)
@@ -263,6 +263,7 @@ static const struct ls_pcie_drvdata ls2088_drvdata = {
 static const struct of_device_id ls_pcie_of_match[] = {
        { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata },
        { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
+       { .compatible = "fsl,ls1028a-pcie", .data = &ls2088_drvdata },
        { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
        { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
        { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
index e35e9ea..3772b02 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/reset.h>
 #include <linux/resource.h>
 #include <linux/types.h>
+#include <linux/phy/phy.h>
 
 #include "pcie-designware.h"
 
@@ -96,12 +97,18 @@ struct meson_pcie_rc_reset {
        struct reset_control *apb;
 };
 
+struct meson_pcie_param {
+       bool has_shared_phy;
+};
+
 struct meson_pcie {
        struct dw_pcie pci;
        struct meson_pcie_mem_res mem_res;
        struct meson_pcie_clk_res clk_res;
        struct meson_pcie_rc_reset mrst;
        struct gpio_desc *reset_gpio;
+       struct phy *phy;
+       const struct meson_pcie_param *param;
 };
 
 static struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp,
@@ -123,10 +130,12 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
 {
        struct meson_pcie_rc_reset *mrst = &mp->mrst;
 
-       mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
-       if (IS_ERR(mrst->phy))
-               return PTR_ERR(mrst->phy);
-       reset_control_deassert(mrst->phy);
+       if (!mp->param->has_shared_phy) {
+               mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
+               if (IS_ERR(mrst->phy))
+                       return PTR_ERR(mrst->phy);
+               reset_control_deassert(mrst->phy);
+       }
 
        mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET);
        if (IS_ERR(mrst->port))
@@ -180,27 +189,52 @@ static int meson_pcie_get_mems(struct platform_device *pdev,
        if (IS_ERR(mp->mem_res.cfg_base))
                return PTR_ERR(mp->mem_res.cfg_base);
 
-       /* Meson SoC has two PCI controllers use same phy register*/
-       mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy");
-       if (IS_ERR(mp->mem_res.phy_base))
-               return PTR_ERR(mp->mem_res.phy_base);
+       /* Meson AXG SoC has two PCI controllers use same phy register */
+       if (!mp->param->has_shared_phy) {
+               mp->mem_res.phy_base =
+                       meson_pcie_get_mem_shared(pdev, mp, "phy");
+               if (IS_ERR(mp->mem_res.phy_base))
+                       return PTR_ERR(mp->mem_res.phy_base);
+       }
 
        return 0;
 }
 
-static void meson_pcie_power_on(struct meson_pcie *mp)
+static int meson_pcie_power_on(struct meson_pcie *mp)
 {
-       writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
+       int ret = 0;
+
+       if (mp->param->has_shared_phy) {
+               ret = phy_init(mp->phy);
+               if (ret)
+                       return ret;
+
+               ret = phy_power_on(mp->phy);
+               if (ret) {
+                       phy_exit(mp->phy);
+                       return ret;
+               }
+       } else
+               writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
+
+       return 0;
 }
 
-static void meson_pcie_reset(struct meson_pcie *mp)
+static int meson_pcie_reset(struct meson_pcie *mp)
 {
        struct meson_pcie_rc_reset *mrst = &mp->mrst;
-
-       reset_control_assert(mrst->phy);
-       udelay(PCIE_RESET_DELAY);
-       reset_control_deassert(mrst->phy);
-       udelay(PCIE_RESET_DELAY);
+       int ret = 0;
+
+       if (mp->param->has_shared_phy) {
+               ret = phy_reset(mp->phy);
+               if (ret)
+                       return ret;
+       } else {
+               reset_control_assert(mrst->phy);
+               udelay(PCIE_RESET_DELAY);
+               reset_control_deassert(mrst->phy);
+               udelay(PCIE_RESET_DELAY);
+       }
 
        reset_control_assert(mrst->port);
        reset_control_assert(mrst->apb);
@@ -208,6 +242,8 @@ static void meson_pcie_reset(struct meson_pcie *mp)
        reset_control_deassert(mrst->port);
        reset_control_deassert(mrst->apb);
        udelay(PCIE_RESET_DELAY);
+
+       return 0;
 }
 
 static inline struct clk *meson_pcie_probe_clock(struct device *dev,
@@ -250,15 +286,17 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
        if (IS_ERR(res->port_clk))
                return PTR_ERR(res->port_clk);
 
-       res->mipi_gate = meson_pcie_probe_clock(dev, "pcie_mipi_en", 0);
-       if (IS_ERR(res->mipi_gate))
-               return PTR_ERR(res->mipi_gate);
+       if (!mp->param->has_shared_phy) {
+               res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0);
+               if (IS_ERR(res->mipi_gate))
+                       return PTR_ERR(res->mipi_gate);
+       }
 
-       res->general_clk = meson_pcie_probe_clock(dev, "pcie_general", 0);
+       res->general_clk = meson_pcie_probe_clock(dev, "general", 0);
        if (IS_ERR(res->general_clk))
                return PTR_ERR(res->general_clk);
 
-       res->clk = meson_pcie_probe_clock(dev, "pcie", 0);
+       res->clk = meson_pcie_probe_clock(dev, "pclk", 0);
        if (IS_ERR(res->clk))
                return PTR_ERR(res->clk);
 
@@ -287,9 +325,9 @@ static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
 
 static void meson_pcie_assert_reset(struct meson_pcie *mp)
 {
-       gpiod_set_value_cansleep(mp->reset_gpio, 0);
-       udelay(500);
        gpiod_set_value_cansleep(mp->reset_gpio, 1);
+       udelay(500);
+       gpiod_set_value_cansleep(mp->reset_gpio, 0);
 }
 
 static void meson_pcie_init_dw(struct meson_pcie *mp)
@@ -524,6 +562,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
 
 static int meson_pcie_probe(struct platform_device *pdev)
 {
+       const struct meson_pcie_param *match_data;
        struct device *dev = &pdev->dev;
        struct dw_pcie *pci;
        struct meson_pcie *mp;
@@ -537,6 +576,19 @@ static int meson_pcie_probe(struct platform_device *pdev)
        pci->dev = dev;
        pci->ops = &dw_pcie_ops;
 
+       match_data = of_device_get_match_data(dev);
+       if (!match_data) {
+               dev_err(dev, "failed to get match data\n");
+               return -ENODEV;
+       }
+       mp->param = match_data;
+
+       if (mp->param->has_shared_phy) {
+               mp->phy = devm_phy_get(dev, "pcie");
+               if (IS_ERR(mp->phy))
+                       return PTR_ERR(mp->phy);
+       }
+
        mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
        if (IS_ERR(mp->reset_gpio)) {
                dev_err(dev, "get reset gpio failed\n");
@@ -555,13 +607,22 @@ static int meson_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       meson_pcie_power_on(mp);
-       meson_pcie_reset(mp);
+       ret = meson_pcie_power_on(mp);
+       if (ret) {
+               dev_err(dev, "phy power on failed, %d\n", ret);
+               return ret;
+       }
+
+       ret = meson_pcie_reset(mp);
+       if (ret) {
+               dev_err(dev, "reset failed, %d\n", ret);
+               goto err_phy;
+       }
 
        ret = meson_pcie_probe_clocks(mp);
        if (ret) {
                dev_err(dev, "init clock resources failed, %d\n", ret);
-               return ret;
+               goto err_phy;
        }
 
        platform_set_drvdata(pdev, mp);
@@ -569,15 +630,36 @@ static int meson_pcie_probe(struct platform_device *pdev)
        ret = meson_add_pcie_port(mp, pdev);
        if (ret < 0) {
                dev_err(dev, "Add PCIe port failed, %d\n", ret);
-               return ret;
+               goto err_phy;
        }
 
        return 0;
+
+err_phy:
+       if (mp->param->has_shared_phy) {
+               phy_power_off(mp->phy);
+               phy_exit(mp->phy);
+       }
+
+       return ret;
 }
 
+static struct meson_pcie_param meson_pcie_axg_param = {
+       .has_shared_phy = false,
+};
+
+static struct meson_pcie_param meson_pcie_g12a_param = {
+       .has_shared_phy = true,
+};
+
 static const struct of_device_id meson_pcie_of_match[] = {
        {
                .compatible = "amlogic,axg-pcie",
+               .data = &meson_pcie_axg_param,
+       },
+       {
+               .compatible = "amlogic,g12a-pcie",
+               .data = &meson_pcie_g12a_param,
        },
        {},
 };
index d00252b..9e2482b 100644 (file)
@@ -422,7 +422,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
        artpec6_pcie_wait_for_phy(artpec6_pcie);
        artpec6_pcie_set_nfts(artpec6_pcie);
 
-       for (bar = BAR_0; bar <= BAR_5; bar++)
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                dw_pcie_ep_reset_bar(pci, bar);
 }
 
index 0f36a92..395feb8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/pci_regs.h>
@@ -78,7 +79,8 @@ static struct msi_domain_info dw_pcie_msi_domain_info = {
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 {
        int i, pos, irq;
-       u32 val, num_ctrls;
+       unsigned long val;
+       u32 status, num_ctrls;
        irqreturn_t ret = IRQ_NONE;
 
        num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
@@ -86,14 +88,14 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
        for (i = 0; i < num_ctrls; i++) {
                dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS +
                                        (i * MSI_REG_CTRL_BLOCK_SIZE),
-                                   4, &val);
-               if (!val)
+                                   4, &status);
+               if (!status)
                        continue;
 
                ret = IRQ_HANDLED;
+               val = status;
                pos = 0;
-               while ((pos = find_next_bit((unsigned long *) &val,
-                                           MAX_MSI_IRQS_PER_CTRL,
+               while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL,
                                            pos)) != MAX_MSI_IRQS_PER_CTRL) {
                        irq = irq_find_mapping(pp->irq_domain,
                                               (i * MAX_MSI_IRQS_PER_CTRL) +
@@ -319,7 +321,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
        struct device *dev = pci->dev;
        struct device_node *np = dev->of_node;
        struct platform_device *pdev = to_platform_device(dev);
-       struct resource_entry *win, *tmp;
+       struct resource_entry *win;
        struct pci_bus *child;
        struct pci_host_bridge *bridge;
        struct resource *cfg_res;
@@ -342,31 +344,20 @@ int dw_pcie_host_init(struct pcie_port *pp)
        if (!bridge)
                return -ENOMEM;
 
-       ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                       &bridge->windows, &pp->io_base);
-       if (ret)
-               return ret;
-
-       ret = devm_request_pci_bus_resources(dev, &bridge->windows);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (ret)
                return ret;
 
        /* Get the I/O and memory ranges from DT */
-       resource_list_for_each_entry_safe(win, tmp, &bridge->windows) {
+       resource_list_for_each_entry(win, &bridge->windows) {
                switch (resource_type(win->res)) {
                case IORESOURCE_IO:
-                       ret = devm_pci_remap_iospace(dev, win->res,
-                                                    pp->io_base);
-                       if (ret) {
-                               dev_warn(dev, "Error %d: failed to map resource %pR\n",
-                                        ret, win->res);
-                               resource_list_destroy_entry(win);
-                       } else {
-                               pp->io = win->res;
-                               pp->io->name = "I/O";
-                               pp->io_size = resource_size(pp->io);
-                               pp->io_bus_addr = pp->io->start - win->offset;
-                       }
+                       pp->io = win->res;
+                       pp->io->name = "I/O";
+                       pp->io_size = resource_size(pp->io);
+                       pp->io_bus_addr = pp->io->start - win->offset;
+                       pp->io_base = pci_pio_to_address(pp->io->start);
                        break;
                case IORESOURCE_MEM:
                        pp->mem = win->res;
index b58fdcb..73646b6 100644 (file)
@@ -70,7 +70,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        enum pci_barno bar;
 
-       for (bar = BAR_0; bar <= BAR_5; bar++)
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
                dw_pcie_ep_reset_bar(pci, bar);
 }
 
index 5a18e94..5accdd6 100644 (file)
@@ -214,7 +214,7 @@ struct dw_pcie_ep {
        phys_addr_t             phys_base;
        size_t                  addr_size;
        size_t                  page_size;
-       u8                      bar_to_atu[6];
+       u8                      bar_to_atu[PCI_STD_NUM_BARS];
        phys_addr_t             *outbound_addr;
        unsigned long           *ib_window_map;
        unsigned long           *ob_window_map;
index f89f5ac..cbe95f0 100644 (file)
@@ -40,8 +40,6 @@
 #define APPL_PINMUX_CLKREQ_OVERRIDE            BIT(3)
 #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN  BIT(4)
 #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE     BIT(5)
-#define APPL_PINMUX_CLKREQ_OUT_OVRD_EN         BIT(9)
-#define APPL_PINMUX_CLKREQ_OUT_OVRD            BIT(10)
 
 #define APPL_CTRL                              0x4
 #define APPL_CTRL_SYS_PRE_DET_STATE            BIT(6)
@@ -1193,8 +1191,8 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
 
        if (!pcie->supports_clkreq) {
                val = appl_readl(pcie, APPL_PINMUX);
-               val |= APPL_PINMUX_CLKREQ_OUT_OVRD_EN;
-               val |= APPL_PINMUX_CLKREQ_OUT_OVRD;
+               val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN;
+               val &= ~APPL_PINMUX_CLKREQ_OVERRIDE;
                appl_writel(pcie, val, APPL_PINMUX);
        }
 
index 3f30ee4..8fd7bad 100644 (file)
 #define PCL_PIPEMON                    0x0044
 #define PCL_PCLK_ALIVE                 BIT(15)
 
+#define PCL_MODE                       0x8000
+#define PCL_MODE_REGEN                 BIT(8)
+#define PCL_MODE_REGVAL                        BIT(0)
+
 #define PCL_APP_READY_CTRL             0x8008
 #define PCL_APP_LTSSM_ENABLE           BIT(0)
 
@@ -85,6 +89,12 @@ static void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv)
 {
        u32 val;
 
+       /* set RC MODE */
+       val = readl(priv->base + PCL_MODE);
+       val |= PCL_MODE_REGEN;
+       val &= ~PCL_MODE_REGVAL;
+       writel(val, priv->base + PCL_MODE);
+
        /* use auxiliary power detection */
        val = readl(priv->base + PCL_APP_PM0);
        val |= PCL_SYS_AUX_PWR_DET;
index fc0fe4d..2a20b64 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 
        (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))    | \
         PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
 
-#define PIO_TIMEOUT_MS                 1
+#define PIO_RETRY_CNT                  500
+#define PIO_RETRY_DELAY                        2 /* 2 us*/
 
 #define LINK_WAIT_MAX_RETRIES          10
 #define LINK_WAIT_USLEEP_MIN           90000
 #define LINK_WAIT_USLEEP_MAX           100000
+#define RETRAIN_WAIT_MAX_RETRIES       10
+#define RETRAIN_WAIT_USLEEP_US         2000
 
 #define MSI_IRQ_NUM                    32
 
 struct advk_pcie {
        struct platform_device *pdev;
        void __iomem *base;
-       struct list_head resources;
        struct irq_domain *irq_domain;
        struct irq_chip irq_chip;
        struct irq_domain *msi_domain;
@@ -239,6 +242,17 @@ static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
        return -ETIMEDOUT;
 }
 
+static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
+{
+       size_t retries;
+
+       for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) {
+               if (!advk_pcie_link_up(pcie))
+                       break;
+               udelay(RETRAIN_WAIT_USLEEP_US);
+       }
+}
+
 static void advk_pcie_setup_hw(struct advk_pcie *pcie)
 {
        u32 reg;
@@ -324,6 +338,14 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
        reg |= PIO_CTRL_ADDR_WIN_DISABLE;
        advk_writel(pcie, reg, PIO_CTRL);
 
+       /*
+        * PERST# signal could have been asserted by pinctrl subsystem before
+        * probe() callback has been called, making the endpoint going into
+        * fundamental reset. As required by PCI Express spec a delay for at
+        * least 100ms after such a reset before link training is needed.
+        */
+       msleep(PCI_PM_D3COLD_WAIT);
+
        /* Start link training */
        reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
        reg |= PCIE_CORE_LINK_TRAINING;
@@ -383,17 +405,16 @@ static void advk_pcie_check_pio_status(struct advk_pcie *pcie)
 static int advk_pcie_wait_pio(struct advk_pcie *pcie)
 {
        struct device *dev = &pcie->pdev->dev;
-       unsigned long timeout;
-
-       timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS);
+       int i;
 
-       while (time_before(jiffies, timeout)) {
+       for (i = 0; i < PIO_RETRY_CNT; i++) {
                u32 start, isr;
 
                start = advk_readl(pcie, PIO_START);
                isr = advk_readl(pcie, PIO_ISR);
                if (!start && isr)
                        return 0;
+               udelay(PIO_RETRY_DELAY);
        }
 
        dev_err(dev, "config read/write timed out\n");
@@ -415,7 +436,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
 
        case PCI_EXP_RTCTL: {
                u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
-               *value = (val & PCIE_MSG_PM_PME_MASK) ? PCI_EXP_RTCTL_PMEIE : 0;
+               *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE;
                return PCI_BRIDGE_EMUL_HANDLED;
        }
 
@@ -426,11 +447,20 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
                return PCI_BRIDGE_EMUL_HANDLED;
        }
 
+       case PCI_EXP_LNKCTL: {
+               /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
+               u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
+                       ~(PCI_EXP_LNKSTA_LT << 16);
+               if (!advk_pcie_link_up(pcie))
+                       val |= (PCI_EXP_LNKSTA_LT << 16);
+               *value = val;
+               return PCI_BRIDGE_EMUL_HANDLED;
+       }
+
        case PCI_CAP_LIST_ID:
        case PCI_EXP_DEVCAP:
        case PCI_EXP_DEVCTL:
        case PCI_EXP_LNKCAP:
-       case PCI_EXP_LNKCTL:
                *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
                return PCI_BRIDGE_EMUL_HANDLED;
        default:
@@ -447,14 +477,24 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
 
        switch (reg) {
        case PCI_EXP_DEVCTL:
+               advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
+               break;
+
        case PCI_EXP_LNKCTL:
                advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
+               if (new & PCI_EXP_LNKCTL_RL)
+                       advk_pcie_wait_for_retrain(pcie);
                break;
 
-       case PCI_EXP_RTCTL:
-               new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
-               advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
+       case PCI_EXP_RTCTL: {
+               /* Only mask/unmask PME interrupt */
+               u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
+                       ~PCIE_MSG_PM_PME_MASK;
+               if ((new & PCI_EXP_RTCTL_PMEIE) == 0)
+                       val |= PCIE_MSG_PM_PME_MASK;
+               advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
                break;
+       }
 
        case PCI_EXP_RTSTA:
                new = (new & PCI_EXP_RTSTA_PME) >> 9;
@@ -479,18 +519,20 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
 {
        struct pci_bridge_emul *bridge = &pcie->bridge;
 
-       bridge->conf.vendor = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff;
-       bridge->conf.device = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) >> 16;
+       bridge->conf.vendor =
+               cpu_to_le16(advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff);
+       bridge->conf.device =
+               cpu_to_le16(advk_readl(pcie, PCIE_CORE_DEV_ID_REG) >> 16);
        bridge->conf.class_revision =
-               advk_readl(pcie, PCIE_CORE_DEV_REV_REG) & 0xff;
+               cpu_to_le32(advk_readl(pcie, PCIE_CORE_DEV_REV_REG) & 0xff);
 
        /* Support 32 bits I/O addressing */
        bridge->conf.iobase = PCI_IO_RANGE_TYPE_32;
        bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32;
 
        /* Support 64 bits memory pref */
-       bridge->conf.pref_mem_base = PCI_PREF_RANGE_TYPE_64;
-       bridge->conf.pref_mem_limit = PCI_PREF_RANGE_TYPE_64;
+       bridge->conf.pref_mem_base = cpu_to_le16(PCI_PREF_RANGE_TYPE_64);
+       bridge->conf.pref_mem_limit = cpu_to_le16(PCI_PREF_RANGE_TYPE_64);
 
        /* Support interrupt A for MSI feature */
        bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE;
@@ -910,63 +952,11 @@ static irqreturn_t advk_pcie_irq_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
-{
-       int err, res_valid = 0;
-       struct device *dev = &pcie->pdev->dev;
-       struct resource_entry *win, *tmp;
-       resource_size_t iobase;
-
-       INIT_LIST_HEAD(&pcie->resources);
-
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                                   &pcie->resources, &iobase);
-       if (err)
-               return err;
-
-       err = devm_request_pci_bus_resources(dev, &pcie->resources);
-       if (err)
-               goto out_release_res;
-
-       resource_list_for_each_entry_safe(win, tmp, &pcie->resources) {
-               struct resource *res = win->res;
-
-               switch (resource_type(res)) {
-               case IORESOURCE_IO:
-                       err = devm_pci_remap_iospace(dev, res, iobase);
-                       if (err) {
-                               dev_warn(dev, "error %d: failed to map resource %pR\n",
-                                        err, res);
-                               resource_list_destroy_entry(win);
-                       }
-                       break;
-               case IORESOURCE_MEM:
-                       res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-                       break;
-               case IORESOURCE_BUS:
-                       pcie->root_bus_nr = res->start;
-                       break;
-               }
-       }
-
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
-       }
-
-       return 0;
-
-out_release_res:
-       pci_free_resource_list(&pcie->resources);
-       return err;
-}
-
 static int advk_pcie_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct advk_pcie *pcie;
-       struct resource *res;
+       struct resource *res, *bus;
        struct pci_host_bridge *bridge;
        int ret, irq;
 
@@ -991,11 +981,13 @@ static int advk_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = advk_pcie_parse_request_of_pci_ranges(pcie);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, &bus);
        if (ret) {
                dev_err(dev, "Failed to parse resources\n");
                return ret;
        }
+       pcie->root_bus_nr = bus->start;
 
        advk_pcie_setup_hw(pcie);
 
@@ -1014,7 +1006,6 @@ static int advk_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       list_splice_init(&pcie->resources, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = pcie;
        bridge->busnr = 0;
index bf5ece5..1b67564 100644 (file)
@@ -375,12 +375,11 @@ static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p)
        return 0;
 }
 
-static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p,
-                                           struct device_node *np)
+static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p)
 {
-       struct of_pci_range range;
-       struct of_pci_range_parser parser;
        struct device *dev = p->dev;
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
+       struct resource_entry *entry;
        u32 confreg[3] = {
                FARADAY_PCI_MEM1_BASE_SIZE,
                FARADAY_PCI_MEM2_BASE_SIZE,
@@ -389,19 +388,13 @@ static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p,
        int i = 0;
        u32 val;
 
-       if (of_pci_dma_range_parser_init(&parser, np)) {
-               dev_err(dev, "missing dma-ranges property\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Get the dma-ranges from the device tree
-        */
-       for_each_of_pci_range(&parser, &range) {
-               u64 end = range.pci_addr + range.size - 1;
+       resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+               u64 pci_addr = entry->res->start - entry->offset;
+               u64 end = entry->res->end - entry->offset;
                int ret;
 
-               ret = faraday_res_to_memcfg(range.pci_addr, range.size, &val);
+               ret = faraday_res_to_memcfg(pci_addr,
+                                           resource_size(entry->res), &val);
                if (ret) {
                        dev_err(dev,
                                "DMA range %d: illegal MEM resource size\n", i);
@@ -409,7 +402,7 @@ static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p,
                }
 
                dev_info(dev, "DMA MEM%d BASE: 0x%016llx -> 0x%016llx config %08x\n",
-                        i + 1, range.pci_addr, end, val);
+                        i + 1, pci_addr, end, val);
                if (i <= 2) {
                        faraday_raw_pci_write_config(p, 0, 0, confreg[i],
                                                     4, val);
@@ -430,10 +423,8 @@ static int faraday_pci_probe(struct platform_device *pdev)
        const struct faraday_pci_variant *variant =
                of_device_get_match_data(dev);
        struct resource *regs;
-       resource_size_t io_base;
        struct resource_entry *win;
        struct faraday_pci *p;
-       struct resource *mem;
        struct resource *io;
        struct pci_host_bridge *host;
        struct clk *clk;
@@ -441,7 +432,6 @@ static int faraday_pci_probe(struct platform_device *pdev)
        unsigned char cur_bus_speed = PCI_SPEED_33MHz;
        int ret;
        u32 val;
-       LIST_HEAD(res);
 
        host = devm_pci_alloc_host_bridge(dev, sizeof(*p));
        if (!host)
@@ -480,44 +470,21 @@ static int faraday_pci_probe(struct platform_device *pdev)
        if (IS_ERR(p->base))
                return PTR_ERR(p->base);
 
-       ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                                   &res, &io_base);
-       if (ret)
-               return ret;
-
-       ret = devm_request_pci_bus_resources(dev, &res);
+       ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
+                                             &host->dma_ranges, NULL);
        if (ret)
                return ret;
 
-       /* Get the I/O and memory ranges from DT */
-       resource_list_for_each_entry(win, &res) {
-               switch (resource_type(win->res)) {
-               case IORESOURCE_IO:
-                       io = win->res;
-                       io->name = "Gemini PCI I/O";
-                       if (!faraday_res_to_memcfg(io->start - win->offset,
-                                                  resource_size(io), &val)) {
-                               /* setup I/O space size */
-                               writel(val, p->base + PCI_IOSIZE);
-                       } else {
-                               dev_err(dev, "illegal IO mem size\n");
-                               return -EINVAL;
-                       }
-                       ret = devm_pci_remap_iospace(dev, io, io_base);
-                       if (ret) {
-                               dev_warn(dev, "error %d: failed to map resource %pR\n",
-                                        ret, io);
-                               continue;
-                       }
-                       break;
-               case IORESOURCE_MEM:
-                       mem = win->res;
-                       mem->name = "Gemini PCI MEM";
-                       break;
-               case IORESOURCE_BUS:
-                       break;
-               default:
-                       break;
+       win = resource_list_first_type(&host->windows, IORESOURCE_IO);
+       if (win) {
+               io = win->res;
+               if (!faraday_res_to_memcfg(io->start - win->offset,
+                                          resource_size(io), &val)) {
+                       /* setup I/O space size */
+                       writel(val, p->base + PCI_IOSIZE);
+               } else {
+                       dev_err(dev, "illegal IO mem size\n");
+                       return -EINVAL;
                }
        }
 
@@ -565,11 +532,10 @@ static int faraday_pci_probe(struct platform_device *pdev)
                        cur_bus_speed = PCI_SPEED_66MHz;
        }
 
-       ret = faraday_pci_parse_map_dma_ranges(p, dev->of_node);
+       ret = faraday_pci_parse_map_dma_ranges(p);
        if (ret)
                return ret;
 
-       list_splice_init(&res, &host->windows);
        ret = pci_scan_root_bus_bridge(host);
        if (ret) {
                dev_err(dev, "failed to scan host: %d\n", ret);
@@ -581,7 +547,6 @@ static int faraday_pci_probe(struct platform_device *pdev)
 
        pci_bus_assign_resources(p->bus);
        pci_bus_add_devices(p->bus);
-       pci_free_resource_list(&res);
 
        return 0;
 }
index c8cb9c5..250a3fc 100644 (file)
@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci_init(struct device *dev,
        struct pci_config_window *cfg;
 
        /* Parse our PCI ranges and request their resources */
-       err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
+       err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
        if (err)
                return ERR_PTR(err);
 
index f1f3002..9977abf 100644 (file)
@@ -76,11 +76,6 @@ static enum pci_protocol_version_t pci_protocol_versions[] = {
        PCI_PROTOCOL_VERSION_1_1,
 };
 
-/*
- * Protocol version negotiated by hv_pci_protocol_negotiation().
- */
-static enum pci_protocol_version_t pci_protocol_version;
-
 #define PCI_CONFIG_MMIO_LENGTH 0x2000
 #define CFG_PAGE_OFFSET 0x1000
 #define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET)
@@ -307,7 +302,7 @@ struct pci_bus_relations {
 struct pci_q_res_req_response {
        struct vmpacket_descriptor hdr;
        s32 status;                     /* negative values are failures */
-       u32 probed_bar[6];
+       u32 probed_bar[PCI_STD_NUM_BARS];
 } __packed;
 
 struct pci_set_power {
@@ -455,12 +450,15 @@ enum hv_pcibus_state {
        hv_pcibus_init = 0,
        hv_pcibus_probed,
        hv_pcibus_installed,
+       hv_pcibus_removing,
        hv_pcibus_removed,
        hv_pcibus_maximum
 };
 
 struct hv_pcibus_device {
        struct pci_sysdata sysdata;
+       /* Protocol version negotiated with the host */
+       enum pci_protocol_version_t protocol_version;
        enum hv_pcibus_state state;
        refcount_t remove_lock;
        struct hv_device *hdev;
@@ -539,7 +537,7 @@ struct hv_pci_dev {
         * What would be observed if one wrote 0xFFFFFFFF to a BAR and then
         * read it back, for each of the BAR offsets within config space.
         */
-       u32 probed_bar[6];
+       u32 probed_bar[PCI_STD_NUM_BARS];
 };
 
 struct hv_pci_compl {
@@ -1224,7 +1222,7 @@ static void hv_irq_unmask(struct irq_data *data)
         * negative effect (yet?).
         */
 
-       if (pci_protocol_version >= PCI_PROTOCOL_VERSION_1_2) {
+       if (hbus->protocol_version >= PCI_PROTOCOL_VERSION_1_2) {
                /*
                 * PCI_PROTOCOL_VERSION_1_2 supports the VP_SET version of the
                 * HVCALL_RETARGET_INTERRUPT hypercall, which also coincides
@@ -1394,7 +1392,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
        ctxt.pci_pkt.completion_func = hv_pci_compose_compl;
        ctxt.pci_pkt.compl_ctxt = &comp;
 
-       switch (pci_protocol_version) {
+       switch (hbus->protocol_version) {
        case PCI_PROTOCOL_VERSION_1_1:
                size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1,
                                        dest,
@@ -1610,7 +1608,7 @@ static void survey_child_resources(struct hv_pcibus_device *hbus)
         * so it's sufficient to just add them up without tracking alignment.
         */
        list_for_each_entry(hpdev, &hbus->children, list_entry) {
-               for (i = 0; i < 6; i++) {
+               for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                        if (hpdev->probed_bar[i] & PCI_BASE_ADDRESS_SPACE_IO)
                                dev_err(&hbus->hdev->device,
                                        "There's an I/O BAR in this list!\n");
@@ -1681,10 +1679,27 @@ static void prepopulate_bars(struct hv_pcibus_device *hbus)
 
        spin_lock_irqsave(&hbus->device_list_lock, flags);
 
+       /*
+        * Clear the memory enable bit, in case it's already set. This occurs
+        * in the suspend path of hibernation, where the device is suspended,
+        * resumed and suspended again: see hibernation_snapshot() and
+        * hibernation_platform_enter().
+        *
+        * If the memory enable bit is already set, Hyper-V sliently ignores
+        * the below BAR updates, and the related PCI device driver can not
+        * work, because reading from the device register(s) always returns
+        * 0xFFFFFFFF.
+        */
+       list_for_each_entry(hpdev, &hbus->children, list_entry) {
+               _hv_pcifront_read_config(hpdev, PCI_COMMAND, 2, &command);
+               command &= ~PCI_COMMAND_MEMORY;
+               _hv_pcifront_write_config(hpdev, PCI_COMMAND, 2, command);
+       }
+
        /* Pick addresses for the BARs. */
        do {
                list_for_each_entry(hpdev, &hbus->children, list_entry) {
-                       for (i = 0; i < 6; i++) {
+                       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                                bar_val = hpdev->probed_bar[i];
                                if (bar_val == 0)
                                        continue;
@@ -1841,7 +1856,7 @@ static void q_resource_requirements(void *context, struct pci_response *resp,
                        "query resource requirements failed: %x\n",
                        resp->status);
        } else {
-               for (i = 0; i < 6; i++) {
+               for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                        completion->hpdev->probed_bar[i] =
                                q_res_req->probed_bar[i];
                }
@@ -2107,6 +2122,12 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
        unsigned long flags;
        bool pending_dr;
 
+       if (hbus->state == hv_pcibus_removing) {
+               dev_info(&hbus->hdev->device,
+                        "PCI VMBus BUS_RELATIONS: ignored\n");
+               return;
+       }
+
        dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT);
        if (!dr_wrk)
                return;
@@ -2223,11 +2244,19 @@ static void hv_eject_device_work(struct work_struct *work)
  */
 static void hv_pci_eject_device(struct hv_pci_dev *hpdev)
 {
+       struct hv_pcibus_device *hbus = hpdev->hbus;
+       struct hv_device *hdev = hbus->hdev;
+
+       if (hbus->state == hv_pcibus_removing) {
+               dev_info(&hdev->device, "PCI VMBus EJECT: ignored\n");
+               return;
+       }
+
        hpdev->state = hv_pcichild_ejecting;
        get_pcichild(hpdev);
        INIT_WORK(&hpdev->wrk, hv_eject_device_work);
-       get_hvpcibus(hpdev->hbus);
-       queue_work(hpdev->hbus->wq, &hpdev->wrk);
+       get_hvpcibus(hbus);
+       queue_work(hbus->wq, &hpdev->wrk);
 }
 
 /**
@@ -2379,8 +2408,11 @@ static void hv_pci_onchannelcallback(void *context)
  * failing if the host doesn't support the necessary protocol
  * level.
  */
-static int hv_pci_protocol_negotiation(struct hv_device *hdev)
+static int hv_pci_protocol_negotiation(struct hv_device *hdev,
+                                      enum pci_protocol_version_t version[],
+                                      int num_version)
 {
+       struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
        struct pci_version_request *version_req;
        struct hv_pci_compl comp_pkt;
        struct pci_packet *pkt;
@@ -2403,8 +2435,8 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev)
        version_req = (struct pci_version_request *)&pkt->message;
        version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION;
 
-       for (i = 0; i < ARRAY_SIZE(pci_protocol_versions); i++) {
-               version_req->protocol_version = pci_protocol_versions[i];
+       for (i = 0; i < num_version; i++) {
+               version_req->protocol_version = version[i];
                ret = vmbus_sendpacket(hdev->channel, version_req,
                                sizeof(struct pci_version_request),
                                (unsigned long)pkt, VM_PKT_DATA_INBAND,
@@ -2420,10 +2452,10 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev)
                }
 
                if (comp_pkt.completion_status >= 0) {
-                       pci_protocol_version = pci_protocol_versions[i];
+                       hbus->protocol_version = version[i];
                        dev_info(&hdev->device,
                                "PCI VMBus probing: Using version %#x\n",
-                               pci_protocol_version);
+                               hbus->protocol_version);
                        goto exit;
                }
 
@@ -2707,7 +2739,7 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
        u32 wslot;
        int ret;
 
-       size_res = (pci_protocol_version < PCI_PROTOCOL_VERSION_1_2)
+       size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2)
                        ? sizeof(*res_assigned) : sizeof(*res_assigned2);
 
        pkt = kmalloc(sizeof(*pkt) + size_res, GFP_KERNEL);
@@ -2726,7 +2758,7 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
                pkt->completion_func = hv_pci_generic_compl;
                pkt->compl_ctxt = &comp_pkt;
 
-               if (pci_protocol_version < PCI_PROTOCOL_VERSION_1_2) {
+               if (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2) {
                        res_assigned =
                                (struct pci_resources_assigned *)&pkt->message;
                        res_assigned->message_type.type =
@@ -2870,9 +2902,27 @@ static int hv_pci_probe(struct hv_device *hdev,
         * hv_pcibus_device contains the hypercall arguments for retargeting in
         * hv_irq_unmask(). Those must not cross a page boundary.
         */
-       BUILD_BUG_ON(sizeof(*hbus) > PAGE_SIZE);
+       BUILD_BUG_ON(sizeof(*hbus) > HV_HYP_PAGE_SIZE);
 
-       hbus = (struct hv_pcibus_device *)get_zeroed_page(GFP_KERNEL);
+       /*
+        * With the recent 59bb47985c1d ("mm, sl[aou]b: guarantee natural
+        * alignment for kmalloc(power-of-two)"), kzalloc() is able to allocate
+        * a 4KB buffer that is guaranteed to be 4KB-aligned. Here the size and
+        * alignment of hbus is important because hbus's field
+        * retarget_msi_interrupt_params must not cross a 4KB page boundary.
+        *
+        * Here we prefer kzalloc to get_zeroed_page(), because a buffer
+        * allocated by the latter is not tracked and scanned by kmemleak, and
+        * hence kmemleak reports the pointer contained in the hbus buffer
+        * (i.e. the hpdev struct, which is created in new_pcichild_device() and
+        * is tracked by hbus->children) as memory leak (false positive).
+        *
+        * If the kernel doesn't have 59bb47985c1d, get_zeroed_page() *must* be
+        * used to allocate the hbus buffer and we can avoid the kmemleak false
+        * positive by using kmemleak_alloc() and kmemleak_free() to ask
+        * kmemleak to track and scan the hbus buffer.
+        */
+       hbus = (struct hv_pcibus_device *)kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
        if (!hbus)
                return -ENOMEM;
        hbus->state = hv_pcibus_init;
@@ -2930,7 +2980,8 @@ static int hv_pci_probe(struct hv_device *hdev,
 
        hv_set_drvdata(hdev, hbus);
 
-       ret = hv_pci_protocol_negotiation(hdev);
+       ret = hv_pci_protocol_negotiation(hdev, pci_protocol_versions,
+                                         ARRAY_SIZE(pci_protocol_versions));
        if (ret)
                goto close;
 
@@ -3011,7 +3062,7 @@ free_bus:
        return ret;
 }
 
-static void hv_pci_bus_exit(struct hv_device *hdev)
+static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
 {
        struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
        struct {
@@ -3027,16 +3078,20 @@ static void hv_pci_bus_exit(struct hv_device *hdev)
         * access the per-channel ringbuffer any longer.
         */
        if (hdev->channel->rescind)
-               return;
+               return 0;
 
-       /* Delete any children which might still exist. */
-       memset(&relations, 0, sizeof(relations));
-       hv_pci_devices_present(hbus, &relations);
+       if (!hibernating) {
+               /* Delete any children which might still exist. */
+               memset(&relations, 0, sizeof(relations));
+               hv_pci_devices_present(hbus, &relations);
+       }
 
        ret = hv_send_resources_released(hdev);
-       if (ret)
+       if (ret) {
                dev_err(&hdev->device,
                        "Couldn't send resources released packet(s)\n");
+               return ret;
+       }
 
        memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
        init_completion(&comp_pkt.host_event);
@@ -3049,8 +3104,13 @@ static void hv_pci_bus_exit(struct hv_device *hdev)
                               (unsigned long)&pkt.teardown_packet,
                               VM_PKT_DATA_INBAND,
                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-       if (!ret)
-               wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ);
+       if (ret)
+               return ret;
+
+       if (wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ) == 0)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
 /**
@@ -3062,6 +3122,7 @@ static void hv_pci_bus_exit(struct hv_device *hdev)
 static int hv_pci_remove(struct hv_device *hdev)
 {
        struct hv_pcibus_device *hbus;
+       int ret;
 
        hbus = hv_get_drvdata(hdev);
        if (hbus->state == hv_pcibus_installed) {
@@ -3074,7 +3135,7 @@ static int hv_pci_remove(struct hv_device *hdev)
                hbus->state = hv_pcibus_removed;
        }
 
-       hv_pci_bus_exit(hdev);
+       ret = hv_pci_bus_exit(hdev, false);
 
        vmbus_close(hdev->channel);
 
@@ -3090,10 +3151,97 @@ static int hv_pci_remove(struct hv_device *hdev)
 
        hv_put_dom_num(hbus->sysdata.domain);
 
-       free_page((unsigned long)hbus);
+       kfree(hbus);
+       return ret;
+}
+
+static int hv_pci_suspend(struct hv_device *hdev)
+{
+       struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+       enum hv_pcibus_state old_state;
+       int ret;
+
+       /*
+        * hv_pci_suspend() must make sure there are no pending work items
+        * before calling vmbus_close(), since it runs in a process context
+        * as a callback in dpm_suspend().  When it starts to run, the channel
+        * callback hv_pci_onchannelcallback(), which runs in a tasklet
+        * context, can be still running concurrently and scheduling new work
+        * items onto hbus->wq in hv_pci_devices_present() and
+        * hv_pci_eject_device(), and the work item handlers can access the
+        * vmbus channel, which can be being closed by hv_pci_suspend(), e.g.
+        * the work item handler pci_devices_present_work() ->
+        * new_pcichild_device() writes to the vmbus channel.
+        *
+        * To eliminate the race, hv_pci_suspend() disables the channel
+        * callback tasklet, sets hbus->state to hv_pcibus_removing, and
+        * re-enables the tasklet. This way, when hv_pci_suspend() proceeds,
+        * it knows that no new work item can be scheduled, and then it flushes
+        * hbus->wq and safely closes the vmbus channel.
+        */
+       tasklet_disable(&hdev->channel->callback_event);
+
+       /* Change the hbus state to prevent new work items. */
+       old_state = hbus->state;
+       if (hbus->state == hv_pcibus_installed)
+               hbus->state = hv_pcibus_removing;
+
+       tasklet_enable(&hdev->channel->callback_event);
+
+       if (old_state != hv_pcibus_installed)
+               return -EINVAL;
+
+       flush_workqueue(hbus->wq);
+
+       ret = hv_pci_bus_exit(hdev, true);
+       if (ret)
+               return ret;
+
+       vmbus_close(hdev->channel);
+
        return 0;
 }
 
+static int hv_pci_resume(struct hv_device *hdev)
+{
+       struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+       enum pci_protocol_version_t version[1];
+       int ret;
+
+       hbus->state = hv_pcibus_init;
+
+       ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0,
+                        hv_pci_onchannelcallback, hbus);
+       if (ret)
+               return ret;
+
+       /* Only use the version that was in use before hibernation. */
+       version[0] = hbus->protocol_version;
+       ret = hv_pci_protocol_negotiation(hdev, version, 1);
+       if (ret)
+               goto out;
+
+       ret = hv_pci_query_relations(hdev);
+       if (ret)
+               goto out;
+
+       ret = hv_pci_enter_d0(hdev);
+       if (ret)
+               goto out;
+
+       ret = hv_send_resources_allocated(hdev);
+       if (ret)
+               goto out;
+
+       prepopulate_bars(hbus);
+
+       hbus->state = hv_pcibus_installed;
+       return 0;
+out:
+       vmbus_close(hdev->channel);
+       return ret;
+}
+
 static const struct hv_vmbus_device_id hv_pci_id_table[] = {
        /* PCI Pass-through Class ID */
        /* 44C4F61D-4444-4400-9D52-802E27EDE19F */
@@ -3108,6 +3256,8 @@ static struct hv_driver hv_pci_drv = {
        .id_table       = hv_pci_id_table,
        .probe          = hv_pci_probe,
        .remove         = hv_pci_remove,
+       .suspend        = hv_pci_suspend,
+       .resume         = hv_pci_resume,
 };
 
 static void __exit exit_hv_pci_drv(void)
index d3a0419..153a646 100644 (file)
@@ -554,7 +554,7 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
        }
 }
 
-struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = {
+static struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = {
        .write_base = mvebu_pci_bridge_emul_base_conf_write,
        .read_pcie = mvebu_pci_bridge_emul_pcie_conf_read,
        .write_pcie = mvebu_pci_bridge_emul_pcie_conf_write,
@@ -713,7 +713,7 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
 
        ret = of_address_to_resource(np, 0, &regs);
        if (ret)
-               return ERR_PTR(ret);
+               return (void __iomem *)ERR_PTR(ret);
 
        return devm_ioremap_resource(&pdev->dev, &regs);
 }
index f127ce8..9491e26 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/bitfield.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/pci-acpi.h>
index d219404..bd05221 100644 (file)
@@ -241,10 +241,8 @@ struct v3_pci {
        void __iomem *config_base;
        struct pci_bus *bus;
        u32 config_mem;
-       u32 io_mem;
        u32 non_pre_mem;
        u32 pre_mem;
-       phys_addr_t io_bus_addr;
        phys_addr_t non_pre_bus_addr;
        phys_addr_t pre_bus_addr;
        struct regmap *map;
@@ -520,35 +518,22 @@ static int v3_integrator_init(struct v3_pci *v3)
 }
 
 static int v3_pci_setup_resource(struct v3_pci *v3,
-                                resource_size_t io_base,
                                 struct pci_host_bridge *host,
                                 struct resource_entry *win)
 {
        struct device *dev = v3->dev;
        struct resource *mem;
        struct resource *io;
-       int ret;
 
        switch (resource_type(win->res)) {
        case IORESOURCE_IO:
                io = win->res;
-               io->name = "V3 PCI I/O";
-               v3->io_mem = io_base;
-               v3->io_bus_addr = io->start - win->offset;
-               dev_dbg(dev, "I/O window %pR, bus addr %pap\n",
-                       io, &v3->io_bus_addr);
-               ret = devm_pci_remap_iospace(dev, io, io_base);
-               if (ret) {
-                       dev_warn(dev,
-                                "error %d: failed to map resource %pR\n",
-                                ret, io);
-                       return ret;
-               }
+
                /* Setup window 2 - PCI I/O */
-               writel(v3_addr_to_lb_base2(v3->io_mem) |
+               writel(v3_addr_to_lb_base2(pci_pio_to_address(io->start)) |
                       V3_LB_BASE2_ENABLE,
                       v3->base + V3_LB_BASE2);
-               writew(v3_addr_to_lb_map2(v3->io_bus_addr),
+               writew(v3_addr_to_lb_map2(io->start - win->offset),
                       v3->base + V3_LB_MAP2);
                break;
        case IORESOURCE_MEM:
@@ -613,28 +598,30 @@ static int v3_pci_setup_resource(struct v3_pci *v3,
 }
 
 static int v3_get_dma_range_config(struct v3_pci *v3,
-                                  struct of_pci_range *range,
+                                  struct resource_entry *entry,
                                   u32 *pci_base, u32 *pci_map)
 {
        struct device *dev = v3->dev;
-       u64 cpu_end = range->cpu_addr + range->size - 1;
-       u64 pci_end = range->pci_addr + range->size - 1;
+       u64 cpu_addr = entry->res->start;
+       u64 cpu_end = entry->res->end;
+       u64 pci_end = cpu_end - entry->offset;
+       u64 pci_addr = entry->res->start - entry->offset;
        u32 val;
 
-       if (range->pci_addr & ~V3_PCI_BASE_M_ADR_BASE) {
+       if (pci_addr & ~V3_PCI_BASE_M_ADR_BASE) {
                dev_err(dev, "illegal range, only PCI bits 31..20 allowed\n");
                return -EINVAL;
        }
-       val = ((u32)range->pci_addr) & V3_PCI_BASE_M_ADR_BASE;
+       val = ((u32)pci_addr) & V3_PCI_BASE_M_ADR_BASE;
        *pci_base = val;
 
-       if (range->cpu_addr & ~V3_PCI_MAP_M_MAP_ADR) {
+       if (cpu_addr & ~V3_PCI_MAP_M_MAP_ADR) {
                dev_err(dev, "illegal range, only CPU bits 31..20 allowed\n");
                return -EINVAL;
        }
-       val = ((u32)range->cpu_addr) & V3_PCI_MAP_M_MAP_ADR;
+       val = ((u32)cpu_addr) & V3_PCI_MAP_M_MAP_ADR;
 
-       switch (range->size) {
+       switch (resource_size(entry->res)) {
        case SZ_1M:
                val |= V3_LB_BASE_ADR_SIZE_1MB;
                break;
@@ -682,8 +669,8 @@ static int v3_get_dma_range_config(struct v3_pci *v3,
        dev_dbg(dev,
                "DMA MEM CPU: 0x%016llx -> 0x%016llx => "
                "PCI: 0x%016llx -> 0x%016llx base %08x map %08x\n",
-               range->cpu_addr, cpu_end,
-               range->pci_addr, pci_end,
+               cpu_addr, cpu_end,
+               pci_addr, pci_end,
                *pci_base, *pci_map);
 
        return 0;
@@ -692,24 +679,16 @@ static int v3_get_dma_range_config(struct v3_pci *v3,
 static int v3_pci_parse_map_dma_ranges(struct v3_pci *v3,
                                       struct device_node *np)
 {
-       struct of_pci_range range;
-       struct of_pci_range_parser parser;
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(v3);
        struct device *dev = v3->dev;
+       struct resource_entry *entry;
        int i = 0;
 
-       if (of_pci_dma_range_parser_init(&parser, np)) {
-               dev_err(dev, "missing dma-ranges property\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Get the dma-ranges from the device tree
-        */
-       for_each_of_pci_range(&parser, &range) {
+       resource_list_for_each_entry(entry, &bridge->dma_ranges) {
                int ret;
                u32 pci_base, pci_map;
 
-               ret = v3_get_dma_range_config(v3, &range, &pci_base, &pci_map);
+               ret = v3_get_dma_range_config(v3, entry, &pci_base, &pci_map);
                if (ret)
                        return ret;
 
@@ -732,7 +711,6 @@ static int v3_pci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       resource_size_t io_base;
        struct resource *regs;
        struct resource_entry *win;
        struct v3_pci *v3;
@@ -741,7 +719,6 @@ static int v3_pci_probe(struct platform_device *pdev)
        u16 val;
        int irq;
        int ret;
-       LIST_HEAD(res);
 
        host = pci_alloc_host_bridge(sizeof(*v3));
        if (!host)
@@ -793,12 +770,8 @@ static int v3_pci_probe(struct platform_device *pdev)
        if (IS_ERR(v3->config_base))
                return PTR_ERR(v3->config_base);
 
-       ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
-                                                   &io_base);
-       if (ret)
-               return ret;
-
-       ret = devm_request_pci_bus_resources(dev, &res);
+       ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
+                                             &host->dma_ranges, NULL);
        if (ret)
                return ret;
 
@@ -852,8 +825,8 @@ static int v3_pci_probe(struct platform_device *pdev)
        writew(val, v3->base + V3_PCI_CMD);
 
        /* Get the I/O and memory ranges from DT */
-       resource_list_for_each_entry(win, &res) {
-               ret = v3_pci_setup_resource(v3, io_base, host, win);
+       resource_list_for_each_entry(win, &host->windows) {
+               ret = v3_pci_setup_resource(v3, host, win);
                if (ret) {
                        dev_err(dev, "error setting up resources\n");
                        return ret;
@@ -931,7 +904,6 @@ static int v3_pci_probe(struct platform_device *pdev)
        val |= V3_SYSTEM_M_LOCK;
        writew(val, v3->base + V3_SYSTEM);
 
-       list_splice_init(&res, &host->windows);
        ret = pci_scan_root_bus_bridge(host);
        if (ret) {
                dev_err(dev, "failed to register host: %d\n", ret);
index f59ad27..b911359 100644 (file)
@@ -62,65 +62,16 @@ static struct pci_ops pci_versatile_ops = {
        .write  = pci_generic_config_write,
 };
 
-static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
-                                                    struct list_head *res)
-{
-       int err, mem = 1, res_valid = 0;
-       resource_size_t iobase;
-       struct resource_entry *win, *tmp;
-
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, res, &iobase);
-       if (err)
-               return err;
-
-       err = devm_request_pci_bus_resources(dev, res);
-       if (err)
-               goto out_release_res;
-
-       resource_list_for_each_entry_safe(win, tmp, res) {
-               struct resource *res = win->res;
-
-               switch (resource_type(res)) {
-               case IORESOURCE_IO:
-                       err = devm_pci_remap_iospace(dev, res, iobase);
-                       if (err) {
-                               dev_warn(dev, "error %d: failed to map resource %pR\n",
-                                        err, res);
-                               resource_list_destroy_entry(win);
-                       }
-                       break;
-               case IORESOURCE_MEM:
-                       res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-
-                       writel(res->start >> 28, PCI_IMAP(mem));
-                       writel(PHYS_OFFSET >> 28, PCI_SMAP(mem));
-                       mem++;
-
-                       break;
-               }
-       }
-
-       if (res_valid)
-               return 0;
-
-       dev_err(dev, "non-prefetchable memory resource required\n");
-       err = -EINVAL;
-
-out_release_res:
-       pci_free_resource_list(res);
-       return err;
-}
-
 static int versatile_pci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
-       int ret, i, myslot = -1;
+       struct resource_entry *entry;
+       int ret, i, myslot = -1, mem = 1;
        u32 val;
        void __iomem *local_pci_cfg_base;
        struct pci_bus *bus, *child;
        struct pci_host_bridge *bridge;
-       LIST_HEAD(pci_res);
 
        bridge = devm_pci_alloc_host_bridge(dev, 0);
        if (!bridge)
@@ -141,10 +92,19 @@ static int versatile_pci_probe(struct platform_device *pdev)
        if (IS_ERR(versatile_cfg_base[1]))
                return PTR_ERR(versatile_cfg_base[1]);
 
-       ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             NULL, NULL);
        if (ret)
                return ret;
 
+       resource_list_for_each_entry(entry, &bridge->windows) {
+               if (resource_type(entry->res) == IORESOURCE_MEM) {
+                       writel(entry->res->start >> 28, PCI_IMAP(mem));
+                       writel(__pa(PAGE_OFFSET) >> 28, PCI_SMAP(mem));
+                       mem++;
+               }
+       }
+
        /*
         * We need to discover the PCI core first to configure itself
         * before the main PCI probing is performed
@@ -177,9 +137,9 @@ static int versatile_pci_probe(struct platform_device *pdev)
        /*
         * Configure the PCI inbound memory windows to be 1:1 mapped to SDRAM
         */
-       writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_0);
-       writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
-       writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
+       writel(__pa(PAGE_OFFSET), local_pci_cfg_base + PCI_BASE_ADDRESS_0);
+       writel(__pa(PAGE_OFFSET), local_pci_cfg_base + PCI_BASE_ADDRESS_1);
+       writel(__pa(PAGE_OFFSET), local_pci_cfg_base + PCI_BASE_ADDRESS_2);
 
        /*
         * For many years the kernel and QEMU were symbiotically buggy
@@ -197,7 +157,6 @@ static int versatile_pci_probe(struct platform_device *pdev)
        pci_add_flags(PCI_ENABLE_PROC_DOMAINS);
        pci_add_flags(PCI_REASSIGN_ALL_BUS);
 
-       list_splice_init(&pci_res, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = NULL;
        bridge->busnr = 0;
index ffda3e8..de195fd 100644 (file)
@@ -405,15 +405,13 @@ static void xgene_pcie_setup_cfg_reg(struct xgene_pcie_port *port)
        xgene_pcie_writel(port, CFGCTL, EN_REG);
 }
 
-static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
-                                struct list_head *res,
-                                resource_size_t io_base)
+static int xgene_pcie_map_ranges(struct xgene_pcie_port *port)
 {
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(port);
        struct resource_entry *window;
        struct device *dev = port->dev;
-       int ret;
 
-       resource_list_for_each_entry(window, res) {
+       resource_list_for_each_entry(window, &bridge->windows) {
                struct resource *res = window->res;
                u64 restype = resource_type(res);
 
@@ -421,11 +419,9 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
 
                switch (restype) {
                case IORESOURCE_IO:
-                       xgene_pcie_setup_ob_reg(port, res, OMR3BARL, io_base,
+                       xgene_pcie_setup_ob_reg(port, res, OMR3BARL,
+                                               pci_pio_to_address(res->start),
                                                res->start - window->offset);
-                       ret = devm_pci_remap_iospace(dev, res, io_base);
-                       if (ret < 0)
-                               return ret;
                        break;
                case IORESOURCE_MEM:
                        if (res->flags & IORESOURCE_PREFETCH)
@@ -485,27 +481,28 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size)
 }
 
 static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
-                                   struct of_pci_range *range, u8 *ib_reg_mask)
+                                   struct resource_entry *entry,
+                                   u8 *ib_reg_mask)
 {
        void __iomem *cfg_base = port->cfg_base;
        struct device *dev = port->dev;
        void *bar_addr;
        u32 pim_reg;
-       u64 cpu_addr = range->cpu_addr;
-       u64 pci_addr = range->pci_addr;
-       u64 size = range->size;
+       u64 cpu_addr = entry->res->start;
+       u64 pci_addr = cpu_addr - entry->offset;
+       u64 size = resource_size(entry->res);
        u64 mask = ~(size - 1) | EN_REG;
        u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64;
        u32 bar_low;
        int region;
 
-       region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size);
+       region = xgene_pcie_select_ib_reg(ib_reg_mask, size);
        if (region < 0) {
                dev_warn(dev, "invalid pcie dma-range config\n");
                return;
        }
 
-       if (range->flags & IORESOURCE_PREFETCH)
+       if (entry->res->flags & IORESOURCE_PREFETCH)
                flags |= PCI_BASE_ADDRESS_MEM_PREFETCH;
 
        bar_low = pcie_bar_low_val((u32)cpu_addr, flags);
@@ -536,25 +533,13 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
 
 static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
 {
-       struct device_node *np = port->node;
-       struct of_pci_range range;
-       struct of_pci_range_parser parser;
-       struct device *dev = port->dev;
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(port);
+       struct resource_entry *entry;
        u8 ib_reg_mask = 0;
 
-       if (of_pci_dma_range_parser_init(&parser, np)) {
-               dev_err(dev, "missing dma-ranges property\n");
-               return -EINVAL;
-       }
-
-       /* Get the dma-ranges from DT */
-       for_each_of_pci_range(&parser, &range) {
-               u64 end = range.cpu_addr + range.size - 1;
+       resource_list_for_each_entry(entry, &bridge->dma_ranges)
+               xgene_pcie_setup_ib_reg(port, entry, &ib_reg_mask);
 
-               dev_dbg(dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
-                       range.flags, range.cpu_addr, end, range.pci_addr);
-               xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask);
-       }
        return 0;
 }
 
@@ -567,8 +552,7 @@ static void xgene_pcie_clear_config(struct xgene_pcie_port *port)
                xgene_pcie_writel(port, i, 0);
 }
 
-static int xgene_pcie_setup(struct xgene_pcie_port *port, struct list_head *res,
-                           resource_size_t io_base)
+static int xgene_pcie_setup(struct xgene_pcie_port *port)
 {
        struct device *dev = port->dev;
        u32 val, lanes = 0, speed = 0;
@@ -580,7 +564,7 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port, struct list_head *res,
        val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID;
        xgene_pcie_writel(port, BRIDGE_CFG_0, val);
 
-       ret = xgene_pcie_map_ranges(port, res, io_base);
+       ret = xgene_pcie_map_ranges(port);
        if (ret)
                return ret;
 
@@ -607,11 +591,9 @@ static int xgene_pcie_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *dn = dev->of_node;
        struct xgene_pcie_port *port;
-       resource_size_t iobase = 0;
        struct pci_bus *bus, *child;
        struct pci_host_bridge *bridge;
        int ret;
-       LIST_HEAD(res);
 
        bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
        if (!bridge)
@@ -634,20 +616,15 @@ static int xgene_pcie_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
-                                                   &iobase);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (ret)
                return ret;
 
-       ret = devm_request_pci_bus_resources(dev, &res);
-       if (ret)
-               goto error;
-
-       ret = xgene_pcie_setup(port, &res, iobase);
+       ret = xgene_pcie_setup(port);
        if (ret)
-               goto error;
+               return ret;
 
-       list_splice_init(&res, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = port;
        bridge->busnr = 0;
@@ -657,7 +634,7 @@ static int xgene_pcie_probe(struct platform_device *pdev)
 
        ret = pci_scan_root_bus_bridge(bridge);
        if (ret < 0)
-               goto error;
+               return ret;
 
        bus = bridge->bus;
 
@@ -666,10 +643,6 @@ static int xgene_pcie_probe(struct platform_device *pdev)
                pcie_bus_configure_settings(child);
        pci_bus_add_devices(bus);
        return 0;
-
-error:
-       pci_free_resource_list(&res);
-       return ret;
 }
 
 static const struct of_device_id xgene_pcie_match_table[] = {
index d2497ca..b447c3e 100644 (file)
@@ -92,7 +92,6 @@ struct altera_pcie {
        u8                      root_bus_nr;
        struct irq_domain       *irq_domain;
        struct resource         bus_range;
-       struct list_head        resources;
        const struct altera_pcie_data   *pcie_data;
 };
 
@@ -670,39 +669,6 @@ static void altera_pcie_isr(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
-{
-       int err, res_valid = 0;
-       struct device *dev = &pcie->pdev->dev;
-       struct resource_entry *win;
-
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                                   &pcie->resources, NULL);
-       if (err)
-               return err;
-
-       err = devm_request_pci_bus_resources(dev, &pcie->resources);
-       if (err)
-               goto out_release_res;
-
-       resource_list_for_each_entry(win, &pcie->resources) {
-               struct resource *res = win->res;
-
-               if (resource_type(res) == IORESOURCE_MEM)
-                       res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-       }
-
-       if (res_valid)
-               return 0;
-
-       dev_err(dev, "non-prefetchable memory resource required\n");
-       err = -EINVAL;
-
-out_release_res:
-       pci_free_resource_list(&pcie->resources);
-       return err;
-}
-
 static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
 {
        struct device *dev = &pcie->pdev->dev;
@@ -833,9 +799,8 @@ static int altera_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       INIT_LIST_HEAD(&pcie->resources);
-
-       ret = altera_pcie_parse_request_of_pci_ranges(pcie);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (ret) {
                dev_err(dev, "Failed add resources\n");
                return ret;
@@ -853,7 +818,6 @@ static int altera_pcie_probe(struct platform_device *pdev)
        cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
        altera_pcie_host_init(pcie);
 
-       list_splice_init(&pcie->resources, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = pcie;
        bridge->busnr = pcie->root_bus_nr;
@@ -884,7 +848,6 @@ static int altera_pcie_remove(struct platform_device *pdev)
 
        pci_stop_root_bus(bridge->bus);
        pci_remove_root_bus(bridge->bus);
-       pci_free_resource_list(&pcie->resources);
        altera_pcie_irq_teardown(pcie);
 
        return 0;
diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
deleted file mode 100644 (file)
index def7820..0000000
+++ /dev/null
@@ -1,565 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017 Cadence
-// Cadence PCIe endpoint controller driver.
-// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/pci-epc.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/sizes.h>
-
-#include "pcie-cadence.h"
-
-#define CDNS_PCIE_EP_MIN_APERTURE              128     /* 128 bytes */
-#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE         0x1
-#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY       0x3
-
-/**
- * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
- * @pcie: Cadence PCIe controller
- * @max_regions: maximum number of regions supported by hardware
- * @ob_region_map: bitmask of mapped outbound regions
- * @ob_addr: base addresses in the AXI bus where the outbound regions start
- * @irq_phys_addr: base address on the AXI bus where the MSI/legacy IRQ
- *                dedicated outbound regions is mapped.
- * @irq_cpu_addr: base address in the CPU space where a write access triggers
- *               the sending of a memory write (MSI) / normal message (legacy
- *               IRQ) TLP through the PCIe bus.
- * @irq_pci_addr: used to save the current mapping of the MSI/legacy IRQ
- *               dedicated outbound region.
- * @irq_pci_fn: the latest PCI function that has updated the mapping of
- *             the MSI/legacy IRQ dedicated outbound region.
- * @irq_pending: bitmask of asserted legacy IRQs.
- */
-struct cdns_pcie_ep {
-       struct cdns_pcie                pcie;
-       u32                             max_regions;
-       unsigned long                   ob_region_map;
-       phys_addr_t                     *ob_addr;
-       phys_addr_t                     irq_phys_addr;
-       void __iomem                    *irq_cpu_addr;
-       u64                             irq_pci_addr;
-       u8                              irq_pci_fn;
-       u8                              irq_pending;
-};
-
-static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn,
-                                    struct pci_epf_header *hdr)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-
-       cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid);
-       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid);
-       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code);
-       cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE,
-                              hdr->subclass_code | hdr->baseclass_code << 8);
-       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE,
-                              hdr->cache_line_size);
-       cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id);
-       cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin);
-
-       /*
-        * Vendor ID can only be modified from function 0, all other functions
-        * use the same vendor ID as function 0.
-        */
-       if (fn == 0) {
-               /* Update the vendor IDs. */
-               u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) |
-                        CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id);
-
-               cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
-       }
-
-       return 0;
-}
-
-static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
-                               struct pci_epf_bar *epf_bar)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       dma_addr_t bar_phys = epf_bar->phys_addr;
-       enum pci_barno bar = epf_bar->barno;
-       int flags = epf_bar->flags;
-       u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
-       u64 sz;
-
-       /* BAR size is 2^(aperture + 7) */
-       sz = max_t(size_t, epf_bar->size, CDNS_PCIE_EP_MIN_APERTURE);
-       /*
-        * roundup_pow_of_two() returns an unsigned long, which is not suited
-        * for 64bit values.
-        */
-       sz = 1ULL << fls64(sz - 1);
-       aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
-
-       if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
-               ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS;
-       } else {
-               bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
-               bool is_64bits = sz > SZ_2G;
-
-               if (is_64bits && (bar & 1))
-                       return -EINVAL;
-
-               if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))
-                       epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
-
-               if (is_64bits && is_prefetch)
-                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
-               else if (is_prefetch)
-                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
-               else if (is_64bits)
-                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS;
-               else
-                       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS;
-       }
-
-       addr0 = lower_32_bits(bar_phys);
-       addr1 = upper_32_bits(bar_phys);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar),
-                        addr0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar),
-                        addr1);
-
-       if (bar < BAR_4) {
-               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
-               b = bar;
-       } else {
-               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
-               b = bar - BAR_4;
-       }
-
-       cfg = cdns_pcie_readl(pcie, reg);
-       cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
-                CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
-       cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
-               CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
-       cdns_pcie_writel(pcie, reg, cfg);
-
-       return 0;
-}
-
-static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
-                                  struct pci_epf_bar *epf_bar)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       enum pci_barno bar = epf_bar->barno;
-       u32 reg, cfg, b, ctrl;
-
-       if (bar < BAR_4) {
-               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
-               b = bar;
-       } else {
-               reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
-               b = bar - BAR_4;
-       }
-
-       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
-       cfg = cdns_pcie_readl(pcie, reg);
-       cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
-                CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
-       cfg |= CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
-       cdns_pcie_writel(pcie, reg, cfg);
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
-}
-
-static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
-                                u64 pci_addr, size_t size)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       u32 r;
-
-       r = find_first_zero_bit(&ep->ob_region_map,
-                               sizeof(ep->ob_region_map) * BITS_PER_LONG);
-       if (r >= ep->max_regions - 1) {
-               dev_err(&epc->dev, "no free outbound region\n");
-               return -EINVAL;
-       }
-
-       cdns_pcie_set_outbound_region(pcie, fn, r, false, addr, pci_addr, size);
-
-       set_bit(r, &ep->ob_region_map);
-       ep->ob_addr[r] = addr;
-
-       return 0;
-}
-
-static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn,
-                                   phys_addr_t addr)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       u32 r;
-
-       for (r = 0; r < ep->max_regions - 1; r++)
-               if (ep->ob_addr[r] == addr)
-                       break;
-
-       if (r == ep->max_regions - 1)
-               return;
-
-       cdns_pcie_reset_outbound_region(pcie, r);
-
-       ep->ob_addr[r] = 0;
-       clear_bit(r, &ep->ob_region_map);
-}
-
-static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 mmc)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
-       u16 flags;
-
-       /*
-        * Set the Multiple Message Capable bitfield into the Message Control
-        * register.
-        */
-       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
-       flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
-       flags |= PCI_MSI_FLAGS_64BIT;
-       flags &= ~PCI_MSI_FLAGS_MASKBIT;
-       cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
-
-       return 0;
-}
-
-static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
-       u16 flags, mme;
-
-       /* Validate that the MSI feature is actually enabled. */
-       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
-       if (!(flags & PCI_MSI_FLAGS_ENABLE))
-               return -EINVAL;
-
-       /*
-        * Get the Multiple Message Enable bitfield from the Message Control
-        * register.
-        */
-       mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
-
-       return mme;
-}
-
-static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
-                                    u8 intx, bool is_asserted)
-{
-       struct cdns_pcie *pcie = &ep->pcie;
-       u32 offset;
-       u16 status;
-       u8 msg_code;
-
-       intx &= 3;
-
-       /* Set the outbound region if needed. */
-       if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
-                    ep->irq_pci_fn != fn)) {
-               /* First region was reserved for IRQ writes. */
-               cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0,
-                                                            ep->irq_phys_addr);
-               ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
-               ep->irq_pci_fn = fn;
-       }
-
-       if (is_asserted) {
-               ep->irq_pending |= BIT(intx);
-               msg_code = MSG_CODE_ASSERT_INTA + intx;
-       } else {
-               ep->irq_pending &= ~BIT(intx);
-               msg_code = MSG_CODE_DEASSERT_INTA + intx;
-       }
-
-       status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
-       if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
-               status ^= PCI_STATUS_INTERRUPT;
-               cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
-       }
-
-       offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
-                CDNS_PCIE_NORMAL_MSG_CODE(msg_code) |
-                CDNS_PCIE_MSG_NO_DATA;
-       writel(0, ep->irq_cpu_addr + offset);
-}
-
-static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx)
-{
-       u16 cmd;
-
-       cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND);
-       if (cmd & PCI_COMMAND_INTX_DISABLE)
-               return -EINVAL;
-
-       cdns_pcie_ep_assert_intx(ep, fn, intx, true);
-       /*
-        * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq()
-        * from drivers/pci/dwc/pci-dra7xx.c
-        */
-       mdelay(1);
-       cdns_pcie_ep_assert_intx(ep, fn, intx, false);
-       return 0;
-}
-
-static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
-                                    u8 interrupt_num)
-{
-       struct cdns_pcie *pcie = &ep->pcie;
-       u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
-       u16 flags, mme, data, data_mask;
-       u8 msi_count;
-       u64 pci_addr, pci_addr_mask = 0xff;
-
-       /* Check whether the MSI feature has been enabled by the PCI host. */
-       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
-       if (!(flags & PCI_MSI_FLAGS_ENABLE))
-               return -EINVAL;
-
-       /* Get the number of enabled MSIs */
-       mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
-       msi_count = 1 << mme;
-       if (!interrupt_num || interrupt_num > msi_count)
-               return -EINVAL;
-
-       /* Compute the data value to be written. */
-       data_mask = msi_count - 1;
-       data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
-       data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
-
-       /* Get the PCI address where to write the data into. */
-       pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
-       pci_addr <<= 32;
-       pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
-       pci_addr &= GENMASK_ULL(63, 2);
-
-       /* Set the outbound region if needed. */
-       if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
-                    ep->irq_pci_fn != fn)) {
-               /* First region was reserved for IRQ writes. */
-               cdns_pcie_set_outbound_region(pcie, fn, 0,
-                                             false,
-                                             ep->irq_phys_addr,
-                                             pci_addr & ~pci_addr_mask,
-                                             pci_addr_mask + 1);
-               ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
-               ep->irq_pci_fn = fn;
-       }
-       writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
-
-       return 0;
-}
-
-static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
-                                 enum pci_epc_irq_type type,
-                                 u16 interrupt_num)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-
-       switch (type) {
-       case PCI_EPC_IRQ_LEGACY:
-               return cdns_pcie_ep_send_legacy_irq(ep, fn, 0);
-
-       case PCI_EPC_IRQ_MSI:
-               return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
-
-       default:
-               break;
-       }
-
-       return -EINVAL;
-}
-
-static int cdns_pcie_ep_start(struct pci_epc *epc)
-{
-       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
-       struct cdns_pcie *pcie = &ep->pcie;
-       struct pci_epf *epf;
-       u32 cfg;
-
-       /*
-        * BIT(0) is hardwired to 1, hence function 0 is always enabled
-        * and can't be disabled anyway.
-        */
-       cfg = BIT(0);
-       list_for_each_entry(epf, &epc->pci_epf, list)
-               cfg |= BIT(epf->func_no);
-       cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
-
-       return 0;
-}
-
-static const struct pci_epc_features cdns_pcie_epc_features = {
-       .linkup_notifier = false,
-       .msi_capable = true,
-       .msix_capable = false,
-};
-
-static const struct pci_epc_features*
-cdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
-{
-       return &cdns_pcie_epc_features;
-}
-
-static const struct pci_epc_ops cdns_pcie_epc_ops = {
-       .write_header   = cdns_pcie_ep_write_header,
-       .set_bar        = cdns_pcie_ep_set_bar,
-       .clear_bar      = cdns_pcie_ep_clear_bar,
-       .map_addr       = cdns_pcie_ep_map_addr,
-       .unmap_addr     = cdns_pcie_ep_unmap_addr,
-       .set_msi        = cdns_pcie_ep_set_msi,
-       .get_msi        = cdns_pcie_ep_get_msi,
-       .raise_irq      = cdns_pcie_ep_raise_irq,
-       .start          = cdns_pcie_ep_start,
-       .get_features   = cdns_pcie_ep_get_features,
-};
-
-static const struct of_device_id cdns_pcie_ep_of_match[] = {
-       { .compatible = "cdns,cdns-pcie-ep" },
-
-       { },
-};
-
-static int cdns_pcie_ep_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       struct cdns_pcie_ep *ep;
-       struct cdns_pcie *pcie;
-       struct pci_epc *epc;
-       struct resource *res;
-       int ret;
-       int phy_count;
-
-       ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
-       if (!ep)
-               return -ENOMEM;
-
-       pcie = &ep->pcie;
-       pcie->is_rc = false;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
-       pcie->reg_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(pcie->reg_base)) {
-               dev_err(dev, "missing \"reg\"\n");
-               return PTR_ERR(pcie->reg_base);
-       }
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
-       if (!res) {
-               dev_err(dev, "missing \"mem\"\n");
-               return -EINVAL;
-       }
-       pcie->mem_res = res;
-
-       ret = of_property_read_u32(np, "cdns,max-outbound-regions",
-                                  &ep->max_regions);
-       if (ret < 0) {
-               dev_err(dev, "missing \"cdns,max-outbound-regions\"\n");
-               return ret;
-       }
-       ep->ob_addr = devm_kcalloc(dev,
-                                  ep->max_regions, sizeof(*ep->ob_addr),
-                                  GFP_KERNEL);
-       if (!ep->ob_addr)
-               return -ENOMEM;
-
-       ret = cdns_pcie_init_phy(dev, pcie);
-       if (ret) {
-               dev_err(dev, "failed to init phy\n");
-               return ret;
-       }
-       platform_set_drvdata(pdev, pcie);
-       pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               dev_err(dev, "pm_runtime_get_sync() failed\n");
-               goto err_get_sync;
-       }
-
-       /* Disable all but function 0 (anyway BIT(0) is hardwired to 1). */
-       cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0));
-
-       epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
-       if (IS_ERR(epc)) {
-               dev_err(dev, "failed to create epc device\n");
-               ret = PTR_ERR(epc);
-               goto err_init;
-       }
-
-       epc_set_drvdata(epc, ep);
-
-       if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
-               epc->max_functions = 1;
-
-       ret = pci_epc_mem_init(epc, pcie->mem_res->start,
-                              resource_size(pcie->mem_res));
-       if (ret < 0) {
-               dev_err(dev, "failed to initialize the memory space\n");
-               goto err_init;
-       }
-
-       ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
-                                                 SZ_128K);
-       if (!ep->irq_cpu_addr) {
-               dev_err(dev, "failed to reserve memory space for MSI\n");
-               ret = -ENOMEM;
-               goto free_epc_mem;
-       }
-       ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
-       /* Reserve region 0 for IRQs */
-       set_bit(0, &ep->ob_region_map);
-
-       return 0;
-
- free_epc_mem:
-       pci_epc_mem_exit(epc);
-
- err_init:
-       pm_runtime_put_sync(dev);
-
- err_get_sync:
-       pm_runtime_disable(dev);
-       cdns_pcie_disable_phy(pcie);
-       phy_count = pcie->phy_count;
-       while (phy_count--)
-               device_link_del(pcie->link[phy_count]);
-
-       return ret;
-}
-
-static void cdns_pcie_ep_shutdown(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct cdns_pcie *pcie = dev_get_drvdata(dev);
-       int ret;
-
-       ret = pm_runtime_put_sync(dev);
-       if (ret < 0)
-               dev_dbg(dev, "pm_runtime_put_sync failed\n");
-
-       pm_runtime_disable(dev);
-
-       cdns_pcie_disable_phy(pcie);
-}
-
-static struct platform_driver cdns_pcie_ep_driver = {
-       .driver = {
-               .name = "cdns-pcie-ep",
-               .of_match_table = cdns_pcie_ep_of_match,
-               .pm     = &cdns_pcie_pm_ops,
-       },
-       .probe = cdns_pcie_ep_probe,
-       .shutdown = cdns_pcie_ep_shutdown,
-};
-builtin_platform_driver(cdns_pcie_ep_driver);
diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c
deleted file mode 100644 (file)
index 97e2510..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017 Cadence
-// Cadence PCIe host controller driver.
-// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
-
-#include <linux/kernel.h>
-#include <linux/of_address.h>
-#include <linux/of_pci.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include "pcie-cadence.h"
-
-/**
- * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
- * @pcie: Cadence PCIe controller
- * @dev: pointer to PCIe device
- * @cfg_res: start/end offsets in the physical system memory to map PCI
- *           configuration space accesses
- * @bus_range: first/last buses behind the PCIe host controller
- * @cfg_base: IO mapped window to access the PCI configuration space of a
- *            single function at a time
- * @max_regions: maximum number of regions supported by the hardware
- * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
- *                translation (nbits sets into the "no BAR match" register)
- * @vendor_id: PCI vendor ID
- * @device_id: PCI device ID
- */
-struct cdns_pcie_rc {
-       struct cdns_pcie        pcie;
-       struct device           *dev;
-       struct resource         *cfg_res;
-       struct resource         *bus_range;
-       void __iomem            *cfg_base;
-       u32                     max_regions;
-       u32                     no_bar_nbits;
-       u16                     vendor_id;
-       u16                     device_id;
-};
-
-static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
-                                     int where)
-{
-       struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
-       struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
-       struct cdns_pcie *pcie = &rc->pcie;
-       unsigned int busn = bus->number;
-       u32 addr0, desc0;
-
-       if (busn == rc->bus_range->start) {
-               /*
-                * Only the root port (devfn == 0) is connected to this bus.
-                * All other PCI devices are behind some bridge hence on another
-                * bus.
-                */
-               if (devfn)
-                       return NULL;
-
-               return pcie->reg_base + (where & 0xfff);
-       }
-       /* Check that the link is up */
-       if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1))
-               return NULL;
-       /* Clear AXI link-down status */
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0);
-
-       /* Update Output registers for AXI region 0. */
-       addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
-               CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
-               CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
-
-       /* Configuration Type 0 or Type 1 access. */
-       desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
-               CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
-       /*
-        * The bus number was already set once for all in desc1 by
-        * cdns_pcie_host_init_address_translation().
-        */
-       if (busn == rc->bus_range->start + 1)
-               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
-       else
-               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
-
-       return rc->cfg_base + (where & 0xfff);
-}
-
-static struct pci_ops cdns_pcie_host_ops = {
-       .map_bus        = cdns_pci_map_bus,
-       .read           = pci_generic_config_read,
-       .write          = pci_generic_config_write,
-};
-
-static const struct of_device_id cdns_pcie_host_of_match[] = {
-       { .compatible = "cdns,cdns-pcie-host" },
-
-       { },
-};
-
-static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
-{
-       struct cdns_pcie *pcie = &rc->pcie;
-       u32 value, ctrl;
-
-       /*
-        * Set the root complex BAR configuration register:
-        * - disable both BAR0 and BAR1.
-        * - enable Prefetchable Memory Base and Limit registers in type 1
-        *   config space (64 bits).
-        * - enable IO Base and Limit registers in type 1 config
-        *   space (32 bits).
-        */
-       ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
-       value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
-               CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
-               CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
-               CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
-               CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
-               CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
-       cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
-
-       /* Set root port configuration space */
-       if (rc->vendor_id != 0xffff)
-               cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
-       if (rc->device_id != 0xffff)
-               cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
-
-       cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
-       cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
-       cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
-
-       return 0;
-}
-
-static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
-{
-       struct cdns_pcie *pcie = &rc->pcie;
-       struct resource *cfg_res = rc->cfg_res;
-       struct resource *mem_res = pcie->mem_res;
-       struct resource *bus_range = rc->bus_range;
-       struct device *dev = rc->dev;
-       struct device_node *np = dev->of_node;
-       struct of_pci_range_parser parser;
-       struct of_pci_range range;
-       u32 addr0, addr1, desc1;
-       u64 cpu_addr;
-       int r, err;
-
-       /*
-        * Reserve region 0 for PCI configure space accesses:
-        * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
-        * cdns_pci_map_bus(), other region registers are set here once for all.
-        */
-       addr1 = 0; /* Should be programmed to zero. */
-       desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
-
-       cpu_addr = cfg_res->start - mem_res->start;
-       addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
-               (lower_32_bits(cpu_addr) & GENMASK(31, 8));
-       addr1 = upper_32_bits(cpu_addr);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
-
-       err = of_pci_range_parser_init(&parser, np);
-       if (err)
-               return err;
-
-       r = 1;
-       for_each_of_pci_range(&parser, &range) {
-               bool is_io;
-
-               if (r >= rc->max_regions)
-                       break;
-
-               if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
-                       is_io = false;
-               else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
-                       is_io = true;
-               else
-                       continue;
-
-               cdns_pcie_set_outbound_region(pcie, 0, r, is_io,
-                                             range.cpu_addr,
-                                             range.pci_addr,
-                                             range.size);
-               r++;
-       }
-
-       /*
-        * Set Root Port no BAR match Inbound Translation registers:
-        * needed for MSI and DMA.
-        * Root Port BAR0 and BAR1 are disabled, hence no need to set their
-        * inbound translation registers.
-        */
-       addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
-       addr1 = 0;
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
-
-       return 0;
-}
-
-static int cdns_pcie_host_init(struct device *dev,
-                              struct list_head *resources,
-                              struct cdns_pcie_rc *rc)
-{
-       struct resource *bus_range = NULL;
-       int err;
-
-       /* Parse our PCI ranges and request their resources */
-       err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
-       if (err)
-               return err;
-
-       rc->bus_range = bus_range;
-       rc->pcie.bus = bus_range->start;
-
-       err = cdns_pcie_host_init_root_port(rc);
-       if (err)
-               goto err_out;
-
-       err = cdns_pcie_host_init_address_translation(rc);
-       if (err)
-               goto err_out;
-
-       return 0;
-
- err_out:
-       pci_free_resource_list(resources);
-       return err;
-}
-
-static int cdns_pcie_host_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       struct pci_host_bridge *bridge;
-       struct list_head resources;
-       struct cdns_pcie_rc *rc;
-       struct cdns_pcie *pcie;
-       struct resource *res;
-       int ret;
-       int phy_count;
-
-       bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
-       if (!bridge)
-               return -ENOMEM;
-
-       rc = pci_host_bridge_priv(bridge);
-       rc->dev = dev;
-
-       pcie = &rc->pcie;
-       pcie->is_rc = true;
-
-       rc->max_regions = 32;
-       of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
-
-       rc->no_bar_nbits = 32;
-       of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
-
-       rc->vendor_id = 0xffff;
-       of_property_read_u16(np, "vendor-id", &rc->vendor_id);
-
-       rc->device_id = 0xffff;
-       of_property_read_u16(np, "device-id", &rc->device_id);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
-       pcie->reg_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(pcie->reg_base)) {
-               dev_err(dev, "missing \"reg\"\n");
-               return PTR_ERR(pcie->reg_base);
-       }
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
-       rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
-       if (IS_ERR(rc->cfg_base)) {
-               dev_err(dev, "missing \"cfg\"\n");
-               return PTR_ERR(rc->cfg_base);
-       }
-       rc->cfg_res = res;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
-       if (!res) {
-               dev_err(dev, "missing \"mem\"\n");
-               return -EINVAL;
-       }
-       pcie->mem_res = res;
-
-       ret = cdns_pcie_init_phy(dev, pcie);
-       if (ret) {
-               dev_err(dev, "failed to init phy\n");
-               return ret;
-       }
-       platform_set_drvdata(pdev, pcie);
-
-       pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               dev_err(dev, "pm_runtime_get_sync() failed\n");
-               goto err_get_sync;
-       }
-
-       ret = cdns_pcie_host_init(dev, &resources, rc);
-       if (ret)
-               goto err_init;
-
-       list_splice_init(&resources, &bridge->windows);
-       bridge->dev.parent = dev;
-       bridge->busnr = pcie->bus;
-       bridge->ops = &cdns_pcie_host_ops;
-       bridge->map_irq = of_irq_parse_and_map_pci;
-       bridge->swizzle_irq = pci_common_swizzle;
-
-       ret = pci_host_probe(bridge);
-       if (ret < 0)
-               goto err_host_probe;
-
-       return 0;
-
- err_host_probe:
-       pci_free_resource_list(&resources);
-
- err_init:
-       pm_runtime_put_sync(dev);
-
- err_get_sync:
-       pm_runtime_disable(dev);
-       cdns_pcie_disable_phy(pcie);
-       phy_count = pcie->phy_count;
-       while (phy_count--)
-               device_link_del(pcie->link[phy_count]);
-
-       return ret;
-}
-
-static void cdns_pcie_shutdown(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct cdns_pcie *pcie = dev_get_drvdata(dev);
-       int ret;
-
-       ret = pm_runtime_put_sync(dev);
-       if (ret < 0)
-               dev_dbg(dev, "pm_runtime_put_sync failed\n");
-
-       pm_runtime_disable(dev);
-       cdns_pcie_disable_phy(pcie);
-}
-
-static struct platform_driver cdns_pcie_host_driver = {
-       .driver = {
-               .name = "cdns-pcie-host",
-               .of_match_table = cdns_pcie_host_of_match,
-               .pm     = &cdns_pcie_pm_ops,
-       },
-       .probe = cdns_pcie_host_probe,
-       .shutdown = cdns_pcie_shutdown,
-};
-builtin_platform_driver(cdns_pcie_host_driver);
diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c
deleted file mode 100644 (file)
index cd795f6..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017 Cadence
-// Cadence PCIe controller driver.
-// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
-
-#include <linux/kernel.h>
-
-#include "pcie-cadence.h"
-
-void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
-                                  u32 r, bool is_io,
-                                  u64 cpu_addr, u64 pci_addr, size_t size)
-{
-       /*
-        * roundup_pow_of_two() returns an unsigned long, which is not suited
-        * for 64bit values.
-        */
-       u64 sz = 1ULL << fls64(size - 1);
-       int nbits = ilog2(sz);
-       u32 addr0, addr1, desc0, desc1;
-
-       if (nbits < 8)
-               nbits = 8;
-
-       /* Set the PCI address */
-       addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
-               (lower_32_bits(pci_addr) & GENMASK(31, 8));
-       addr1 = upper_32_bits(pci_addr);
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1);
-
-       /* Set the PCIe header descriptor */
-       if (is_io)
-               desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO;
-       else
-               desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM;
-       desc1 = 0;
-
-       /*
-        * Whatever Bit [23] is set or not inside DESC0 register of the outbound
-        * PCIe descriptor, the PCI function number must be set into
-        * Bits [26:24] of DESC0 anyway.
-        *
-        * In Root Complex mode, the function number is always 0 but in Endpoint
-        * mode, the PCIe controller may support more than one function. This
-        * function number needs to be set properly into the outbound PCIe
-        * descriptor.
-        *
-        * Besides, setting Bit [23] is mandatory when in Root Complex mode:
-        * then the driver must provide the bus, resp. device, number in
-        * Bits [7:0] of DESC1, resp. Bits[31:27] of DESC0. Like the function
-        * number, the device number is always 0 in Root Complex mode.
-        *
-        * However when in Endpoint mode, we can clear Bit [23] of DESC0, hence
-        * the PCIe controller will use the captured values for the bus and
-        * device numbers.
-        */
-       if (pcie->is_rc) {
-               /* The device and function numbers are always 0. */
-               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
-                        CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
-               desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
-       } else {
-               /*
-                * Use captured values for bus and device numbers but still
-                * need to set the function number.
-                */
-               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
-       }
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
-
-       /* Set the CPU address */
-       cpu_addr -= pcie->mem_res->start;
-       addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
-               (lower_32_bits(cpu_addr) & GENMASK(31, 8));
-       addr1 = upper_32_bits(cpu_addr);
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
-}
-
-void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
-                                                 u32 r, u64 cpu_addr)
-{
-       u32 addr0, addr1, desc0, desc1;
-
-       desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
-       desc1 = 0;
-
-       /* See cdns_pcie_set_outbound_region() comments above. */
-       if (pcie->is_rc) {
-               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
-                        CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
-               desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
-       } else {
-               desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
-       }
-
-       /* Set the CPU address */
-       cpu_addr -= pcie->mem_res->start;
-       addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
-               (lower_32_bits(cpu_addr) & GENMASK(31, 8));
-       addr1 = upper_32_bits(cpu_addr);
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
-}
-
-void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
-{
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
-
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
-       cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
-}
-
-void cdns_pcie_disable_phy(struct cdns_pcie *pcie)
-{
-       int i = pcie->phy_count;
-
-       while (i--) {
-               phy_power_off(pcie->phy[i]);
-               phy_exit(pcie->phy[i]);
-       }
-}
-
-int cdns_pcie_enable_phy(struct cdns_pcie *pcie)
-{
-       int ret;
-       int i;
-
-       for (i = 0; i < pcie->phy_count; i++) {
-               ret = phy_init(pcie->phy[i]);
-               if (ret < 0)
-                       goto err_phy;
-
-               ret = phy_power_on(pcie->phy[i]);
-               if (ret < 0) {
-                       phy_exit(pcie->phy[i]);
-                       goto err_phy;
-               }
-       }
-
-       return 0;
-
-err_phy:
-       while (--i >= 0) {
-               phy_power_off(pcie->phy[i]);
-               phy_exit(pcie->phy[i]);
-       }
-
-       return ret;
-}
-
-int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
-{
-       struct device_node *np = dev->of_node;
-       int phy_count;
-       struct phy **phy;
-       struct device_link **link;
-       int i;
-       int ret;
-       const char *name;
-
-       phy_count = of_property_count_strings(np, "phy-names");
-       if (phy_count < 1) {
-               dev_err(dev, "no phy-names.  PHY will not be initialized\n");
-               pcie->phy_count = 0;
-               return 0;
-       }
-
-       phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
-       if (!phy)
-               return -ENOMEM;
-
-       link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
-       if (!link)
-               return -ENOMEM;
-
-       for (i = 0; i < phy_count; i++) {
-               of_property_read_string_index(np, "phy-names", i, &name);
-               phy[i] = devm_phy_get(dev, name);
-               if (IS_ERR(phy[i])) {
-                       ret = PTR_ERR(phy[i]);
-                       goto err_phy;
-               }
-               link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
-               if (!link[i]) {
-                       devm_phy_put(dev, phy[i]);
-                       ret = -EINVAL;
-                       goto err_phy;
-               }
-       }
-
-       pcie->phy_count = phy_count;
-       pcie->phy = phy;
-       pcie->link = link;
-
-       ret =  cdns_pcie_enable_phy(pcie);
-       if (ret)
-               goto err_phy;
-
-       return 0;
-
-err_phy:
-       while (--i >= 0) {
-               device_link_del(link[i]);
-               devm_phy_put(dev, phy[i]);
-       }
-
-       return ret;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int cdns_pcie_suspend_noirq(struct device *dev)
-{
-       struct cdns_pcie *pcie = dev_get_drvdata(dev);
-
-       cdns_pcie_disable_phy(pcie);
-
-       return 0;
-}
-
-static int cdns_pcie_resume_noirq(struct device *dev)
-{
-       struct cdns_pcie *pcie = dev_get_drvdata(dev);
-       int ret;
-
-       ret = cdns_pcie_enable_phy(pcie);
-       if (ret) {
-               dev_err(dev, "failed to enable phy\n");
-               return ret;
-       }
-
-       return 0;
-}
-#endif
-
-const struct dev_pm_ops cdns_pcie_pm_ops = {
-       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
-                                     cdns_pcie_resume_noirq)
-};
diff --git a/drivers/pci/controller/pcie-cadence.h b/drivers/pci/controller/pcie-cadence.h
deleted file mode 100644 (file)
index ae6bf2a..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017 Cadence
-// Cadence PCIe controller driver.
-// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
-
-#ifndef _PCIE_CADENCE_H
-#define _PCIE_CADENCE_H
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/phy/phy.h>
-
-/*
- * Local Management Registers
- */
-#define CDNS_PCIE_LM_BASE      0x00100000
-
-/* Vendor ID Register */
-#define CDNS_PCIE_LM_ID                (CDNS_PCIE_LM_BASE + 0x0044)
-#define  CDNS_PCIE_LM_ID_VENDOR_MASK   GENMASK(15, 0)
-#define  CDNS_PCIE_LM_ID_VENDOR_SHIFT  0
-#define  CDNS_PCIE_LM_ID_VENDOR(vid) \
-       (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
-#define  CDNS_PCIE_LM_ID_SUBSYS_MASK   GENMASK(31, 16)
-#define  CDNS_PCIE_LM_ID_SUBSYS_SHIFT  16
-#define  CDNS_PCIE_LM_ID_SUBSYS(sub) \
-       (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
-
-/* Root Port Requestor ID Register */
-#define CDNS_PCIE_LM_RP_RID    (CDNS_PCIE_LM_BASE + 0x0228)
-#define  CDNS_PCIE_LM_RP_RID_MASK      GENMASK(15, 0)
-#define  CDNS_PCIE_LM_RP_RID_SHIFT     0
-#define  CDNS_PCIE_LM_RP_RID_(rid) \
-       (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
-
-/* Endpoint Bus and Device Number Register */
-#define CDNS_PCIE_LM_EP_ID     (CDNS_PCIE_LM_BASE + 0x022c)
-#define  CDNS_PCIE_LM_EP_ID_DEV_MASK   GENMASK(4, 0)
-#define  CDNS_PCIE_LM_EP_ID_DEV_SHIFT  0
-#define  CDNS_PCIE_LM_EP_ID_BUS_MASK   GENMASK(15, 8)
-#define  CDNS_PCIE_LM_EP_ID_BUS_SHIFT  8
-
-/* Endpoint Function f BAR b Configuration Registers */
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
-       (CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
-       (CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
-#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
-       (GENMASK(4, 0) << ((b) * 8))
-#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
-       (((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
-#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
-       (GENMASK(7, 5) << ((b) * 8))
-#define  CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
-       (((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
-
-/* Endpoint Function Configuration Register */
-#define CDNS_PCIE_LM_EP_FUNC_CFG       (CDNS_PCIE_LM_BASE + 0x02c0)
-
-/* Root Complex BAR Configuration Register */
-#define CDNS_PCIE_LM_RC_BAR_CFG        (CDNS_PCIE_LM_BASE + 0x0300)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK    GENMASK(5, 0)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
-       (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK                GENMASK(8, 6)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
-       (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK    GENMASK(13, 9)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
-       (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK                GENMASK(16, 14)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
-       (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE   BIT(17)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS   0
-#define  CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS   BIT(18)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE             BIT(19)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS             0
-#define  CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS             BIT(20)
-#define  CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE          BIT(31)
-
-/* BAR control values applicable to both Endpoint Function and Root Complex */
-#define  CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED            0x0
-#define  CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS           0x1
-#define  CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS          0x4
-#define  CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
-#define  CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS          0x6
-#define  CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
-
-
-/*
- * Endpoint Function Registers (PCI configuration space for endpoint functions)
- */
-#define CDNS_PCIE_EP_FUNC_BASE(fn)     (((fn) << 12) & GENMASK(19, 12))
-
-#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET       0x90
-
-/*
- * Root Port Registers (PCI configuration space for the root port function)
- */
-#define CDNS_PCIE_RP_BASE      0x00200000
-
-
-/*
- * Address Translation Registers
- */
-#define CDNS_PCIE_AT_BASE      0x00400000
-
-/* Region r Outbound AXI to PCIe Address Translation Register 0 */
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
-       (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
-#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK   GENMASK(5, 0)
-#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
-       (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
-#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK   GENMASK(19, 12)
-#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
-       (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
-#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK     GENMASK(27, 20)
-#define  CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
-       (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
-
-/* Region r Outbound AXI to PCIe Address Translation Register 1 */
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
-       (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
-
-/* Region r Outbound PCIe Descriptor Register 0 */
-#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
-       (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK                GENMASK(3, 0)
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM         0x2
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO          0x6
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0  0xa
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1  0xb
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG  0xc
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG  0xd
-/* Bit 23 MUST be set in RC mode. */
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID    BIT(23)
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK       GENMASK(31, 24)
-#define  CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
-       (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
-
-/* Region r Outbound PCIe Descriptor Register 1 */
-#define CDNS_PCIE_AT_OB_REGION_DESC1(r)        \
-       (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
-#define  CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
-#define  CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
-       ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
-
-/* Region r AXI Region Base Address Register 0 */
-#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
-       (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
-#define  CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK   GENMASK(5, 0)
-#define  CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
-       (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
-
-/* Region r AXI Region Base Address Register 1 */
-#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
-       (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
-
-/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
-#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
-       (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
-#define  CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK       GENMASK(5, 0)
-#define  CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
-       (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
-#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
-       (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
-
-/* AXI link down register */
-#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
-
-enum cdns_pcie_rp_bar {
-       RP_BAR0,
-       RP_BAR1,
-       RP_NO_BAR
-};
-
-/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
-#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
-       (CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
-#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
-       (CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
-
-/* Normal/Vendor specific message access: offset inside some outbound region */
-#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK      GENMASK(7, 5)
-#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
-       (((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
-#define CDNS_PCIE_NORMAL_MSG_CODE_MASK         GENMASK(15, 8)
-#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
-       (((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
-#define CDNS_PCIE_MSG_NO_DATA                  BIT(16)
-
-enum cdns_pcie_msg_code {
-       MSG_CODE_ASSERT_INTA    = 0x20,
-       MSG_CODE_ASSERT_INTB    = 0x21,
-       MSG_CODE_ASSERT_INTC    = 0x22,
-       MSG_CODE_ASSERT_INTD    = 0x23,
-       MSG_CODE_DEASSERT_INTA  = 0x24,
-       MSG_CODE_DEASSERT_INTB  = 0x25,
-       MSG_CODE_DEASSERT_INTC  = 0x26,
-       MSG_CODE_DEASSERT_INTD  = 0x27,
-};
-
-enum cdns_pcie_msg_routing {
-       /* Route to Root Complex */
-       MSG_ROUTING_TO_RC,
-
-       /* Use Address Routing */
-       MSG_ROUTING_BY_ADDR,
-
-       /* Use ID Routing */
-       MSG_ROUTING_BY_ID,
-
-       /* Route as Broadcast Message from Root Complex */
-       MSG_ROUTING_BCAST,
-
-       /* Local message; terminate at receiver (INTx messages) */
-       MSG_ROUTING_LOCAL,
-
-       /* Gather & route to Root Complex (PME_TO_Ack message) */
-       MSG_ROUTING_GATHER,
-};
-
-/**
- * struct cdns_pcie - private data for Cadence PCIe controller drivers
- * @reg_base: IO mapped register base
- * @mem_res: start/end offsets in the physical system memory to map PCI accesses
- * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
- * @bus: In Root Complex mode, the bus number
- */
-struct cdns_pcie {
-       void __iomem            *reg_base;
-       struct resource         *mem_res;
-       bool                    is_rc;
-       u8                      bus;
-       int                     phy_count;
-       struct phy              **phy;
-       struct device_link      **link;
-};
-
-/* Register access */
-static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
-{
-       writeb(value, pcie->reg_base + reg);
-}
-
-static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
-{
-       writew(value, pcie->reg_base + reg);
-}
-
-static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
-{
-       writel(value, pcie->reg_base + reg);
-}
-
-static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
-{
-       return readl(pcie->reg_base + reg);
-}
-
-/* Root Port register access */
-static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
-                                      u32 reg, u8 value)
-{
-       writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
-}
-
-static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
-                                      u32 reg, u16 value)
-{
-       writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
-}
-
-/* Endpoint Function register access */
-static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
-                                         u32 reg, u8 value)
-{
-       writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
-static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
-                                         u32 reg, u16 value)
-{
-       writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
-static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
-                                         u32 reg, u32 value)
-{
-       writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
-static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
-{
-       return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
-static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
-{
-       return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
-static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
-{
-       return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
-void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
-                                  u32 r, bool is_io,
-                                  u64 cpu_addr, u64 pci_addr, size_t size);
-
-void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
-                                                 u32 r, u64 cpu_addr);
-
-void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
-void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
-int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
-int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
-extern const struct dev_pm_ops cdns_pcie_pm_ops;
-
-#endif /* _PCIE_CADENCE_H */
index 0a3f61b..3176ad3 100644 (file)
@@ -293,11 +293,12 @@ static const struct irq_domain_ops msi_domain_ops = {
 
 static inline u32 decode_msi_hwirq(struct iproc_msi *msi, u32 eq, u32 head)
 {
-       u32 *msg, hwirq;
+       u32 __iomem *msg;
+       u32 hwirq;
        unsigned int offs;
 
        offs = iproc_msi_eq_offset(msi, eq) + head * sizeof(u32);
-       msg = (u32 *)(msi->eq_cpu + offs);
+       msg = (u32 __iomem *)(msi->eq_cpu + offs);
        hwirq = readl(msg);
        hwirq = (hwirq >> 5) + (hwirq & 0x1f);
 
index 9ee6200..ff0a81a 100644 (file)
@@ -43,8 +43,6 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
        struct iproc_pcie *pcie;
        struct device_node *np = dev->of_node;
        struct resource reg;
-       resource_size_t iobase = 0;
-       LIST_HEAD(resources);
        struct pci_host_bridge *bridge;
        int ret;
 
@@ -97,8 +95,8 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
        if (IS_ERR(pcie->phy))
                return PTR_ERR(pcie->phy);
 
-       ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources,
-                                                   &iobase);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (ret) {
                dev_err(dev, "unable to get PCI host bridge resources\n");
                return ret;
@@ -113,10 +111,9 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
                pcie->map_irq = of_irq_parse_and_map_pci;
        }
 
-       ret = iproc_pcie_setup(pcie, &resources);
+       ret = iproc_pcie_setup(pcie, &bridge->windows);
        if (ret) {
                dev_err(dev, "PCIe controller setup failed\n");
-               pci_free_resource_list(&resources);
                return ret;
        }
 
index 2d457bf..0a468c7 100644 (file)
@@ -1122,15 +1122,16 @@ static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx,
 }
 
 static int iproc_pcie_setup_ib(struct iproc_pcie *pcie,
-                              struct of_pci_range *range,
+                              struct resource_entry *entry,
                               enum iproc_pcie_ib_map_type type)
 {
        struct device *dev = pcie->dev;
        struct iproc_pcie_ib *ib = &pcie->ib;
        int ret;
        unsigned int region_idx, size_idx;
-       u64 axi_addr = range->cpu_addr, pci_addr = range->pci_addr;
-       resource_size_t size = range->size;
+       u64 axi_addr = entry->res->start;
+       u64 pci_addr = entry->res->start - entry->offset;
+       resource_size_t size = resource_size(entry->res);
 
        /* iterate through all IARR mapping regions */
        for (region_idx = 0; region_idx < ib->nr_regions; region_idx++) {
@@ -1182,67 +1183,46 @@ err_ib:
        return ret;
 }
 
-static int iproc_pcie_add_dma_range(struct device *dev,
-                                   struct list_head *resources,
-                                   struct of_pci_range *range)
+static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
 {
-       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;
+       struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+       struct resource_entry *entry;
+       int ret = 0;
 
-       resource_list_for_each_entry(tmp, resources) {
-               if (tmp->res->start < range->cpu_addr)
-                       head = &tmp->node;
+       resource_list_for_each_entry(entry, &host->dma_ranges) {
+               /* Each range entry corresponds to an inbound mapping region */
+               ret = iproc_pcie_setup_ib(pcie, entry, IPROC_PCIE_IB_MAP_MEM);
+               if (ret)
+                       break;
        }
 
-       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;
+       return ret;
 }
 
-static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
+static void iproc_pcie_invalidate_mapping(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);
+       struct iproc_pcie_ib *ib = &pcie->ib;
+       struct iproc_pcie_ob *ob = &pcie->ob;
+       int idx;
 
-       /* Get the dma-ranges from DT */
-       ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node);
-       if (ret)
-               return ret;
+       if (pcie->ep_is_internal)
+               return;
 
-       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)
-                       goto out;
+       if (pcie->need_ob_cfg) {
+               /* iterate through all OARR mapping regions */
+               for (idx = ob->nr_windows - 1; idx >= 0; idx--) {
+                       iproc_pcie_write_reg(pcie,
+                                            MAP_REG(IPROC_PCIE_OARR0, idx), 0);
+               }
        }
 
-       list_splice_init(&resources, &host->dma_ranges);
-
-       return 0;
-out:
-       pci_free_resource_list(&resources);
-       return ret;
+       if (pcie->need_ib_cfg) {
+               /* iterate through all IARR mapping regions */
+               for (idx = 0; idx < ib->nr_regions; idx++) {
+                       iproc_pcie_write_reg(pcie,
+                                            MAP_REG(IPROC_PCIE_IARR0, idx), 0);
+               }
+       }
 }
 
 static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
@@ -1276,13 +1256,16 @@ static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
 static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr)
 {
        int ret;
-       struct of_pci_range range;
+       struct resource_entry entry;
 
-       memset(&range, 0, sizeof(range));
-       range.size = SZ_32K;
-       range.pci_addr = range.cpu_addr = msi_addr & ~(range.size - 1);
+       memset(&entry, 0, sizeof(entry));
+       entry.res = &entry.__res;
 
-       ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_IO);
+       msi_addr &= ~(SZ_32K - 1);
+       entry.res->start = msi_addr;
+       entry.res->end = msi_addr + SZ_32K - 1;
+
+       ret = iproc_pcie_setup_ib(pcie, &entry, IPROC_PCIE_IB_MAP_IO);
        return ret;
 }
 
@@ -1498,10 +1481,6 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
                return ret;
        }
 
-       ret = devm_request_pci_bus_resources(dev, res);
-       if (ret)
-               return ret;
-
        ret = phy_init(pcie->phy);
        if (ret) {
                dev_err(dev, "unable to initialize PCIe PHY\n");
@@ -1517,6 +1496,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
        iproc_pcie_perst_ctrl(pcie, true);
        iproc_pcie_perst_ctrl(pcie, false);
 
+       iproc_pcie_invalidate_mapping(pcie);
+
        if (pcie->need_ob_cfg) {
                ret = iproc_pcie_map_ranges(pcie, res);
                if (ret) {
@@ -1543,7 +1524,6 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
                if (iproc_pcie_msi_enable(pcie))
                        dev_info(dev, "not using iProc MSI\n");
 
-       list_splice_init(res, &host->windows);
        host->busnr = 0;
        host->dev.parent = dev;
        host->ops = &iproc_pcie_ops;
index 626a7c3..cb98289 100644 (file)
@@ -216,7 +216,6 @@ struct mtk_pcie {
        void __iomem *base;
        struct clk *free_ck;
 
-       struct resource mem;
        struct list_head ports;
        const struct mtk_pcie_soc *soc;
        unsigned int busnr;
@@ -661,11 +660,19 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
 static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
 {
        struct mtk_pcie *pcie = port->pcie;
-       struct resource *mem = &pcie->mem;
+       struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+       struct resource *mem = NULL;
+       struct resource_entry *entry;
        const struct mtk_pcie_soc *soc = port->pcie->soc;
        u32 val;
        int err;
 
+       entry = resource_list_first_type(&host->windows, IORESOURCE_MEM);
+       if (entry)
+               mem = entry->res;
+       if (!mem)
+               return -EINVAL;
+
        /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
        if (pcie->base) {
                val = readl(pcie->base + PCIE_SYS_CFG_V2);
@@ -1023,39 +1030,15 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
        struct mtk_pcie_port *port, *tmp;
        struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
        struct list_head *windows = &host->windows;
-       struct resource_entry *win, *tmp_win;
-       resource_size_t io_base;
+       struct resource *bus;
        int err;
 
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                                   windows, &io_base);
+       err = pci_parse_request_of_pci_ranges(dev, windows,
+                                             &host->dma_ranges, &bus);
        if (err)
                return err;
 
-       err = devm_request_pci_bus_resources(dev, windows);
-       if (err < 0)
-               return err;
-
-       /* Get the I/O and memory ranges from DT */
-       resource_list_for_each_entry_safe(win, tmp_win, windows) {
-               switch (resource_type(win->res)) {
-               case IORESOURCE_IO:
-                       err = devm_pci_remap_iospace(dev, win->res, io_base);
-                       if (err) {
-                               dev_warn(dev, "error %d: failed to map resource %pR\n",
-                                        err, win->res);
-                               resource_list_destroy_entry(win);
-                       }
-                       break;
-               case IORESOURCE_MEM:
-                       memcpy(&pcie->mem, win->res, sizeof(*win->res));
-                       pcie->mem.name = "non-prefetchable";
-                       break;
-               case IORESOURCE_BUS:
-                       pcie->busnr = win->res->start;
-                       break;
-               }
-       }
+       pcie->busnr = bus->start;
 
        for_each_available_child_of_node(node, child) {
                int slot;
index a45a644..3a696ca 100644 (file)
@@ -140,7 +140,6 @@ struct mobiveil_msi {                       /* MSI information */
 
 struct mobiveil_pcie {
        struct platform_device *pdev;
-       struct list_head resources;
        void __iomem *config_axi_slave_base;    /* endpoint config base */
        void __iomem *csr_axi_slave_base;       /* root port config base */
        void __iomem *apb_csr_base;     /* MSI register base */
@@ -235,7 +234,7 @@ static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
        return PCIBIOS_SUCCESSFUL;
 }
 
-static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
+static u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
 {
        void *addr;
        u32 val;
@@ -250,7 +249,8 @@ static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
        return val;
 }
 
-static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
+static void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off,
+                              size_t size)
 {
        void *addr;
        int ret;
@@ -262,19 +262,19 @@ static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
                dev_err(&pcie->pdev->dev, "write CSR address failed\n");
 }
 
-static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
+static u32 mobiveil_csr_readl(struct mobiveil_pcie *pcie, u32 off)
 {
-       return csr_read(pcie, off, 0x4);
+       return mobiveil_csr_read(pcie, off, 0x4);
 }
 
-static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
+static void mobiveil_csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
 {
-       csr_write(pcie, val, off, 0x4);
+       mobiveil_csr_write(pcie, val, off, 0x4);
 }
 
 static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
 {
-       return (csr_readl(pcie, LTSSM_STATUS) &
+       return (mobiveil_csr_readl(pcie, LTSSM_STATUS) &
                LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
 }
 
@@ -323,7 +323,7 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
                PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
                PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
 
-       csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
+       mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
 
        return pcie->config_axi_slave_base + where;
 }
@@ -353,13 +353,14 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
        chained_irq_enter(chip, desc);
 
        /* read INTx status */
-       val = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
-       mask = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+       val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+       mask = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
        intr_status = val & mask;
 
        /* Handle INTx */
        if (intr_status & PAB_INTP_INTX_MASK) {
-               shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+               shifted_status = mobiveil_csr_readl(pcie,
+                                                   PAB_INTP_AMBA_MISC_STAT);
                shifted_status &= PAB_INTP_INTX_MASK;
                shifted_status >>= PAB_INTX_START;
                do {
@@ -373,12 +374,13 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
                                                            bit);
 
                                /* clear interrupt handled */
-                               csr_writel(pcie, 1 << (PAB_INTX_START + bit),
-                                          PAB_INTP_AMBA_MISC_STAT);
+                               mobiveil_csr_writel(pcie,
+                                                   1 << (PAB_INTX_START + bit),
+                                                   PAB_INTP_AMBA_MISC_STAT);
                        }
 
-                       shifted_status = csr_readl(pcie,
-                                                  PAB_INTP_AMBA_MISC_STAT);
+                       shifted_status = mobiveil_csr_readl(pcie,
+                                                           PAB_INTP_AMBA_MISC_STAT);
                        shifted_status &= PAB_INTP_INTX_MASK;
                        shifted_status >>= PAB_INTX_START;
                } while (shifted_status != 0);
@@ -413,7 +415,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
        }
 
        /* Clear the interrupt status */
-       csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
+       mobiveil_csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
        chained_irq_exit(chip, desc);
 }
 
@@ -474,24 +476,24 @@ static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
                return;
        }
 
-       value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
+       value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
        value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
        value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
                 (lower_32_bits(size64) & WIN_SIZE_MASK);
-       csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
+       mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
 
-       csr_writel(pcie, upper_32_bits(size64),
-                  PAB_EXT_PEX_AMAP_SIZEN(win_num));
+       mobiveil_csr_writel(pcie, upper_32_bits(size64),
+                           PAB_EXT_PEX_AMAP_SIZEN(win_num));
 
-       csr_writel(pcie, lower_32_bits(cpu_addr),
-                  PAB_PEX_AMAP_AXI_WIN(win_num));
-       csr_writel(pcie, upper_32_bits(cpu_addr),
-                  PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
+       mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr),
+                           PAB_PEX_AMAP_AXI_WIN(win_num));
+       mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
+                           PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
 
-       csr_writel(pcie, lower_32_bits(pci_addr),
-                  PAB_PEX_AMAP_PEX_WIN_L(win_num));
-       csr_writel(pcie, upper_32_bits(pci_addr),
-                  PAB_PEX_AMAP_PEX_WIN_H(win_num));
+       mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
+                           PAB_PEX_AMAP_PEX_WIN_L(win_num));
+       mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
+                           PAB_PEX_AMAP_PEX_WIN_H(win_num));
 
        pcie->ib_wins_configured++;
 }
@@ -515,27 +517,29 @@ static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
         * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
         * to 4 KB in PAB_AXI_AMAP_CTRL register
         */
-       value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
+       value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
        value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
        value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
                 (lower_32_bits(size64) & WIN_SIZE_MASK);
-       csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
+       mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
 
-       csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
+       mobiveil_csr_writel(pcie, upper_32_bits(size64),
+                           PAB_EXT_AXI_AMAP_SIZE(win_num));
 
        /*
         * program AXI window base with appropriate value in
         * PAB_AXI_AMAP_AXI_WIN0 register
         */
-       csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
-                  PAB_AXI_AMAP_AXI_WIN(win_num));
-       csr_writel(pcie, upper_32_bits(cpu_addr),
-                  PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
+       mobiveil_csr_writel(pcie,
+                           lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
+                           PAB_AXI_AMAP_AXI_WIN(win_num));
+       mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
+                           PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
 
-       csr_writel(pcie, lower_32_bits(pci_addr),
-                  PAB_AXI_AMAP_PEX_WIN_L(win_num));
-       csr_writel(pcie, upper_32_bits(pci_addr),
-                  PAB_AXI_AMAP_PEX_WIN_H(win_num));
+       mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
+                           PAB_AXI_AMAP_PEX_WIN_L(win_num));
+       mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
+                           PAB_AXI_AMAP_PEX_WIN_H(win_num));
 
        pcie->ob_wins_configured++;
 }
@@ -575,46 +579,47 @@ static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
 
 static int mobiveil_host_init(struct mobiveil_pcie *pcie)
 {
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
        u32 value, pab_ctrl, type;
        struct resource_entry *win;
 
        /* setup bus numbers */
-       value = csr_readl(pcie, PCI_PRIMARY_BUS);
+       value = mobiveil_csr_readl(pcie, PCI_PRIMARY_BUS);
        value &= 0xff000000;
        value |= 0x00ff0100;
-       csr_writel(pcie, value, PCI_PRIMARY_BUS);
+       mobiveil_csr_writel(pcie, value, PCI_PRIMARY_BUS);
 
        /*
         * program Bus Master Enable Bit in Command Register in PAB Config
         * Space
         */
-       value = csr_readl(pcie, PCI_COMMAND);
+       value = mobiveil_csr_readl(pcie, PCI_COMMAND);
        value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-       csr_writel(pcie, value, PCI_COMMAND);
+       mobiveil_csr_writel(pcie, value, PCI_COMMAND);
 
        /*
         * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
         * register
         */
-       pab_ctrl = csr_readl(pcie, PAB_CTRL);
+       pab_ctrl = mobiveil_csr_readl(pcie, PAB_CTRL);
        pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
-       csr_writel(pcie, pab_ctrl, PAB_CTRL);
+       mobiveil_csr_writel(pcie, pab_ctrl, PAB_CTRL);
 
-       csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
-                  PAB_INTP_AMBA_MISC_ENB);
+       mobiveil_csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
+                           PAB_INTP_AMBA_MISC_ENB);
 
        /*
         * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
         * PAB_AXI_PIO_CTRL Register
         */
-       value = csr_readl(pcie, PAB_AXI_PIO_CTRL);
+       value = mobiveil_csr_readl(pcie, PAB_AXI_PIO_CTRL);
        value |= APIO_EN_MASK;
-       csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
+       mobiveil_csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
 
        /* Enable PCIe PIO master */
-       value = csr_readl(pcie, PAB_PEX_PIO_CTRL);
+       value = mobiveil_csr_readl(pcie, PAB_PEX_PIO_CTRL);
        value |= 1 << PIO_ENABLE_SHIFT;
-       csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
+       mobiveil_csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
 
        /*
         * we'll program one outbound window for config reads and
@@ -631,7 +636,7 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
        program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
 
        /* Get the I/O and memory ranges from DT */
-       resource_list_for_each_entry(win, &pcie->resources) {
+       resource_list_for_each_entry(win, &bridge->windows) {
                if (resource_type(win->res) == IORESOURCE_MEM)
                        type = MEM_WINDOW_TYPE;
                else if (resource_type(win->res) == IORESOURCE_IO)
@@ -647,10 +652,10 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
        }
 
        /* fixup for PCIe class register */
-       value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
+       value = mobiveil_csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
        value &= 0xff;
        value |= (PCI_CLASS_BRIDGE_PCI << 16);
-       csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
+       mobiveil_csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
 
        /* setup MSI hardware registers */
        mobiveil_pcie_enable_msi(pcie);
@@ -668,9 +673,9 @@ static void mobiveil_mask_intx_irq(struct irq_data *data)
        pcie = irq_desc_get_chip_data(desc);
        mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
        raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
-       shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+       shifted_val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
        shifted_val &= ~mask;
-       csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
+       mobiveil_csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
        raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
 }
 
@@ -684,9 +689,9 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data)
        pcie = irq_desc_get_chip_data(desc);
        mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
        raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
-       shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+       shifted_val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
        shifted_val |= mask;
-       csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
+       mobiveil_csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
        raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
 }
 
@@ -857,7 +862,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
        struct pci_bus *child;
        struct pci_host_bridge *bridge;
        struct device *dev = &pdev->dev;
-       resource_size_t iobase;
        int ret;
 
        /* allocate the PCIe port */
@@ -875,11 +879,9 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       INIT_LIST_HEAD(&pcie->resources);
-
        /* parse the host bridge base addresses from the device tree file */
-       ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                                   &pcie->resources, &iobase);
+       ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (ret) {
                dev_err(dev, "Getting bridge resources failed\n");
                return ret;
@@ -892,24 +894,19 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
        ret = mobiveil_host_init(pcie);
        if (ret) {
                dev_err(dev, "Failed to initialize host\n");
-               goto error;
+               return ret;
        }
 
        /* initialize the IRQ domains */
        ret = mobiveil_pcie_init_irq_domain(pcie);
        if (ret) {
                dev_err(dev, "Failed creating IRQ Domain\n");
-               goto error;
+               return ret;
        }
 
        irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
 
-       ret = devm_request_pci_bus_resources(dev, &pcie->resources);
-       if (ret)
-               goto error;
-
        /* Initialize bridge */
-       list_splice_init(&pcie->resources, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = pcie;
        bridge->busnr = pcie->root_bus_nr;
@@ -920,13 +917,13 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
        ret = mobiveil_bringup_link(pcie);
        if (ret) {
                dev_info(dev, "link bring-up failed\n");
-               goto error;
+               return ret;
        }
 
        /* setup the kernel resources for the newly added PCIe root bus */
        ret = pci_scan_root_bus_bridge(bridge);
        if (ret)
-               goto error;
+               return ret;
 
        bus = bridge->bus;
 
@@ -936,9 +933,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
        pci_bus_add_devices(bus);
 
        return 0;
-error:
-       pci_free_resource_list(&pcie->resources);
-       return ret;
 }
 
 static const struct of_device_id mobiveil_pcie_of_match[] = {
index f6a669a..759c654 100644 (file)
@@ -30,8 +30,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
-#include "../pci.h"
-
 #define PCIECAR                        0x000010
 #define PCIECCTLR              0x000018
 #define  CONFIG_SEND_ENABLE    BIT(31)
 #define  LINK_SPEED_2_5GTS     (1 << 16)
 #define  LINK_SPEED_5_0GTS     (2 << 16)
 #define MACCTLR                        0x011058
+#define  MACCTLR_NFTS_MASK     GENMASK(23, 16) /* The name is from SH7786 */
 #define  SPEED_CHANGE          BIT(24)
 #define  SCRAMBLE_DISABLE      BIT(27)
+#define  LTSMDIS               BIT(31)
+#define  MACCTLR_INIT_VAL      (LTSMDIS | MACCTLR_NFTS_MASK)
 #define PMSR                   0x01105c
 #define MACS2R                 0x011078
 #define MACCGSPSETR            0x011084
@@ -615,6 +616,8 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
        if (IS_ENABLED(CONFIG_PCI_MSI))
                rcar_pci_write_reg(pcie, 0x801f0000, PCIEMSITXR);
 
+       rcar_pci_write_reg(pcie, MACCTLR_INIT_VAL, MACCTLR);
+
        /* Finish initialization - establish a PCI Express link */
        rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
 
@@ -1014,40 +1017,43 @@ err_irq1:
 }
 
 static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
-                                   struct of_pci_range *range,
+                                   struct resource_entry *entry,
                                    int *index)
 {
-       u64 restype = range->flags;
-       u64 cpu_addr = range->cpu_addr;
-       u64 cpu_end = range->cpu_addr + range->size;
-       u64 pci_addr = range->pci_addr;
+       u64 restype = entry->res->flags;
+       u64 cpu_addr = entry->res->start;
+       u64 cpu_end = entry->res->end;
+       u64 pci_addr = entry->res->start - entry->offset;
        u32 flags = LAM_64BIT | LAR_ENABLE;
        u64 mask;
-       u64 size;
+       u64 size = resource_size(entry->res);
        int idx = *index;
 
        if (restype & IORESOURCE_PREFETCH)
                flags |= LAM_PREFETCH;
 
-       /*
-        * If the size of the range is larger than the alignment of the start
-        * address, we have to use multiple entries to perform the mapping.
-        */
-       if (cpu_addr > 0) {
-               unsigned long nr_zeros = __ffs64(cpu_addr);
-               u64 alignment = 1ULL << nr_zeros;
+       while (cpu_addr < cpu_end) {
+               if (idx >= MAX_NR_INBOUND_MAPS - 1) {
+                       dev_err(pcie->dev, "Failed to map inbound regions!\n");
+                       return -EINVAL;
+               }
+               /*
+                * If the size of the range is larger than the alignment of
+                * the start address, we have to use multiple entries to
+                * perform the mapping.
+                */
+               if (cpu_addr > 0) {
+                       unsigned long nr_zeros = __ffs64(cpu_addr);
+                       u64 alignment = 1ULL << nr_zeros;
 
-               size = min(range->size, alignment);
-       } else {
-               size = range->size;
-       }
-       /* Hardware supports max 4GiB inbound region */
-       size = min(size, 1ULL << 32);
+                       size = min(size, alignment);
+               }
+               /* Hardware supports max 4GiB inbound region */
+               size = min(size, 1ULL << 32);
 
-       mask = roundup_pow_of_two(size) - 1;
-       mask &= ~0xf;
+               mask = roundup_pow_of_two(size) - 1;
+               mask &= ~0xf;
 
-       while (cpu_addr < cpu_end) {
                /*
                 * Set up 64-bit inbound regions as the range parser doesn't
                 * distinguish between 32 and 64-bit types.
@@ -1067,41 +1073,25 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
                pci_addr += size;
                cpu_addr += size;
                idx += 2;
-
-               if (idx > MAX_NR_INBOUND_MAPS) {
-                       dev_err(pcie->dev, "Failed to map inbound regions!\n");
-                       return -EINVAL;
-               }
        }
        *index = idx;
 
        return 0;
 }
 
-static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
-                                         struct device_node *np)
+static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie)
 {
-       struct of_pci_range range;
-       struct of_pci_range_parser parser;
-       int index = 0;
-       int err;
-
-       if (of_pci_dma_range_parser_init(&parser, np))
-               return -EINVAL;
-
-       /* Get the dma-ranges from DT */
-       for_each_of_pci_range(&parser, &range) {
-               u64 end = range.cpu_addr + range.size - 1;
-
-               dev_dbg(pcie->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
-                       range.flags, range.cpu_addr, end, range.pci_addr);
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
+       struct resource_entry *entry;
+       int index = 0, err = 0;
 
-               err = rcar_pcie_inbound_ranges(pcie, &range, &index);
+       resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+               err = rcar_pcie_inbound_ranges(pcie, entry, &index);
                if (err)
-                       return err;
+                       break;
        }
 
-       return 0;
+       return err;
 }
 
 static const struct of_device_id rcar_pcie_of_match[] = {
@@ -1138,7 +1128,8 @@ static int rcar_pcie_probe(struct platform_device *pdev)
        pcie->dev = dev;
        platform_set_drvdata(pdev, pcie);
 
-       err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
+       err = pci_parse_request_of_pci_ranges(dev, &pcie->resources,
+                                             &bridge->dma_ranges, NULL);
        if (err)
                goto err_free_bridge;
 
@@ -1161,7 +1152,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
                goto err_unmap_msi_irqs;
        }
 
-       err = rcar_pcie_parse_map_dma_ranges(pcie, dev->of_node);
+       err = rcar_pcie_parse_map_dma_ranges(pcie);
        if (err)
                goto err_clk_disable;
 
@@ -1237,6 +1228,7 @@ static int rcar_pcie_resume_noirq(struct device *dev)
                return 0;
 
        /* Re-establish the PCIe link */
+       rcar_pci_write_reg(pcie, MACCTLR_INIT_VAL, MACCTLR);
        rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
        return rcar_pcie_wait_for_dl(pcie);
 }
index ef8e677..d9b63bf 100644 (file)
@@ -620,19 +620,13 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip)
                dev_info(dev, "no vpcie3v3 regulator found\n");
        }
 
-       rockchip->vpcie1v8 = devm_regulator_get_optional(dev, "vpcie1v8");
-       if (IS_ERR(rockchip->vpcie1v8)) {
-               if (PTR_ERR(rockchip->vpcie1v8) != -ENODEV)
-                       return PTR_ERR(rockchip->vpcie1v8);
-               dev_info(dev, "no vpcie1v8 regulator found\n");
-       }
+       rockchip->vpcie1v8 = devm_regulator_get(dev, "vpcie1v8");
+       if (IS_ERR(rockchip->vpcie1v8))
+               return PTR_ERR(rockchip->vpcie1v8);
 
-       rockchip->vpcie0v9 = devm_regulator_get_optional(dev, "vpcie0v9");
-       if (IS_ERR(rockchip->vpcie0v9)) {
-               if (PTR_ERR(rockchip->vpcie0v9) != -ENODEV)
-                       return PTR_ERR(rockchip->vpcie0v9);
-               dev_info(dev, "no vpcie0v9 regulator found\n");
-       }
+       rockchip->vpcie0v9 = devm_regulator_get(dev, "vpcie0v9");
+       if (IS_ERR(rockchip->vpcie0v9))
+               return PTR_ERR(rockchip->vpcie0v9);
 
        return 0;
 }
@@ -658,27 +652,22 @@ static int rockchip_pcie_set_vpcie(struct rockchip_pcie *rockchip)
                }
        }
 
-       if (!IS_ERR(rockchip->vpcie1v8)) {
-               err = regulator_enable(rockchip->vpcie1v8);
-               if (err) {
-                       dev_err(dev, "fail to enable vpcie1v8 regulator\n");
-                       goto err_disable_3v3;
-               }
+       err = regulator_enable(rockchip->vpcie1v8);
+       if (err) {
+               dev_err(dev, "fail to enable vpcie1v8 regulator\n");
+               goto err_disable_3v3;
        }
 
-       if (!IS_ERR(rockchip->vpcie0v9)) {
-               err = regulator_enable(rockchip->vpcie0v9);
-               if (err) {
-                       dev_err(dev, "fail to enable vpcie0v9 regulator\n");
-                       goto err_disable_1v8;
-               }
+       err = regulator_enable(rockchip->vpcie0v9);
+       if (err) {
+               dev_err(dev, "fail to enable vpcie0v9 regulator\n");
+               goto err_disable_1v8;
        }
 
        return 0;
 
 err_disable_1v8:
-       if (!IS_ERR(rockchip->vpcie1v8))
-               regulator_disable(rockchip->vpcie1v8);
+       regulator_disable(rockchip->vpcie1v8);
 err_disable_3v3:
        if (!IS_ERR(rockchip->vpcie3v3))
                regulator_disable(rockchip->vpcie3v3);
@@ -806,19 +795,28 @@ static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie *rockchip,
 static int rockchip_pcie_cfg_atu(struct rockchip_pcie *rockchip)
 {
        struct device *dev = rockchip->dev;
+       struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rockchip);
+       struct resource_entry *entry;
+       u64 pci_addr, size;
        int offset;
        int err;
        int reg_no;
 
        rockchip_pcie_cfg_configuration_accesses(rockchip,
                                                 AXI_WRAPPER_TYPE0_CFG);
+       entry = resource_list_first_type(&bridge->windows, IORESOURCE_MEM);
+       if (!entry)
+               return -ENODEV;
+
+       size = resource_size(entry->res);
+       pci_addr = entry->res->start - entry->offset;
+       rockchip->msg_bus_addr = pci_addr;
 
-       for (reg_no = 0; reg_no < (rockchip->mem_size >> 20); reg_no++) {
+       for (reg_no = 0; reg_no < (size >> 20); reg_no++) {
                err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1,
                                                AXI_WRAPPER_MEM_WRITE,
                                                20 - 1,
-                                               rockchip->mem_bus_addr +
-                                               (reg_no << 20),
+                                               pci_addr + (reg_no << 20),
                                                0);
                if (err) {
                        dev_err(dev, "program RC mem outbound ATU failed\n");
@@ -832,14 +830,20 @@ static int rockchip_pcie_cfg_atu(struct rockchip_pcie *rockchip)
                return err;
        }
 
-       offset = rockchip->mem_size >> 20;
-       for (reg_no = 0; reg_no < (rockchip->io_size >> 20); reg_no++) {
+       entry = resource_list_first_type(&bridge->windows, IORESOURCE_IO);
+       if (!entry)
+               return -ENODEV;
+
+       size = resource_size(entry->res);
+       pci_addr = entry->res->start - entry->offset;
+
+       offset = size >> 20;
+       for (reg_no = 0; reg_no < (size >> 20); reg_no++) {
                err = rockchip_pcie_prog_ob_atu(rockchip,
                                                reg_no + 1 + offset,
                                                AXI_WRAPPER_IO_WRITE,
                                                20 - 1,
-                                               rockchip->io_bus_addr +
-                                               (reg_no << 20),
+                                               pci_addr + (reg_no << 20),
                                                0);
                if (err) {
                        dev_err(dev, "program RC io outbound ATU failed\n");
@@ -852,8 +856,7 @@ static int rockchip_pcie_cfg_atu(struct rockchip_pcie *rockchip)
                                  AXI_WRAPPER_NOR_MSG,
                                  20 - 1, 0, 0);
 
-       rockchip->msg_bus_addr = rockchip->mem_bus_addr +
-                                       ((reg_no + offset) << 20);
+       rockchip->msg_bus_addr += ((reg_no + offset) << 20);
        return err;
 }
 
@@ -897,8 +900,7 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
 
        rockchip_pcie_disable_clocks(rockchip);
 
-       if (!IS_ERR(rockchip->vpcie0v9))
-               regulator_disable(rockchip->vpcie0v9);
+       regulator_disable(rockchip->vpcie0v9);
 
        return ret;
 }
@@ -908,12 +910,10 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev)
        struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
        int err;
 
-       if (!IS_ERR(rockchip->vpcie0v9)) {
-               err = regulator_enable(rockchip->vpcie0v9);
-               if (err) {
-                       dev_err(dev, "fail to enable vpcie0v9 regulator\n");
-                       return err;
-               }
+       err = regulator_enable(rockchip->vpcie0v9);
+       if (err) {
+               dev_err(dev, "fail to enable vpcie0v9 regulator\n");
+               return err;
        }
 
        err = rockchip_pcie_enable_clocks(rockchip);
@@ -939,8 +939,7 @@ err_err_deinit_port:
 err_pcie_resume:
        rockchip_pcie_disable_clocks(rockchip);
 err_disable_0v9:
-       if (!IS_ERR(rockchip->vpcie0v9))
-               regulator_disable(rockchip->vpcie0v9);
+       regulator_disable(rockchip->vpcie0v9);
        return err;
 }
 
@@ -950,14 +949,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct pci_bus *bus, *child;
        struct pci_host_bridge *bridge;
-       struct resource_entry *win;
-       resource_size_t io_base;
-       struct resource *mem;
-       struct resource *io;
+       struct resource *bus_res;
        int err;
 
-       LIST_HEAD(res);
-
        if (!dev->of_node)
                return -ENODEV;
 
@@ -995,56 +989,23 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
        if (err < 0)
                goto err_deinit_port;
 
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
-                                                   &res, &io_base);
+       err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, &bus_res);
        if (err)
                goto err_remove_irq_domain;
 
-       err = devm_request_pci_bus_resources(dev, &res);
-       if (err)
-               goto err_free_res;
-
-       /* Get the I/O and memory ranges from DT */
-       resource_list_for_each_entry(win, &res) {
-               switch (resource_type(win->res)) {
-               case IORESOURCE_IO:
-                       io = win->res;
-                       io->name = "I/O";
-                       rockchip->io_size = resource_size(io);
-                       rockchip->io_bus_addr = io->start - win->offset;
-                       err = pci_remap_iospace(io, io_base);
-                       if (err) {
-                               dev_warn(dev, "error %d: failed to map resource %pR\n",
-                                        err, io);
-                               continue;
-                       }
-                       rockchip->io = io;
-                       break;
-               case IORESOURCE_MEM:
-                       mem = win->res;
-                       mem->name = "MEM";
-                       rockchip->mem_size = resource_size(mem);
-                       rockchip->mem_bus_addr = mem->start - win->offset;
-                       break;
-               case IORESOURCE_BUS:
-                       rockchip->root_bus_nr = win->res->start;
-                       break;
-               default:
-                       continue;
-               }
-       }
+       rockchip->root_bus_nr = bus_res->start;
 
        err = rockchip_pcie_cfg_atu(rockchip);
        if (err)
-               goto err_unmap_iospace;
+               goto err_remove_irq_domain;
 
        rockchip->msg_region = devm_ioremap(dev, rockchip->msg_bus_addr, SZ_1M);
        if (!rockchip->msg_region) {
                err = -ENOMEM;
-               goto err_unmap_iospace;
+               goto err_remove_irq_domain;
        }
 
-       list_splice_init(&res, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = rockchip;
        bridge->busnr = 0;
@@ -1054,7 +1015,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
 
        err = pci_scan_root_bus_bridge(bridge);
        if (err < 0)
-               goto err_unmap_iospace;
+               goto err_remove_irq_domain;
 
        bus = bridge->bus;
 
@@ -1068,10 +1029,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
        pci_bus_add_devices(bus);
        return 0;
 
-err_unmap_iospace:
-       pci_unmap_iospace(rockchip->io);
-err_free_res:
-       pci_free_resource_list(&res);
 err_remove_irq_domain:
        irq_domain_remove(rockchip->irq_domain);
 err_deinit_port:
@@ -1081,10 +1038,8 @@ err_vpcie:
                regulator_disable(rockchip->vpcie12v);
        if (!IS_ERR(rockchip->vpcie3v3))
                regulator_disable(rockchip->vpcie3v3);
-       if (!IS_ERR(rockchip->vpcie1v8))
-               regulator_disable(rockchip->vpcie1v8);
-       if (!IS_ERR(rockchip->vpcie0v9))
-               regulator_disable(rockchip->vpcie0v9);
+       regulator_disable(rockchip->vpcie1v8);
+       regulator_disable(rockchip->vpcie0v9);
 err_set_vpcie:
        rockchip_pcie_disable_clocks(rockchip);
        return err;
@@ -1097,7 +1052,6 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
 
        pci_stop_root_bus(rockchip->root_bus);
        pci_remove_root_bus(rockchip->root_bus);
-       pci_unmap_iospace(rockchip->io);
        irq_domain_remove(rockchip->irq_domain);
 
        rockchip_pcie_deinit_phys(rockchip);
@@ -1108,10 +1062,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
                regulator_disable(rockchip->vpcie12v);
        if (!IS_ERR(rockchip->vpcie3v3))
                regulator_disable(rockchip->vpcie3v3);
-       if (!IS_ERR(rockchip->vpcie1v8))
-               regulator_disable(rockchip->vpcie1v8);
-       if (!IS_ERR(rockchip->vpcie0v9))
-               regulator_disable(rockchip->vpcie0v9);
+       regulator_disable(rockchip->vpcie1v8);
+       regulator_disable(rockchip->vpcie0v9);
 
        return 0;
 }
index 8e87a05..d90dfb3 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Rockchip AXI PCIe controller driver
  *
@@ -304,13 +304,8 @@ struct rockchip_pcie {
        struct  irq_domain *irq_domain;
        int     offset;
        struct pci_bus *root_bus;
-       struct resource *io;
-       phys_addr_t io_bus_addr;
-       u32     io_size;
        void    __iomem *msg_region;
-       u32     mem_size;
        phys_addr_t msg_bus_addr;
-       phys_addr_t mem_bus_addr;
        bool is_rc;
        struct resource *mem_res;
 };
index 45c0f34..9bd1427 100644 (file)
@@ -821,8 +821,6 @@ static int nwl_pcie_probe(struct platform_device *pdev)
        struct pci_bus *child;
        struct pci_host_bridge *bridge;
        int err;
-       resource_size_t iobase = 0;
-       LIST_HEAD(res);
 
        bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
        if (!bridge)
@@ -845,24 +843,19 @@ static int nwl_pcie_probe(struct platform_device *pdev)
                return err;
        }
 
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
-                                                   &iobase);
+       err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (err) {
                dev_err(dev, "Getting bridge resources failed\n");
                return err;
        }
 
-       err = devm_request_pci_bus_resources(dev, &res);
-       if (err)
-               goto error;
-
        err = nwl_pcie_init_irq_domain(pcie);
        if (err) {
                dev_err(dev, "Failed creating IRQ Domain\n");
-               goto error;
+               return err;
        }
 
-       list_splice_init(&res, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = pcie;
        bridge->busnr = pcie->root_busno;
@@ -874,13 +867,13 @@ static int nwl_pcie_probe(struct platform_device *pdev)
                err = nwl_pcie_enable_msi(pcie);
                if (err < 0) {
                        dev_err(dev, "failed to enable MSI support: %d\n", err);
-                       goto error;
+                       return err;
                }
        }
 
        err = pci_scan_root_bus_bridge(bridge);
        if (err)
-               goto error;
+               return err;
 
        bus = bridge->bus;
 
@@ -889,10 +882,6 @@ static int nwl_pcie_probe(struct platform_device *pdev)
                pcie_bus_configure_settings(child);
        pci_bus_add_devices(bus);
        return 0;
-
-error:
-       pci_free_resource_list(&res);
-       return err;
 }
 
 static struct platform_driver nwl_pcie_driver = {
index 5bf3af3..98e5529 100644 (file)
@@ -619,8 +619,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
        struct pci_bus *bus, *child;
        struct pci_host_bridge *bridge;
        int err;
-       resource_size_t iobase = 0;
-       LIST_HEAD(res);
 
        if (!dev->of_node)
                return -ENODEV;
@@ -647,19 +645,13 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
                return err;
        }
 
-       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
-                                                   &iobase);
+       err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
+                                             &bridge->dma_ranges, NULL);
        if (err) {
                dev_err(dev, "Getting bridge resources failed\n");
                return err;
        }
 
-       err = devm_request_pci_bus_resources(dev, &res);
-       if (err)
-               goto error;
-
-
-       list_splice_init(&res, &bridge->windows);
        bridge->dev.parent = dev;
        bridge->sysdata = port;
        bridge->busnr = 0;
@@ -673,7 +665,7 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
 #endif
        err = pci_scan_root_bus_bridge(bridge);
        if (err < 0)
-               goto error;
+               return err;
 
        bus = bridge->bus;
 
@@ -682,10 +674,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
                pcie_bus_configure_settings(child);
        pci_bus_add_devices(bus);
        return 0;
-
-error:
-       pci_free_resource_list(&res);
-       return err;
 }
 
 static const struct of_device_id xilinx_pcie_of_match[] = {
index a35d3f3..2128422 100644 (file)
@@ -602,16 +602,30 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
 
        /*
         * Certain VMD devices may have a root port configuration option which
-        * limits the bus range to between 0-127 or 128-255
+        * limits the bus range to between 0-127, 128-255, or 224-255
         */
        if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) {
-               u32 vmcap, vmconfig;
-
-               pci_read_config_dword(vmd->dev, PCI_REG_VMCAP, &vmcap);
-               pci_read_config_dword(vmd->dev, PCI_REG_VMCONFIG, &vmconfig);
-               if (BUS_RESTRICT_CAP(vmcap) &&
-                   (BUS_RESTRICT_CFG(vmconfig) == 0x1))
-                       vmd->busn_start = 128;
+               u16 reg16;
+
+               pci_read_config_word(vmd->dev, PCI_REG_VMCAP, &reg16);
+               if (BUS_RESTRICT_CAP(reg16)) {
+                       pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG,
+                                            &reg16);
+
+                       switch (BUS_RESTRICT_CFG(reg16)) {
+                       case 1:
+                               vmd->busn_start = 128;
+                               break;
+                       case 2:
+                               vmd->busn_start = 224;
+                               break;
+                       case 3:
+                               pci_err(vmd->dev, "Unknown Bus Offset Setting\n");
+                               return -ENODEV;
+                       default:
+                               break;
+                       }
+               }
        }
 
        res = &vmd->dev->resource[VMD_CFGBAR];
@@ -823,7 +837,7 @@ static int vmd_suspend(struct device *dev)
        int i;
 
        for (i = 0; i < vmd->msix_count; i++)
-                devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);
+               devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);
 
        pci_save_state(pdev);
        return 0;
@@ -854,6 +868,8 @@ static const struct pci_device_id vmd_ids[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
                .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
                                VMD_FEAT_HAS_BUS_RESTRICTIONS,},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
+               .driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, vmd_ids);
index 1cfe368..5d74f81 100644 (file)
@@ -44,7 +44,7 @@
 static struct workqueue_struct *kpcitest_workqueue;
 
 struct pci_epf_test {
-       void                    *reg[6];
+       void                    *reg[PCI_STD_NUM_BARS];
        struct pci_epf          *epf;
        enum pci_barno          test_reg_bar;
        struct delayed_work     cmd_handler;
@@ -377,7 +377,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
 
        cancel_delayed_work(&epf_test->cmd_handler);
        pci_epc_stop(epc);
-       for (bar = BAR_0; bar <= BAR_5; bar++) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                epf_bar = &epf->bar[bar];
 
                if (epf_test->reg[bar]) {
@@ -400,7 +400,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
 
        epc_features = epf_test->epc_features;
 
-       for (bar = BAR_0; bar <= BAR_5; bar += add) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) {
                epf_bar = &epf->bar[bar];
                /*
                 * pci_epc_set_bar() sets PCI_BASE_ADDRESS_MEM_TYPE_64
@@ -450,7 +450,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
        }
        epf_test->reg[test_reg_bar] = base;
 
-       for (bar = BAR_0; bar <= BAR_5; bar += add) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) {
                epf_bar = &epf->bar[bar];
                add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
 
@@ -478,7 +478,7 @@ static void pci_epf_configure_bar(struct pci_epf *epf,
        bool bar_fixed_64bit;
        int i;
 
-       for (i = BAR_0; i <= BAR_5; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                epf_bar = &epf->bar[i];
                bar_fixed_64bit = !!(epc_features->bar_fixed_64bit & (1 << i));
                if (bar_fixed_64bit)
index 2bf8bd1..d2b174c 100644 (file)
@@ -134,7 +134,7 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
        if (pageno < 0)
                return NULL;
 
-       *phys_addr = mem->phys_base + (pageno << page_shift);
+       *phys_addr = mem->phys_base + ((phys_addr_t)pageno << page_shift);
        virt_addr = ioremap(*phys_addr, size);
        if (!virt_addr)
                bitmap_release_region(mem->bitmap, pageno, order);
index e7b493c..32455a7 100644 (file)
@@ -83,7 +83,7 @@ config HOTPLUG_PCI_CPCI_ZT5550
        depends on HOTPLUG_PCI_CPCI && X86
        help
          Say Y here if you have an Performance Technologies (formerly Intel,
-          formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
+         formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
 
          To compile this driver as a module, choose M here: the
          module will be called cpcihp_zt5550.
index e4c4663..b386995 100644 (file)
@@ -449,8 +449,15 @@ static void acpiphp_native_scan_bridge(struct pci_dev *bridge)
 
        /* Scan non-hotplug bridges that need to be reconfigured */
        for_each_pci_bridge(dev, bus) {
-               if (!hotplug_is_native(dev))
-                       max = pci_scan_bridge(bus, dev, max, 1);
+               if (hotplug_is_native(dev))
+                       continue;
+
+               max = pci_scan_bridge(bus, dev, max, 1);
+               if (dev->subordinate) {
+                       pcibios_resource_survey_bus(dev->subordinate);
+                       pci_bus_size_bridges(dev->subordinate);
+                       pci_bus_assign_resources(dev->subordinate);
+               }
        }
 }
 
@@ -480,7 +487,6 @@ static void enable_slot(struct acpiphp_slot *slot, bool bridge)
                        if (PCI_SLOT(dev->devfn) == slot->device)
                                acpiphp_native_scan_bridge(dev);
                }
-               pci_assign_unassigned_bridge_resources(bus->self);
        } else {
                LIST_HEAD(add_list);
                int max, pass;
index 654c972..aa61d4c 100644 (file)
@@ -72,6 +72,7 @@ extern int pciehp_poll_time;
  * @reset_lock: prevents access to the Data Link Layer Link Active bit in the
  *     Link Status register and to the Presence Detect State bit in the Slot
  *     Status register during a slot reset which may cause them to flap
+ * @ist_running: flag to keep user request waiting while IRQ thread is running
  * @request_result: result of last user request submitted to the IRQ thread
  * @requester: wait queue to wake up on completion of user request,
  *     used for synchronous slot enable/disable request via sysfs
@@ -101,6 +102,7 @@ struct controller {
 
        struct hotplug_slot hotplug_slot;       /* hotplug core interface */
        struct rw_semaphore reset_lock;
+       unsigned int ist_running;
        int request_result;
        wait_queue_head_t requester;
 };
@@ -172,10 +174,10 @@ void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn);
 
 void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
 int pciehp_query_power_fault(struct controller *ctrl);
-bool pciehp_card_present(struct controller *ctrl);
-bool pciehp_card_present_or_link_active(struct controller *ctrl);
+int pciehp_card_present(struct controller *ctrl);
+int pciehp_card_present_or_link_active(struct controller *ctrl);
 int pciehp_check_link_status(struct controller *ctrl);
-bool pciehp_check_link_active(struct controller *ctrl);
+int pciehp_check_link_active(struct controller *ctrl);
 void pciehp_release_ctrl(struct controller *ctrl);
 
 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot);
index b3122c1..312cc45 100644 (file)
@@ -139,10 +139,15 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 {
        struct controller *ctrl = to_ctrl(hotplug_slot);
        struct pci_dev *pdev = ctrl->pcie->port;
+       int ret;
 
        pci_config_pm_runtime_get(pdev);
-       *value = pciehp_card_present_or_link_active(ctrl);
+       ret = pciehp_card_present_or_link_active(ctrl);
        pci_config_pm_runtime_put(pdev);
+       if (ret < 0)
+               return ret;
+
+       *value = ret;
        return 0;
 }
 
@@ -158,13 +163,13 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
  */
 static void pciehp_check_presence(struct controller *ctrl)
 {
-       bool occupied;
+       int occupied;
 
        down_read(&ctrl->reset_lock);
        mutex_lock(&ctrl->state_lock);
 
        occupied = pciehp_card_present_or_link_active(ctrl);
-       if ((occupied && (ctrl->state == OFF_STATE ||
+       if ((occupied > 0 && (ctrl->state == OFF_STATE ||
                          ctrl->state == BLINKINGON_STATE)) ||
            (!occupied && (ctrl->state == ON_STATE ||
                           ctrl->state == BLINKINGOFF_STATE)))
@@ -253,7 +258,7 @@ static bool pme_is_native(struct pcie_device *dev)
        return pcie_ports_native || host->native_pme;
 }
 
-static int pciehp_suspend(struct pcie_device *dev)
+static void pciehp_disable_interrupt(struct pcie_device *dev)
 {
        /*
         * Disable hotplug interrupt so that it does not trigger
@@ -261,7 +266,19 @@ static int pciehp_suspend(struct pcie_device *dev)
         */
        if (pme_is_native(dev))
                pcie_disable_interrupt(get_service_data(dev));
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pciehp_suspend(struct pcie_device *dev)
+{
+       /*
+        * If the port is already runtime suspended we can keep it that
+        * way.
+        */
+       if (dev_pm_smart_suspend_and_suspended(&dev->port->dev))
+               return 0;
 
+       pciehp_disable_interrupt(dev);
        return 0;
 }
 
@@ -279,6 +296,7 @@ static int pciehp_resume_noirq(struct pcie_device *dev)
 
        return 0;
 }
+#endif
 
 static int pciehp_resume(struct pcie_device *dev)
 {
@@ -292,6 +310,12 @@ static int pciehp_resume(struct pcie_device *dev)
        return 0;
 }
 
+static int pciehp_runtime_suspend(struct pcie_device *dev)
+{
+       pciehp_disable_interrupt(dev);
+       return 0;
+}
+
 static int pciehp_runtime_resume(struct pcie_device *dev)
 {
        struct controller *ctrl = get_service_data(dev);
@@ -318,10 +342,12 @@ static struct pcie_port_service_driver hpdriver_portdrv = {
        .remove         = pciehp_remove,
 
 #ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend        = pciehp_suspend,
        .resume_noirq   = pciehp_resume_noirq,
        .resume         = pciehp_resume,
-       .runtime_suspend = pciehp_suspend,
+#endif
+       .runtime_suspend = pciehp_runtime_suspend,
        .runtime_resume = pciehp_runtime_resume,
 #endif /* PM */
 };
index 21af7b1..6503d15 100644 (file)
@@ -226,7 +226,7 @@ void pciehp_handle_disable_request(struct controller *ctrl)
 
 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
 {
-       bool present, link_active;
+       int present, link_active;
 
        /*
         * If the slot is on and presence or link has changed, turn it off.
@@ -257,7 +257,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
        mutex_lock(&ctrl->state_lock);
        present = pciehp_card_present(ctrl);
        link_active = pciehp_check_link_active(ctrl);
-       if (!present && !link_active) {
+       if (present <= 0 && link_active <= 0) {
                mutex_unlock(&ctrl->state_lock);
                return;
        }
@@ -375,7 +375,8 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
                ctrl->request_result = -ENODEV;
                pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
                wait_event(ctrl->requester,
-                          !atomic_read(&ctrl->pending_events));
+                          !atomic_read(&ctrl->pending_events) &&
+                          !ctrl->ist_running);
                return ctrl->request_result;
        case POWERON_STATE:
                ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
@@ -408,7 +409,8 @@ int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
                mutex_unlock(&ctrl->state_lock);
                pciehp_request(ctrl, DISABLE_SLOT);
                wait_event(ctrl->requester,
-                          !atomic_read(&ctrl->pending_events));
+                          !atomic_read(&ctrl->pending_events) &&
+                          !ctrl->ist_running);
                return ctrl->request_result;
        case POWEROFF_STATE:
                ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
index 1a522c1..8a2cb17 100644 (file)
@@ -68,7 +68,7 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout)
        struct pci_dev *pdev = ctrl_dev(ctrl);
        u16 slot_status;
 
-       while (true) {
+       do {
                pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
                if (slot_status == (u16) ~0) {
                        ctrl_info(ctrl, "%s: no response from device\n",
@@ -81,11 +81,9 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout)
                                                   PCI_EXP_SLTSTA_CC);
                        return 1;
                }
-               if (timeout < 0)
-                       break;
                msleep(10);
                timeout -= 10;
-       }
+       } while (timeout >= 0);
        return 0;       /* timeout */
 }
 
@@ -201,17 +199,29 @@ static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask)
        pcie_do_write_cmd(ctrl, cmd, mask, false);
 }
 
-bool pciehp_check_link_active(struct controller *ctrl)
+/**
+ * pciehp_check_link_active() - Is the link active
+ * @ctrl: PCIe hotplug controller
+ *
+ * Check whether the downstream link is currently active. Note it is
+ * possible that the card is removed immediately after this so the
+ * caller may need to take it into account.
+ *
+ * If the hotplug controller itself is not available anymore returns
+ * %-ENODEV.
+ */
+int pciehp_check_link_active(struct controller *ctrl)
 {
        struct pci_dev *pdev = ctrl_dev(ctrl);
        u16 lnk_status;
-       bool ret;
+       int ret;
 
-       pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
-       ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+       ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
+       if (ret == PCIBIOS_DEVICE_NOT_FOUND || lnk_status == (u16)~0)
+               return -ENODEV;
 
-       if (ret)
-               ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
+       ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+       ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
 
        return ret;
 }
@@ -373,13 +383,29 @@ void pciehp_get_latch_status(struct controller *ctrl, u8 *status)
        *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS);
 }
 
-bool pciehp_card_present(struct controller *ctrl)
+/**
+ * pciehp_card_present() - Is the card present
+ * @ctrl: PCIe hotplug controller
+ *
+ * Function checks whether the card is currently present in the slot and
+ * in that case returns true. Note it is possible that the card is
+ * removed immediately after the check so the caller may need to take
+ * this into account.
+ *
+ * It the hotplug controller itself is not available anymore returns
+ * %-ENODEV.
+ */
+int pciehp_card_present(struct controller *ctrl)
 {
        struct pci_dev *pdev = ctrl_dev(ctrl);
        u16 slot_status;
+       int ret;
 
-       pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
-       return slot_status & PCI_EXP_SLTSTA_PDS;
+       ret = pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
+       if (ret == PCIBIOS_DEVICE_NOT_FOUND || slot_status == (u16)~0)
+               return -ENODEV;
+
+       return !!(slot_status & PCI_EXP_SLTSTA_PDS);
 }
 
 /**
@@ -390,10 +416,19 @@ bool pciehp_card_present(struct controller *ctrl)
  * Presence Detect State bit, this helper also returns true if the Link Active
  * bit is set.  This is a concession to broken hotplug ports which hardwire
  * Presence Detect State to zero, such as Wilocity's [1ae9:0200].
+ *
+ * Returns: %1 if the slot is occupied and %0 if it is not. If the hotplug
+ *         port is not present anymore returns %-ENODEV.
  */
-bool pciehp_card_present_or_link_active(struct controller *ctrl)
+int pciehp_card_present_or_link_active(struct controller *ctrl)
 {
-       return pciehp_card_present(ctrl) || pciehp_check_link_active(ctrl);
+       int ret;
+
+       ret = pciehp_card_present(ctrl);
+       if (ret)
+               return ret;
+
+       return pciehp_check_link_active(ctrl);
 }
 
 int pciehp_query_power_fault(struct controller *ctrl)
@@ -583,6 +618,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
        irqreturn_t ret;
        u32 events;
 
+       ctrl->ist_running = true;
        pci_config_pm_runtime_get(pdev);
 
        /* rerun pciehp_isr() if the port was inaccessible on interrupt */
@@ -629,6 +665,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
        up_read(&ctrl->reset_lock);
 
        pci_config_pm_runtime_put(pdev);
+       ctrl->ist_running = false;
        wake_up(&ctrl->requester);
        return IRQ_HANDLED;
 }
index 951f7f2..e408e40 100644 (file)
@@ -185,8 +185,8 @@ static int get_children_props(struct device_node *dn, const __be32 **drc_indexes
 
 
 /* Verify the existence of 'drc_name' and/or 'drc_type' within the
- * current node.  First obtain it's my-drc-index property.  Next,
- * obtain the DRC info from it's parent.  Use the my-drc-index for
+ * current node.  First obtain its my-drc-index property.  Next,
+ * obtain the DRC info from its parent.  Use the my-drc-index for
  * correlation, and obtain/validate the requested properties.
  */
 
index b3f972e..1e88fd4 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/mutex.h>
 #include <linux/export.h>
 #include <linux/string.h>
 #include <linux/delay.h>
@@ -254,8 +253,14 @@ static ssize_t sriov_numvfs_show(struct device *dev,
                                 char *buf)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
+       u16 num_vfs;
+
+       /* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */
+       device_lock(&pdev->dev);
+       num_vfs = pdev->sriov->num_VFs;
+       device_unlock(&pdev->dev);
 
-       return sprintf(buf, "%u\n", pdev->sriov->num_VFs);
+       return sprintf(buf, "%u\n", num_vfs);
 }
 
 /*
index 0884bed..c7709e4 100644 (file)
@@ -213,12 +213,13 @@ u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
 
        if (pci_msi_ignore_mask)
                return 0;
+
        desc_addr = pci_msix_desc_addr(desc);
        if (!desc_addr)
                return 0;
 
        mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
-       if (flag)
+       if (flag & PCI_MSIX_ENTRY_CTRL_MASKBIT)
                mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
 
        writel(mask_bits, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
@@ -861,7 +862,7 @@ static int pci_msi_supported(struct pci_dev *dev, int nvec)
        if (!pci_msi_enable)
                return 0;
 
-       if (!dev || dev->no_msi || dev->current_state != PCI_D0)
+       if (!dev || dev->no_msi)
                return 0;
 
        /*
@@ -972,7 +973,7 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
        int nr_entries;
        int i, j;
 
-       if (!pci_msi_supported(dev, nvec))
+       if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0)
                return -EINVAL;
 
        nr_entries = pci_msix_vec_count(dev);
@@ -1058,7 +1059,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
        int nvec;
        int rc;
 
-       if (!pci_msi_supported(dev, minvec))
+       if (!pci_msi_supported(dev, minvec) || dev->current_state != PCI_D0)
                return -EINVAL;
 
        /* Check whether driver already requested MSI-X IRQs */
@@ -1315,22 +1316,6 @@ const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
 }
 EXPORT_SYMBOL(pci_irq_get_affinity);
 
-/**
- * pci_irq_get_node - return the NUMA node of a particular MSI vector
- * @pdev:      PCI device to operate on
- * @vec:       device-relative interrupt vector index (0-based).
- */
-int pci_irq_get_node(struct pci_dev *pdev, int vec)
-{
-       const struct cpumask *mask;
-
-       mask = pci_irq_get_affinity(pdev, vec);
-       if (mask)
-               return local_memory_node(cpu_to_node(cpumask_first(mask)));
-       return dev_to_node(&pdev->dev);
-}
-EXPORT_SYMBOL(pci_irq_get_node);
-
 struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
 {
        return to_pci_dev(desc->dev);
index 36891e7..81ceeaa 100644 (file)
@@ -236,7 +236,6 @@ void of_pci_check_probe_only(void)
 }
 EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
 
-#if defined(CONFIG_OF_ADDRESS)
 /**
  * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI
  *                                           host bridge resources from DT
@@ -255,16 +254,18 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
  * It returns zero if the range parsing has been successful or a standard error
  * value if it failed.
  */
-int devm_of_pci_get_host_bridge_resources(struct device *dev,
+static int devm_of_pci_get_host_bridge_resources(struct device *dev,
                        unsigned char busno, unsigned char bus_max,
-                       struct list_head *resources, resource_size_t *io_base)
+                       struct list_head *resources,
+                       struct list_head *ib_resources,
+                       resource_size_t *io_base)
 {
        struct device_node *dev_node = dev->of_node;
        struct resource *res, tmp_res;
        struct resource *bus_range;
        struct of_pci_range range;
        struct of_pci_range_parser parser;
-       char range_type[4];
+       const char *range_type;
        int err;
 
        if (io_base)
@@ -298,12 +299,12 @@ int devm_of_pci_get_host_bridge_resources(struct device *dev,
        for_each_of_pci_range(&parser, &range) {
                /* Read next ranges element */
                if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
-                       snprintf(range_type, 4, " IO");
+                       range_type = "IO";
                else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
-                       snprintf(range_type, 4, "MEM");
+                       range_type = "MEM";
                else
-                       snprintf(range_type, 4, "err");
-               dev_info(dev, "  %s %#010llx..%#010llx -> %#010llx\n",
+                       range_type = "err";
+               dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx\n",
                         range_type, range.cpu_addr,
                         range.cpu_addr + range.size - 1, range.pci_addr);
 
@@ -340,14 +341,54 @@ int devm_of_pci_get_host_bridge_resources(struct device *dev,
                pci_add_resource_offset(resources, res, res->start - range.pci_addr);
        }
 
+       /* Check for dma-ranges property */
+       if (!ib_resources)
+               return 0;
+       err = of_pci_dma_range_parser_init(&parser, dev_node);
+       if (err)
+               return 0;
+
+       dev_dbg(dev, "Parsing dma-ranges property...\n");
+       for_each_of_pci_range(&parser, &range) {
+               struct resource_entry *entry;
+               /*
+                * If we failed translation or got a zero-sized region
+                * then skip this range
+                */
+               if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) ||
+                   range.cpu_addr == OF_BAD_ADDR || range.size == 0)
+                       continue;
+
+               dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx\n",
+                        "IB MEM", range.cpu_addr,
+                        range.cpu_addr + range.size - 1, range.pci_addr);
+
+
+               err = of_pci_range_to_resource(&range, dev_node, &tmp_res);
+               if (err)
+                       continue;
+
+               res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL);
+               if (!res) {
+                       err = -ENOMEM;
+                       goto failed;
+               }
+
+               /* Keep the resource list sorted */
+               resource_list_for_each_entry(entry, ib_resources)
+                       if (entry->res->start > res->start)
+                               break;
+
+               pci_add_resource_offset(&entry->node, res,
+                                       res->start - range.pci_addr);
+       }
+
        return 0;
 
 failed:
        pci_free_resource_list(resources);
        return err;
 }
-EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources);
-#endif /* CONFIG_OF_ADDRESS */
 
 #if IS_ENABLED(CONFIG_OF_IRQ)
 /**
@@ -482,6 +523,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci);
 
 int pci_parse_request_of_pci_ranges(struct device *dev,
                                    struct list_head *resources,
+                                   struct list_head *ib_resources,
                                    struct resource **bus_range)
 {
        int err, res_valid = 0;
@@ -489,8 +531,10 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
        struct resource_entry *win, *tmp;
 
        INIT_LIST_HEAD(resources);
+       if (ib_resources)
+               INIT_LIST_HEAD(ib_resources);
        err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
-                                                   &iobase);
+                                                   ib_resources, &iobase);
        if (err)
                return err;
 
@@ -530,6 +574,7 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
        pci_free_resource_list(resources);
        return err;
 }
+EXPORT_SYMBOL_GPL(pci_parse_request_of_pci_ranges);
 
 #endif /* CONFIG_PCI */
 
index 5fd9010..fffa770 100644 (file)
@@ -270,10 +270,10 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
 int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
                         unsigned int flags)
 {
-       bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16;
+       bridge->conf.class_revision |= cpu_to_le32(PCI_CLASS_BRIDGE_PCI << 16);
        bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE;
        bridge->conf.cache_line_size = 0x10;
-       bridge->conf.status = PCI_STATUS_CAP_LIST;
+       bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST);
        bridge->pci_regs_behavior = kmemdup(pci_regs_behavior,
                                            sizeof(pci_regs_behavior),
                                            GFP_KERNEL);
@@ -284,8 +284,9 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
                bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START;
                bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP;
                /* Set PCIe v2, root port, slot support */
-               bridge->pcie_conf.cap = PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
-                       PCI_EXP_FLAGS_SLOT;
+               bridge->pcie_conf.cap =
+                       cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
+                                   PCI_EXP_FLAGS_SLOT);
                bridge->pcie_cap_regs_behavior =
                        kmemdup(pcie_cap_regs_behavior,
                                sizeof(pcie_cap_regs_behavior),
@@ -327,7 +328,7 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
        int reg = where & ~3;
        pci_bridge_emul_read_status_t (*read_op)(struct pci_bridge_emul *bridge,
                                                 int reg, u32 *value);
-       u32 *cfgspace;
+       __le32 *cfgspace;
        const struct pci_bridge_reg_behavior *behavior;
 
        if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) {
@@ -343,11 +344,11 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
        if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) {
                reg -= PCI_CAP_PCIE_START;
                read_op = bridge->ops->read_pcie;
-               cfgspace = (u32 *) &bridge->pcie_conf;
+               cfgspace = (__le32 *) &bridge->pcie_conf;
                behavior = bridge->pcie_cap_regs_behavior;
        } else {
                read_op = bridge->ops->read_base;
-               cfgspace = (u32 *) &bridge->conf;
+               cfgspace = (__le32 *) &bridge->conf;
                behavior = bridge->pci_regs_behavior;
        }
 
@@ -357,7 +358,7 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
                ret = PCI_BRIDGE_EMUL_NOT_HANDLED;
 
        if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED)
-               *value = cfgspace[reg / 4];
+               *value = le32_to_cpu(cfgspace[reg / 4]);
 
        /*
         * Make sure we never return any reserved bit with a value
@@ -387,7 +388,7 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
        int mask, ret, old, new, shift;
        void (*write_op)(struct pci_bridge_emul *bridge, int reg,
                         u32 old, u32 new, u32 mask);
-       u32 *cfgspace;
+       __le32 *cfgspace;
        const struct pci_bridge_reg_behavior *behavior;
 
        if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END)
@@ -414,11 +415,11 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
        if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) {
                reg -= PCI_CAP_PCIE_START;
                write_op = bridge->ops->write_pcie;
-               cfgspace = (u32 *) &bridge->pcie_conf;
+               cfgspace = (__le32 *) &bridge->pcie_conf;
                behavior = bridge->pcie_cap_regs_behavior;
        } else {
                write_op = bridge->ops->write_base;
-               cfgspace = (u32 *) &bridge->conf;
+               cfgspace = (__le32 *) &bridge->conf;
                behavior = bridge->pci_regs_behavior;
        }
 
@@ -431,7 +432,7 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
        /* Clear the W1C bits */
        new &= ~((value << shift) & (behavior[reg / 4].w1c & mask));
 
-       cfgspace[reg / 4] = new;
+       cfgspace[reg / 4] = cpu_to_le32(new);
 
        if (write_op)
                write_op(bridge, reg, old, new, mask);
index e65b1b7..b318830 100644 (file)
@@ -6,65 +6,65 @@
 
 /* PCI configuration space of a PCI-to-PCI bridge. */
 struct pci_bridge_emul_conf {
-       u16 vendor;
-       u16 device;
-       u16 command;
-       u16 status;
-       u32 class_revision;
+       __le16 vendor;
+       __le16 device;
+       __le16 command;
+       __le16 status;
+       __le32 class_revision;
        u8 cache_line_size;
        u8 latency_timer;
        u8 header_type;
        u8 bist;
-       u32 bar[2];
+       __le32 bar[2];
        u8 primary_bus;
        u8 secondary_bus;
        u8 subordinate_bus;
        u8 secondary_latency_timer;
        u8 iobase;
        u8 iolimit;
-       u16 secondary_status;
-       u16 membase;
-       u16 memlimit;
-       u16 pref_mem_base;
-       u16 pref_mem_limit;
-       u32 prefbaseupper;
-       u32 preflimitupper;
-       u16 iobaseupper;
-       u16 iolimitupper;
+       __le16 secondary_status;
+       __le16 membase;
+       __le16 memlimit;
+       __le16 pref_mem_base;
+       __le16 pref_mem_limit;
+       __le32 prefbaseupper;
+       __le32 preflimitupper;
+       __le16 iobaseupper;
+       __le16 iolimitupper;
        u8 capabilities_pointer;
        u8 reserve[3];
-       u32 romaddr;
+       __le32 romaddr;
        u8 intline;
        u8 intpin;
-       u16 bridgectrl;
+       __le16 bridgectrl;
 };
 
 /* PCI configuration space of the PCIe capabilities */
 struct pci_bridge_emul_pcie_conf {
        u8 cap_id;
        u8 next;
-       u16 cap;
-       u32 devcap;
-       u16 devctl;
-       u16 devsta;
-       u32 lnkcap;
-       u16 lnkctl;
-       u16 lnksta;
-       u32 slotcap;
-       u16 slotctl;
-       u16 slotsta;
-       u16 rootctl;
-       u16 rsvd;
-       u32 rootsta;
-       u32 devcap2;
-       u16 devctl2;
-       u16 devsta2;
-       u32 lnkcap2;
-       u16 lnkctl2;
-       u16 lnksta2;
-       u32 slotcap2;
-       u16 slotctl2;
-       u16 slotsta2;
+       __le16 cap;
+       __le32 devcap;
+       __le16 devctl;
+       __le16 devsta;
+       __le32 lnkcap;
+       __le16 lnkctl;
+       __le16 lnksta;
+       __le32 slotcap;
+       __le16 slotctl;
+       __le16 slotsta;
+       __le16 rootctl;
+       __le16 rsvd;
+       __le32 rootsta;
+       __le32 devcap2;
+       __le16 devctl2;
+       __le16 devsta2;
+       __le32 lnkcap2;
+       __le16 lnkctl2;
+       __le16 lnksta2;
+       __le32 slotcap2;
+       __le16 slotctl2;
+       __le16 slotsta2;
 };
 
 struct pci_bridge_emul;
index a8124e4..0454ca0 100644 (file)
@@ -315,7 +315,8 @@ static long local_pci_probe(void *_ddi)
         * Probe function should return < 0 for failure, 0 for success
         * Treat values > 0 as success, but warn.
         */
-       dev_warn(dev, "Driver probe function unexpectedly returned %d\n", rc);
+       pci_warn(pci_dev, "Driver probe function unexpectedly returned %d\n",
+                rc);
        return 0;
 }
 
@@ -517,6 +518,12 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
        return 0;
 }
 
+static void pci_pm_default_resume(struct pci_dev *pci_dev)
+{
+       pci_fixup_device(pci_fixup_resume, pci_dev);
+       pci_enable_wake(pci_dev, PCI_D0, false);
+}
+
 #endif
 
 #ifdef CONFIG_PM_SLEEP
@@ -524,6 +531,7 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
 static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
 {
        pci_power_up(pci_dev);
+       pci_update_current_state(pci_dev, PCI_D0);
        pci_restore_state(pci_dev);
        pci_pme_restore(pci_dev);
 }
@@ -578,9 +586,9 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
 
                if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
-                       WARN_ONCE(pci_dev->current_state != prev,
-                               "PCI PM: Device state not saved by %pS\n",
-                               drv->suspend);
+                       pci_WARN_ONCE(pci_dev, pci_dev->current_state != prev,
+                                     "PCI PM: Device state not saved by %pS\n",
+                                     drv->suspend);
                }
        }
 
@@ -592,46 +600,17 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
 static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct pci_driver *drv = pci_dev->driver;
-
-       if (drv && drv->suspend_late) {
-               pci_power_t prev = pci_dev->current_state;
-               int error;
-
-               error = drv->suspend_late(pci_dev, state);
-               suspend_report_result(drv->suspend_late, error);
-               if (error)
-                       return error;
-
-               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
-                   && pci_dev->current_state != PCI_UNKNOWN) {
-                       WARN_ONCE(pci_dev->current_state != prev,
-                               "PCI PM: Device state not saved by %pS\n",
-                               drv->suspend_late);
-                       goto Fixup;
-               }
-       }
 
        if (!pci_dev->state_saved)
                pci_save_state(pci_dev);
 
        pci_pm_set_unknown_state(pci_dev);
 
-Fixup:
        pci_fixup_device(pci_fixup_suspend_late, pci_dev);
 
        return 0;
 }
 
-static int pci_legacy_resume_early(struct device *dev)
-{
-       struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct pci_driver *drv = pci_dev->driver;
-
-       return drv && drv->resume_early ?
-                       drv->resume_early(pci_dev) : 0;
-}
-
 static int pci_legacy_resume(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -645,12 +624,6 @@ static int pci_legacy_resume(struct device *dev)
 
 /* Auxiliary functions used by the new power management framework */
 
-static void pci_pm_default_resume(struct pci_dev *pci_dev)
-{
-       pci_fixup_device(pci_fixup_resume, pci_dev);
-       pci_enable_wake(pci_dev, PCI_D0, false);
-}
-
 static void pci_pm_default_suspend(struct pci_dev *pci_dev)
 {
        /* Disable non-bridge devices without PM support */
@@ -661,16 +634,15 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev)
 static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
 {
        struct pci_driver *drv = pci_dev->driver;
-       bool ret = drv && (drv->suspend || drv->suspend_late || drv->resume
-               || drv->resume_early);
+       bool ret = drv && (drv->suspend || drv->resume);
 
        /*
         * Legacy PM support is used by default, so warn if the new framework is
         * supported as well.  Drivers are supposed to support either the
         * former, or the latter, but not both at the same time.
         */
-       WARN(ret && drv->driver.pm, "driver %s device %04x:%04x\n",
-               drv->name, pci_dev->vendor, pci_dev->device);
+       pci_WARN(pci_dev, ret && drv->driver.pm, "device %04x:%04x\n",
+                pci_dev->vendor, pci_dev->device);
 
        return ret;
 }
@@ -679,11 +651,11 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
 
 static int pci_pm_prepare(struct device *dev)
 {
-       struct device_driver *drv = dev->driver;
        struct pci_dev *pci_dev = to_pci_dev(dev);
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
-       if (drv && drv->pm && drv->pm->prepare) {
-               int error = drv->pm->prepare(dev);
+       if (pm && pm->prepare) {
+               int error = pm->prepare(dev);
                if (error < 0)
                        return error;
 
@@ -793,9 +765,9 @@ static int pci_pm_suspend(struct device *dev)
 
                if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
-                       WARN_ONCE(pci_dev->current_state != prev,
-                               "PCI PM: State of device not saved by %pS\n",
-                               pm->suspend);
+                       pci_WARN_ONCE(pci_dev, pci_dev->current_state != prev,
+                                     "PCI PM: State of device not saved by %pS\n",
+                                     pm->suspend);
                }
        }
 
@@ -841,9 +813,9 @@ static int pci_pm_suspend_noirq(struct device *dev)
 
                if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
-                       WARN_ONCE(pci_dev->current_state != prev,
-                               "PCI PM: State of device not saved by %pS\n",
-                               pm->suspend_noirq);
+                       pci_WARN_ONCE(pci_dev, pci_dev->current_state != prev,
+                                     "PCI PM: State of device not saved by %pS\n",
+                                     pm->suspend_noirq);
                        goto Fixup;
                }
        }
@@ -865,7 +837,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
                        pci_prepare_to_sleep(pci_dev);
        }
 
-       dev_dbg(dev, "PCI PM: Suspend power state: %s\n",
+       pci_dbg(pci_dev, "PCI PM: Suspend power state: %s\n",
                pci_power_name(pci_dev->current_state));
 
        if (pci_dev->current_state == PCI_D0) {
@@ -880,7 +852,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
        }
 
        if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) {
-               dev_dbg(dev, "PCI PM: Skipped\n");
+               pci_dbg(pci_dev, "PCI PM: Skipped\n");
                goto Fixup;
        }
 
@@ -917,8 +889,9 @@ Fixup:
 static int pci_pm_resume_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
-       int error = 0;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       pci_power_t prev_state = pci_dev->current_state;
+       bool skip_bus_pm = pci_dev->skip_bus_pm;
 
        if (dev_pm_may_skip_resume(dev))
                return 0;
@@ -937,27 +910,28 @@ static int pci_pm_resume_noirq(struct device *dev)
         * configuration here and attempting to put them into D0 again is
         * pointless, so avoid doing that.
         */
-       if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform()))
+       if (!(skip_bus_pm && pm_suspend_no_platform()))
                pci_pm_default_resume_early(pci_dev);
 
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
+       pcie_pme_root_status_cleanup(pci_dev);
 
-       if (pci_has_legacy_pm_support(pci_dev))
-               return pci_legacy_resume_early(dev);
+       if (!skip_bus_pm && prev_state == PCI_D3cold)
+               pci_bridge_wait_for_secondary_bus(pci_dev);
 
-       pcie_pme_root_status_cleanup(pci_dev);
+       if (pci_has_legacy_pm_support(pci_dev))
+               return 0;
 
-       if (drv && drv->pm && drv->pm->resume_noirq)
-               error = drv->pm->resume_noirq(dev);
+       if (pm && pm->resume_noirq)
+               return pm->resume_noirq(dev);
 
-       return error;
+       return 0;
 }
 
 static int pci_pm_resume(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int error = 0;
 
        /*
         * This is necessary for the suspend error path in which resume is
@@ -973,12 +947,12 @@ static int pci_pm_resume(struct device *dev)
 
        if (pm) {
                if (pm->resume)
-                       error = pm->resume(dev);
+                       return pm->resume(dev);
        } else {
                pci_pm_reenable_device(pci_dev);
        }
 
-       return error;
+       return 0;
 }
 
 #else /* !CONFIG_SUSPEND */
@@ -993,7 +967,6 @@ static int pci_pm_resume(struct device *dev)
 
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 
-
 /*
  * pcibios_pm_ops - provide arch-specific hooks when a PCI device is doing
  * a hibernate transition
@@ -1039,16 +1012,16 @@ static int pci_pm_freeze(struct device *dev)
 static int pci_pm_freeze_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_FREEZE);
 
-       if (drv && drv->pm && drv->pm->freeze_noirq) {
+       if (pm && pm->freeze_noirq) {
                int error;
 
-               error = drv->pm->freeze_noirq(dev);
-               suspend_report_result(drv->pm->freeze_noirq, error);
+               error = pm->freeze_noirq(dev);
+               suspend_report_result(pm->freeze_noirq, error);
                if (error)
                        return error;
        }
@@ -1067,8 +1040,8 @@ static int pci_pm_freeze_noirq(struct device *dev)
 static int pci_pm_thaw_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
-       int error = 0;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       int error;
 
        if (pcibios_pm_ops.thaw_noirq) {
                error = pcibios_pm_ops.thaw_noirq(dev);
@@ -1076,21 +1049,25 @@ static int pci_pm_thaw_noirq(struct device *dev)
                        return error;
        }
 
-       if (pci_has_legacy_pm_support(pci_dev))
-               return pci_legacy_resume_early(dev);
-
        /*
-        * pci_restore_state() requires the device to be in D0 (because of MSI
-        * restoration among other things), so force it into D0 in case the
-        * driver's "freeze" callbacks put it into a low-power state directly.
+        * The pm->thaw_noirq() callback assumes the device has been
+        * returned to D0 and its config state has been restored.
+        *
+        * In addition, pci_restore_state() restores MSI-X state in MMIO
+        * space, which requires the device to be in D0, so return it to D0
+        * in case the driver's "freeze" callbacks put it into a low-power
+        * state.
         */
        pci_set_power_state(pci_dev, PCI_D0);
        pci_restore_state(pci_dev);
 
-       if (drv && drv->pm && drv->pm->thaw_noirq)
-               error = drv->pm->thaw_noirq(dev);
+       if (pci_has_legacy_pm_support(pci_dev))
+               return 0;
+
+       if (pm && pm->thaw_noirq)
+               return pm->thaw_noirq(dev);
 
-       return error;
+       return 0;
 }
 
 static int pci_pm_thaw(struct device *dev)
@@ -1161,24 +1138,24 @@ static int pci_pm_poweroff_late(struct device *dev)
 static int pci_pm_poweroff_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (dev_pm_smart_suspend_and_suspended(dev))
                return 0;
 
-       if (pci_has_legacy_pm_support(to_pci_dev(dev)))
+       if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
 
-       if (!drv || !drv->pm) {
+       if (!pm) {
                pci_fixup_device(pci_fixup_suspend_late, pci_dev);
                return 0;
        }
 
-       if (drv->pm->poweroff_noirq) {
+       if (pm->poweroff_noirq) {
                int error;
 
-               error = drv->pm->poweroff_noirq(dev);
-               suspend_report_result(drv->pm->poweroff_noirq, error);
+               error = pm->poweroff_noirq(dev);
+               suspend_report_result(pm->poweroff_noirq, error);
                if (error)
                        return error;
        }
@@ -1204,8 +1181,8 @@ static int pci_pm_poweroff_noirq(struct device *dev)
 static int pci_pm_restore_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
-       int error = 0;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       int error;
 
        if (pcibios_pm_ops.restore_noirq) {
                error = pcibios_pm_ops.restore_noirq(dev);
@@ -1217,19 +1194,18 @@ static int pci_pm_restore_noirq(struct device *dev)
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
 
        if (pci_has_legacy_pm_support(pci_dev))
-               return pci_legacy_resume_early(dev);
+               return 0;
 
-       if (drv && drv->pm && drv->pm->restore_noirq)
-               error = drv->pm->restore_noirq(dev);
+       if (pm && pm->restore_noirq)
+               return pm->restore_noirq(dev);
 
-       return error;
+       return 0;
 }
 
 static int pci_pm_restore(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int error = 0;
 
        /*
         * This is necessary for the hibernation error path in which restore is
@@ -1245,12 +1221,12 @@ static int pci_pm_restore(struct device *dev)
 
        if (pm) {
                if (pm->restore)
-                       error = pm->restore(dev);
+                       return pm->restore(dev);
        } else {
                pci_pm_reenable_device(pci_dev);
        }
 
-       return error;
+       return 0;
 }
 
 #else /* !CONFIG_HIBERNATE_CALLBACKS */
@@ -1295,11 +1271,11 @@ static int pci_pm_runtime_suspend(struct device *dev)
                 * log level.
                 */
                if (error == -EBUSY || error == -EAGAIN) {
-                       dev_dbg(dev, "can't suspend now (%ps returned %d)\n",
+                       pci_dbg(pci_dev, "can't suspend now (%ps returned %d)\n",
                                pm->runtime_suspend, error);
                        return error;
                } else if (error) {
-                       dev_err(dev, "can't suspend (%ps returned %d)\n",
+                       pci_err(pci_dev, "can't suspend (%ps returned %d)\n",
                                pm->runtime_suspend, error);
                        return error;
                }
@@ -1310,9 +1286,9 @@ static int pci_pm_runtime_suspend(struct device *dev)
        if (pm && pm->runtime_suspend
            && !pci_dev->state_saved && pci_dev->current_state != PCI_D0
            && pci_dev->current_state != PCI_UNKNOWN) {
-               WARN_ONCE(pci_dev->current_state != prev,
-                       "PCI PM: State of device not saved by %pS\n",
-                       pm->runtime_suspend);
+               pci_WARN_ONCE(pci_dev, pci_dev->current_state != prev,
+                             "PCI PM: State of device not saved by %pS\n",
+                             pm->runtime_suspend);
                return 0;
        }
 
@@ -1326,9 +1302,10 @@ static int pci_pm_runtime_suspend(struct device *dev)
 
 static int pci_pm_runtime_resume(struct device *dev)
 {
-       int rc = 0;
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       pci_power_t prev_state = pci_dev->current_state;
+       int error = 0;
 
        /*
         * Restoring config space is necessary even if the device is not bound
@@ -1341,22 +1318,23 @@ static int pci_pm_runtime_resume(struct device *dev)
                return 0;
 
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
-       pci_enable_wake(pci_dev, PCI_D0, false);
-       pci_fixup_device(pci_fixup_resume, pci_dev);
+       pci_pm_default_resume(pci_dev);
+
+       if (prev_state == PCI_D3cold)
+               pci_bridge_wait_for_secondary_bus(pci_dev);
 
        if (pm && pm->runtime_resume)
-               rc = pm->runtime_resume(dev);
+               error = pm->runtime_resume(dev);
 
        pci_dev->runtime_d3cold = false;
 
-       return rc;
+       return error;
 }
 
 static int pci_pm_runtime_idle(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int ret = 0;
 
        /*
         * If pci_dev->driver is not set (unbound), the device should
@@ -1369,9 +1347,9 @@ static int pci_pm_runtime_idle(struct device *dev)
                return -ENOSYS;
 
        if (pm->runtime_idle)
-               ret = pm->runtime_idle(dev);
+               return pm->runtime_idle(dev);
 
-       return ret;
+       return 0;
 }
 
 static const struct dev_pm_ops pci_dev_pm_ops = {
index 7934129..13f766d 100644 (file)
@@ -1122,7 +1122,7 @@ static void pci_remove_resource_files(struct pci_dev *pdev)
 {
        int i;
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                struct bin_attribute *res_attr;
 
                res_attr = pdev->res_attr[i];
@@ -1193,7 +1193,7 @@ static int pci_create_resource_files(struct pci_dev *pdev)
        int retval;
 
        /* Expose the PCI resources from this device as files */
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
 
                /* skip empty resources */
                if (!pci_resource_len(pdev, i))
@@ -1330,7 +1330,6 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
        int retval;
 
        pcie_vpd_create_sysfs_dev_files(dev);
-       pcie_aspm_create_sysfs_dev_files(dev);
 
        if (dev->reset_fn) {
                retval = device_create_file(&dev->dev, &dev_attr_reset);
@@ -1340,7 +1339,6 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
        return 0;
 
 error:
-       pcie_aspm_remove_sysfs_dev_files(dev);
        pcie_vpd_remove_sysfs_dev_files(dev);
        return retval;
 }
@@ -1416,7 +1414,6 @@ err:
 static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
 {
        pcie_vpd_remove_sysfs_dev_files(dev);
-       pcie_aspm_remove_sysfs_dev_files(dev);
        if (dev->reset_fn) {
                device_remove_file(&dev->dev, &dev_attr_reset);
                dev->reset_fn = 0;
@@ -1539,24 +1536,6 @@ const struct attribute_group *pci_dev_groups[] = {
        NULL,
 };
 
-static const struct attribute_group pci_bridge_group = {
-       .attrs = pci_bridge_attrs,
-};
-
-const struct attribute_group *pci_bridge_groups[] = {
-       &pci_bridge_group,
-       NULL,
-};
-
-static const struct attribute_group pcie_dev_group = {
-       .attrs = pcie_dev_attrs,
-};
-
-const struct attribute_group *pcie_dev_groups[] = {
-       &pcie_dev_group,
-       NULL,
-};
-
 static const struct attribute_group pci_dev_hp_attr_group = {
        .attrs = pci_dev_hp_attrs,
        .is_visible = pci_dev_hp_attrs_are_visible,
@@ -1587,6 +1566,9 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
        &pcie_dev_attr_group,
 #ifdef CONFIG_PCIEAER
        &aer_stats_attr_group,
+#endif
+#ifdef CONFIG_PCIEASPM
+       &aspm_ctrl_attr_group,
 #endif
        NULL,
 };
index fcfaadc..e87196c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/dmi.h>
 #include <linux/init.h>
+#include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/of_pci.h>
 #include <linux/pci.h>
@@ -85,10 +86,17 @@ unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
 unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
 
 #define DEFAULT_HOTPLUG_IO_SIZE                (256)
-#define DEFAULT_HOTPLUG_MEM_SIZE       (2*1024*1024)
-/* pci=hpmemsize=nnM,hpiosize=nn can override this */
+#define DEFAULT_HOTPLUG_MMIO_SIZE      (2*1024*1024)
+#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
+/* hpiosize=nn can override this */
 unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
-unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
+/*
+ * pci=hpmmiosize=nnM overrides non-prefetchable MMIO size,
+ * pci=hpmmioprefsize=nnM overrides prefetchable MMIO size;
+ * pci=hpmemsize=nnM overrides both
+ */
+unsigned long pci_hotplug_mmio_size = DEFAULT_HOTPLUG_MMIO_SIZE;
+unsigned long pci_hotplug_mmio_pref_size = DEFAULT_HOTPLUG_MMIO_PREF_SIZE;
 
 #define DEFAULT_HOTPLUG_BUS_SIZE       1
 unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
@@ -674,7 +682,7 @@ struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res)
 {
        int i;
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                struct resource *r = &dev->resource[i];
 
                if (r->start && resource_contains(r, res))
@@ -834,14 +842,16 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
                return -EINVAL;
 
        /*
-        * 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
+        * Validate transition: We can enter D0 from any state, but if
+        * we're already in a low-power state, we can only go deeper.  E.g.,
+        * we can go from D1 to D3, but we can't go directly from D3 to D1;
+        * we'd have to go from D3 to D0, then to D1.
         */
        if (state != PCI_D0 && dev->current_state <= PCI_D3cold
            && dev->current_state > state) {
-               pci_err(dev, "invalid power transition (from state %d to %d)\n",
-                       dev->current_state, state);
+               pci_err(dev, "invalid power transition (from %s to %s)\n",
+                       pci_power_name(dev->current_state),
+                       pci_power_name(state));
                return -EINVAL;
        }
 
@@ -851,6 +861,12 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
                return -EIO;
 
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+       if (pmcsr == (u16) ~0) {
+               pci_err(dev, "can't change power state from %s to %s (config space inaccessible)\n",
+                       pci_power_name(dev->current_state),
+                       pci_power_name(state));
+               return -EIO;
+       }
 
        /*
         * If we're (effectively) in D3, force entire word to 0.
@@ -886,13 +902,14 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
        if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
                pci_dev_d3_sleep(dev);
        else if (state == PCI_D2 || dev->current_state == PCI_D2)
-               udelay(PCI_PM_D2_DELAY);
+               msleep(PCI_PM_D2_DELAY);
 
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
        dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
        if (dev->current_state != state)
-               pci_info_ratelimited(dev, "Refused to change power state, currently in D%d\n",
-                        dev->current_state);
+               pci_info_ratelimited(dev, "refused to change power state from %s to %s\n",
+                        pci_power_name(dev->current_state),
+                        pci_power_name(state));
 
        /*
         * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
@@ -963,7 +980,7 @@ void pci_refresh_power_state(struct pci_dev *dev)
  * @dev: PCI device to handle.
  * @state: State to put the device into.
  */
-static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
+int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
 {
        int error;
 
@@ -979,6 +996,7 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
 
        return error;
 }
+EXPORT_SYMBOL_GPL(pci_platform_power_transition);
 
 /**
  * pci_wakeup - Wake up a PCI device
@@ -1002,34 +1020,70 @@ void pci_wakeup_bus(struct pci_bus *bus)
                pci_walk_bus(bus, pci_wakeup, NULL);
 }
 
+static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
+{
+       int delay = 1;
+       u32 id;
+
+       /*
+        * After reset, the device should not silently discard config
+        * requests, but it may still indicate that it needs more time by
+        * responding to them with CRS completions.  The Root Port will
+        * generally synthesize ~0 data to complete the read (except when
+        * CRS SV is enabled and the read was for the Vendor ID; in that
+        * case it synthesizes 0x0001 data).
+        *
+        * Wait for the device to return a non-CRS completion.  Read the
+        * Command register instead of Vendor ID so we don't have to
+        * contend with the CRS SV value.
+        */
+       pci_read_config_dword(dev, PCI_COMMAND, &id);
+       while (id == ~0) {
+               if (delay > timeout) {
+                       pci_warn(dev, "not ready %dms after %s; giving up\n",
+                                delay - 1, reset_type);
+                       return -ENOTTY;
+               }
+
+               if (delay > 1000)
+                       pci_info(dev, "not ready %dms after %s; waiting\n",
+                                delay - 1, reset_type);
+
+               msleep(delay);
+               delay *= 2;
+               pci_read_config_dword(dev, PCI_COMMAND, &id);
+       }
+
+       if (delay > 1000)
+               pci_info(dev, "ready %dms after %s\n", delay - 1,
+                        reset_type);
+
+       return 0;
+}
+
 /**
- * __pci_start_power_transition - Start power transition of a PCI device
- * @dev: PCI device to handle.
- * @state: State to put the device into.
+ * pci_power_up - Put the given device into D0
+ * @dev: PCI device to power up
  */
-static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
+int pci_power_up(struct pci_dev *dev)
 {
-       if (state == PCI_D0) {
-               pci_platform_power_transition(dev, PCI_D0);
+       pci_platform_power_transition(dev, PCI_D0);
+
+       /*
+        * Mandatory power management transition delays are handled in
+        * pci_pm_resume_noirq() and pci_pm_runtime_resume() of the
+        * corresponding bridge.
+        */
+       if (dev->runtime_d3cold) {
                /*
-                * Mandatory power management transition delays, see
-                * PCI Express Base Specification Revision 2.0 Section
-                * 6.6.1: Conventional Reset.  Do not delay for
-                * devices powered on/off by corresponding bridge,
-                * because have already delayed for the bridge.
+                * When powering on a bridge from D3cold, the whole hierarchy
+                * may be powered on into D0uninitialized state, resume them to
+                * give them a chance to suspend again
                 */
-               if (dev->runtime_d3cold) {
-                       if (dev->d3cold_delay && !dev->imm_ready)
-                               msleep(dev->d3cold_delay);
-                       /*
-                        * When powering on a bridge from D3cold, the
-                        * whole hierarchy may be powered on into
-                        * D0uninitialized state, resume them to give
-                        * them a chance to suspend again
-                        */
-                       pci_wakeup_bus(dev->subordinate);
-               }
+               pci_wakeup_bus(dev->subordinate);
        }
+
+       return pci_raw_set_power_state(dev, PCI_D0);
 }
 
 /**
@@ -1056,27 +1110,6 @@ void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
                pci_walk_bus(bus, __pci_dev_set_current_state, &state);
 }
 
-/**
- * __pci_complete_power_transition - Complete power transition of a PCI device
- * @dev: PCI device to handle.
- * @state: State to put the device into.
- *
- * This function should not be called directly by device drivers.
- */
-int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
-{
-       int ret;
-
-       if (state <= PCI_D0)
-               return -EINVAL;
-       ret = pci_platform_power_transition(dev, state);
-       /* Power off the bridge may power off the whole hierarchy */
-       if (!ret && state == PCI_D3cold)
-               pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
-
 /**
  * pci_set_power_state - Set the power state of a PCI device
  * @dev: PCI device to handle.
@@ -1117,7 +1150,8 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        if (dev->current_state == state)
                return 0;
 
-       __pci_start_power_transition(dev, state);
+       if (state == PCI_D0)
+               return pci_power_up(dev);
 
        /*
         * This device is quirked not to be put into D3, so don't put it in
@@ -1133,23 +1167,16 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        error = pci_raw_set_power_state(dev, state > PCI_D3hot ?
                                        PCI_D3hot : state);
 
-       if (!__pci_complete_power_transition(dev, state))
-               error = 0;
+       if (pci_platform_power_transition(dev, state))
+               return error;
 
-       return error;
-}
-EXPORT_SYMBOL(pci_set_power_state);
+       /* Powering off a bridge may power off the whole hierarchy */
+       if (state == PCI_D3cold)
+               pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
 
-/**
- * pci_power_up - Put the given device into D0 forcibly
- * @dev: PCI device to power up
- */
-void pci_power_up(struct pci_dev *dev)
-{
-       __pci_start_power_transition(dev, PCI_D0);
-       pci_raw_set_power_state(dev, PCI_D0);
-       pci_update_current_state(dev, PCI_D0);
+       return 0;
 }
+EXPORT_SYMBOL(pci_set_power_state);
 
 /**
  * pci_choose_state - Choose the power state of a PCI device
@@ -1359,6 +1386,7 @@ int pci_save_state(struct pci_dev *dev)
 
        pci_save_ltr_state(dev);
        pci_save_dpc_state(dev);
+       pci_save_aer_state(dev);
        return pci_save_vc_state(dev);
 }
 EXPORT_SYMBOL(pci_save_state);
@@ -1472,6 +1500,7 @@ void pci_restore_state(struct pci_dev *dev)
        pci_restore_dpc_state(dev);
 
        pci_cleanup_aer_error_status_regs(dev);
+       pci_restore_aer_state(dev);
 
        pci_restore_config_space(dev);
 
@@ -3766,7 +3795,7 @@ void pci_release_selected_regions(struct pci_dev *pdev, int bars)
 {
        int i;
 
-       for (i = 0; i < 6; i++)
+       for (i = 0; i < PCI_STD_NUM_BARS; i++)
                if (bars & (1 << i))
                        pci_release_region(pdev, i);
 }
@@ -3777,7 +3806,7 @@ static int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
 {
        int i;
 
-       for (i = 0; i < 6; i++)
+       for (i = 0; i < PCI_STD_NUM_BARS; i++)
                if (bars & (1 << i))
                        if (__pci_request_region(pdev, i, res_name, excl))
                                goto err_out;
@@ -3825,7 +3854,7 @@ EXPORT_SYMBOL(pci_request_selected_regions_exclusive);
 
 void pci_release_regions(struct pci_dev *pdev)
 {
-       pci_release_selected_regions(pdev, (1 << 6) - 1);
+       pci_release_selected_regions(pdev, (1 << PCI_STD_NUM_BARS) - 1);
 }
 EXPORT_SYMBOL(pci_release_regions);
 
@@ -3844,7 +3873,8 @@ EXPORT_SYMBOL(pci_release_regions);
  */
 int pci_request_regions(struct pci_dev *pdev, const char *res_name)
 {
-       return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
+       return pci_request_selected_regions(pdev,
+                       ((1 << PCI_STD_NUM_BARS) - 1), res_name);
 }
 EXPORT_SYMBOL(pci_request_regions);
 
@@ -3866,7 +3896,7 @@ EXPORT_SYMBOL(pci_request_regions);
 int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
 {
        return pci_request_selected_regions_exclusive(pdev,
-                                       ((1 << 6) - 1), res_name);
+                               ((1 << PCI_STD_NUM_BARS) - 1), res_name);
 }
 EXPORT_SYMBOL(pci_request_regions_exclusive);
 
@@ -4428,47 +4458,6 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
 }
 EXPORT_SYMBOL(pci_wait_for_pending_transaction);
 
-static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
-{
-       int delay = 1;
-       u32 id;
-
-       /*
-        * After reset, the device should not silently discard config
-        * requests, but it may still indicate that it needs more time by
-        * responding to them with CRS completions.  The Root Port will
-        * generally synthesize ~0 data to complete the read (except when
-        * CRS SV is enabled and the read was for the Vendor ID; in that
-        * case it synthesizes 0x0001 data).
-        *
-        * Wait for the device to return a non-CRS completion.  Read the
-        * Command register instead of Vendor ID so we don't have to
-        * contend with the CRS SV value.
-        */
-       pci_read_config_dword(dev, PCI_COMMAND, &id);
-       while (id == ~0) {
-               if (delay > timeout) {
-                       pci_warn(dev, "not ready %dms after %s; giving up\n",
-                                delay - 1, reset_type);
-                       return -ENOTTY;
-               }
-
-               if (delay > 1000)
-                       pci_info(dev, "not ready %dms after %s; waiting\n",
-                                delay - 1, reset_type);
-
-               msleep(delay);
-               delay *= 2;
-               pci_read_config_dword(dev, PCI_COMMAND, &id);
-       }
-
-       if (delay > 1000)
-               pci_info(dev, "ready %dms after %s\n", delay - 1,
-                        reset_type);
-
-       return 0;
-}
-
 /**
  * pcie_has_flr - check if a device supports function level resets
  * @dev: device to check
@@ -4603,16 +4592,19 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
        pci_dev_d3_sleep(dev);
 
-       return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
+       return pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
 }
+
 /**
- * pcie_wait_for_link - Wait until link is active or inactive
+ * pcie_wait_for_link_delay - Wait until link is active or inactive
  * @pdev: Bridge device
  * @active: waiting for active or inactive?
+ * @delay: Delay to wait after link has become active (in ms)
  *
  * Use this to wait till link becomes active or inactive.
  */
-bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
+static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
+                                    int delay)
 {
        int timeout = 1000;
        bool ret;
@@ -4649,13 +4641,144 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
                timeout -= 10;
        }
        if (active && ret)
-               msleep(100);
+               msleep(delay);
        else if (ret != active)
                pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
                        active ? "set" : "cleared");
        return ret == active;
 }
 
+/**
+ * pcie_wait_for_link - Wait until link is active or inactive
+ * @pdev: Bridge device
+ * @active: waiting for active or inactive?
+ *
+ * Use this to wait till link becomes active or inactive.
+ */
+bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
+{
+       return pcie_wait_for_link_delay(pdev, active, 100);
+}
+
+/*
+ * Find maximum D3cold delay required by all the devices on the bus.  The
+ * spec says 100 ms, but firmware can lower it and we allow drivers to
+ * increase it as well.
+ *
+ * Called with @pci_bus_sem locked for reading.
+ */
+static int pci_bus_max_d3cold_delay(const struct pci_bus *bus)
+{
+       const struct pci_dev *pdev;
+       int min_delay = 100;
+       int max_delay = 0;
+
+       list_for_each_entry(pdev, &bus->devices, bus_list) {
+               if (pdev->d3cold_delay < min_delay)
+                       min_delay = pdev->d3cold_delay;
+               if (pdev->d3cold_delay > max_delay)
+                       max_delay = pdev->d3cold_delay;
+       }
+
+       return max(min_delay, max_delay);
+}
+
+/**
+ * pci_bridge_wait_for_secondary_bus - Wait for secondary bus to be accessible
+ * @dev: PCI bridge
+ *
+ * Handle necessary delays before access to the devices on the secondary
+ * side of the bridge are permitted after D3cold to D0 transition.
+ *
+ * For PCIe this means the delays in PCIe 5.0 section 6.6.1. For
+ * conventional PCI it means Tpvrh + Trhfa specified in PCI 3.0 section
+ * 4.3.2.
+ */
+void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
+{
+       struct pci_dev *child;
+       int delay;
+
+       if (pci_dev_is_disconnected(dev))
+               return;
+
+       if (!pci_is_bridge(dev) || !dev->bridge_d3)
+               return;
+
+       down_read(&pci_bus_sem);
+
+       /*
+        * We only deal with devices that are present currently on the bus.
+        * For any hot-added devices the access delay is handled in pciehp
+        * board_added(). In case of ACPI hotplug the firmware is expected
+        * to configure the devices before OS is notified.
+        */
+       if (!dev->subordinate || list_empty(&dev->subordinate->devices)) {
+               up_read(&pci_bus_sem);
+               return;
+       }
+
+       /* Take d3cold_delay requirements into account */
+       delay = pci_bus_max_d3cold_delay(dev->subordinate);
+       if (!delay) {
+               up_read(&pci_bus_sem);
+               return;
+       }
+
+       child = list_first_entry(&dev->subordinate->devices, struct pci_dev,
+                                bus_list);
+       up_read(&pci_bus_sem);
+
+       /*
+        * Conventional PCI and PCI-X we need to wait Tpvrh + Trhfa before
+        * accessing the device after reset (that is 1000 ms + 100 ms). In
+        * practice this should not be needed because we don't do power
+        * management for them (see pci_bridge_d3_possible()).
+        */
+       if (!pci_is_pcie(dev)) {
+               pci_dbg(dev, "waiting %d ms for secondary bus\n", 1000 + delay);
+               msleep(1000 + delay);
+               return;
+       }
+
+       /*
+        * For PCIe downstream and root ports that do not support speeds
+        * greater than 5 GT/s need to wait minimum 100 ms. For higher
+        * speeds (gen3) we need to wait first for the data link layer to
+        * become active.
+        *
+        * However, 100 ms is the minimum and the PCIe spec says the
+        * software must allow at least 1s before it can determine that the
+        * device that did not respond is a broken device. There is
+        * evidence that 100 ms is not always enough, for example certain
+        * Titan Ridge xHCI controller does not always respond to
+        * configuration requests if we only wait for 100 ms (see
+        * https://bugzilla.kernel.org/show_bug.cgi?id=203885).
+        *
+        * Therefore we wait for 100 ms and check for the device presence.
+        * If it is still not present give it an additional 100 ms.
+        */
+       if (!pcie_downstream_port(dev))
+               return;
+
+       if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
+               pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
+               msleep(delay);
+       } else {
+               pci_dbg(dev, "waiting %d ms for downstream link, after activation\n",
+                       delay);
+               if (!pcie_wait_for_link_delay(dev, true, delay)) {
+                       /* Did not train, no need to wait any further */
+                       return;
+               }
+       }
+
+       if (!pci_device_is_present(child)) {
+               pci_dbg(child, "waiting additional %d ms to become accessible\n", delay);
+               msleep(delay);
+       }
+}
+
 void pci_reset_secondary_bus(struct pci_dev *dev)
 {
        u16 ctrl;
@@ -6304,8 +6427,13 @@ static int __init pci_setup(char *str)
                                pcie_ecrc_get_policy(str + 5);
                        } else if (!strncmp(str, "hpiosize=", 9)) {
                                pci_hotplug_io_size = memparse(str + 9, &str);
+                       } else if (!strncmp(str, "hpmmiosize=", 11)) {
+                               pci_hotplug_mmio_size = memparse(str + 11, &str);
+                       } else if (!strncmp(str, "hpmmioprefsize=", 15)) {
+                               pci_hotplug_mmio_pref_size = memparse(str + 15, &str);
                        } else if (!strncmp(str, "hpmemsize=", 10)) {
-                               pci_hotplug_mem_size = memparse(str + 10, &str);
+                               pci_hotplug_mmio_size = memparse(str + 10, &str);
+                               pci_hotplug_mmio_pref_size = pci_hotplug_mmio_size;
                        } else if (!strncmp(str, "hpbussize=", 10)) {
                                pci_hotplug_bus_size =
                                        simple_strtoul(str + 10, &str, 0);
index 3f6947e..a0a53bd 100644 (file)
@@ -12,6 +12,7 @@ extern const unsigned char pcie_link_speed[];
 extern bool pci_early_dump;
 
 bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
+bool pcie_cap_has_rtctl(const struct pci_dev *dev);
 
 /* Functions internal to the PCI core code */
 
@@ -85,7 +86,7 @@ struct pci_platform_pm_ops {
 int pci_set_platform_pm(const struct pci_platform_pm_ops *ops);
 void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
 void pci_refresh_power_state(struct pci_dev *dev);
-void pci_power_up(struct pci_dev *dev);
+int pci_power_up(struct pci_dev *dev);
 void pci_disable_enabled_device(struct pci_dev *dev);
 int pci_finish_runtime_suspend(struct pci_dev *dev);
 void pcie_clear_root_pme_status(struct pci_dev *dev);
@@ -104,6 +105,7 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev);
 void pci_free_cap_save_buffers(struct pci_dev *dev);
 bool pci_bridge_d3_possible(struct pci_dev *dev);
 void pci_bridge_d3_update(struct pci_dev *dev);
+void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
 {
@@ -218,7 +220,8 @@ extern const struct device_type pci_dev_type;
 extern const struct attribute_group *pci_bus_groups[];
 
 extern unsigned long pci_hotplug_io_size;
-extern unsigned long pci_hotplug_mem_size;
+extern unsigned long pci_hotplug_mmio_size;
+extern unsigned long pci_hotplug_mmio_pref_size;
 extern unsigned long pci_hotplug_bus_size;
 
 /**
@@ -456,6 +459,22 @@ static inline void pci_ats_init(struct pci_dev *d) { }
 static inline void pci_restore_ats_state(struct pci_dev *dev) { }
 #endif /* CONFIG_PCI_ATS */
 
+#ifdef CONFIG_PCI_PRI
+void pci_pri_init(struct pci_dev *dev);
+void pci_restore_pri_state(struct pci_dev *pdev);
+#else
+static inline void pci_pri_init(struct pci_dev *dev) { }
+static inline void pci_restore_pri_state(struct pci_dev *pdev) { }
+#endif
+
+#ifdef CONFIG_PCI_PASID
+void pci_pasid_init(struct pci_dev *dev);
+void pci_restore_pasid_state(struct pci_dev *pdev);
+#else
+static inline void pci_pasid_init(struct pci_dev *dev) { }
+static inline void pci_restore_pasid_state(struct pci_dev *pdev) { }
+#endif
+
 #ifdef CONFIG_PCI_IOV
 int pci_iov_init(struct pci_dev *dev);
 void pci_iov_release(struct pci_dev *dev);
@@ -541,14 +560,6 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
 #endif
 
-#ifdef CONFIG_PCIEASPM_DEBUG
-void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
-void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
-#else
-static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { }
-static inline void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { }
-#endif
-
 #ifdef CONFIG_PCIE_ECRC
 void pcie_set_ecrc_checking(struct pci_dev *dev);
 void pcie_ecrc_get_policy(char *str);
@@ -630,19 +641,6 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
 static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
 #endif /* CONFIG_OF */
 
-#if defined(CONFIG_OF_ADDRESS)
-int devm_of_pci_get_host_bridge_resources(struct device *dev,
-                       unsigned char busno, unsigned char bus_max,
-                       struct list_head *resources, resource_size_t *io_base);
-#else
-static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
-                       unsigned char busno, unsigned char bus_max,
-                       struct list_head *resources, resource_size_t *io_base)
-{
-       return -EINVAL;
-}
-#endif
-
 #ifdef CONFIG_PCIEAER
 void pci_no_aer(void);
 void pci_aer_init(struct pci_dev *dev);
@@ -667,4 +665,8 @@ static inline int pci_acpi_program_hp_params(struct pci_dev *dev)
 }
 #endif
 
+#ifdef CONFIG_PCIEASPM
+extern const struct attribute_group aspm_ctrl_attr_group;
+#endif
+
 #endif /* DRIVERS_PCI_H */
index 362eb8c..6e3c04b 100644 (file)
@@ -4,7 +4,6 @@
 #
 config PCIEPORTBUS
        bool "PCI Express Port Bus support"
-       depends on PCI
        help
          This enables PCI Express Port Bus support. Users can then enable
          support for Native Hot-Plug, Advanced Error Reporting, Power
@@ -63,7 +62,6 @@ config PCIE_ECRC
 #
 config PCIEASPM
        bool "PCI Express ASPM control" if EXPERT
-       depends on PCI && PCIEPORTBUS
        default y
        help
          This enables OS control over PCI Express ASPM (Active State
@@ -79,13 +77,6 @@ config PCIEASPM
 
          When in doubt, say Y.
 
-config PCIEASPM_DEBUG
-       bool "Debug PCI Express ASPM"
-       depends on PCIEASPM
-       help
-         This enables PCI Express ASPM debug support. It will add per-device
-         interface to control ASPM.
-
 choice
        prompt "Default ASPM policy"
        default PCIEASPM_DEFAULT
@@ -135,7 +126,6 @@ config PCIE_DPC
 
 config PCIE_PTM
        bool "PCI Express Precision Time Measurement support"
-       depends on PCIEPORTBUS
        help
          This enables PCI Express Precision Time Measurement (PTM)
          support.
index b45bc47..1ca86f2 100644 (file)
@@ -15,6 +15,7 @@
 #define pr_fmt(fmt) "AER: " fmt
 #define dev_fmt pr_fmt
 
+#include <linux/bitops.h>
 #include <linux/cper.h>
 #include <linux/pci.h>
 #include <linux/pci-acpi.h>
@@ -36,7 +37,7 @@
 #define AER_ERROR_SOURCES_MAX          128
 
 #define AER_MAX_TYPEOF_COR_ERRS                16      /* as per PCI_ERR_COR_STATUS */
-#define AER_MAX_TYPEOF_UNCOR_ERRS      26      /* as per PCI_ERR_UNCOR_STATUS*/
+#define AER_MAX_TYPEOF_UNCOR_ERRS      27      /* as per PCI_ERR_UNCOR_STATUS*/
 
 struct aer_err_source {
        unsigned int status;
@@ -201,6 +202,7 @@ void pcie_set_ecrc_checking(struct pci_dev *dev)
 
 /**
  * pcie_ecrc_get_policy - parse kernel command-line ecrc option
+ * @str: ECRC policy from kernel command line to use
  */
 void pcie_ecrc_get_policy(char *str)
 {
@@ -448,12 +450,70 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
        return 0;
 }
 
+void pci_save_aer_state(struct pci_dev *dev)
+{
+       struct pci_cap_saved_state *save_state;
+       u32 *cap;
+       int pos;
+
+       pos = dev->aer_cap;
+       if (!pos)
+               return;
+
+       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
+       if (!save_state)
+               return;
+
+       cap = &save_state->cap.data[0];
+       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, cap++);
+       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, cap++);
+       pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, cap++);
+       pci_read_config_dword(dev, pos + PCI_ERR_CAP, cap++);
+       if (pcie_cap_has_rtctl(dev))
+               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, cap++);
+}
+
+void pci_restore_aer_state(struct pci_dev *dev)
+{
+       struct pci_cap_saved_state *save_state;
+       u32 *cap;
+       int pos;
+
+       pos = dev->aer_cap;
+       if (!pos)
+               return;
+
+       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
+       if (!save_state)
+               return;
+
+       cap = &save_state->cap.data[0];
+       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, *cap++);
+       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, *cap++);
+       pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, *cap++);
+       pci_write_config_dword(dev, pos + PCI_ERR_CAP, *cap++);
+       if (pcie_cap_has_rtctl(dev))
+               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, *cap++);
+}
+
 void pci_aer_init(struct pci_dev *dev)
 {
+       int n;
+
        dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!dev->aer_cap)
+               return;
 
-       if (dev->aer_cap)
-               dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);
+       dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);
+
+       /*
+        * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER,
+        * PCI_ERR_COR_MASK, and PCI_ERR_CAP.  Root and Root Complex Event
+        * Collectors also implement PCI_ERR_ROOT_COMMAND (PCIe r5.0, sec
+        * 7.8.4).
+        */
+       n = pcie_cap_has_rtctl(dev) ? 5 : 4;
+       pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n);
 
        pci_cleanup_aer_error_status_regs(dev);
 }
@@ -560,6 +620,7 @@ static const char *aer_uncorrectable_error_string[AER_MAX_TYPEOF_UNCOR_ERRS] = {
        "BlockedTLP",                   /* Bit Position 23      */
        "AtomicOpBlocked",              /* Bit Position 24      */
        "TLPBlockedErr",                /* Bit Position 25      */
+       "PoisonTLPBlocked",             /* Bit Position 26      */
 };
 
 static const char *aer_agent_string[] = {
@@ -657,7 +718,8 @@ const struct attribute_group aer_stats_attr_group = {
 static void pci_dev_aer_stats_incr(struct pci_dev *pdev,
                                   struct aer_err_info *info)
 {
-       int status, i, max = -1;
+       unsigned long status = info->status & ~info->mask;
+       int i, max = -1;
        u64 *counter = NULL;
        struct aer_stats *aer_stats = pdev->aer_stats;
 
@@ -682,10 +744,8 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev,
                break;
        }
 
-       status = (info->status & ~info->mask);
-       for (i = 0; i < max; i++)
-               if (status & (1 << i))
-                       counter[i]++;
+       for_each_set_bit(i, &status, max)
+               counter[i]++;
 }
 
 static void pci_rootport_aer_stats_incr(struct pci_dev *pdev,
@@ -717,14 +777,11 @@ static void __print_tlp_header(struct pci_dev *dev,
 static void __aer_print_error(struct pci_dev *dev,
                              struct aer_err_info *info)
 {
-       int i, status;
+       unsigned long status = info->status & ~info->mask;
        const char *errmsg = NULL;
-       status = (info->status & ~info->mask);
-
-       for (i = 0; i < 32; i++) {
-               if (!(status & (1 << i)))
-                       continue;
+       int i;
 
+       for_each_set_bit(i, &status, 32) {
                if (info->severity == AER_CORRECTABLE)
                        errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ?
                                aer_correctable_error_string[i] : NULL;
@@ -1204,7 +1261,8 @@ static void aer_isr_one_error(struct aer_rpc *rpc,
 
 /**
  * aer_isr - consume errors detected by root port
- * @work: definition of this work item
+ * @irq: IRQ assigned to Root Port
+ * @context: pointer to Root Port data structure
  *
  * Invoked, as DPC, when root port records new detected error
  */
index 652ef23..0dcd443 100644 (file)
@@ -64,6 +64,7 @@ struct pcie_link_state {
        u32 clkpm_capable:1;            /* Clock PM capable? */
        u32 clkpm_enabled:1;            /* Current Clock PM state */
        u32 clkpm_default:1;            /* Default Clock PM state by BIOS */
+       u32 clkpm_disable:1;            /* Clock PM disabled */
 
        /* Exit latencies */
        struct aspm_latency latency_up; /* Upstream direction exit latency */
@@ -161,8 +162,11 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
 
 static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
 {
-       /* Don't enable Clock PM if the link is not Clock PM capable */
-       if (!link->clkpm_capable)
+       /*
+        * Don't enable Clock PM if the link is not Clock PM capable
+        * or Clock PM is disabled
+        */
+       if (!link->clkpm_capable || link->clkpm_disable)
                enable = 0;
        /* Need nothing if the specified equals to current state */
        if (link->clkpm_enabled == enable)
@@ -192,7 +196,8 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
        }
        link->clkpm_enabled = enabled;
        link->clkpm_default = enabled;
-       link->clkpm_capable = (blacklist) ? 0 : capable;
+       link->clkpm_capable = capable;
+       link->clkpm_disable = blacklist ? 1 : 0;
 }
 
 static bool pcie_retrain_link(struct pcie_link_state *link)
@@ -894,6 +899,14 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
        return link;
 }
 
+static void pcie_aspm_update_sysfs_visibility(struct pci_dev *pdev)
+{
+       struct pci_dev *child;
+
+       list_for_each_entry(child, &pdev->subordinate->devices, bus_list)
+               sysfs_update_group(&child->dev.kobj, &aspm_ctrl_attr_group);
+}
+
 /*
  * pcie_aspm_init_link_state: Initiate PCI express link state.
  * It is called after the pcie and its children devices are scanned.
@@ -955,6 +968,8 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
                pcie_set_clkpm(link, policy_to_clkpm_state(link));
        }
 
+       pcie_aspm_update_sysfs_visibility(pdev);
+
 unlock:
        mutex_unlock(&aspm_lock);
 out:
@@ -1061,19 +1076,26 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
        up_read(&pci_bus_sem);
 }
 
-static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
+static struct pcie_link_state *pcie_aspm_get_link(struct pci_dev *pdev)
 {
-       struct pci_dev *parent = pdev->bus->self;
-       struct pcie_link_state *link;
+       struct pci_dev *bridge;
 
        if (!pci_is_pcie(pdev))
-               return 0;
+               return NULL;
 
-       if (pcie_downstream_port(pdev))
-               parent = pdev;
-       if (!parent || !parent->link_state)
-               return -EINVAL;
+       bridge = pci_upstream_bridge(pdev);
+       if (!bridge || !pci_is_pcie(bridge))
+               return NULL;
 
+       return bridge->link_state;
+}
+
+static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
+{
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
+
+       if (!link)
+               return -EINVAL;
        /*
         * A driver requested that ASPM be disabled on this device, but
         * if we don't have permission to manage ASPM (e.g., on ACPI
@@ -1090,17 +1112,24 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
        if (sem)
                down_read(&pci_bus_sem);
        mutex_lock(&aspm_lock);
-       link = parent->link_state;
        if (state & PCIE_LINK_STATE_L0S)
                link->aspm_disable |= ASPM_STATE_L0S;
        if (state & PCIE_LINK_STATE_L1)
-               link->aspm_disable |= ASPM_STATE_L1;
+               /* L1 PM substates require L1 */
+               link->aspm_disable |= ASPM_STATE_L1 | ASPM_STATE_L1SS;
+       if (state & PCIE_LINK_STATE_L1_1)
+               link->aspm_disable |= ASPM_STATE_L1_1;
+       if (state & PCIE_LINK_STATE_L1_2)
+               link->aspm_disable |= ASPM_STATE_L1_2;
+       if (state & PCIE_LINK_STATE_L1_1_PCIPM)
+               link->aspm_disable |= ASPM_STATE_L1_1_PCIPM;
+       if (state & PCIE_LINK_STATE_L1_2_PCIPM)
+               link->aspm_disable |= ASPM_STATE_L1_2_PCIPM;
        pcie_config_aspm_link(link, policy_to_aspm_state(link));
 
-       if (state & PCIE_LINK_STATE_CLKPM) {
-               link->clkpm_capable = 0;
-               pcie_set_clkpm(link, 0);
-       }
+       if (state & PCIE_LINK_STATE_CLKPM)
+               link->clkpm_disable = 1;
+       pcie_set_clkpm(link, policy_to_clkpm_state(link));
        mutex_unlock(&aspm_lock);
        if (sem)
                up_read(&pci_bus_sem);
@@ -1172,127 +1201,161 @@ module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
 /**
  * pcie_aspm_enabled - Check if PCIe ASPM has been enabled for a device.
  * @pdev: Target device.
+ *
+ * Relies on the upstream bridge's link_state being valid.  The link_state
+ * is deallocated only when the last child of the bridge (i.e., @pdev or a
+ * sibling) is removed, and the caller should be holding a reference to
+ * @pdev, so this should be safe.
  */
 bool pcie_aspm_enabled(struct pci_dev *pdev)
 {
-       struct pci_dev *bridge = pci_upstream_bridge(pdev);
-       bool ret;
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
 
-       if (!bridge)
+       if (!link)
                return false;
 
-       mutex_lock(&aspm_lock);
-       ret = bridge->link_state ? !!bridge->link_state->aspm_enabled : false;
-       mutex_unlock(&aspm_lock);
-
-       return ret;
+       return link->aspm_enabled;
 }
 EXPORT_SYMBOL_GPL(pcie_aspm_enabled);
 
-#ifdef CONFIG_PCIEASPM_DEBUG
-static ssize_t link_state_show(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+static ssize_t aspm_attr_show_common(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf, u8 state)
 {
-       struct pci_dev *pci_device = to_pci_dev(dev);
-       struct pcie_link_state *link_state = pci_device->link_state;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
 
-       return sprintf(buf, "%d\n", link_state->aspm_enabled);
+       return sprintf(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
 }
 
-static ssize_t link_state_store(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t n)
+static ssize_t aspm_attr_store_common(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t len, u8 state)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct pcie_link_state *link, *root = pdev->link_state->root;
-       u32 state;
-
-       if (aspm_disabled)
-               return -EPERM;
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
+       bool state_enable;
 
-       if (kstrtouint(buf, 10, &state))
-               return -EINVAL;
-       if ((state & ~ASPM_STATE_ALL) != 0)
+       if (strtobool(buf, &state_enable) < 0)
                return -EINVAL;
 
        down_read(&pci_bus_sem);
        mutex_lock(&aspm_lock);
-       list_for_each_entry(link, &link_list, sibling) {
-               if (link->root != root)
-                       continue;
-               pcie_config_aspm_link(link, state);
+
+       if (state_enable) {
+               link->aspm_disable &= ~state;
+               /* need to enable L1 for substates */
+               if (state & ASPM_STATE_L1SS)
+                       link->aspm_disable &= ~ASPM_STATE_L1;
+       } else {
+               link->aspm_disable |= state;
        }
+
+       pcie_config_aspm_link(link, policy_to_aspm_state(link));
+
        mutex_unlock(&aspm_lock);
        up_read(&pci_bus_sem);
-       return n;
+
+       return len;
 }
 
-static ssize_t clk_ctl_show(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+#define ASPM_ATTR(_f, _s)                                              \
+static ssize_t _f##_show(struct device *dev,                           \
+                        struct device_attribute *attr, char *buf)      \
+{ return aspm_attr_show_common(dev, attr, buf, ASPM_STATE_##_s); }     \
+                                                                       \
+static ssize_t _f##_store(struct device *dev,                          \
+                         struct device_attribute *attr,                \
+                         const char *buf, size_t len)                  \
+{ return aspm_attr_store_common(dev, attr, buf, len, ASPM_STATE_##_s); }
+
+ASPM_ATTR(l0s_aspm, L0S)
+ASPM_ATTR(l1_aspm, L1)
+ASPM_ATTR(l1_1_aspm, L1_1)
+ASPM_ATTR(l1_2_aspm, L1_2)
+ASPM_ATTR(l1_1_pcipm, L1_1_PCIPM)
+ASPM_ATTR(l1_2_pcipm, L1_2_PCIPM)
+
+static ssize_t clkpm_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
 {
-       struct pci_dev *pci_device = to_pci_dev(dev);
-       struct pcie_link_state *link_state = pci_device->link_state;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
 
-       return sprintf(buf, "%d\n", link_state->clkpm_enabled);
+       return sprintf(buf, "%d\n", link->clkpm_enabled);
 }
 
-static ssize_t clk_ctl_store(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t n)
+static ssize_t clkpm_store(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t len)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
-       bool state;
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
+       bool state_enable;
 
-       if (strtobool(buf, &state))
+       if (strtobool(buf, &state_enable) < 0)
                return -EINVAL;
 
        down_read(&pci_bus_sem);
        mutex_lock(&aspm_lock);
-       pcie_set_clkpm_nocheck(pdev->link_state, state);
+
+       link->clkpm_disable = !state_enable;
+       pcie_set_clkpm(link, policy_to_clkpm_state(link));
+
        mutex_unlock(&aspm_lock);
        up_read(&pci_bus_sem);
 
-       return n;
+       return len;
 }
 
-static DEVICE_ATTR_RW(link_state);
-static DEVICE_ATTR_RW(clk_ctl);
+static DEVICE_ATTR_RW(clkpm);
+static DEVICE_ATTR_RW(l0s_aspm);
+static DEVICE_ATTR_RW(l1_aspm);
+static DEVICE_ATTR_RW(l1_1_aspm);
+static DEVICE_ATTR_RW(l1_2_aspm);
+static DEVICE_ATTR_RW(l1_1_pcipm);
+static DEVICE_ATTR_RW(l1_2_pcipm);
+
+static struct attribute *aspm_ctrl_attrs[] = {
+       &dev_attr_clkpm.attr,
+       &dev_attr_l0s_aspm.attr,
+       &dev_attr_l1_aspm.attr,
+       &dev_attr_l1_1_aspm.attr,
+       &dev_attr_l1_2_aspm.attr,
+       &dev_attr_l1_1_pcipm.attr,
+       &dev_attr_l1_2_pcipm.attr,
+       NULL
+};
 
-static char power_group[] = "power";
-void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
+static umode_t aspm_ctrl_attrs_are_visible(struct kobject *kobj,
+                                          struct attribute *a, int n)
 {
-       struct pcie_link_state *link_state = pdev->link_state;
-
-       if (!link_state)
-               return;
-
-       if (link_state->aspm_support)
-               sysfs_add_file_to_group(&pdev->dev.kobj,
-                       &dev_attr_link_state.attr, power_group);
-       if (link_state->clkpm_capable)
-               sysfs_add_file_to_group(&pdev->dev.kobj,
-                       &dev_attr_clk_ctl.attr, power_group);
-}
+       struct device *dev = kobj_to_dev(kobj);
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pcie_link_state *link = pcie_aspm_get_link(pdev);
+       static const u8 aspm_state_map[] = {
+               ASPM_STATE_L0S,
+               ASPM_STATE_L1,
+               ASPM_STATE_L1_1,
+               ASPM_STATE_L1_2,
+               ASPM_STATE_L1_1_PCIPM,
+               ASPM_STATE_L1_2_PCIPM,
+       };
 
-void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
-{
-       struct pcie_link_state *link_state = pdev->link_state;
+       if (aspm_disabled || !link)
+               return 0;
 
-       if (!link_state)
-               return;
+       if (n == 0)
+               return link->clkpm_capable ? a->mode : 0;
 
-       if (link_state->aspm_support)
-               sysfs_remove_file_from_group(&pdev->dev.kobj,
-                       &dev_attr_link_state.attr, power_group);
-       if (link_state->clkpm_capable)
-               sysfs_remove_file_from_group(&pdev->dev.kobj,
-                       &dev_attr_clk_ctl.attr, power_group);
+       return link->aspm_capable & aspm_state_map[n - 1] ? a->mode : 0;
 }
-#endif
+
+const struct attribute_group aspm_ctrl_attr_group = {
+       .name = "link",
+       .attrs = aspm_ctrl_attrs,
+       .is_visible = aspm_ctrl_attrs_are_visible,
+};
 
 static int __init pcie_aspm_disable(char *str)
 {
index a32ec34..e06f42f 100644 (file)
@@ -291,7 +291,7 @@ static int dpc_probe(struct pcie_device *dev)
        int status;
        u16 ctl, cap;
 
-       if (pcie_aer_get_firmware_first(pdev))
+       if (pcie_aer_get_firmware_first(pdev) && !pcie_ports_dpc_native)
                return -ENOTSUPP;
 
        dpc = devm_kzalloc(device, sizeof(*dpc), GFP_KERNEL);
index 944827a..1e67361 100644 (file)
@@ -25,6 +25,8 @@
 
 #define PCIE_PORT_DEVICE_MAXSERVICES   5
 
+extern bool pcie_ports_dpc_native;
+
 #ifdef CONFIG_PCIEAER
 int pcie_aer_init(void);
 #else
index 1b33012..5075cb9 100644 (file)
@@ -250,8 +250,13 @@ static int get_port_device_capability(struct pci_dev *dev)
                pcie_pme_interrupt_enable(dev, false);
        }
 
+       /*
+        * With dpc-native, allow Linux to use DPC even if it doesn't have
+        * permission to use AER.
+        */
        if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC) &&
-           pci_aer_available() && services & PCIE_PORT_SERVICE_AER)
+           pci_aer_available() &&
+           (pcie_ports_dpc_native || (services & PCIE_PORT_SERVICE_AER)))
                services |= PCIE_PORT_SERVICE_DPC;
 
        if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
index 0a87091..160d67c 100644 (file)
@@ -29,12 +29,20 @@ bool pcie_ports_disabled;
  */
 bool pcie_ports_native;
 
+/*
+ * If the user specified "pcie_ports=dpc-native", use the Linux DPC PCIe
+ * service even if the platform hasn't given us permission.
+ */
+bool pcie_ports_dpc_native;
+
 static int __init pcie_port_setup(char *str)
 {
        if (!strncmp(str, "compat", 6))
                pcie_ports_disabled = true;
        else if (!strncmp(str, "native", 6))
                pcie_ports_native = true;
+       else if (!strncmp(str, "dpc-native", 10))
+               pcie_ports_dpc_native = true;
 
        return 1;
 }
index 98cfa30..9361f3a 100644 (file)
@@ -21,7 +21,7 @@ static void pci_ptm_info(struct pci_dev *dev)
                snprintf(clock_desc, sizeof(clock_desc), ">254ns");
                break;
        default:
-               snprintf(clock_desc, sizeof(clock_desc), "%udns",
+               snprintf(clock_desc, sizeof(clock_desc), "%uns",
                         dev->ptm_granularity);
                break;
        }
index 3d5271a..512cb43 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/msi.h>
 #include <linux/of_device.h>
 #include <linux/of_pci.h>
 #include <linux/pci_hotplug.h>
@@ -572,6 +573,7 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)
                bridge->release_fn(bridge);
 
        pci_free_resource_list(&bridge->windows);
+       pci_free_resource_list(&bridge->dma_ranges);
 }
 
 static void pci_release_host_bridge_dev(struct device *dev)
@@ -897,6 +899,9 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
        else
                pr_info("PCI host bridge to bus %s\n", name);
 
+       if (nr_node_ids > 1 && pcibus_to_node(bus) == NUMA_NO_NODE)
+               dev_warn(&bus->dev, "Unknown NUMA node; performance will be reduced\n");
+
        /* Add initial resources to the bus */
        resource_list_for_each_entry_safe(window, n, &resources) {
                list_move_tail(&window->node, &bridge->windows);
@@ -1089,14 +1094,15 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
  * @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.
+ * If @dev is a bridge with EA capability that specifies valid secondary
+ * and subordinate bus numbers, return true with the bus numbers in @sec
+ * and @sub.  Otherwise return false.
  */
 static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
 {
        int ea, offset;
        u32 dw;
+       u8 ea_sec, ea_sub;
 
        if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
                return false;
@@ -1108,8 +1114,13 @@ static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
 
        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;
+       ea_sec =  dw & PCI_EA_SEC_BUS_MASK;
+       ea_sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT;
+       if (ea_sec  == 0 || ea_sub < ea_sec)
+               return false;
+
+       *sec = ea_sec;
+       *sub = ea_sub;
        return true;
 }
 
@@ -2300,8 +2311,7 @@ void pcie_report_downtraining(struct pci_dev *dev)
 
 static void pci_init_capabilities(struct pci_dev *dev)
 {
-       /* Enhanced Allocation */
-       pci_ea_init(dev);
+       pci_ea_init(dev);               /* Enhanced Allocation */
 
        /* Setup MSI caps & disable MSI/MSI-X interrupts */
        pci_msi_setup_pci_dev(dev);
@@ -2309,29 +2319,16 @@ static void pci_init_capabilities(struct pci_dev *dev)
        /* Buffers for saving PCIe and PCI-X capabilities */
        pci_allocate_cap_save_buffers(dev);
 
-       /* Power Management */
-       pci_pm_init(dev);
-
-       /* Vital Product Data */
-       pci_vpd_init(dev);
-
-       /* Alternative Routing-ID Forwarding */
-       pci_configure_ari(dev);
-
-       /* Single Root I/O Virtualization */
-       pci_iov_init(dev);
-
-       /* Address Translation Services */
-       pci_ats_init(dev);
-
-       /* Enable ACS P2P upstream forwarding */
-       pci_enable_acs(dev);
-
-       /* Precision Time Measurement */
-       pci_ptm_init(dev);
-
-       /* Advanced Error Reporting */
-       pci_aer_init(dev);
+       pci_pm_init(dev);               /* Power Management */
+       pci_vpd_init(dev);              /* Vital Product Data */
+       pci_configure_ari(dev);         /* Alternative Routing-ID Forwarding */
+       pci_iov_init(dev);              /* Single Root I/O Virtualization */
+       pci_ats_init(dev);              /* Address Translation Services */
+       pci_pri_init(dev);              /* Page Request Interface */
+       pci_pasid_init(dev);            /* Process Address Space ID */
+       pci_enable_acs(dev);            /* Enable ACS P2P upstream forwarding */
+       pci_ptm_init(dev);              /* Precision Time Measurement */
+       pci_aer_init(dev);              /* Advanced Error Reporting */
 
        pcie_report_downtraining(dev);
 
@@ -2403,13 +2400,10 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        /* Fix up broken headers */
        pci_fixup_device(pci_fixup_header, dev);
 
-       /* Moved out from quirk header fixup code */
        pci_reassigndev_resource_alignment(dev);
 
-       /* Clear the state_saved flag */
        dev->state_saved = false;
 
-       /* Initialize various capabilities */
        pci_init_capabilities(dev);
 
        /*
index 5495537..6ef74bf 100644 (file)
@@ -258,13 +258,13 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
        }
 
        /* Make sure the caller is mapping a real resource for this device */
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (dev->resource[i].flags & res_bit &&
                    pci_mmap_fits(dev, i, vma,  PCI_MMAP_PROCFS))
                        break;
        }
 
-       if (i >= PCI_ROM_RESOURCE)
+       if (i >= PCI_STD_NUM_BARS)
                return -ENODEV;
 
        if (fpriv->mmap_state == pci_mmap_mem &&
index 320255e..4937a08 100644 (file)
@@ -474,7 +474,7 @@ static void quirk_extend_bar_to_page(struct pci_dev *dev)
 {
        int i;
 
-       for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                struct resource *r = &dev->resource[i];
 
                if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) {
@@ -1809,7 +1809,7 @@ static void quirk_alder_ioapic(struct pci_dev *pdev)
         * The next five BARs all seem to be rubbish, so just clean
         * them out.
         */
-       for (i = 1; i < 6; i++)
+       for (i = 1; i < PCI_STD_NUM_BARS; i++)
                memset(&pdev->resource[i], 0, sizeof(pdev->resource[i]));
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_EESSC,      quirk_alder_ioapic);
@@ -4033,7 +4033,6 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev)
        if (id)
                pci_add_dma_alias(dev, id->driver_data);
 }
-
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);
 
 /*
@@ -4080,6 +4079,40 @@ static void quirk_mic_x200_dma_alias(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias);
 
+/*
+ * Intel Visual Compute Accelerator (VCA) is a family of PCIe add-in devices
+ * exposing computational units via Non Transparent Bridges (NTB, PEX 87xx).
+ *
+ * Similarly to MIC x200, we need to add DMA aliases to allow buffer access
+ * when IOMMU is enabled.  These aliases allow computational unit access to
+ * host memory.  These aliases mark the whole VCA device as one IOMMU
+ * group.
+ *
+ * All possible slot numbers (0x20) are used, since we are unable to tell
+ * what slot is used on other side.  This quirk is intended for both host
+ * and computational unit sides.  The VCA devices have up to five functions
+ * (four for DMA channels and one additional).
+ */
+static void quirk_pex_vca_alias(struct pci_dev *pdev)
+{
+       const unsigned int num_pci_slots = 0x20;
+       unsigned int slot;
+
+       for (slot = 0; slot < num_pci_slots; slot++) {
+               pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x0));
+               pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x1));
+               pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x2));
+               pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x3));
+               pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x4));
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2954, quirk_pex_vca_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2955, quirk_pex_vca_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2956, quirk_pex_vca_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2958, quirk_pex_vca_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2959, quirk_pex_vca_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x295A, quirk_pex_vca_alias);
+
 /*
  * The IOMMU and interrupt controller on Broadcom Vulcan/Cavium ThunderX2 are
  * associated not at the root bus, but at a bridge below. This quirk avoids
@@ -4262,6 +4295,24 @@ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
                         quirk_chelsio_T5_disable_root_port_attributes);
 
+/*
+ * pci_acs_ctrl_enabled - compare desired ACS controls with those provided
+ *                       by a device
+ * @acs_ctrl_req: Bitmask of desired ACS controls
+ * @acs_ctrl_ena: Bitmask of ACS controls enabled or provided implicitly by
+ *               the hardware design
+ *
+ * Return 1 if all ACS controls in the @acs_ctrl_req bitmask are included
+ * in @acs_ctrl_ena, i.e., the device provides all the access controls the
+ * caller desires.  Return 0 otherwise.
+ */
+static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena)
+{
+       if ((acs_ctrl_req & acs_ctrl_ena) == acs_ctrl_req)
+               return 1;
+       return 0;
+}
+
 /*
  * AMD has indicated that the devices below do not support peer-to-peer
  * in any system where they are found in the southbridge with an AMD
@@ -4305,7 +4356,7 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
        /* Filter out flags not applicable to multifunction */
        acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
 
-       return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1;
+       return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_RR | PCI_ACS_CR);
 #else
        return -ENODEV;
 #endif
@@ -4313,33 +4364,38 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
 
 static bool pci_quirk_cavium_acs_match(struct pci_dev *dev)
 {
+       if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
+               return false;
+
+       switch (dev->device) {
        /*
-        * Effectively selects all downstream ports for whole ThunderX 1
-        * family by 0xf800 mask (which represents 8 SoCs), while the lower
-        * bits of device ID are used to indicate which subdevice is used
-        * within the SoC.
+        * Effectively selects all downstream ports for whole ThunderX1
+        * (which represents 8 SoCs).
         */
-       return (pci_is_pcie(dev) &&
-               (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) &&
-               ((dev->device & 0xf800) == 0xa000));
+       case 0xa000 ... 0xa7ff: /* ThunderX1 */
+       case 0xaf84:  /* ThunderX2 */
+       case 0xb884:  /* ThunderX3 */
+               return true;
+       default:
+               return false;
+       }
 }
 
 static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
 {
+       if (!pci_quirk_cavium_acs_match(dev))
+               return -ENOTTY;
+
        /*
-        * Cavium root ports don't advertise an ACS capability.  However,
+        * Cavium Root Ports don't advertise an ACS capability.  However,
         * the RTL internally implements similar protection as if ACS had
-        * Request Redirection, Completion Redirection, Source Validation,
+        * Source Validation, Request Redirection, Completion Redirection,
         * and Upstream Forwarding features enabled.  Assert that the
         * hardware implements and enables equivalent ACS functionality for
         * these flags.
         */
-       acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF);
-
-       if (!pci_quirk_cavium_acs_match(dev))
-               return -ENOTTY;
-
-       return acs_flags ? 0 : 1;
+       return pci_acs_ctrl_enabled(acs_flags,
+               PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
 }
 
 static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4349,13 +4405,12 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
         * transactions with others, allowing masking out these bits as if they
         * were unimplemented in the ACS capability.
         */
-       acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
-
-       return acs_flags ? 0 : 1;
+       return pci_acs_ctrl_enabled(acs_flags,
+               PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
 }
 
 /*
- * Many Intel PCH root ports do provide ACS-like features to disable peer
+ * Many Intel PCH Root Ports do provide ACS-like features to disable peer
  * transactions and validate bus numbers in requests, but do not provide an
  * actual PCIe ACS capability.  This is the list of device IDs known to fall
  * into that category as provided by Intel in Red Hat bugzilla 1037684.
@@ -4403,37 +4458,32 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
        return false;
 }
 
-#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV)
-
 static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
 {
-       u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ?
-                   INTEL_PCH_ACS_FLAGS : 0;
-
        if (!pci_quirk_intel_pch_acs_match(dev))
                return -ENOTTY;
 
-       return acs_flags & ~flags ? 0 : 1;
+       if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK)
+               return pci_acs_ctrl_enabled(acs_flags,
+                       PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+
+       return pci_acs_ctrl_enabled(acs_flags, 0);
 }
 
 /*
- * These QCOM root ports do provide ACS-like features to disable peer
+ * These QCOM Root Ports do provide ACS-like features to disable peer
  * transactions and validate bus numbers in requests, but do not provide an
  * actual PCIe ACS capability.  Hardware supports source validation but it
  * will report the issue as Completer Abort instead of ACS Violation.
- * Hardware doesn't support peer-to-peer and each root port is a root
- * complex with unique segment numbers.  It is not possible for one root
- * port to pass traffic to another root port.  All PCIe transactions are
- * terminated inside the root port.
+ * Hardware doesn't support peer-to-peer and each Root Port is a Root
+ * Complex with unique segment numbers.  It is not possible for one Root
+ * Port to pass traffic to another Root Port.  All PCIe transactions are
+ * terminated inside the Root Port.
  */
 static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)
 {
-       u16 flags = (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV);
-       int ret = acs_flags & ~flags ? 0 : 1;
-
-       pci_info(dev, "Using QCOM ACS Quirk (%d)\n", ret);
-
-       return ret;
+       return pci_acs_ctrl_enabled(acs_flags,
+               PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
 }
 
 static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4534,7 +4584,7 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)
 
        pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
 
-       return acs_flags & ~ctrl ? 0 : 1;
+       return pci_acs_ctrl_enabled(acs_flags, ctrl);
 }
 
 static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4548,10 +4598,9 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
         * perform peer-to-peer with other functions, allowing us to mask out
         * these bits as if they were unimplemented in the ACS capability.
         */
-       acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
-                      PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
-
-       return acs_flags ? 0 : 1;
+       return pci_acs_ctrl_enabled(acs_flags,
+               PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
+               PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
 }
 
 static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4562,9 +4611,8 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
         * Allow each Root Port to be in a separate IOMMU group by masking
         * SV/RR/CR/UF bits.
         */
-       acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
-
-       return acs_flags ? 0 : 1;
+       return pci_acs_ctrl_enabled(acs_flags,
+               PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
 }
 
 static const struct pci_dev_acs_enabled {
@@ -4666,6 +4714,17 @@ static const struct pci_dev_acs_enabled {
        { 0 }
 };
 
+/*
+ * pci_dev_specific_acs_enabled - check whether device provides ACS controls
+ * @dev:       PCI device
+ * @acs_flags: Bitmask of desired ACS controls
+ *
+ * Returns:
+ *   -ENOTTY:  No quirk applies to this device; we can't tell whether the
+ *             device provides the desired controls
+ *   0:                Device does not provide all the desired controls
+ *   >0:       Device provides all the controls in @acs_flags
+ */
 int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
 {
        const struct pci_dev_acs_enabled *i;
@@ -4706,7 +4765,7 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
 #define INTEL_BSPR_REG_BPPD  (1 << 9)
 
 /* Upstream Peer Decode Configuration Register */
-#define INTEL_UPDCR_REG 0x1114
+#define INTEL_UPDCR_REG 0x1014
 /* 5:0 Peer Decode Enable bits */
 #define INTEL_UPDCR_REG_MASK 0x3f
 
index e7dbe21..f279826 100644 (file)
@@ -752,24 +752,32 @@ 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.  Assigned resources have non-NULL
+ * parent resource.
+ *
+ * Return first unassigned resource of the correct type.  If there is none,
+ * return first assigned resource of the correct type.  If none of the
+ * above, return NULL.
+ *
+ * Returning an assigned resource of the correct type allows the caller to
+ * distinguish between already assigned and no resource of the correct type.
  */
-static struct resource *find_free_bus_resource(struct pci_bus *bus,
-                                              unsigned long type_mask,
-                                              unsigned long type)
+static struct resource *find_bus_resource_of_type(struct pci_bus *bus,
+                                                 unsigned long type_mask,
+                                                 unsigned long type)
 {
+       struct resource *r, *r_assigned = NULL;
        int i;
-       struct resource *r;
 
        pci_bus_for_each_resource(bus, r, i) {
                if (r == &ioport_resource || r == &iomem_resource)
                        continue;
                if (r && (r->flags & type_mask) == type && !r->parent)
                        return r;
+               if (r && (r->flags & type_mask) == type && !r_assigned)
+                       r_assigned = r;
        }
-       return NULL;
+       return r_assigned;
 }
 
 static resource_size_t calculate_iosize(resource_size_t size,
@@ -866,8 +874,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
                         struct list_head *realloc_head)
 {
        struct pci_dev *dev;
-       struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO,
-                                                       IORESOURCE_IO);
+       struct resource *b_res = find_bus_resource_of_type(bus, IORESOURCE_IO,
+                                                          IORESOURCE_IO);
        resource_size_t size = 0, size0 = 0, size1 = 0;
        resource_size_t children_add_size = 0;
        resource_size_t min_align, align;
@@ -875,6 +883,10 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        if (!b_res)
                return;
 
+       /* If resource is already assigned, nothing more to do */
+       if (b_res->parent)
+               return;
+
        min_align = window_alignment(bus, IORESOURCE_IO);
        list_for_each_entry(dev, &bus->devices, bus_list) {
                int i;
@@ -978,7 +990,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        resource_size_t min_align, align, size, size0, size1;
        resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */
        int order, max_order;
-       struct resource *b_res = find_free_bus_resource(bus,
+       struct resource *b_res = find_bus_resource_of_type(bus,
                                        mask | IORESOURCE_PREFETCH, type);
        resource_size_t children_add_size = 0;
        resource_size_t children_add_align = 0;
@@ -987,6 +999,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        if (!b_res)
                return -ENOSPC;
 
+       /* If resource is already assigned, nothing more to do */
+       if (b_res->parent)
+               return 0;
+
        memset(aligns, 0, sizeof(aligns));
        max_order = 0;
        size = 0;
@@ -1178,7 +1194,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask, type2 = 0, type3 = 0;
-       resource_size_t additional_mem_size = 0, additional_io_size = 0;
+       resource_size_t additional_io_size = 0, additional_mmio_size = 0,
+                       additional_mmio_pref_size = 0;
        struct resource *b_res;
        int ret;
 
@@ -1212,7 +1229,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                pci_bridge_check_ranges(bus);
                if (bus->self->is_hotplug_bridge) {
                        additional_io_size  = pci_hotplug_io_size;
-                       additional_mem_size = pci_hotplug_mem_size;
+                       additional_mmio_size = pci_hotplug_mmio_size;
+                       additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
                }
                /* Fall through */
        default:
@@ -1230,9 +1248,9 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                if (b_res[2].flags & IORESOURCE_MEM_64) {
                        prefmask |= IORESOURCE_MEM_64;
                        ret = pbus_size_mem(bus, prefmask, prefmask,
-                                 prefmask, prefmask,
-                                 realloc_head ? 0 : additional_mem_size,
-                                 additional_mem_size, realloc_head);
+                               prefmask, prefmask,
+                               realloc_head ? 0 : additional_mmio_pref_size,
+                               additional_mmio_pref_size, realloc_head);
 
                        /*
                         * If successful, all non-prefetchable resources
@@ -1254,9 +1272,9 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                if (!type2) {
                        prefmask &= ~IORESOURCE_MEM_64;
                        ret = pbus_size_mem(bus, prefmask, prefmask,
-                                        prefmask, prefmask,
-                                        realloc_head ? 0 : additional_mem_size,
-                                        additional_mem_size, realloc_head);
+                               prefmask, prefmask,
+                               realloc_head ? 0 : additional_mmio_pref_size,
+                               additional_mmio_pref_size, realloc_head);
 
                        /*
                         * If successful, only non-prefetchable resources
@@ -1265,7 +1283,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                        if (ret == 0)
                                mask = prefmask;
                        else
-                               additional_mem_size += additional_mem_size;
+                               additional_mmio_size += additional_mmio_pref_size;
 
                        type2 = type3 = IORESOURCE_MEM;
                }
@@ -1285,8 +1303,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                 * prefetchable resource in a 64-bit prefetchable window.
                 */
                pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
-                               realloc_head ? 0 : additional_mem_size,
-                               additional_mem_size, realloc_head);
+                             realloc_head ? 0 : additional_mmio_size,
+                             additional_mmio_size, realloc_head);
                break;
        }
 }
@@ -2066,6 +2084,8 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
        unsigned int i;
        int ret;
 
+       down_read(&pci_bus_sem);
+
        /* Walk to the root hub, releasing bridge BARs when possible */
        next = bridge;
        do {
@@ -2100,8 +2120,10 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
                next = bridge->bus ? bridge->bus->self : NULL;
        } while (next);
 
-       if (list_empty(&saved))
+       if (list_empty(&saved)) {
+               up_read(&pci_bus_sem);
                return -ENOENT;
+       }
 
        __pci_bus_size_bridges(bridge->subordinate, &added);
        __pci_bridge_assign_resources(bridge, &added, &failed);
@@ -2122,6 +2144,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
        }
 
        free_list(&saved);
+       up_read(&pci_bus_sem);
        return 0;
 
 cleanup:
@@ -2150,6 +2173,7 @@ cleanup:
                pci_setup_bridge(bridge->subordinate);
        }
        free_list(&saved);
+       up_read(&pci_bus_sem);
 
        return ret;
 }
index 66610f0..88091bb 100644 (file)
@@ -675,7 +675,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev,
                return -ENOMEM;
 
        s->global = ioread32(&stdev->mmio_sw_event->global_summary);
-       s->part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
+       s->part_bitmap = ioread64(&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++) {
index ac322d6..08e3227 100644 (file)
@@ -50,6 +50,8 @@
        #define PHY_R5_PHY_CR_ACK                               BIT(16)
        #define PHY_R5_PHY_BS_OUT                               BIT(17)
 
+#define PCIE_RESET_DELAY                                       500
+
 struct phy_g12a_usb3_pcie_priv {
        struct regmap           *regmap;
        struct regmap           *regmap_cr;
@@ -196,6 +198,10 @@ static int phy_g12a_usb3_init(struct phy *phy)
        struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
        int data, ret;
 
+       ret = reset_control_reset(priv->reset);
+       if (ret)
+               return ret;
+
        /* Switch PHY to USB3 */
        /* TODO figure out how to handle when PCIe was set in the bootloader */
        regmap_update_bits(priv->regmap, PHY_R0,
@@ -272,24 +278,64 @@ static int phy_g12a_usb3_init(struct phy *phy)
        return 0;
 }
 
-static int phy_g12a_usb3_pcie_init(struct phy *phy)
+static int phy_g12a_usb3_pcie_power_on(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
+
+       if (priv->mode == PHY_TYPE_USB3)
+               return 0;
+
+       regmap_update_bits(priv->regmap, PHY_R0,
+                          PHY_R0_PCIE_POWER_STATE,
+                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c));
+
+       return 0;
+}
+
+static int phy_g12a_usb3_pcie_power_off(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
+
+       if (priv->mode == PHY_TYPE_USB3)
+               return 0;
+
+       regmap_update_bits(priv->regmap, PHY_R0,
+                          PHY_R0_PCIE_POWER_STATE,
+                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d));
+
+       return 0;
+}
+
+static int phy_g12a_usb3_pcie_reset(struct phy *phy)
 {
        struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
        int ret;
 
-       ret = reset_control_reset(priv->reset);
+       if (priv->mode == PHY_TYPE_USB3)
+               return 0;
+
+       ret = reset_control_assert(priv->reset);
        if (ret)
                return ret;
 
+       udelay(PCIE_RESET_DELAY);
+
+       ret = reset_control_deassert(priv->reset);
+       if (ret)
+               return ret;
+
+       udelay(PCIE_RESET_DELAY);
+
+       return 0;
+}
+
+static int phy_g12a_usb3_pcie_init(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
+
        if (priv->mode == PHY_TYPE_USB3)
                return phy_g12a_usb3_init(phy);
 
-       /* Power UP PCIE */
-       /* TODO figure out when the bootloader has set USB3 mode before */
-       regmap_update_bits(priv->regmap, PHY_R0,
-                          PHY_R0_PCIE_POWER_STATE,
-                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c));
-
        return 0;
 }
 
@@ -297,7 +343,10 @@ static int phy_g12a_usb3_pcie_exit(struct phy *phy)
 {
        struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
 
-       return reset_control_reset(priv->reset);
+       if (priv->mode == PHY_TYPE_USB3)
+               return reset_control_reset(priv->reset);
+
+       return 0;
 }
 
 static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev,
@@ -326,6 +375,9 @@ static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev,
 static const struct phy_ops phy_g12a_usb3_pcie_ops = {
        .init           = phy_g12a_usb3_pcie_init,
        .exit           = phy_g12a_usb3_pcie_exit,
+       .power_on       = phy_g12a_usb3_pcie_power_on,
+       .power_off      = phy_g12a_usb3_pcie_power_off,
+       .reset          = phy_g12a_usb3_pcie_reset,
        .owner          = THIS_MODULE,
 };
 
index 4053ba6..005e02d 100644 (file)
@@ -103,3 +103,14 @@ config PHY_PXA_USB
          The PHY driver will be used by Marvell udc/ehci/otg driver.
 
          To compile this driver as a module, choose M here.
+
+config PHY_MMP3_USB
+       tristate "Marvell MMP3 USB PHY Driver"
+       depends on MACH_MMP3_DT || COMPILE_TEST
+       select GENERIC_PHY
+       help
+         Enable this to support Marvell MMP3 USB PHY driver for Marvell
+         SoC. This driver will do the PHY initialization and shutdown.
+         The PHY driver will be used by Marvell udc/ehci/otg driver.
+
+         To compile this driver as a module, choose M here.
index 434eb9c..5a106b1 100644 (file)
@@ -2,6 +2,7 @@
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
 obj-$(CONFIG_PHY_BERLIN_SATA)          += phy-berlin-sata.o
 obj-$(CONFIG_PHY_BERLIN_USB)           += phy-berlin-usb.o
+obj-$(CONFIG_PHY_MMP3_USB)             += phy-mmp3-usb.o
 obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY)   += phy-mvebu-a3700-comphy.o
 obj-$(CONFIG_PHY_MVEBU_A3700_UTMI)     += phy-mvebu-a3700-utmi.o
 obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY)    += phy-armada38x-comphy.o
diff --git a/drivers/phy/marvell/phy-mmp3-usb.c b/drivers/phy/marvell/phy-mmp3-usb.c
new file mode 100644 (file)
index 0000000..4998695
--- /dev/null
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Copyright (C) 2018,2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mmp/cputype.h>
+
+#define USB2_PLL_REG0          0x4
+#define USB2_PLL_REG1          0x8
+#define USB2_TX_REG0           0x10
+#define USB2_TX_REG1           0x14
+#define USB2_TX_REG2           0x18
+#define USB2_RX_REG0           0x20
+#define USB2_RX_REG1           0x24
+#define USB2_RX_REG2           0x28
+#define USB2_ANA_REG0          0x30
+#define USB2_ANA_REG1          0x34
+#define USB2_ANA_REG2          0x38
+#define USB2_DIG_REG0          0x3C
+#define USB2_DIG_REG1          0x40
+#define USB2_DIG_REG2          0x44
+#define USB2_DIG_REG3          0x48
+#define USB2_TEST_REG0         0x4C
+#define USB2_TEST_REG1         0x50
+#define USB2_TEST_REG2         0x54
+#define USB2_CHARGER_REG0      0x58
+#define USB2_OTG_REG0          0x5C
+#define USB2_PHY_MON0          0x60
+#define USB2_RESETVE_REG0      0x64
+#define USB2_ICID_REG0         0x78
+#define USB2_ICID_REG1         0x7C
+
+/* USB2_PLL_REG0 */
+
+/* This is for Ax stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3              0
+#define USB2_PLL_FBDIV_MASK_MMP3               (0xFF << 0)
+
+#define USB2_PLL_REFDIV_SHIFT_MMP3             8
+#define USB2_PLL_REFDIV_MASK_MMP3              (0xF << 8)
+
+#define USB2_PLL_VDD12_SHIFT_MMP3              12
+#define USB2_PLL_VDD18_SHIFT_MMP3              14
+
+/* This is for B0 stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3_B0           0
+#define USB2_PLL_REFDIV_SHIFT_MMP3_B0          9
+#define USB2_PLL_VDD18_SHIFT_MMP3_B0           14
+#define USB2_PLL_FBDIV_MASK_MMP3_B0            0x01FF
+#define USB2_PLL_REFDIV_MASK_MMP3_B0           0x3E00
+
+#define USB2_PLL_CAL12_SHIFT_MMP3              0
+#define USB2_PLL_CALI12_MASK_MMP3              (0x3 << 0)
+
+#define USB2_PLL_VCOCAL_START_SHIFT_MMP3       2
+
+#define USB2_PLL_KVCO_SHIFT_MMP3               4
+#define USB2_PLL_KVCO_MASK_MMP3                        (0x7<<4)
+
+#define USB2_PLL_ICP_SHIFT_MMP3                        8
+#define USB2_PLL_ICP_MASK_MMP3                 (0x7<<8)
+
+#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3                12
+
+#define USB2_PLL_PU_PLL_SHIFT_MMP3             13
+#define USB2_PLL_PU_PLL_MASK                   (0x1 << 13)
+
+#define USB2_PLL_READY_MASK_MMP3               (0x1 << 15)
+
+/* USB2_TX_REG0 */
+#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3          8
+#define USB2_TX_IMPCAL_VTH_MASK_MMP3           (0x7 << 8)
+
+#define USB2_TX_RCAL_START_SHIFT_MMP3          13
+
+/* USB2_TX_REG1 */
+#define USB2_TX_CK60_PHSEL_SHIFT_MMP3          0
+#define USB2_TX_CK60_PHSEL_MASK_MMP3           (0xf << 0)
+
+#define USB2_TX_AMP_SHIFT_MMP3                 4
+#define USB2_TX_AMP_MASK_MMP3                  (0x7 << 4)
+
+#define USB2_TX_VDD12_SHIFT_MMP3               8
+#define USB2_TX_VDD12_MASK_MMP3                        (0x3 << 8)
+
+/* USB2_TX_REG2 */
+#define USB2_TX_DRV_SLEWRATE_SHIFT             10
+
+/* USB2_RX_REG0 */
+#define USB2_RX_SQ_THRESH_SHIFT_MMP3           4
+#define USB2_RX_SQ_THRESH_MASK_MMP3            (0xf << 4)
+
+#define USB2_RX_SQ_LENGTH_SHIFT_MMP3           10
+#define USB2_RX_SQ_LENGTH_MASK_MMP3            (0x3 << 10)
+
+/* USB2_ANA_REG1*/
+#define USB2_ANA_PU_ANA_SHIFT_MMP3             14
+
+/* USB2_OTG_REG0 */
+#define USB2_OTG_PU_OTG_SHIFT_MMP3             3
+
+struct mmp3_usb_phy {
+       struct phy *phy;
+       void __iomem *base;
+};
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+       return readl_relaxed(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+               unsigned int value)
+{
+       u32 reg;
+
+       reg = readl_relaxed(base + offset);
+       reg |= value;
+       writel_relaxed(reg, base + offset);
+       readl_relaxed(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+               unsigned int value)
+{
+       u32 reg;
+
+       reg = readl_relaxed(base + offset);
+       reg &= ~value;
+       writel_relaxed(reg, base + offset);
+       readl_relaxed(base + offset);
+}
+
+static int mmp3_usb_phy_init(struct phy *phy)
+{
+       struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
+       void __iomem *base = mmp3_usb_phy->base;
+
+       if (cpu_is_mmp3_a0()) {
+               u2o_clear(base, USB2_PLL_REG0, (USB2_PLL_FBDIV_MASK_MMP3
+                       | USB2_PLL_REFDIV_MASK_MMP3));
+               u2o_set(base, USB2_PLL_REG0,
+                       0xd << USB2_PLL_REFDIV_SHIFT_MMP3
+                       | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3);
+       } else if (cpu_is_mmp3_b0()) {
+               u2o_clear(base, USB2_PLL_REG0, USB2_PLL_REFDIV_MASK_MMP3_B0
+                       | USB2_PLL_FBDIV_MASK_MMP3_B0);
+               u2o_set(base, USB2_PLL_REG0,
+                       0xd << USB2_PLL_REFDIV_SHIFT_MMP3_B0
+                       | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3_B0);
+       } else {
+               dev_err(&phy->dev, "unsupported silicon revision\n");
+               return -ENODEV;
+       }
+
+       u2o_clear(base, USB2_PLL_REG1, USB2_PLL_PU_PLL_MASK
+               | USB2_PLL_ICP_MASK_MMP3
+               | USB2_PLL_KVCO_MASK_MMP3
+               | USB2_PLL_CALI12_MASK_MMP3);
+       u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_PU_PLL_SHIFT_MMP3
+               | 1 << USB2_PLL_LOCK_BYPASS_SHIFT_MMP3
+               | 3 << USB2_PLL_ICP_SHIFT_MMP3
+               | 3 << USB2_PLL_KVCO_SHIFT_MMP3
+               | 3 << USB2_PLL_CAL12_SHIFT_MMP3);
+
+       u2o_clear(base, USB2_TX_REG0, USB2_TX_IMPCAL_VTH_MASK_MMP3);
+       u2o_set(base, USB2_TX_REG0, 2 << USB2_TX_IMPCAL_VTH_SHIFT_MMP3);
+
+       u2o_clear(base, USB2_TX_REG1, USB2_TX_VDD12_MASK_MMP3
+               | USB2_TX_AMP_MASK_MMP3
+               | USB2_TX_CK60_PHSEL_MASK_MMP3);
+       u2o_set(base, USB2_TX_REG1, 3 << USB2_TX_VDD12_SHIFT_MMP3
+               | 4 << USB2_TX_AMP_SHIFT_MMP3
+               | 4 << USB2_TX_CK60_PHSEL_SHIFT_MMP3);
+
+       u2o_clear(base, USB2_TX_REG2, 3 << USB2_TX_DRV_SLEWRATE_SHIFT);
+       u2o_set(base, USB2_TX_REG2, 2 << USB2_TX_DRV_SLEWRATE_SHIFT);
+
+       u2o_clear(base, USB2_RX_REG0, USB2_RX_SQ_THRESH_MASK_MMP3);
+       u2o_set(base, USB2_RX_REG0, 0xa << USB2_RX_SQ_THRESH_SHIFT_MMP3);
+
+       u2o_set(base, USB2_ANA_REG1, 0x1 << USB2_ANA_PU_ANA_SHIFT_MMP3);
+
+       u2o_set(base, USB2_OTG_REG0, 0x1 << USB2_OTG_PU_OTG_SHIFT_MMP3);
+
+       return 0;
+}
+
+static int mmp3_usb_phy_calibrate(struct phy *phy)
+{
+       struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
+       void __iomem *base = mmp3_usb_phy->base;
+       int loops;
+
+       /*
+        * PLL VCO and TX Impedance Calibration Timing:
+        *
+        *                _____________________________________
+        * PU  __________|
+        *                        _____________________________
+        * VCOCAL START _________|
+        *                                 ___
+        * REG_RCAL_START ________________|   |________|_______
+        *               | 200us | 400us  | 40| 400us  | USB PHY READY
+        */
+
+       udelay(200);
+       u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_VCOCAL_START_SHIFT_MMP3);
+       udelay(400);
+       u2o_set(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
+       udelay(40);
+       u2o_clear(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
+       udelay(400);
+
+       loops = 0;
+       while ((u2o_get(base, USB2_PLL_REG1) & USB2_PLL_READY_MASK_MMP3) == 0) {
+               mdelay(1);
+               loops++;
+               if (loops > 100) {
+                       dev_err(&phy->dev, "PLL_READY not set after 100mS.\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static const struct phy_ops mmp3_usb_phy_ops = {
+       .init           = mmp3_usb_phy_init,
+       .calibrate      = mmp3_usb_phy_calibrate,
+       .owner          = THIS_MODULE,
+};
+
+static const struct of_device_id mmp3_usb_phy_of_match[] = {
+       { .compatible = "marvell,mmp3-usb-phy", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, mmp3_usb_phy_of_match);
+
+static int mmp3_usb_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *resource;
+       struct mmp3_usb_phy *mmp3_usb_phy;
+       struct phy_provider *provider;
+
+       mmp3_usb_phy = devm_kzalloc(dev, sizeof(*mmp3_usb_phy), GFP_KERNEL);
+       if (!mmp3_usb_phy)
+               return -ENOMEM;
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mmp3_usb_phy->base = devm_ioremap_resource(dev, resource);
+       if (IS_ERR(mmp3_usb_phy->base)) {
+               dev_err(dev, "failed to remap PHY regs\n");
+               return PTR_ERR(mmp3_usb_phy->base);
+       }
+
+       mmp3_usb_phy->phy = devm_phy_create(dev, NULL, &mmp3_usb_phy_ops);
+       if (IS_ERR(mmp3_usb_phy->phy)) {
+               dev_err(dev, "failed to create PHY\n");
+               return PTR_ERR(mmp3_usb_phy->phy);
+       }
+
+       phy_set_drvdata(mmp3_usb_phy->phy, mmp3_usb_phy);
+       provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(provider)) {
+               dev_err(dev, "failed to register PHY provider\n");
+               return PTR_ERR(provider);
+       }
+
+       return 0;
+}
+
+static struct platform_driver mmp3_usb_phy_driver = {
+       .probe          = mmp3_usb_phy_probe,
+       .driver         = {
+               .name   = "mmp3-usb-phy",
+               .of_match_table = mmp3_usb_phy_of_match,
+       },
+};
+module_platform_driver(mmp3_usb_phy_driver);
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Marvell MMP3 USB PHY Driver");
+MODULE_LICENSE("GPL v2");
index 62fcae9..5d6f9f6 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/pm.h>
 #include <linux/log2.h>
 
+#include <linux/soc/qcom/irq.h>
+
 #include "../core.h"
 #include "../pinconf.h"
 #include "pinctrl-msm.h"
@@ -44,6 +46,7 @@
  * @enabled_irqs:   Bitmap of currently enabled irqs.
  * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
  *                  detection.
+ * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt controller
  * @soc;            Reference to soc_data of platform specific data.
  * @regs:           Base addresses for the TLMM tiles.
  */
@@ -61,6 +64,7 @@ struct msm_pinctrl {
 
        DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
        DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+       DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO);
 
        const struct msm_pinctrl_soc_data *soc;
        void __iomem *regs[MAX_NR_TILES];
@@ -707,6 +711,12 @@ static void msm_gpio_irq_mask(struct irq_data *d)
        unsigned long flags;
        u32 val;
 
+       if (d->parent_data)
+               irq_chip_mask_parent(d);
+
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return;
+
        g = &pctrl->soc->groups[d->hwirq];
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -751,6 +761,12 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
        unsigned long flags;
        u32 val;
 
+       if (d->parent_data)
+               irq_chip_unmask_parent(d);
+
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return;
+
        g = &pctrl->soc->groups[d->hwirq];
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -778,10 +794,35 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
 
 static void msm_gpio_irq_enable(struct irq_data *d)
 {
+       /*
+        * Clear the interrupt that may be pending before we enable
+        * the line.
+        * This is especially a problem with the GPIOs routed to the
+        * PDC. These GPIOs are direct-connect interrupts to the GIC.
+        * Disabling the interrupt line at the PDC does not prevent
+        * the interrupt from being latched at the GIC. The state at
+        * GIC needs to be cleared before enabling.
+        */
+       if (d->parent_data) {
+               irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0);
+               irq_chip_enable_parent(d);
+       }
 
        msm_gpio_irq_clear_unmask(d, true);
 }
 
+static void msm_gpio_irq_disable(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+
+       if (d->parent_data)
+               irq_chip_disable_parent(d);
+
+       if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               msm_gpio_irq_mask(d);
+}
+
 static void msm_gpio_irq_unmask(struct irq_data *d)
 {
        msm_gpio_irq_clear_unmask(d, false);
@@ -795,6 +836,9 @@ static void msm_gpio_irq_ack(struct irq_data *d)
        unsigned long flags;
        u32 val;
 
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return;
+
        g = &pctrl->soc->groups[d->hwirq];
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -820,6 +864,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        unsigned long flags;
        u32 val;
 
+       if (d->parent_data)
+               irq_chip_set_type_parent(d, type);
+
+       if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return 0;
+
        g = &pctrl->soc->groups[d->hwirq];
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -912,6 +962,15 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        unsigned long flags;
 
+       /*
+        * While they may not wake up when the TLMM is powered off,
+        * some GPIOs would like to wakeup the system from suspend
+        * when TLMM is powered on. To allow that, enable the GPIO
+        * summary line to be wakeup capable at GIC.
+        */
+       if (d->parent_data)
+               irq_chip_set_wake_parent(d, on);
+
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        irq_set_irq_wake(pctrl->irq, on);
@@ -990,6 +1049,30 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
+static int msm_gpio_wakeirq(struct gpio_chip *gc,
+                           unsigned int child,
+                           unsigned int child_type,
+                           unsigned int *parent,
+                           unsigned int *parent_type)
+{
+       struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+       const struct msm_gpio_wakeirq_map *map;
+       int i;
+
+       *parent = GPIO_NO_WAKE_IRQ;
+       *parent_type = IRQ_TYPE_EDGE_RISING;
+
+       for (i = 0; i < pctrl->soc->nwakeirq_map; i++) {
+               map = &pctrl->soc->wakeirq_map[i];
+               if (map->gpio == child) {
+                       *parent = map->wakeirq;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
 {
        if (pctrl->soc->reserved_gpios)
@@ -1002,8 +1085,10 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 {
        struct gpio_chip *chip;
        struct gpio_irq_chip *girq;
-       int ret;
-       unsigned ngpio = pctrl->soc->ngpios;
+       int i, ret;
+       unsigned gpio, ngpio = pctrl->soc->ngpios;
+       struct device_node *np;
+       bool skip;
 
        if (WARN_ON(ngpio > MAX_NR_GPIO))
                return -EINVAL;
@@ -1020,17 +1105,40 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 
        pctrl->irq_chip.name = "msmgpio";
        pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
+       pctrl->irq_chip.irq_disable = msm_gpio_irq_disable;
        pctrl->irq_chip.irq_mask = msm_gpio_irq_mask;
        pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask;
        pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
+       pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent;
        pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type;
        pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
        pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
        pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
 
+       np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
+       if (np) {
+               chip->irq.parent_domain = irq_find_matching_host(np,
+                                                DOMAIN_BUS_WAKEUP);
+               of_node_put(np);
+               if (!chip->irq.parent_domain)
+                       return -EPROBE_DEFER;
+               chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq;
+
+               /*
+                * Let's skip handling the GPIOs, if the parent irqchip
+                * is handling the direct connect IRQ of the GPIO.
+                */
+               skip = irq_domain_qcom_handle_wakeup(chip->irq.parent_domain);
+               for (i = 0; skip && i < pctrl->soc->nwakeirq_map; i++) {
+                       gpio = pctrl->soc->wakeirq_map[i].gpio;
+                       set_bit(gpio, pctrl->skip_wake_irqs);
+               }
+       }
+
        girq = &chip->irq;
        girq->chip = &pctrl->irq_chip;
        girq->parent_handler = msm_gpio_irq_handler;
+       girq->fwnode = pctrl->dev->fwnode;
        girq->num_parents = 1;
        girq->parents = devm_kcalloc(pctrl->dev, 1, sizeof(*girq->parents),
                                     GFP_KERNEL);
index 48569cd..9452da1 100644 (file)
@@ -91,6 +91,16 @@ struct msm_pingroup {
        unsigned intr_detection_width:5;
 };
 
+/**
+ * struct msm_gpio_wakeirq_map - Map of GPIOs and their wakeup pins
+ * @gpio:          The GPIOs that are wakeup capable
+ * @wakeirq:       The interrupt at the always-on interrupt controller
+ */
+struct msm_gpio_wakeirq_map {
+       unsigned int gpio;
+       unsigned int wakeirq;
+};
+
 /**
  * struct msm_pinctrl_soc_data - Qualcomm pin controller driver configuration
  * @pins:          An array describing all pins the pin controller affects.
@@ -101,6 +111,8 @@ struct msm_pingroup {
  * @ngroups:       The numbmer of entries in @groups.
  * @ngpio:         The number of pingroups the driver should expose as GPIOs.
  * @pull_no_keeper: The SoC does not support keeper bias.
+ * @wakeirq_map:    The map of wakeup capable GPIOs and the pin at PDC/MPM
+ * @nwakeirq_map:   The number of entries in @wakeirq_map
  */
 struct msm_pinctrl_soc_data {
        const struct pinctrl_pin_desc *pins;
@@ -114,6 +126,8 @@ struct msm_pinctrl_soc_data {
        const char *const *tiles;
        unsigned int ntiles;
        const int *reserved_gpios;
+       const struct msm_gpio_wakeirq_map *wakeirq_map;
+       unsigned int nwakeirq_map;
 };
 
 extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
index ce49597..2834d2c 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/acpi.h>
@@ -1282,6 +1282,24 @@ static const int sdm845_acpi_reserved_gpios[] = {
        0, 1, 2, 3, 81, 82, 83, 84, -1
 };
 
+static const struct msm_gpio_wakeirq_map sdm845_pdc_map[] = {
+       { 1, 30 }, { 3, 31 }, { 5, 32 }, { 10, 33 }, { 11, 34 },
+       { 20, 35 }, { 22, 36 }, { 24, 37 }, { 26, 38 }, { 30, 39 },
+       { 31, 117 }, { 32, 41 }, { 34, 42 }, { 36, 43 }, { 37, 44 },
+       { 38, 45 }, { 39, 46 }, { 40, 47 }, { 41, 115 }, { 43, 49 },
+       { 44, 50 }, { 46, 51 }, { 48, 52 }, { 49, 118 }, { 52, 54 },
+       { 53, 55 }, { 54, 56 }, { 56, 57 }, { 57, 58 }, { 58, 59 },
+       { 59, 60 }, { 60, 61 }, { 61, 62 }, { 62, 63 }, { 63, 64 },
+       { 64, 65 }, { 66, 66 }, { 68, 67 }, { 71, 68 }, { 73, 69 },
+       { 77, 70 }, { 78, 71 }, { 79, 72 }, { 80, 73 }, { 84, 74 },
+       { 85, 75 }, { 86, 76 }, { 88, 77 }, { 89, 116 }, { 91, 79 },
+       { 92, 80 }, { 95, 81 }, { 96, 82 }, { 97, 83 }, { 101, 84 },
+       { 103, 85 }, { 104, 86 }, { 115, 90 }, { 116, 91 }, { 117, 92 },
+       { 118, 93 }, { 119, 94 }, { 120, 95 }, { 121, 96 }, { 122, 97 },
+       { 123, 98 }, { 124, 99 }, { 125, 100 }, { 127, 102 }, { 128, 103 },
+       { 129, 104 }, { 130, 105 }, { 132, 106 }, { 133, 107 }, { 145, 108 },
+};
+
 static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
        .pins = sdm845_pins,
        .npins = ARRAY_SIZE(sdm845_pins),
@@ -1290,6 +1308,9 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
        .groups = sdm845_groups,
        .ngroups = ARRAY_SIZE(sdm845_groups),
        .ngpios = 151,
+       .wakeirq_map = sdm845_pdc_map,
+       .nwakeirq_map = ARRAY_SIZE(sdm845_pdc_map),
+
 };
 
 static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = {
index ee5f08e..5f57282 100644 (file)
@@ -132,9 +132,9 @@ config CROS_EC_LPC
          module will be called cros_ec_lpcs.
 
 config CROS_EC_PROTO
-        bool
-        help
-          ChromeOS EC communication protocol helpers.
+       bool
+       help
+         ChromeOS EC communication protocol helpers.
 
 config CROS_KBD_LED_BACKLIGHT
        tristate "Backlight LED support for Chrome OS keyboards"
@@ -190,6 +190,19 @@ config CROS_EC_DEBUGFS
          To compile this driver as a module, choose M here: the
          module will be called cros_ec_debugfs.
 
+config CROS_EC_SENSORHUB
+       tristate "ChromeOS EC MEMS Sensor Hub"
+       depends on MFD_CROS_EC_DEV
+       default MFD_CROS_EC_DEV
+       help
+         Allow loading IIO sensors. This driver is loaded by MFD and will in
+         turn query the EC and register the sensors.
+         It also spreads the sensor data coming from the EC to the IIO sensor
+         object.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cros_ec_sensorhub.
+
 config CROS_EC_SYSFS
        tristate "ChromeOS EC control and information through sysfs"
        depends on MFD_CROS_EC_DEV && SYSFS
index 477ec3d..aacd592 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV)         += cros_ec_chardev.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_SENSORHUB)                += cros_ec_sensorhub.o
 obj-$(CONFIG_CROS_EC_SYSFS)            += cros_ec_sysfs.o
 obj-$(CONFIG_CROS_USBPD_LOGGER)                += cros_usbpd_logger.o
 
index fd77e6f..6d6ce86 100644 (file)
@@ -31,13 +31,32 @@ static struct cros_ec_platform pd_p = {
        .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),
 };
 
-static irqreturn_t ec_irq_thread(int irq, void *data)
+static irqreturn_t ec_irq_handler(int irq, void *data)
 {
        struct cros_ec_device *ec_dev = data;
-       bool wake_event = true;
+
+       ec_dev->last_event_time = cros_ec_get_time_ns();
+
+       return IRQ_WAKE_THREAD;
+}
+
+/**
+ * cros_ec_handle_event() - process and forward pending events on EC
+ * @ec_dev: Device with events to process.
+ *
+ * Call this function in a loop when the kernel is notified that the EC has
+ * pending events.
+ *
+ * Return: true if more events are still pending and this function should be
+ * called again.
+ */
+bool cros_ec_handle_event(struct cros_ec_device *ec_dev)
+{
+       bool wake_event;
+       bool ec_has_more_events;
        int ret;
 
-       ret = cros_ec_get_next_event(ec_dev, &wake_event);
+       ret = cros_ec_get_next_event(ec_dev, &wake_event, &ec_has_more_events);
 
        /*
         * Signal only if wake host events or any interrupt if
@@ -50,6 +69,20 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
        if (ret > 0)
                blocking_notifier_call_chain(&ec_dev->event_notifier,
                                             0, ec_dev);
+
+       return ec_has_more_events;
+}
+EXPORT_SYMBOL(cros_ec_handle_event);
+
+static irqreturn_t ec_irq_thread(int irq, void *data)
+{
+       struct cros_ec_device *ec_dev = data;
+       bool ec_has_more_events;
+
+       do {
+               ec_has_more_events = cros_ec_handle_event(ec_dev);
+       } while (ec_has_more_events);
+
        return IRQ_HANDLED;
 }
 
@@ -104,6 +137,15 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
        return ret;
 }
 
+/**
+ * cros_ec_register() - Register a new ChromeOS EC, using the provided info.
+ * @ec_dev: Device to register.
+ *
+ * Before calling this, allocate a pointer to a new device and then fill
+ * in all the fields up to the --private-- marker.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_register(struct cros_ec_device *ec_dev)
 {
        struct device *dev = ec_dev->dev;
@@ -131,10 +173,12 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
                return err;
        }
 
-       if (ec_dev->irq) {
-               err = devm_request_threaded_irq(dev, ec_dev->irq, NULL,
-                               ec_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-                               "chromeos-ec", ec_dev);
+       if (ec_dev->irq > 0) {
+               err = devm_request_threaded_irq(dev, ec_dev->irq,
+                                               ec_irq_handler,
+                                               ec_irq_thread,
+                                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                               "chromeos-ec", ec_dev);
                if (err) {
                        dev_err(dev, "Failed to request IRQ %d: %d",
                                ec_dev->irq, err);
@@ -198,6 +242,14 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 }
 EXPORT_SYMBOL(cros_ec_register);
 
+/**
+ * cros_ec_unregister() - Remove a ChromeOS EC.
+ * @ec_dev: Device to unregister.
+ *
+ * Call this to deregister a ChromeOS EC, then clean up any private data.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_unregister(struct cros_ec_device *ec_dev)
 {
        if (ec_dev->pd)
@@ -209,6 +261,14 @@ int cros_ec_unregister(struct cros_ec_device *ec_dev)
 EXPORT_SYMBOL(cros_ec_unregister);
 
 #ifdef CONFIG_PM_SLEEP
+/**
+ * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
+ * @ec_dev: Device to suspend.
+ *
+ * This can be called by drivers to handle a suspend event.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_suspend(struct cros_ec_device *ec_dev)
 {
        struct device *dev = ec_dev->dev;
@@ -238,11 +298,19 @@ EXPORT_SYMBOL(cros_ec_suspend);
 static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
 {
        while (ec_dev->mkbp_event_supported &&
-              cros_ec_get_next_event(ec_dev, NULL) > 0)
+              cros_ec_get_next_event(ec_dev, NULL, NULL) > 0)
                blocking_notifier_call_chain(&ec_dev->event_notifier,
                                             1, ec_dev);
 }
 
+/**
+ * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
+ * @ec_dev: Device to resume.
+ *
+ * This can be called by drivers to handle a resume event.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_resume(struct cros_ec_device *ec_dev)
 {
        int ret;
index 25ca2c8..e599682 100644 (file)
@@ -136,11 +136,11 @@ static void ish_evt_handler(struct work_struct *work)
        struct ishtp_cl_data *client_data =
                container_of(work, struct ishtp_cl_data, work_ec_evt);
        struct cros_ec_device *ec_dev = client_data->ec_dev;
+       bool ec_has_more_events;
 
-       if (cros_ec_get_next_event(ec_dev, NULL) > 0) {
-               blocking_notifier_call_chain(&ec_dev->event_notifier,
-                                            0, ec_dev);
-       }
+       do {
+               ec_has_more_events = cros_ec_handle_event(ec_dev);
+       } while (ec_has_more_events);
 }
 
 /**
@@ -200,13 +200,14 @@ static int ish_send(struct ishtp_cl_data *client_data,
  * process_recv() - Received and parse incoming packet
  * @cros_ish_cl: Client instance to get stats
  * @rb_in_proc: Host interface message buffer
+ * @timestamp: Timestamp of when parent callback started
  *
  * Parse the incoming packet. If it is a response packet then it will
  * update per instance flags and wake up the caller waiting to for the
  * response. If it is an event packet then it will schedule event work.
  */
 static void process_recv(struct ishtp_cl *cros_ish_cl,
-                        struct ishtp_cl_rb *rb_in_proc)
+                        struct ishtp_cl_rb *rb_in_proc, ktime_t timestamp)
 {
        size_t data_len = rb_in_proc->buf_idx;
        struct ishtp_cl_data *client_data =
@@ -295,6 +296,11 @@ error_wake_up:
                break;
 
        case CROS_MKBP_EVENT:
+               /*
+                * Set timestamp from beginning of function since we actually
+                * got an incoming MKBP event
+                */
+               client_data->ec_dev->last_event_time = timestamp;
                /* The event system doesn't send any data in buffer */
                schedule_work(&client_data->work_ec_evt);
 
@@ -322,10 +328,17 @@ static void ish_event_cb(struct ishtp_cl_device *cl_device)
 {
        struct ishtp_cl_rb *rb_in_proc;
        struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+       ktime_t timestamp;
+
+       /*
+        * Take timestamp as close to hardware interrupt as possible for sensor
+        * timestamps.
+        */
+       timestamp = cros_ec_get_time_ns();
 
        while ((rb_in_proc = ishtp_cl_rx_get_rb(cros_ish_cl)) != NULL) {
                /* Decide what to do with received data */
-               process_recv(cros_ish_cl, rb_in_proc);
+               process_recv(cros_ish_cl, rb_in_proc, timestamp);
        }
 }
 
index 7d10d90..dccf479 100644 (file)
@@ -312,11 +312,20 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
 static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
 {
        struct cros_ec_device *ec_dev = data;
+       bool ec_has_more_events;
+       int ret;
 
-       if (ec_dev->mkbp_event_supported &&
-           cros_ec_get_next_event(ec_dev, NULL) > 0)
-               blocking_notifier_call_chain(&ec_dev->event_notifier, 0,
-                                            ec_dev);
+       ec_dev->last_event_time = cros_ec_get_time_ns();
+
+       if (ec_dev->mkbp_event_supported)
+               do {
+                       ret = cros_ec_get_next_event(ec_dev, NULL,
+                                                    &ec_has_more_events);
+                       if (ret > 0)
+                               blocking_notifier_call_chain(
+                                               &ec_dev->event_notifier, 0,
+                                               ec_dev);
+               } while (ec_has_more_events);
 
        if (value == ACPI_NOTIFY_DEVICE_WAKE)
                pm_system_wakeup();
index f659f96..da1b1c4 100644 (file)
@@ -117,6 +117,17 @@ static int send_command(struct cros_ec_device *ec_dev,
        return ret;
 }
 
+/**
+ * cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
+ * @ec_dev: Device to register.
+ * @msg: Message to write.
+ *
+ * This is intended to be used by all ChromeOS EC drivers, but at present
+ * only SPI uses it. Once LPC uses the same protocol it can start using it.
+ * I2C could use it now, with a refactor of the existing code.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
                       struct cros_ec_command *msg)
 {
@@ -141,6 +152,16 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
 }
 EXPORT_SYMBOL(cros_ec_prepare_tx);
 
+/**
+ * cros_ec_check_result() - Check ec_msg->result.
+ * @ec_dev: EC device.
+ * @msg: Message to check.
+ *
+ * This is used by ChromeOS EC drivers to check the ec_msg->result for
+ * errors and to warn about them.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_check_result(struct cros_ec_device *ec_dev,
                         struct cros_ec_command *msg)
 {
@@ -326,6 +347,13 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
        return ret;
 }
 
+/**
+ * cros_ec_query_all() -  Query the protocol version supported by the
+ *         ChromeOS EC.
+ * @ec_dev: Device to register.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_query_all(struct cros_ec_device *ec_dev)
 {
        struct device *dev = ec_dev->dev;
@@ -428,7 +456,10 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
        if (ret < 0 || ver_mask == 0)
                ec_dev->mkbp_event_supported = 0;
        else
-               ec_dev->mkbp_event_supported = 1;
+               ec_dev->mkbp_event_supported = fls(ver_mask);
+
+       dev_dbg(ec_dev->dev, "MKBP support version %u\n",
+               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,
@@ -453,6 +484,16 @@ exit:
 }
 EXPORT_SYMBOL(cros_ec_query_all);
 
+/**
+ * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
+ * @ec_dev: EC device.
+ * @msg: Message to write.
+ *
+ * Call this to send a command to the ChromeOS EC.  This should be used
+ * instead of calling the EC's cmd_xfer() callback directly.
+ *
+ * Return: 0 on success or negative error code.
+ */
 int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
                     struct cros_ec_command *msg)
 {
@@ -500,6 +541,18 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
 }
 EXPORT_SYMBOL(cros_ec_cmd_xfer);
 
+/**
+ * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
+ * @ec_dev: EC device.
+ * @msg: Message to write.
+ *
+ * This function is identical to cros_ec_cmd_xfer, except it returns success
+ * status only if both the command was transmitted successfully and the EC
+ * replied with success status. It's not necessary to check msg->result when
+ * using this function.
+ *
+ * Return: The number of bytes transferred on success or negative error code.
+ */
 int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
                            struct cros_ec_command *msg)
 {
@@ -519,6 +572,7 @@ EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
 
 static int get_next_event_xfer(struct cros_ec_device *ec_dev,
                               struct cros_ec_command *msg,
+                              struct ec_response_get_next_event_v1 *event,
                               int version, uint32_t size)
 {
        int ret;
@@ -531,7 +585,7 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
        ret = cros_ec_cmd_xfer(ec_dev, msg);
        if (ret > 0) {
                ec_dev->event_size = ret - 1;
-               memcpy(&ec_dev->event_data, msg->data, ret);
+               ec_dev->event_data = *event;
        }
 
        return ret;
@@ -539,30 +593,26 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
 
 static int get_next_event(struct cros_ec_device *ec_dev)
 {
-       u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
-       struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
-       static int cmd_version = 1;
-       int ret;
+       struct {
+               struct cros_ec_command msg;
+               struct ec_response_get_next_event_v1 event;
+       } __packed buf;
+       struct cros_ec_command *msg = &buf.msg;
+       struct ec_response_get_next_event_v1 *event = &buf.event;
+       const int cmd_version = ec_dev->mkbp_event_supported - 1;
 
+       memset(msg, 0, sizeof(*msg));
        if (ec_dev->suspended) {
                dev_dbg(ec_dev->dev, "Device suspended.\n");
                return -EHOSTDOWN;
        }
 
-       if (cmd_version == 1) {
-               ret = get_next_event_xfer(ec_dev, msg, cmd_version,
-                               sizeof(struct ec_response_get_next_event_v1));
-               if (ret < 0 || msg->result != EC_RES_INVALID_VERSION)
-                       return ret;
-
-               /* Fallback to version 0 for future send attempts */
-               cmd_version = 0;
-       }
-
-       ret = get_next_event_xfer(ec_dev, msg, cmd_version,
+       if (cmd_version == 0)
+               return get_next_event_xfer(ec_dev, msg, event, 0,
                                  sizeof(struct ec_response_get_next_event));
 
-       return ret;
+       return get_next_event_xfer(ec_dev, msg, event, cmd_version,
+                               sizeof(struct ec_response_get_next_event_v1));
 }
 
 static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
@@ -584,27 +634,60 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
        return ec_dev->event_size;
 }
 
-int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
+/**
+ * cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.
+ * @ec_dev: Device to fetch event from.
+ * @wake_event: Pointer to a bool set to true upon return if the event might be
+ *              treated as a wake event. Ignored if null.
+ * @has_more_events: Pointer to bool set to true if more than one event is
+ *              pending.
+ *              Some EC will set this flag to indicate cros_ec_get_next_event()
+ *              can be called multiple times in a row.
+ *              It is an optimization to prevent issuing a EC command for
+ *              nothing or wait for another interrupt from the EC to process
+ *              the next message.
+ *              Ignored if null.
+ *
+ * Return: negative error code on errors; 0 for no data; or else number of
+ * bytes received (i.e., an event was retrieved successfully). Event types are
+ * written out to @ec_dev->event_data.event_type on success.
+ */
+int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
+                          bool *wake_event,
+                          bool *has_more_events)
 {
        u8 event_type;
        u32 host_event;
        int ret;
 
-       if (!ec_dev->mkbp_event_supported) {
-               ret = get_keyboard_state_event(ec_dev);
-               if (ret <= 0)
-                       return ret;
+       /*
+        * Default value for wake_event.
+        * Wake up on keyboard event, wake up for spurious interrupt or link
+        * error to the EC.
+        */
+       if (wake_event)
+               *wake_event = true;
 
-               if (wake_event)
-                       *wake_event = true;
+       /*
+        * Default value for has_more_events.
+        * EC will raise another interrupt if AP does not process all events
+        * anyway.
+        */
+       if (has_more_events)
+               *has_more_events = false;
 
-               return ret;
-       }
+       if (!ec_dev->mkbp_event_supported)
+               return get_keyboard_state_event(ec_dev);
 
        ret = get_next_event(ec_dev);
        if (ret <= 0)
                return ret;
 
+       if (has_more_events)
+               *has_more_events = ec_dev->event_data.event_type &
+                       EC_MKBP_HAS_MORE_EVENTS;
+       ec_dev->event_data.event_type &= EC_MKBP_EVENT_TYPE_MASK;
+
        if (wake_event) {
                event_type = ec_dev->event_data.event_type;
                host_event = cros_ec_get_host_event(ec_dev);
@@ -619,15 +702,22 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
                else if (host_event &&
                         !(host_event & ec_dev->host_event_wake_mask))
                        *wake_event = false;
-               /* Consider all other events as wake events. */
-               else
-                       *wake_event = true;
        }
 
        return ret;
 }
 EXPORT_SYMBOL(cros_ec_get_next_event);
 
+/**
+ * cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.
+ * @ec_dev: Device to fetch event from.
+ *
+ * When MKBP is supported, when the EC raises an interrupt, we collect the
+ * events raised and call the functions in the ec notifier. This function
+ * is a helper to know which events are raised.
+ *
+ * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
+ */
 u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
 {
        u32 host_event;
@@ -647,3 +737,120 @@ u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
        return host_event;
 }
 EXPORT_SYMBOL(cros_ec_get_host_event);
+
+/**
+ * cros_ec_check_features() - Test for the presence of EC features
+ *
+ * @ec: EC device, does not have to be connected directly to the AP,
+ *      can be daisy chained through another device.
+ * @feature: One of ec_feature_code bit.
+ *
+ * Call this function to test whether the ChromeOS EC supports a feature.
+ *
+ * Return: 1 if supported, 0 if not
+ */
+int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
+{
+       struct cros_ec_command *msg;
+       int ret;
+
+       if (ec->features[0] == -1U && ec->features[1] == -1U) {
+               /* features bitmap not read yet */
+               msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
+               if (!msg)
+                       return -ENOMEM;
+
+               msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
+               msg->insize = sizeof(ec->features);
+
+               ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+               if (ret < 0) {
+                       dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
+                                ret, msg->result);
+                       memset(ec->features, 0, sizeof(ec->features));
+               } else {
+                       memcpy(ec->features, msg->data, sizeof(ec->features));
+               }
+
+               dev_dbg(ec->dev, "EC features %08x %08x\n",
+                       ec->features[0], ec->features[1]);
+
+               kfree(msg);
+       }
+
+       return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
+}
+EXPORT_SYMBOL_GPL(cros_ec_check_features);
+
+/**
+ * cros_ec_get_sensor_count() - Return the number of MEMS sensors supported.
+ *
+ * @ec: EC device, does not have to be connected directly to the AP,
+ *      can be daisy chained through another device.
+ * Return: < 0 in case of error.
+ */
+int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
+{
+       /*
+        * Issue a command to get the number of sensor reported.
+        * If not supported, check for legacy mode.
+        */
+       int ret, sensor_count;
+       struct ec_params_motion_sense *params;
+       struct ec_response_motion_sense *resp;
+       struct cros_ec_command *msg;
+       struct cros_ec_device *ec_dev = ec->ec_dev;
+       u8 status;
+
+       msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
+                     GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->version = 1;
+       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
+       msg->outsize = sizeof(*params);
+       msg->insize = sizeof(*resp);
+
+       params = (struct ec_params_motion_sense *)msg->data;
+       params->cmd = MOTIONSENSE_CMD_DUMP;
+
+       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       if (ret < 0) {
+               sensor_count = ret;
+       } else if (msg->result != EC_RES_SUCCESS) {
+               sensor_count = -EPROTO;
+       } else {
+               resp = (struct ec_response_motion_sense *)msg->data;
+               sensor_count = resp->dump.sensor_count;
+       }
+       kfree(msg);
+
+       /*
+        * Check legacy mode: Let's find out if sensors are accessible
+        * via LPC interface.
+        */
+       if (sensor_count == -EPROTO &&
+           ec->cmd_offset == 0 &&
+           ec_dev->cmd_readmem) {
+               ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS,
+                               1, &status);
+               if (ret >= 0 &&
+                   (status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
+                       /*
+                        * We have 2 sensors, one in the lid, one in the base.
+                        */
+                       sensor_count = 2;
+               } else {
+                       /*
+                        * EC uses LPC interface and no sensors are presented.
+                        */
+                       sensor_count = 0;
+               }
+       } else if (sensor_count == -EPROTO) {
+               /* EC responded, but does not understand DUMP command. */
+               sensor_count = 0;
+       }
+       return sensor_count;
+}
+EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
index 0c3738c..bd068af 100644 (file)
@@ -143,22 +143,11 @@ cros_ec_rpmsg_host_event_function(struct work_struct *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);
+       bool ec_has_more_events;
 
-       if (ret > 0)
-               blocking_notifier_call_chain(&ec_dev->event_notifier,
-                                            0, ec_dev);
+       do {
+               ec_has_more_events = cros_ec_handle_event(ec_dev);
+       } while (ec_has_more_events);
 }
 
 static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c
new file mode 100644 (file)
index 0000000..04d8879
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sensor HUB driver that discovers sensors behind a ChromeOS Embedded
+ * Controller.
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_ec_sensorhub.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define DRV_NAME               "cros-ec-sensorhub"
+
+static void cros_ec_sensorhub_free_sensor(void *arg)
+{
+       struct platform_device *pdev = arg;
+
+       platform_device_unregister(pdev);
+}
+
+static int cros_ec_sensorhub_allocate_sensor(struct device *parent,
+                                            char *sensor_name,
+                                            int sensor_num)
+{
+       struct cros_ec_sensor_platform sensor_platforms = {
+               .sensor_num = sensor_num,
+       };
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_data(parent, sensor_name,
+                                            PLATFORM_DEVID_AUTO,
+                                            &sensor_platforms,
+                                            sizeof(sensor_platforms));
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return devm_add_action_or_reset(parent,
+                                       cros_ec_sensorhub_free_sensor,
+                                       pdev);
+}
+
+static int cros_ec_sensorhub_register(struct device *dev,
+                                     struct cros_ec_sensorhub *sensorhub)
+{
+       int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 };
+       struct cros_ec_dev *ec = sensorhub->ec;
+       struct ec_params_motion_sense *params;
+       struct ec_response_motion_sense *resp;
+       struct cros_ec_command *msg;
+       int ret, i, sensor_num;
+       char *name;
+
+       sensor_num = cros_ec_get_sensor_count(ec);
+       if (sensor_num < 0) {
+               dev_err(dev,
+                       "Unable to retrieve sensor information (err:%d)\n",
+                       sensor_num);
+               return sensor_num;
+       }
+
+       if (sensor_num == 0) {
+               dev_err(dev, "Zero sensors reported.\n");
+               return -EINVAL;
+       }
+
+       /* Prepare a message to send INFO command to each sensor. */
+       msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
+                     GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->version = 1;
+       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
+       msg->outsize = sizeof(*params);
+       msg->insize = sizeof(*resp);
+       params = (struct ec_params_motion_sense *)msg->data;
+       resp = (struct ec_response_motion_sense *)msg->data;
+
+       for (i = 0; i < sensor_num; i++) {
+               params->cmd = MOTIONSENSE_CMD_INFO;
+               params->info.sensor_num = i;
+
+               ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+               if (ret < 0) {
+                       dev_warn(dev, "no info for EC sensor %d : %d/%d\n",
+                                i, ret, msg->result);
+                       continue;
+               }
+
+               switch (resp->info.type) {
+               case MOTIONSENSE_TYPE_ACCEL:
+                       name = "cros-ec-accel";
+                       break;
+               case MOTIONSENSE_TYPE_BARO:
+                       name = "cros-ec-baro";
+                       break;
+               case MOTIONSENSE_TYPE_GYRO:
+                       name = "cros-ec-gyro";
+                       break;
+               case MOTIONSENSE_TYPE_MAG:
+                       name = "cros-ec-mag";
+                       break;
+               case MOTIONSENSE_TYPE_PROX:
+                       name = "cros-ec-prox";
+                       break;
+               case MOTIONSENSE_TYPE_LIGHT:
+                       name = "cros-ec-light";
+                       break;
+               case MOTIONSENSE_TYPE_ACTIVITY:
+                       name = "cros-ec-activity";
+                       break;
+               default:
+                       dev_warn(dev, "unknown type %d\n", resp->info.type);
+                       continue;
+               }
+
+               ret = cros_ec_sensorhub_allocate_sensor(dev, name, i);
+               if (ret)
+                       goto error;
+
+               sensor_type[resp->info.type]++;
+       }
+
+       if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
+               ec->has_kb_wake_angle = true;
+
+       if (cros_ec_check_features(ec,
+                                  EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
+               ret = cros_ec_sensorhub_allocate_sensor(dev,
+                                                       "cros-ec-lid-angle",
+                                                       0);
+               if (ret)
+                       goto error;
+       }
+
+       kfree(msg);
+       return 0;
+
+error:
+       kfree(msg);
+       return ret;
+}
+
+static int cros_ec_sensorhub_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct cros_ec_sensorhub *data;
+       int ret;
+       int i;
+
+       data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->ec = dev_get_drvdata(dev->parent);
+       dev_set_drvdata(dev, data);
+
+       /* Check whether this EC is a sensor hub. */
+       if (cros_ec_check_features(data->ec, EC_FEATURE_MOTION_SENSE)) {
+               ret = cros_ec_sensorhub_register(dev, data);
+               if (ret)
+                       return ret;
+       } else {
+               /*
+                * If the device has sensors but does not claim to
+                * be a sensor hub, we are in legacy mode.
+                */
+               for (i = 0; i < 2; i++) {
+                       ret = cros_ec_sensorhub_allocate_sensor(dev,
+                                               "cros-ec-accel-legacy", i);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver cros_ec_sensorhub_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = cros_ec_sensorhub_probe,
+};
+
+module_platform_driver(cros_ec_sensorhub_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
+MODULE_DESCRIPTION("ChromeOS EC MEMS Sensor Hub Driver");
+MODULE_LICENSE("GPL");
index 2430e8b..374cdd1 100644 (file)
@@ -224,6 +224,7 @@ 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);
+       destroy_workqueue(logger->log_workqueue);
 
        return 0;
 }
index 89007b0..365f30e 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config WILCO_EC
        tristate "ChromeOS Wilco Embedded Controller"
-       depends on ACPI && X86 && CROS_EC_LPC
+       depends on ACPI && X86 && CROS_EC_LPC && LEDS_CLASS
        help
          If you say Y here, you get support for talking to the ChromeOS
          Wilco EC over an eSPI bus. This uses a simple byte-level protocol
index bc81716..ecb3145 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
-wilco_ec-objs                          := core.o mailbox.o properties.o sysfs.o
+wilco_ec-objs                          := core.o keyboard_leds.o mailbox.o \
+                                          properties.o sysfs.o
 obj-$(CONFIG_WILCO_EC)                 += wilco_ec.o
 wilco_ec_debugfs-objs                  := debugfs.o
 obj-$(CONFIG_WILCO_EC_DEBUGFS)         += wilco_ec_debugfs.o
index 3724bf4..5210c35 100644 (file)
@@ -5,10 +5,6 @@
  * Copyright 2018 Google LLC
  *
  * This is the entry point for the drivers that control the Wilco EC.
- * This driver is responsible for several tasks:
- * - Initialize the register interface that is used by wilco_ec_mailbox()
- * - Create a platform device which is picked up by the debugfs driver
- * - Create a platform device which is picked up by the RTC driver
  */
 
 #include <linux/acpi.h>
@@ -87,12 +83,31 @@ static int wilco_ec_probe(struct platform_device *pdev)
                goto unregister_debugfs;
        }
 
+       /* Set up the keyboard backlight LEDs. */
+       ret = wilco_keyboard_leds_init(ec);
+       if (ret < 0) {
+               dev_err(dev,
+                       "Failed to initialize keyboard LEDs: %d\n",
+                       ret);
+               goto unregister_rtc;
+       }
+
        ret = wilco_ec_add_sysfs(ec);
        if (ret < 0) {
                dev_err(dev, "Failed to create sysfs entries: %d", ret);
                goto unregister_rtc;
        }
 
+       /* Register child device to be found by charger config driver. */
+       ec->charger_pdev = platform_device_register_data(dev, "wilco-charger",
+                                                        PLATFORM_DEVID_AUTO,
+                                                        NULL, 0);
+       if (IS_ERR(ec->charger_pdev)) {
+               dev_err(dev, "Failed to create charger platform device\n");
+               ret = PTR_ERR(ec->charger_pdev);
+               goto remove_sysfs;
+       }
+
        /* Register child device that will be found by the telemetry driver. */
        ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
                                                       PLATFORM_DEVID_AUTO,
@@ -100,11 +115,13 @@ static int wilco_ec_probe(struct platform_device *pdev)
        if (IS_ERR(ec->telem_pdev)) {
                dev_err(dev, "Failed to create telemetry platform device\n");
                ret = PTR_ERR(ec->telem_pdev);
-               goto remove_sysfs;
+               goto unregister_charge_config;
        }
 
        return 0;
 
+unregister_charge_config:
+       platform_device_unregister(ec->charger_pdev);
 remove_sysfs:
        wilco_ec_remove_sysfs(ec);
 unregister_rtc:
@@ -120,6 +137,7 @@ static int wilco_ec_remove(struct platform_device *pdev)
 {
        struct wilco_ec_device *ec = platform_get_drvdata(pdev);
 
+       platform_device_unregister(ec->charger_pdev);
        wilco_ec_remove_sysfs(ec);
        platform_device_unregister(ec->telem_pdev);
        platform_device_unregister(ec->rtc_pdev);
index 8d65a1e..df5a5f6 100644 (file)
@@ -160,29 +160,29 @@ static const struct file_operations fops_raw = {
 
 #define CMD_KB_CHROME          0x88
 #define SUB_CMD_H1_GPIO                0x0A
+#define SUB_CMD_TEST_EVENT     0x0B
 
-struct h1_gpio_status_request {
+struct ec_request {
        u8 cmd;         /* Always CMD_KB_CHROME */
        u8 reserved;
-       u8 sub_cmd;     /* Always SUB_CMD_H1_GPIO */
+       u8 sub_cmd;
 } __packed;
 
-struct hi_gpio_status_response {
+struct ec_response {
        u8 status;      /* 0 if allowed */
-       u8 val;         /* BIT(0)=ENTRY_TO_FACT_MODE, BIT(1)=SPI_CHROME_SEL */
+       u8 val;
 } __packed;
 
-static int h1_gpio_get(void *arg, u64 *val)
+static int send_ec_cmd(struct wilco_ec_device *ec, u8 sub_cmd, u8 *out_val)
 {
-       struct wilco_ec_device *ec = arg;
-       struct h1_gpio_status_request rq;
-       struct hi_gpio_status_response rs;
+       struct ec_request rq;
+       struct ec_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;
+       rq.sub_cmd = sub_cmd;
 
        memset(&msg, 0, sizeof(msg));
        msg.type = WILCO_EC_MSG_LEGACY;
@@ -196,13 +196,38 @@ static int h1_gpio_get(void *arg, u64 *val)
        if (rs.status)
                return -EIO;
 
-       *val = rs.val;
+       *out_val = rs.val;
 
        return 0;
 }
 
+/**
+ * h1_gpio_get() - Gets h1 gpio status.
+ * @arg: The wilco EC device.
+ * @val: BIT(0)=ENTRY_TO_FACT_MODE, BIT(1)=SPI_CHROME_SEL
+ */
+static int h1_gpio_get(void *arg, u64 *val)
+{
+       return send_ec_cmd(arg, SUB_CMD_H1_GPIO, (u8 *)val);
+}
+
 DEFINE_DEBUGFS_ATTRIBUTE(fops_h1_gpio, h1_gpio_get, NULL, "0x%02llx\n");
 
+/**
+ * test_event_set() - Sends command to EC to cause an EC test event.
+ * @arg: The wilco EC device.
+ * @val: unused.
+ */
+static int test_event_set(void *arg, u64 val)
+{
+       u8 ret;
+
+       return send_ec_cmd(arg, SUB_CMD_TEST_EVENT, &ret);
+}
+
+/* Format is unused since it is only required for get method which is NULL */
+DEFINE_DEBUGFS_ATTRIBUTE(fops_test_event, NULL, test_event_set, "%llu\n");
+
 /**
  * wilco_ec_debugfs_probe() - Create the debugfs node
  * @pdev: The platform device, probably created in core.c
@@ -226,6 +251,8 @@ static int wilco_ec_debugfs_probe(struct platform_device *pdev)
        debugfs_create_file("raw", 0644, debug_info->dir, NULL, &fops_raw);
        debugfs_create_file("h1_gpio", 0444, debug_info->dir, ec,
                            &fops_h1_gpio);
+       debugfs_create_file("test_event", 0200, debug_info->dir, ec,
+                           &fops_test_event);
 
        return 0;
 }
diff --git a/drivers/platform/chrome/wilco_ec/keyboard_leds.c b/drivers/platform/chrome/wilco_ec/keyboard_leds.c
new file mode 100644 (file)
index 0000000..bb0edf5
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Keyboard backlight LED driver for the Wilco Embedded Controller
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Since the EC will never change the backlight level of its own accord,
+ * we don't need to implement a brightness_get() method.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/slab.h>
+
+#define WILCO_EC_COMMAND_KBBL          0x75
+#define WILCO_KBBL_MODE_FLAG_PWM       BIT(1)  /* Set brightness by percent. */
+#define WILCO_KBBL_DEFAULT_BRIGHTNESS   0
+
+struct wilco_keyboard_leds {
+       struct wilco_ec_device *ec;
+       struct led_classdev keyboard;
+};
+
+enum wilco_kbbl_subcommand {
+       WILCO_KBBL_SUBCMD_GET_FEATURES = 0x00,
+       WILCO_KBBL_SUBCMD_GET_STATE    = 0x01,
+       WILCO_KBBL_SUBCMD_SET_STATE    = 0x02,
+};
+
+/**
+ * struct wilco_keyboard_leds_msg - Message to/from EC for keyboard LED control.
+ * @command: Always WILCO_EC_COMMAND_KBBL.
+ * @status: Set by EC to 0 on success, 0xFF on failure.
+ * @subcmd: One of enum wilco_kbbl_subcommand.
+ * @reserved3: Should be 0.
+ * @mode: Bit flags for used mode, we want to use WILCO_KBBL_MODE_FLAG_PWM.
+ * @reserved5to8: Should be 0.
+ * @percent: Brightness in 0-100. Only meaningful in PWM mode.
+ * @reserved10to15: Should be 0.
+ */
+struct wilco_keyboard_leds_msg {
+       u8 command;
+       u8 status;
+       u8 subcmd;
+       u8 reserved3;
+       u8 mode;
+       u8 reserved5to8[4];
+       u8 percent;
+       u8 reserved10to15[6];
+} __packed;
+
+/* Send a request, get a response, and check that the response is good. */
+static int send_kbbl_msg(struct wilco_ec_device *ec,
+                        struct wilco_keyboard_leds_msg *request,
+                        struct wilco_keyboard_leds_msg *response)
+{
+       struct wilco_ec_message msg;
+       int ret;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.type = WILCO_EC_MSG_LEGACY;
+       msg.request_data = request;
+       msg.request_size = sizeof(*request);
+       msg.response_data = response;
+       msg.response_size = sizeof(*response);
+
+       ret = wilco_ec_mailbox(ec, &msg);
+       if (ret < 0) {
+               dev_err(ec->dev,
+                       "Failed sending keyboard LEDs command: %d", ret);
+               return ret;
+       }
+
+       if (response->status) {
+               dev_err(ec->dev,
+                       "EC reported failure sending keyboard LEDs command: %d",
+                       response->status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int set_kbbl(struct wilco_ec_device *ec, enum led_brightness brightness)
+{
+       struct wilco_keyboard_leds_msg request;
+       struct wilco_keyboard_leds_msg response;
+
+       memset(&request, 0, sizeof(request));
+       request.command = WILCO_EC_COMMAND_KBBL;
+       request.subcmd  = WILCO_KBBL_SUBCMD_SET_STATE;
+       request.mode    = WILCO_KBBL_MODE_FLAG_PWM;
+       request.percent = brightness;
+
+       return send_kbbl_msg(ec, &request, &response);
+}
+
+static int kbbl_exist(struct wilco_ec_device *ec, bool *exists)
+{
+       struct wilco_keyboard_leds_msg request;
+       struct wilco_keyboard_leds_msg response;
+       int ret;
+
+       memset(&request, 0, sizeof(request));
+       request.command = WILCO_EC_COMMAND_KBBL;
+       request.subcmd  = WILCO_KBBL_SUBCMD_GET_FEATURES;
+
+       ret = send_kbbl_msg(ec, &request, &response);
+       if (ret < 0)
+               return ret;
+
+       *exists = response.status != 0xFF;
+
+       return 0;
+}
+
+/**
+ * kbbl_init() - Initialize the state of the keyboard backlight.
+ * @ec: EC device to talk to.
+ *
+ * Gets the current brightness, ensuring that the BIOS already initialized the
+ * backlight to PWM mode. If not in PWM mode, then the current brightness is
+ * meaningless, so set the brightness to WILCO_KBBL_DEFAULT_BRIGHTNESS.
+ *
+ * Return: Final brightness of the keyboard, or negative error code on failure.
+ */
+static int kbbl_init(struct wilco_ec_device *ec)
+{
+       struct wilco_keyboard_leds_msg request;
+       struct wilco_keyboard_leds_msg response;
+       int ret;
+
+       memset(&request, 0, sizeof(request));
+       request.command = WILCO_EC_COMMAND_KBBL;
+       request.subcmd  = WILCO_KBBL_SUBCMD_GET_STATE;
+
+       ret = send_kbbl_msg(ec, &request, &response);
+       if (ret < 0)
+               return ret;
+
+       if (response.mode & WILCO_KBBL_MODE_FLAG_PWM)
+               return response.percent;
+
+       ret = set_kbbl(ec, WILCO_KBBL_DEFAULT_BRIGHTNESS);
+       if (ret < 0)
+               return ret;
+
+       return WILCO_KBBL_DEFAULT_BRIGHTNESS;
+}
+
+static int wilco_keyboard_leds_set(struct led_classdev *cdev,
+                                  enum led_brightness brightness)
+{
+       struct wilco_keyboard_leds *wkl =
+               container_of(cdev, struct wilco_keyboard_leds, keyboard);
+       return set_kbbl(wkl->ec, brightness);
+}
+
+int wilco_keyboard_leds_init(struct wilco_ec_device *ec)
+{
+       struct wilco_keyboard_leds *wkl;
+       bool leds_exist;
+       int ret;
+
+       ret = kbbl_exist(ec, &leds_exist);
+       if (ret < 0) {
+               dev_err(ec->dev,
+                       "Failed checking keyboard LEDs support: %d", ret);
+               return ret;
+       }
+       if (!leds_exist)
+               return 0;
+
+       wkl = devm_kzalloc(ec->dev, sizeof(*wkl), GFP_KERNEL);
+       if (!wkl)
+               return -ENOMEM;
+
+       wkl->ec = ec;
+       wkl->keyboard.name = "platform::kbd_backlight";
+       wkl->keyboard.max_brightness = 100;
+       wkl->keyboard.flags = LED_CORE_SUSPENDRESUME;
+       wkl->keyboard.brightness_set_blocking = wilco_keyboard_leds_set;
+       ret = kbbl_init(ec);
+       if (ret < 0)
+               return ret;
+       wkl->keyboard.brightness = ret;
+
+       return devm_led_classdev_register(ec->dev, &wkl->keyboard);
+}
index 3b86a21..f0d174b 100644 (file)
@@ -23,6 +23,26 @@ struct boot_on_ac_request {
        u8 reserved7;
 } __packed;
 
+#define CMD_USB_CHARGE 0x39
+
+enum usb_charge_op {
+       USB_CHARGE_GET = 0,
+       USB_CHARGE_SET = 1,
+};
+
+struct usb_charge_request {
+       u8 cmd;         /* Always CMD_USB_CHARGE */
+       u8 reserved;
+       u8 op;          /* One of enum usb_charge_op */
+       u8 val;         /* When setting, either 0 or 1 */
+} __packed;
+
+struct usb_charge_response {
+       u8 reserved;
+       u8 status;      /* Set by EC to 0 on success, other value on failure */
+       u8 val;         /* When getting, set by EC to either 0 or 1 */
+} __packed;
+
 #define CMD_EC_INFO                    0x38
 enum get_ec_info_op {
        CMD_GET_EC_LABEL        = 0,
@@ -131,12 +151,83 @@ static ssize_t model_number_show(struct device *dev,
 
 static DEVICE_ATTR_RO(model_number);
 
+static int send_usb_charge(struct wilco_ec_device *ec,
+                               struct usb_charge_request *rq,
+                               struct usb_charge_response *rs)
+{
+       struct wilco_ec_message msg;
+       int ret;
+
+       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;
+
+       return 0;
+}
+
+static ssize_t usb_charge_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(dev);
+       struct usb_charge_request rq;
+       struct usb_charge_response rs;
+       int ret;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.cmd = CMD_USB_CHARGE;
+       rq.op = USB_CHARGE_GET;
+
+       ret = send_usb_charge(ec, &rq, &rs);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", rs.val);
+}
+
+static ssize_t usb_charge_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(dev);
+       struct usb_charge_request rq;
+       struct usb_charge_response rs;
+       int ret;
+       u8 val;
+
+       ret = kstrtou8(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+       if (val > 1)
+               return -EINVAL;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.cmd = CMD_USB_CHARGE;
+       rq.op = USB_CHARGE_SET;
+       rq.val = val;
+
+       ret = send_usb_charge(ec, &rq, &rs);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(usb_charge);
 
 static struct attribute *wilco_dev_attrs[] = {
        &dev_attr_boot_on_ac.attr,
        &dev_attr_build_date.attr,
        &dev_attr_build_revision.attr,
        &dev_attr_model_number.attr,
+       &dev_attr_usb_charge.attr,
        &dev_attr_version.attr,
        NULL,
 };
index b9d03c3..1176d54 100644 (file)
@@ -406,8 +406,8 @@ static int telem_device_remove(struct platform_device *pdev)
        struct telem_device_data *dev_data = platform_get_drvdata(pdev);
 
        cdev_device_del(&dev_data->cdev, &dev_data->dev);
-       put_device(&dev_data->dev);
        ida_simple_remove(&telem_ida, MINOR(dev_data->dev.devt));
+       put_device(&dev_data->dev);
 
        return 0;
 }
index 1041d80..27d5b40 100644 (file)
@@ -258,7 +258,7 @@ config DELL_RBU
         DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
         supporting application to communicate with the BIOS regarding the new
         image for the image update to take effect.
-        See <file:Documentation/driver-api/dell_rbu.rst> for more details on the driver.
+        See <file:Documentation/admin-guide/dell_rbu.rst> for more details on the driver.
 
 
 config FUJITSU_LAPTOP
index 3691391..7d54533 100644 (file)
@@ -24,7 +24,7 @@
  * on every time the packet data is written. This driver requires an
  * application to break the BIOS image in to fixed sized packet chunks.
  *
- * See Documentation/driver-api/dell_rbu.rst for more info.
+ * See Documentation/admin-guide/dell_rbu.rst for more info.
  */
 #include <linux/init.h>
 #include <linux/module.h>
index b5a217b..089b624 100644 (file)
@@ -13,9 +13,9 @@ menuconfig POWER_AVS
          Say Y here to enable Adaptive Voltage Scaling class support.
 
 config ROCKCHIP_IODOMAIN
-        tristate "Rockchip IO domain support"
-        depends on POWER_AVS && ARCH_ROCKCHIP && OF
-        help
-          Say y here to enable support io domains on Rockchip SoCs. It is
-          necessary for the io domain setting of the SoC to match the
-          voltage supplied by the regulators.
+       tristate "Rockchip IO domain support"
+       depends on POWER_AVS && ARCH_ROCKCHIP && OF
+       help
+         Say y here to enable support io domains on Rockchip SoCs. It is
+         necessary for the io domain setting of the SoC to match the
+         voltage supplied by the regulators.
index 359b085..7ff48c1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mfd/stm32-timers.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 
 #define CCMR_CHANNEL_MASK  0xFF
 #define MAX_BREAKINPUT 2
 
+struct stm32_breakinput {
+       u32 index;
+       u32 level;
+       u32 filter;
+};
+
 struct stm32_pwm {
        struct pwm_chip chip;
        struct mutex lock; /* protect pwm config/enable */
@@ -26,15 +33,11 @@ struct stm32_pwm {
        struct regmap *regmap;
        u32 max_arr;
        bool have_complementary_output;
+       struct stm32_breakinput breakinputs[MAX_BREAKINPUT];
+       unsigned int num_breakinputs;
        u32 capture[4] ____cacheline_aligned; /* DMA'able buffer */
 };
 
-struct stm32_breakinput {
-       u32 index;
-       u32 level;
-       u32 filter;
-};
-
 static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
 {
        return container_of(chip, struct stm32_pwm, chip);
@@ -488,22 +491,19 @@ static const struct pwm_ops stm32pwm_ops = {
 };
 
 static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
-                                   int index, int level, int filter)
+                                   const struct stm32_breakinput *bi)
 {
-       u32 bke = (index == 0) ? TIM_BDTR_BKE : TIM_BDTR_BK2E;
-       int shift = (index == 0) ? TIM_BDTR_BKF_SHIFT : TIM_BDTR_BK2F_SHIFT;
-       u32 mask = (index == 0) ? TIM_BDTR_BKE | TIM_BDTR_BKP | TIM_BDTR_BKF
-                               : TIM_BDTR_BK2E | TIM_BDTR_BK2P | TIM_BDTR_BK2F;
-       u32 bdtr = bke;
+       u32 shift = TIM_BDTR_BKF_SHIFT(bi->index);
+       u32 bke = TIM_BDTR_BKE(bi->index);
+       u32 bkp = TIM_BDTR_BKP(bi->index);
+       u32 bkf = TIM_BDTR_BKF(bi->index);
+       u32 mask = bkf | bkp | bke;
+       u32 bdtr;
 
-       /*
-        * The both bits could be set since only one will be wrote
-        * due to mask value.
-        */
-       if (level)
-               bdtr |= TIM_BDTR_BKP | TIM_BDTR_BK2P;
+       bdtr = (bi->filter & TIM_BDTR_BKF_MASK) << shift | bke;
 
-       bdtr |= (filter & TIM_BDTR_BKF_MASK) << shift;
+       if (bi->level)
+               bdtr |= bkp;
 
        regmap_update_bits(priv->regmap, TIM_BDTR, mask, bdtr);
 
@@ -512,11 +512,25 @@ static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
        return (bdtr & bke) ? 0 : -EINVAL;
 }
 
-static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv,
+static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv)
+{
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < priv->num_breakinputs; i++) {
+               ret = stm32_pwm_set_breakinput(priv, &priv->breakinputs[i]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int stm32_pwm_probe_breakinputs(struct stm32_pwm *priv,
                                       struct device_node *np)
 {
-       struct stm32_breakinput breakinput[MAX_BREAKINPUT];
-       int nb, ret, i, array_size;
+       int nb, ret, array_size;
+       unsigned int i;
 
        nb = of_property_count_elems_of_size(np, "st,breakinput",
                                             sizeof(struct stm32_breakinput));
@@ -531,20 +545,21 @@ static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv,
        if (nb > MAX_BREAKINPUT)
                return -EINVAL;
 
+       priv->num_breakinputs = nb;
        array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32);
        ret = of_property_read_u32_array(np, "st,breakinput",
-                                        (u32 *)breakinput, array_size);
+                                        (u32 *)priv->breakinputs, array_size);
        if (ret)
                return ret;
 
-       for (i = 0; i < nb && !ret; i++) {
-               ret = stm32_pwm_set_breakinput(priv,
-                                              breakinput[i].index,
-                                              breakinput[i].level,
-                                              breakinput[i].filter);
+       for (i = 0; i < priv->num_breakinputs; i++) {
+               if (priv->breakinputs[i].index > 1 ||
+                   priv->breakinputs[i].level > 1 ||
+                   priv->breakinputs[i].filter > 15)
+                       return -EINVAL;
        }
 
-       return ret;
+       return stm32_pwm_apply_breakinputs(priv);
 }
 
 static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
@@ -614,7 +629,7 @@ static int stm32_pwm_probe(struct platform_device *pdev)
        if (!priv->regmap || !priv->clk)
                return -EINVAL;
 
-       ret = stm32_pwm_apply_breakinputs(priv, np);
+       ret = stm32_pwm_probe_breakinputs(priv, np);
        if (ret)
                return ret;
 
@@ -647,6 +662,42 @@ static int stm32_pwm_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused stm32_pwm_suspend(struct device *dev)
+{
+       struct stm32_pwm *priv = dev_get_drvdata(dev);
+       unsigned int i;
+       u32 ccer, mask;
+
+       /* Look for active channels */
+       ccer = active_channels(priv);
+
+       for (i = 0; i < priv->chip.npwm; i++) {
+               mask = TIM_CCER_CC1E << (i * 4);
+               if (ccer & mask) {
+                       dev_err(dev, "PWM %u still in use by consumer %s\n",
+                               i, priv->chip.pwms[i].label);
+                       return -EBUSY;
+               }
+       }
+
+       return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int __maybe_unused stm32_pwm_resume(struct device *dev)
+{
+       struct stm32_pwm *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pinctrl_pm_select_default_state(dev);
+       if (ret)
+               return ret;
+
+       /* restore breakinput registers that may have been lost in low power */
+       return stm32_pwm_apply_breakinputs(priv);
+}
+
+static SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
+
 static const struct of_device_id stm32_pwm_of_match[] = {
        { .compatible = "st,stm32-pwm", },
        { /* end node */ },
@@ -659,6 +710,7 @@ static struct platform_driver stm32_pwm_driver = {
        .driver = {
                .name = "stm32-pwm",
                .of_match_table = stm32_pwm_of_match,
+               .pm = &stm32_pwm_pm_ops,
        },
 };
 module_platform_driver(stm32_pwm_driver);
index 6f5840a..581d232 100644 (file)
@@ -137,10 +137,10 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip,
 
        val = sun4i_pwm_readl(sun4i_pwm, PWM_CH_PRD(pwm->hwpwm));
 
-       tmp = prescaler * NSEC_PER_SEC * PWM_REG_DTY(val);
+       tmp = (u64)prescaler * NSEC_PER_SEC * PWM_REG_DTY(val);
        state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
 
-       tmp = prescaler * NSEC_PER_SEC * PWM_REG_PRD(val);
+       tmp = (u64)prescaler * NSEC_PER_SEC * PWM_REG_PRD(val);
        state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
 }
 
@@ -156,7 +156,6 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
        if (sun4i_pwm->data->has_prescaler_bypass) {
                /* First, test without any prescaler when available */
                prescaler = PWM_PRESCAL_MASK;
-               pval = 1;
                /*
                 * When not using any prescaler, the clock period in nanoseconds
                 * is not an integer so round it half up instead of
index 125a173..4dd31dd 100644 (file)
@@ -2755,7 +2755,7 @@ static int tsi721_probe(struct pci_dev *pdev,
        {
                int i;
 
-               for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+               for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                        tsi_debug(INIT, &pdev->dev, "res%d %pR",
                                  i, &pdev->resource[i]);
                }
index 33c8d1e..f9e1064 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/rio.h>
 #include <linux/module.h>
 
+#include <linux/rio_drv.h>
+
 /*
  *  Wrappers for all RIO configuration access functions.  They just check
  *  alignment and call the low-level functions pointed to by rio_mport->ops.
index 2d99a37..7287415 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/rio.h>
 #include <linux/rio_ids.h>
+#include <linux/rio_drv.h>
 
 #include "rio.h"
 
index 7b07281..3ad7817 100644 (file)
@@ -129,7 +129,7 @@ config RESET_SCMI
 
 config RESET_SIMPLE
        bool "Simple Reset Controller Driver" if COMPILE_TEST
-       default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN || ARC
+       default ARCH_AGILEX || ARCH_ASPEED || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARC
        help
          This enables a simple reset controller driver for reset lines that
          that can be asserted and deasserted by toggling bits in a contiguous,
@@ -138,10 +138,11 @@ config RESET_SIMPLE
          Currently this driver supports:
           - Altera SoCFPGAs
           - ASPEED BMC SoCs
+          - Bitmain BM1880 SoC
+          - Realtek SoCs
           - RCC reset controller in STM32 MCUs
           - Allwinner SoCs
           - ZTE's zx2967 family
-          - Bitmain BM1880 SoC
 
 config RESET_STM32MP157
        bool "STM32MP157 Reset Driver" if COMPILE_TEST
index 3c9a64c..ca1d491 100644 (file)
@@ -77,8 +77,10 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
  * @rcdev: a pointer to the reset controller device
  * @reset_spec: reset line specifier as found in the device tree
  *
- * This simple translation function should be used for reset controllers
- * with 1:1 mapping, where reset lines can be indexed by number without gaps.
+ * This static translation function is used by default if of_xlate in
+ * :c:type:`reset_controller_dev` is not set. It is useful for all reset
+ * controllers with 1:1 mapping, where reset lines can be indexed by number
+ * without gaps.
  */
 static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
                          const struct of_phandle_args *reset_spec)
@@ -333,7 +335,6 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
  * internal state to be reset, but must be prepared for this to happen.
  * Consumers must not use reset_control_reset on shared reset lines when
  * reset_control_(de)assert has been used.
- * return 0.
  *
  * If rstc is NULL it is an optional reset and the function will just
  * return 0.
@@ -392,7 +393,6 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
  * After calling this function, the reset is guaranteed to be deasserted.
  * Consumers must not use reset_control_reset on shared reset lines when
  * reset_control_(de)assert has been used.
- * return 0.
  *
  * If rstc is NULL it is an optional reset and the function will just
  * return 0.
index f690b18..a7d4445 100644 (file)
@@ -56,7 +56,7 @@ static int hi3660_reset_dev(struct reset_controller_dev *rcdev,
        return hi3660_reset_deassert(rcdev, idx);
 }
 
-static struct reset_control_ops hi3660_reset_ops = {
+static const struct reset_control_ops hi3660_reset_ops = {
        .reset    = hi3660_reset_dev,
        .assert   = hi3660_reset_assert,
        .deassert = hi3660_reset_deassert,
index c53a218..1dc06e0 100644 (file)
@@ -19,6 +19,11 @@ struct meson_audio_arb_data {
        spinlock_t lock;
 };
 
+struct meson_audio_arb_match_data {
+       const unsigned int *reset_bits;
+       unsigned int reset_num;
+};
+
 #define ARB_GENERAL_BIT        31
 
 static const unsigned int axg_audio_arb_reset_bits[] = {
@@ -30,6 +35,27 @@ static const unsigned int axg_audio_arb_reset_bits[] = {
        [AXG_ARB_FRDDR_C]       = 6,
 };
 
+static const struct meson_audio_arb_match_data axg_audio_arb_match = {
+       .reset_bits = axg_audio_arb_reset_bits,
+       .reset_num = ARRAY_SIZE(axg_audio_arb_reset_bits),
+};
+
+static const unsigned int sm1_audio_arb_reset_bits[] = {
+       [AXG_ARB_TODDR_A]       = 0,
+       [AXG_ARB_TODDR_B]       = 1,
+       [AXG_ARB_TODDR_C]       = 2,
+       [AXG_ARB_FRDDR_A]       = 4,
+       [AXG_ARB_FRDDR_B]       = 5,
+       [AXG_ARB_FRDDR_C]       = 6,
+       [AXG_ARB_TODDR_D]       = 3,
+       [AXG_ARB_FRDDR_D]       = 7,
+};
+
+static const struct meson_audio_arb_match_data sm1_audio_arb_match = {
+       .reset_bits = sm1_audio_arb_reset_bits,
+       .reset_num = ARRAY_SIZE(sm1_audio_arb_reset_bits),
+};
+
 static int meson_audio_arb_update(struct reset_controller_dev *rcdev,
                                  unsigned long id, bool assert)
 {
@@ -82,7 +108,13 @@ static const struct reset_control_ops meson_audio_arb_rstc_ops = {
 };
 
 static const struct of_device_id meson_audio_arb_of_match[] = {
-       { .compatible = "amlogic,meson-axg-audio-arb", },
+       {
+               .compatible = "amlogic,meson-axg-audio-arb",
+               .data = &axg_audio_arb_match,
+       }, {
+               .compatible = "amlogic,meson-sm1-audio-arb",
+               .data = &sm1_audio_arb_match,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match);
@@ -104,10 +136,15 @@ static int meson_audio_arb_remove(struct platform_device *pdev)
 static int meson_audio_arb_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct meson_audio_arb_match_data *data;
        struct meson_audio_arb_data *arb;
        struct resource *res;
        int ret;
 
+       data = of_device_get_match_data(dev);
+       if (!data)
+               return -EINVAL;
+
        arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
        if (!arb)
                return -ENOMEM;
@@ -126,8 +163,8 @@ static int meson_audio_arb_probe(struct platform_device *pdev)
                return PTR_ERR(arb->regs);
 
        spin_lock_init(&arb->lock);
-       arb->reset_bits = axg_audio_arb_reset_bits;
-       arb->rstc.nr_resets = ARRAY_SIZE(axg_audio_arb_reset_bits);
+       arb->reset_bits = data->reset_bits;
+       arb->rstc.nr_resets = data->reset_num;
        arb->rstc.ops = &meson_audio_arb_rstc_ops;
        arb->rstc.of_node = dev->of_node;
        arb->rstc.owner = THIS_MODULE;
index 7d05d76..94d7ba8 100644 (file)
 #include <linux/types.h>
 #include <linux/of_device.h>
 
-#define REG_COUNT      8
 #define BITS_PER_REG   32
-#define LEVEL_OFFSET   0x7c
+
+struct meson_reset_param {
+       int reg_count;
+       int level_offset;
+};
 
 struct meson_reset {
        void __iomem *reg_base;
+       const struct meson_reset_param *param;
        struct reset_controller_dev rcdev;
        spinlock_t lock;
 };
@@ -46,10 +50,12 @@ static int meson_reset_level(struct reset_controller_dev *rcdev,
                container_of(rcdev, struct meson_reset, rcdev);
        unsigned int bank = id / BITS_PER_REG;
        unsigned int offset = id % BITS_PER_REG;
-       void __iomem *reg_addr = data->reg_base + LEVEL_OFFSET + (bank << 2);
+       void __iomem *reg_addr;
        unsigned long flags;
        u32 reg;
 
+       reg_addr = data->reg_base + data->param->level_offset + (bank << 2);
+
        spin_lock_irqsave(&data->lock, flags);
 
        reg = readl(reg_addr);
@@ -81,10 +87,21 @@ static const struct reset_control_ops meson_reset_ops = {
        .deassert       = meson_reset_deassert,
 };
 
+static const struct meson_reset_param meson8b_param = {
+       .reg_count      = 8,
+       .level_offset   = 0x7c,
+};
+
+static const struct meson_reset_param meson_a1_param = {
+       .reg_count      = 3,
+       .level_offset   = 0x40,
+};
+
 static const struct of_device_id meson_reset_dt_ids[] = {
-        { .compatible = "amlogic,meson8b-reset" },
-        { .compatible = "amlogic,meson-gxbb-reset" },
-        { .compatible = "amlogic,meson-axg-reset" },
+        { .compatible = "amlogic,meson8b-reset",    .data = &meson8b_param},
+        { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param},
+        { .compatible = "amlogic,meson-axg-reset",  .data = &meson8b_param},
+        { .compatible = "amlogic,meson-a1-reset",   .data = &meson_a1_param},
         { /* sentinel */ },
 };
 
@@ -102,12 +119,16 @@ static int meson_reset_probe(struct platform_device *pdev)
        if (IS_ERR(data->reg_base))
                return PTR_ERR(data->reg_base);
 
+       data->param = of_device_get_match_data(&pdev->dev);
+       if (!data->param)
+               return -ENODEV;
+
        platform_set_drvdata(pdev, data);
 
        spin_lock_init(&data->lock);
 
        data->rcdev.owner = THIS_MODULE;
-       data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG;
+       data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG;
        data->rcdev.ops = &meson_reset_ops;
        data->rcdev.of_node = pdev->dev.of_node;
 
index a45923f..2b188b3 100644 (file)
@@ -140,6 +140,10 @@ static const struct of_device_id uniphier_glue_reset_match[] = {
                .compatible = "socionext,uniphier-pro4-usb3-reset",
                .data = &uniphier_pro4_data,
        },
+       {
+               .compatible = "socionext,uniphier-pro5-usb3-reset",
+               .data = &uniphier_pro4_data,
+       },
        {
                .compatible = "socionext,uniphier-pxs2-usb3-reset",
                .data = &uniphier_pxs2_data,
index 99e75d9..0144075 100644 (file)
@@ -64,7 +64,7 @@ static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
                                            PM_RESET_ACTION_PULSE);
 }
 
-static struct reset_control_ops zynqmp_reset_ops = {
+static const struct reset_control_ops zynqmp_reset_ops = {
        .reset = zynqmp_reset_reset,
        .assert = zynqmp_reset_assert,
        .deassert = zynqmp_reset_deassert,
index 1adf9f8..d77515d 100644 (file)
@@ -373,17 +373,6 @@ config RTC_DRV_MAX77686
          This driver can also be built as a module. If so, the module
          will be called rtc-max77686.
 
-config RTC_DRV_MESON_VRTC
-       tristate "Amlogic Meson Virtual RTC"
-       depends on ARCH_MESON || COMPILE_TEST
-       default m if ARCH_MESON
-       help
-         If you say yes here you will get support for the
-         Virtual RTC of Amlogic SoCs.
-
-         This driver can also be built as a module. If so, the module
-         will be called rtc-meson-vrtc.
-
 config RTC_DRV_RK808
        tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
        depends on MFD_RK808
@@ -1337,8 +1326,6 @@ config RTC_DRV_IMXDI
 config RTC_DRV_FSL_FTM_ALARM
        tristate "Freescale FlexTimer alarm timer"
        depends on ARCH_LAYERSCAPE || SOC_LS1021A
-       select FSL_RCPM
-       default y
        help
           For the FlexTimer in LS1012A, LS1021A, LS1028A, LS1043A, LS1046A,
           LS1088A, LS208xA, we can use FTM as the wakeup source.
@@ -1360,6 +1347,17 @@ config RTC_DRV_MESON
           This driver can also be built as a module, if so, the module
           will be called "rtc-meson".
 
+config RTC_DRV_MESON_VRTC
+       tristate "Amlogic Meson Virtual RTC"
+       depends on ARCH_MESON || COMPILE_TEST
+       default m if ARCH_MESON
+       help
+         If you say yes here you will get support for the
+         Virtual RTC of Amlogic SoCs.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-meson-vrtc.
+
 config RTC_DRV_OMAP
        tristate "TI OMAP Real Time Clock"
        depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
@@ -1459,6 +1457,7 @@ config RTC_DRV_PL031
 config RTC_DRV_AT91RM9200
        tristate "AT91RM9200 or some AT91SAM9 RTC"
        depends on ARCH_AT91 || COMPILE_TEST
+       depends on OF
        help
          Driver for the internal RTC (Realtime Clock) module found on
          Atmel AT91RM9200's and some  AT91SAM9 chips. On AT91SAM9 chips
@@ -1510,9 +1509,9 @@ config RTC_DRV_PXA
        depends on ARCH_PXA
        select RTC_DRV_SA1100
        help
-         If you say Y here you will get access to the real time clock
-         built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs
-         consisting of an SA1100 compatible RTC and the extended PXA RTC.
+        If you say Y here you will get access to the real time clock
+        built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs
+        consisting of an SA1100 compatible RTC and the extended PXA RTC.
 
         This RTC driver uses PXA RTC registers available since pxa27x
         series (RDxR, RYxR) instead of legacy RCNR, RTAR.
index c93ef33..794a4f0 100644 (file)
@@ -70,7 +70,7 @@ static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
                time64_t time = rtc_tm_to_time64(tm);
                time64_t range_min = rtc->set_start_time ? rtc->start_secs :
                        rtc->range_min;
-               time64_t range_max = rtc->set_start_time ?
+               timeu64_t range_max = rtc->set_start_time ?
                        (rtc->start_secs + rtc->range_max - rtc->range_min) :
                        rtc->range_max;
 
@@ -125,7 +125,7 @@ EXPORT_SYMBOL_GPL(rtc_read_time);
 
 int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
 {
-       int err;
+       int err, uie;
 
        err = rtc_valid_tm(tm);
        if (err != 0)
@@ -137,6 +137,17 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
 
        rtc_subtract_offset(rtc, tm);
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       uie = rtc->uie_rtctimer.enabled || rtc->uie_irq_active;
+#else
+       uie = rtc->uie_rtctimer.enabled;
+#endif
+       if (uie) {
+               err = rtc_update_irq_enable(rtc, 0);
+               if (err)
+                       return err;
+       }
+
        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
                return err;
@@ -153,6 +164,12 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
        /* A timer might have just expired */
        schedule_work(&rtc->irqwork);
 
+       if (uie) {
+               err = rtc_update_irq_enable(rtc, 1);
+               if (err)
+                       return err;
+       }
+
        trace_rtc_set_time(rtc_tm_to_time64(tm), err);
        return err;
 }
@@ -528,7 +545,7 @@ EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
 
 int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
 {
-       int err;
+       int rc = 0, err;
 
        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
@@ -553,7 +570,9 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
                struct rtc_time tm;
                ktime_t now, onesec;
 
-               __rtc_read_time(rtc, &tm);
+               rc = __rtc_read_time(rtc, &tm);
+               if (rc)
+                       goto out;
                onesec = ktime_set(1, 0);
                now = rtc_tm_to_ktime(tm);
                rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
@@ -565,6 +584,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
 
 out:
        mutex_unlock(&rtc->ops_lock);
+
+       /*
+        * __rtc_read_time() failed, this probably means that the RTC time has
+        * never been set or less probably there is a transient error on the
+        * bus. In any case, avoid enabling emulation has this will fail when
+        * reading the time too.
+        */
+       if (rc)
+               return rc;
+
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
        /*
         * Enable emulation if the driver returned -EINVAL to signal that it has
@@ -581,6 +610,8 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
 /**
  * rtc_handle_legacy_irq - AIE, UIE and PIE event hook
  * @rtc: pointer to the rtc device
+ * @num: number of occurence of the event
+ * @mode: type of the event, RTC_AF, RTC_UF of RTC_PF
  *
  * This function is called when an AIE, UIE or PIE mode interrupt
  * has occurred (or been emulated).
@@ -761,8 +792,8 @@ int rtc_irq_set_freq(struct rtc_device *rtc, int freq)
 
 /**
  * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
- * @rtc rtc device
- * @timer timer being added.
+ * @rtc: rtc device
+ * @timer: timer being added.
  *
  * Enqueues a timer onto the rtc devices timerqueue and sets
  * the next alarm event appropriately.
@@ -821,8 +852,8 @@ static void rtc_alarm_disable(struct rtc_device *rtc)
 
 /**
  * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
- * @rtc rtc device
- * @timer timer being removed.
+ * @rtc: rtc device
+ * @timer: timer being removed.
  *
  * Removes a timer onto the rtc devices timerqueue and sets
  * the next alarm event appropriately.
@@ -859,8 +890,7 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
 
 /**
  * rtc_timer_do_work - Expires rtc timers
- * @rtc rtc device
- * @timer timer being removed.
+ * @work: work item
  *
  * Expires rtc timers. Reprograms next alarm event if needed.
  * Called via worktask.
@@ -993,8 +1023,8 @@ void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
 
 /**
  * rtc_read_offset - Read the amount of rtc offset in parts per billion
- * @ rtc: rtc device to be used
- * @ offset: the offset in parts per billion
+ * @rtc: rtc device to be used
+ * @offset: the offset in parts per billion
  *
  * see below for details.
  *
@@ -1022,8 +1052,8 @@ int rtc_read_offset(struct rtc_device *rtc, long *offset)
 
 /**
  * rtc_set_offset - Adjusts the duration of the average second
- * @ rtc: rtc device to be used
- * @ offset: the offset in parts per billion
+ * @rtc: rtc device to be used
+ * @offset: the offset in parts per billion
  *
  * Some rtc's allow an adjustment to the average duration of a second
  * to compensate for differences in the actual clock rate due to temperature,
index cdad6f0..811fe20 100644 (file)
@@ -900,16 +900,6 @@ err:
        return ret;
 }
 
-static int abb5zes3_remove(struct i2c_client *client)
-{
-       struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(&client->dev);
-
-       if (rtc_data->irq > 0)
-               device_init_wakeup(&client->dev, false);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int abb5zes3_rtc_suspend(struct device *dev)
 {
@@ -956,7 +946,6 @@ static struct i2c_driver abb5zes3_driver = {
                .of_match_table = of_match_ptr(abb5zes3_dt_match),
        },
        .probe    = abb5zes3_probe,
-       .remove   = abb5zes3_remove,
        .id_table = abb5zes3_id,
 };
 module_i2c_driver(abb5zes3_driver);
index 9351bd5..94d7c22 100644 (file)
@@ -74,7 +74,7 @@ struct armada38x_rtc {
        int                 irq;
        bool                initialized;
        struct value_to_freq *val_to_freq;
-       struct armada38x_rtc_data *data;
+       const struct armada38x_rtc_data *data;
 };
 
 #define ALARM1 0
@@ -501,17 +501,14 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct armada38x_rtc *rtc;
-       const struct of_device_id *match;
-
-       match = of_match_device(armada38x_rtc_of_match_table, &pdev->dev);
-       if (!match)
-               return -ENODEV;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
                            GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
+       rtc->data = of_device_get_match_data(&pdev->dev);
+
        rtc->val_to_freq = devm_kcalloc(&pdev->dev, SAMPLE_NR,
                                sizeof(struct value_to_freq), GFP_KERNEL);
        if (!rtc->val_to_freq)
@@ -553,7 +550,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
                 */
                rtc->rtc_dev->ops = &armada38x_rtc_ops_noirq;
        }
-       rtc->data = (struct armada38x_rtc_data *)match->data;
 
        /* Update RTC-MBUS bridge timing parameters */
        rtc->data->update_mbus_timing(rtc);
index 10413d8..10064bd 100644 (file)
@@ -245,7 +245,6 @@ static int asm9260_rtc_probe(struct platform_device *pdev)
 {
        struct asm9260_rtc_priv *priv;
        struct device *dev = &pdev->dev;
-       struct resource *res;
        int irq_alarm, ret;
        u32 ccr;
 
@@ -260,8 +259,7 @@ static int asm9260_rtc_probe(struct platform_device *pdev)
        if (irq_alarm < 0)
                return irq_alarm;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->iobase = devm_ioremap_resource(dev, res);
+       priv->iobase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->iobase))
                return PTR_ERR(priv->iobase);
 
index e351d35..eacdd06 100644 (file)
@@ -85,14 +85,12 @@ static const struct rtc_class_ops aspeed_rtc_ops = {
 static int aspeed_rtc_probe(struct platform_device *pdev)
 {
        struct aspeed_rtc *rtc;
-       struct resource *res;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->base = devm_ioremap_resource(&pdev->dev, res);
+       rtc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->base))
                return PTR_ERR(rtc->base);
 
index d119c6e..3b833e0 100644 (file)
@@ -319,7 +319,6 @@ static const struct at91_rtc_config at91sam9x5_config = {
        .use_shadow_imr = true,
 };
 
-#ifdef CONFIG_OF
 static const struct of_device_id at91_rtc_dt_ids[] = {
        {
                .compatible = "atmel,at91rm9200-rtc",
@@ -332,22 +331,6 @@ static const struct of_device_id at91_rtc_dt_ids[] = {
        }
 };
 MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
-#endif
-
-static const struct at91_rtc_config *
-at91_rtc_get_config(struct platform_device *pdev)
-{
-       const struct of_device_id *match;
-
-       if (pdev->dev.of_node) {
-               match = of_match_node(at91_rtc_dt_ids, pdev->dev.of_node);
-               if (!match)
-                       return NULL;
-               return (const struct at91_rtc_config *)match->data;
-       }
-
-       return &at91rm9200_config;
-}
 
 static const struct rtc_class_ops at91_rtc_ops = {
        .read_time      = at91_rtc_readtime,
@@ -367,7 +350,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        struct resource *regs;
        int ret = 0;
 
-       at91_rtc_config = at91_rtc_get_config(pdev);
+       at91_rtc_config = of_device_get_match_data(&pdev->dev);
        if (!at91_rtc_config)
                return -ENODEV;
 
index bb3ba7b..e39e898 100644 (file)
@@ -334,7 +334,6 @@ static const struct rtc_class_ops at91_rtc_ops = {
  */
 static int at91_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *r;
        struct sam9_rtc *rtc;
        int             ret, irq;
        u32             mr;
@@ -358,8 +357,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->rtt = devm_ioremap_resource(&pdev->dev, r);
+       rtc->rtt = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->rtt))
                return PTR_ERR(rtc->rtt);
 
index 7744333..627037a 100644 (file)
@@ -491,3 +491,4 @@ module_platform_driver(bd70528_rtc);
 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
 MODULE_DESCRIPTION("BD70528 RTC driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bd70528-rtc");
index 3e9800f..4fee57c 100644 (file)
@@ -200,7 +200,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct brcmstb_waketmr *timer;
-       struct resource *res;
        int ret;
 
        timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
@@ -210,8 +209,7 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, timer);
        timer->dev = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       timer->base = devm_ioremap_resource(dev, res);
+       timer->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(timer->base))
                return PTR_ERR(timer->base);
 
@@ -277,6 +275,7 @@ static int brcmstb_waketmr_remove(struct platform_device *pdev)
        struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
 
        unregister_reboot_notifier(&timer->reboot_notifier);
+       clk_disable_unprepare(timer->clk);
 
        return 0;
 }
index 592aae2..595d5d2 100644 (file)
@@ -255,7 +255,6 @@ static const struct rtc_class_ops cdns_rtc_ops = {
 static int cdns_rtc_probe(struct platform_device *pdev)
 {
        struct cdns_rtc *crtc;
-       struct resource *res;
        int ret;
        unsigned long ref_clk_freq;
 
@@ -263,8 +262,7 @@ static int cdns_rtc_probe(struct platform_device *pdev)
        if (!crtc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       crtc->regs = devm_ioremap_resource(&pdev->dev, res);
+       crtc->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(crtc->regs))
                return PTR_ERR(crtc->regs);
 
index 4ac8508..da59917 100644 (file)
@@ -164,15 +164,13 @@ static int __init coh901331_probe(struct platform_device *pdev)
 {
        int ret;
        struct coh901331_port *rtap;
-       struct resource *res;
 
        rtap = devm_kzalloc(&pdev->dev,
                            sizeof(struct coh901331_port), GFP_KERNEL);
        if (!rtap)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtap->virtbase  = devm_ioremap_resource(&pdev->dev, res);
+       rtap->virtbase  = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtap->virtbase))
                return PTR_ERR(rtap->virtbase);
 
index 6909e01..d043d30 100644 (file)
@@ -107,11 +107,7 @@ static int cros_ec_rtc_set_time(struct device *dev, struct rtc_time *tm)
        struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev);
        struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec;
        int ret;
-       time64_t time;
-
-       time = rtc_tm_to_time64(tm);
-       if (time < 0 || time > U32_MAX)
-               return -EINVAL;
+       time64_t time = rtc_tm_to_time64(tm);
 
        ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_VALUE, (u32)time);
        if (ret < 0) {
@@ -348,14 +344,16 @@ static int cros_ec_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       cros_ec_rtc->rtc = devm_rtc_device_register(&pdev->dev, DRV_NAME,
-                                                   &cros_ec_rtc_ops,
-                                                   THIS_MODULE);
-       if (IS_ERR(cros_ec_rtc->rtc)) {
-               ret = PTR_ERR(cros_ec_rtc->rtc);
-               dev_err(&pdev->dev, "failed to register rtc device\n");
+       cros_ec_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(cros_ec_rtc->rtc))
+               return PTR_ERR(cros_ec_rtc->rtc);
+
+       cros_ec_rtc->rtc->ops = &cros_ec_rtc_ops;
+       cros_ec_rtc->rtc->range_max = U32_MAX;
+
+       ret = rtc_register_device(cros_ec_rtc->rtc);
+       if (ret)
                return ret;
-       }
 
        /* Get RTC events from the EC. */
        cros_ec_rtc->notifier.notifier_call = cros_ec_rtc_event;
index 15908d5..046b1d4 100644 (file)
@@ -483,6 +483,9 @@ static int da9063_rtc_probe(struct platform_device *pdev)
                rtc->rtc_dev->uie_unsupported = 1;
 
        irq_alarm = platform_get_irq_byname(pdev, "ALARM");
+       if (irq_alarm < 0)
+               return irq_alarm;
+
        ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
                                        da9063_alarm_event,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
index d8e0db2..390b735 100644 (file)
@@ -469,7 +469,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct davinci_rtc *davinci_rtc;
-       struct resource *res;
        int ret = 0;
 
        davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL);
@@ -480,8 +479,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        if (davinci_rtc->irq < 0)
                return davinci_rtc->irq;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       davinci_rtc->base = devm_ioremap_resource(dev, res);
+       davinci_rtc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(davinci_rtc->base))
                return PTR_ERR(davinci_rtc->base);
 
index 0aecc3f..200d85b 100644 (file)
@@ -175,7 +175,6 @@ static irqreturn_t dc_rtc_irq(int irq, void *dev_id)
 
 static int __init dc_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct dc_rtc *rtc;
        int irq, ret;
 
@@ -183,8 +182,7 @@ static int __init dc_rtc_probe(struct platform_device *pdev)
        if (!rtc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->regs = devm_ioremap_resource(&pdev->dev, res);
+       rtc->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->regs))
                return PTR_ERR(rtc->regs);
 
index b225bcf..7eeb3f3 100644 (file)
@@ -137,7 +137,6 @@ static const struct rtc_class_ops ds1216_rtc_ops = {
 
 static int __init ds1216_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct ds1216_priv *priv;
        u8 dummy[8];
 
@@ -147,8 +146,7 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, priv);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       priv->ioaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->ioaddr))
                return PTR_ERR(priv->ioaddr);
 
index a06508b..7acf849 100644 (file)
@@ -323,15 +323,13 @@ static const struct rtc_class_ops ds1286_ops = {
 static int ds1286_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
-       struct resource *res;
        struct ds1286_priv *priv;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(struct ds1286_priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->rtcregs = devm_ioremap_resource(&pdev->dev, res);
+       priv->rtcregs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->rtcregs))
                return PTR_ERR(priv->rtcregs);
 
index 4faa24c..b3de6d2 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/rtc.h>
 #include <linux/spi/spi.h>
 
-#define DRV_NAME       "rtc-ds1302"
-
 #define        RTC_CMD_READ    0x81            /* Read command */
 #define        RTC_CMD_WRITE   0x80            /* Write command */
 
index fa6de31..d21004a 100644 (file)
@@ -78,42 +78,19 @@ struct ds1343_priv {
        struct spi_device *spi;
        struct rtc_device *rtc;
        struct regmap *map;
-       struct mutex mutex;
-       unsigned int irqen;
        int irq;
-       int alarm_sec;
-       int alarm_min;
-       int alarm_hour;
-       int alarm_mday;
 };
 
-static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-#ifdef RTC_SET_CHARGE
-       case RTC_SET_CHARGE:
-       {
-               int val;
-
-               if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
-                       return -EFAULT;
-
-               return regmap_write(priv->map, DS1343_TRICKLE_REG, val);
-       }
-       break;
-#endif
-       }
-
-       return -ENOIOCTLCMD;
-}
-
 static ssize_t ds1343_show_glitchfilter(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct ds1343_priv *priv = dev_get_drvdata(dev);
+       struct ds1343_priv *priv = dev_get_drvdata(dev->parent);
        int glitch_filt_status, data;
+       int res;
 
-       regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+       res = regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+       if (res)
+               return res;
 
        glitch_filt_status = !!(data & DS1343_EGFIL);
 
@@ -127,21 +104,19 @@ static ssize_t ds1343_store_glitchfilter(struct device *dev,
                                        struct device_attribute *attr,
                                        const char *buf, size_t count)
 {
-       struct ds1343_priv *priv = dev_get_drvdata(dev);
-       int data;
-
-       regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+       struct ds1343_priv *priv = dev_get_drvdata(dev->parent);
+       int data = 0;
+       int res;
 
        if (strncmp(buf, "enabled", 7) == 0)
-               data |= DS1343_EGFIL;
-
-       else if (strncmp(buf, "disabled", 8) == 0)
-               data &= ~(DS1343_EGFIL);
-
-       else
+               data = DS1343_EGFIL;
+       else if (strncmp(buf, "disabled", 8))
                return -EINVAL;
 
-       regmap_write(priv->map, DS1343_CONTROL_REG, data);
+       res = regmap_update_bits(priv->map, DS1343_CONTROL_REG,
+                                DS1343_EGFIL, data);
+       if (res)
+               return res;
 
        return count;
 }
@@ -168,11 +143,13 @@ static int ds1343_nvram_read(void *priv, unsigned int off, void *val,
 static ssize_t ds1343_show_tricklecharger(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct ds1343_priv *priv = dev_get_drvdata(dev);
-       int data;
+       struct ds1343_priv *priv = dev_get_drvdata(dev->parent);
+       int res, data;
        char *diodes = "disabled", *resistors = " ";
 
-       regmap_read(priv->map, DS1343_TRICKLE_REG, &data);
+       res = regmap_read(priv->map, DS1343_TRICKLE_REG, &data);
+       if (res)
+               return res;
 
        if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) {
                switch (data & 0x0c) {
@@ -209,28 +186,15 @@ static ssize_t ds1343_show_tricklecharger(struct device *dev,
 
 static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL);
 
-static int ds1343_sysfs_register(struct device *dev)
-{
-       int err;
-
-       err = device_create_file(dev, &dev_attr_glitch_filter);
-       if (err)
-               return err;
-
-       err = device_create_file(dev, &dev_attr_trickle_charger);
-       if (!err)
-               return 0;
-
-       device_remove_file(dev, &dev_attr_glitch_filter);
-
-       return err;
-}
+static struct attribute *ds1343_attrs[] = {
+       &dev_attr_glitch_filter.attr,
+       &dev_attr_trickle_charger.attr,
+       NULL
+};
 
-static void ds1343_sysfs_unregister(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_glitch_filter);
-       device_remove_file(dev, &dev_attr_trickle_charger);
-}
+static const struct attribute_group ds1343_attr_group = {
+       .attrs  = ds1343_attrs,
+};
 
 static int ds1343_read_time(struct device *dev, struct rtc_time *dt)
 {
@@ -256,144 +220,78 @@ static int ds1343_read_time(struct device *dev, struct rtc_time *dt)
 static int ds1343_set_time(struct device *dev, struct rtc_time *dt)
 {
        struct ds1343_priv *priv = dev_get_drvdata(dev);
-       int res;
-
-       res = regmap_write(priv->map, DS1343_SECONDS_REG,
-                               bin2bcd(dt->tm_sec));
-       if (res)
-               return res;
-
-       res = regmap_write(priv->map, DS1343_MINUTES_REG,
-                               bin2bcd(dt->tm_min));
-       if (res)
-               return res;
-
-       res = regmap_write(priv->map, DS1343_HOURS_REG,
-                               bin2bcd(dt->tm_hour) & 0x3F);
-       if (res)
-               return res;
-
-       res = regmap_write(priv->map, DS1343_DAY_REG,
-                               bin2bcd(dt->tm_wday + 1));
-       if (res)
-               return res;
-
-       res = regmap_write(priv->map, DS1343_DATE_REG,
-                               bin2bcd(dt->tm_mday));
-       if (res)
-               return res;
-
-       res = regmap_write(priv->map, DS1343_MONTH_REG,
-                               bin2bcd(dt->tm_mon + 1));
-       if (res)
-               return res;
-
-       dt->tm_year %= 100;
-
-       res = regmap_write(priv->map, DS1343_YEAR_REG,
-                               bin2bcd(dt->tm_year));
-       if (res)
-               return res;
-
-       return 0;
+       u8 buf[7];
+
+       buf[0] = bin2bcd(dt->tm_sec);
+       buf[1] = bin2bcd(dt->tm_min);
+       buf[2] = bin2bcd(dt->tm_hour) & 0x3F;
+       buf[3] = bin2bcd(dt->tm_wday + 1);
+       buf[4] = bin2bcd(dt->tm_mday);
+       buf[5] = bin2bcd(dt->tm_mon + 1);
+       buf[6] = bin2bcd(dt->tm_year - 100);
+
+       return regmap_bulk_write(priv->map, DS1343_SECONDS_REG,
+                                buf, sizeof(buf));
 }
 
-static int ds1343_update_alarm(struct device *dev)
+static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct ds1343_priv *priv = dev_get_drvdata(dev);
-       unsigned int control, stat;
        unsigned char buf[4];
-       int res = 0;
+       unsigned int val;
+       int res;
 
-       res = regmap_read(priv->map, DS1343_CONTROL_REG, &control);
-       if (res)
-               return res;
+       if (priv->irq <= 0)
+               return -EINVAL;
 
-       res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
+       res = regmap_read(priv->map, DS1343_STATUS_REG, &val);
        if (res)
                return res;
 
-       control &= ~(DS1343_A0IE);
-       stat &= ~(DS1343_IRQF0);
-
-       res = regmap_write(priv->map, DS1343_CONTROL_REG, control);
-       if (res)
-               return res;
+       alarm->pending = !!(val & DS1343_IRQF0);
 
-       res = regmap_write(priv->map, DS1343_STATUS_REG, stat);
+       res = regmap_read(priv->map, DS1343_CONTROL_REG, &val);
        if (res)
                return res;
+       alarm->enabled = !!(val & DS1343_A0IE);
 
-       buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ?
-               0x80 : bin2bcd(priv->alarm_sec) & 0x7F;
-       buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ?
-               0x80 : bin2bcd(priv->alarm_min) & 0x7F;
-       buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ?
-               0x80 : bin2bcd(priv->alarm_hour) & 0x3F;
-       buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ?
-               0x80 : bin2bcd(priv->alarm_mday) & 0x7F;
-
-       res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4);
+       res = regmap_bulk_read(priv->map, DS1343_ALM0_SEC_REG, buf, 4);
        if (res)
                return res;
 
-       if (priv->irqen) {
-               control |= DS1343_A0IE;
-               res = regmap_write(priv->map, DS1343_CONTROL_REG, control);
-       }
+       alarm->time.tm_sec = bcd2bin(buf[0]) & 0x7f;
+       alarm->time.tm_min = bcd2bin(buf[1]) & 0x7f;
+       alarm->time.tm_hour = bcd2bin(buf[2]) & 0x3f;
+       alarm->time.tm_mday = bcd2bin(buf[3]) & 0x3f;
 
-       return res;
+       return 0;
 }
 
-static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct ds1343_priv *priv = dev_get_drvdata(dev);
+       unsigned char buf[4];
        int res = 0;
-       unsigned int stat;
 
        if (priv->irq <= 0)
                return -EINVAL;
 
-       mutex_lock(&priv->mutex);
-
-       res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
+       res = regmap_update_bits(priv->map, DS1343_CONTROL_REG, DS1343_A0IE, 0);
        if (res)
-               goto out;
-
-       alarm->enabled = !!(priv->irqen & RTC_AF);
-       alarm->pending = !!(stat & DS1343_IRQF0);
-
-       alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec;
-       alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min;
-       alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour;
-       alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday;
-
-out:
-       mutex_unlock(&priv->mutex);
-       return res;
-}
-
-static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
-       struct ds1343_priv *priv = dev_get_drvdata(dev);
-       int res = 0;
-
-       if (priv->irq <= 0)
-               return -EINVAL;
+               return res;
 
-       mutex_lock(&priv->mutex);
+       buf[0] = bin2bcd(alarm->time.tm_sec);
+       buf[1] = bin2bcd(alarm->time.tm_min);
+       buf[2] = bin2bcd(alarm->time.tm_hour);
+       buf[3] = bin2bcd(alarm->time.tm_mday);
 
-       priv->alarm_sec = alarm->time.tm_sec;
-       priv->alarm_min = alarm->time.tm_min;
-       priv->alarm_hour = alarm->time.tm_hour;
-       priv->alarm_mday = alarm->time.tm_mday;
+       res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4);
+       if (res)
+               return res;
 
        if (alarm->enabled)
-               priv->irqen |= RTC_AF;
-
-       res = ds1343_update_alarm(dev);
-
-       mutex_unlock(&priv->mutex);
+               res = regmap_update_bits(priv->map, DS1343_CONTROL_REG,
+                                        DS1343_A0IE, DS1343_A0IE);
 
        return res;
 }
@@ -401,32 +299,21 @@ static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct ds1343_priv *priv = dev_get_drvdata(dev);
-       int res = 0;
 
        if (priv->irq <= 0)
                return -EINVAL;
 
-       mutex_lock(&priv->mutex);
-
-       if (enabled)
-               priv->irqen |= RTC_AF;
-       else
-               priv->irqen &= ~RTC_AF;
-
-       res = ds1343_update_alarm(dev);
-
-       mutex_unlock(&priv->mutex);
-
-       return res;
+       return regmap_update_bits(priv->map, DS1343_CONTROL_REG,
+                                 DS1343_A0IE, enabled ? DS1343_A0IE : 0);
 }
 
 static irqreturn_t ds1343_thread(int irq, void *dev_id)
 {
        struct ds1343_priv *priv = dev_id;
-       unsigned int stat, control;
+       unsigned int stat;
        int res = 0;
 
-       mutex_lock(&priv->mutex);
+       rtc_lock(priv->rtc);
 
        res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
        if (res)
@@ -436,23 +323,18 @@ static irqreturn_t ds1343_thread(int irq, void *dev_id)
                stat &= ~DS1343_IRQF0;
                regmap_write(priv->map, DS1343_STATUS_REG, stat);
 
-               res = regmap_read(priv->map, DS1343_CONTROL_REG, &control);
-               if (res)
-                       goto out;
-
-               control &= ~DS1343_A0IE;
-               regmap_write(priv->map, DS1343_CONTROL_REG, control);
-
                rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF);
+
+               regmap_update_bits(priv->map, DS1343_CONTROL_REG,
+                                  DS1343_A0IE, 0);
        }
 
 out:
-       mutex_unlock(&priv->mutex);
+       rtc_unlock(priv->rtc);
        return IRQ_HANDLED;
 }
 
 static const struct rtc_class_ops ds1343_rtc_ops = {
-       .ioctl          = ds1343_ioctl,
        .read_time      = ds1343_read_time,
        .set_time       = ds1343_set_time,
        .read_alarm     = ds1343_read_alarm,
@@ -481,7 +363,6 @@ static int ds1343_probe(struct spi_device *spi)
                return -ENOMEM;
 
        priv->spi = spi;
-       mutex_init(&priv->mutex);
 
        /* RTC DS1347 works in spi mode 3 and
         * its chip select is active high
@@ -520,6 +401,13 @@ static int ds1343_probe(struct spi_device *spi)
 
        priv->rtc->nvram_old_abi = true;
        priv->rtc->ops = &ds1343_rtc_ops;
+       priv->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+       priv->rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+       res = rtc_add_group(priv->rtc, &ds1343_attr_group);
+       if (res)
+               dev_err(&spi->dev,
+                       "unable to create sysfs entries for rtc ds1343\n");
 
        res = rtc_register_device(priv->rtc);
        if (res)
@@ -544,31 +432,12 @@ static int ds1343_probe(struct spi_device *spi)
                }
        }
 
-       res = ds1343_sysfs_register(&spi->dev);
-       if (res)
-               dev_err(&spi->dev,
-                       "unable to create sysfs entries for rtc ds1343\n");
-
        return 0;
 }
 
 static int ds1343_remove(struct spi_device *spi)
 {
-       struct ds1343_priv *priv = spi_get_drvdata(spi);
-
-       if (spi->irq) {
-               mutex_lock(&priv->mutex);
-               priv->irqen &= ~RTC_AF;
-               mutex_unlock(&priv->mutex);
-
-               dev_pm_clear_wake_irq(&spi->dev);
-               device_init_wakeup(&spi->dev, false);
-               devm_free_irq(&spi->dev, spi->irq, priv);
-       }
-
-       spi_set_drvdata(spi, NULL);
-
-       ds1343_sysfs_unregister(&spi->dev);
+       dev_pm_clear_wake_irq(&spi->dev);
 
        return 0;
 }
index d392a7b..7025cf3 100644 (file)
 #define DS1347_DAY_REG         0x0B
 #define DS1347_YEAR_REG                0x0D
 #define DS1347_CONTROL_REG     0x0F
+#define DS1347_CENTURY_REG     0x13
 #define DS1347_STATUS_REG      0x17
 #define DS1347_CLOCK_BURST     0x3F
 
+#define DS1347_WP_BIT          BIT(7)
+
+#define DS1347_NEOSC_BIT       BIT(7)
+#define DS1347_OSF_BIT         BIT(2)
+
 static const struct regmap_range ds1347_ranges[] = {
        {
                .range_min = DS1347_SECONDS_REG,
@@ -43,35 +49,54 @@ static const struct regmap_access_table ds1347_access_table = {
 
 static int ds1347_read_time(struct device *dev, struct rtc_time *dt)
 {
-       struct spi_device *spi = to_spi_device(dev);
-       struct regmap *map;
-       int err;
+       struct regmap *map = dev_get_drvdata(dev);
+       unsigned int status, century, secs;
        unsigned char buf[8];
+       int err;
 
-       map = spi_get_drvdata(spi);
-
-       err = regmap_bulk_read(map, DS1347_CLOCK_BURST, buf, 8);
+       err = regmap_read(map, DS1347_STATUS_REG, &status);
        if (err)
                return err;
 
+       if (status & DS1347_OSF_BIT)
+               return -EINVAL;
+
+       do {
+               err = regmap_bulk_read(map, DS1347_CLOCK_BURST, buf, 8);
+               if (err)
+                       return err;
+
+               err = regmap_read(map, DS1347_CENTURY_REG, &century);
+               if (err)
+                       return err;
+
+               err = regmap_read(map, DS1347_SECONDS_REG, &secs);
+               if (err)
+                       return err;
+       } while (buf[0] != secs);
+
        dt->tm_sec = bcd2bin(buf[0]);
-       dt->tm_min = bcd2bin(buf[1]);
+       dt->tm_min = bcd2bin(buf[1] & 0x7f);
        dt->tm_hour = bcd2bin(buf[2] & 0x3F);
        dt->tm_mday = bcd2bin(buf[3]);
        dt->tm_mon = bcd2bin(buf[4]) - 1;
        dt->tm_wday = bcd2bin(buf[5]) - 1;
-       dt->tm_year = bcd2bin(buf[6]) + 100;
+       dt->tm_year = (bcd2bin(century) * 100) + bcd2bin(buf[6]) - 1900;
 
        return 0;
 }
 
 static int ds1347_set_time(struct device *dev, struct rtc_time *dt)
 {
-       struct spi_device *spi = to_spi_device(dev);
-       struct regmap *map;
+       struct regmap *map = dev_get_drvdata(dev);
+       unsigned int century;
        unsigned char buf[8];
+       int err;
 
-       map = spi_get_drvdata(spi);
+       err = regmap_update_bits(map, DS1347_STATUS_REG,
+                                DS1347_NEOSC_BIT, DS1347_NEOSC_BIT);
+       if (err)
+               return err;
 
        buf[0] = bin2bcd(dt->tm_sec);
        buf[1] = bin2bcd(dt->tm_min);
@@ -79,16 +104,20 @@ static int ds1347_set_time(struct device *dev, struct rtc_time *dt)
        buf[3] = bin2bcd(dt->tm_mday);
        buf[4] = bin2bcd(dt->tm_mon + 1);
        buf[5] = bin2bcd(dt->tm_wday + 1);
+       buf[6] = bin2bcd(dt->tm_year % 100);
+       buf[7] = bin2bcd(0x00);
 
-       /* year in linux is from 1900 i.e in range of 100
-       in rtc it is from 00 to 99 */
-       dt->tm_year = dt->tm_year % 100;
+       err = regmap_bulk_write(map, DS1347_CLOCK_BURST, buf, 8);
+       if (err)
+               return err;
 
-       buf[6] = bin2bcd(dt->tm_year);
-       buf[7] = bin2bcd(0x00);
+       century = (dt->tm_year / 100) + 19;
+       err = regmap_write(map, DS1347_CENTURY_REG, century);
+       if (err)
+               return err;
 
-       /* write the rtc settings */
-       return regmap_bulk_write(map, DS1347_CLOCK_BURST, buf, 8);
+       return regmap_update_bits(map, DS1347_STATUS_REG,
+                                 DS1347_NEOSC_BIT | DS1347_OSF_BIT, 0);
 }
 
 static const struct rtc_class_ops ds1347_rtc_ops = {
@@ -101,8 +130,7 @@ static int ds1347_probe(struct spi_device *spi)
        struct rtc_device *rtc;
        struct regmap_config config;
        struct regmap *map;
-       unsigned int data;
-       int res;
+       int err;
 
        memset(&config, 0, sizeof(config));
        config.reg_bits = 8;
@@ -125,36 +153,20 @@ static int ds1347_probe(struct spi_device *spi)
 
        spi_set_drvdata(spi, map);
 
-       /* RTC Settings */
-       res = regmap_read(map, DS1347_SECONDS_REG, &data);
-       if (res)
-               return res;
-
        /* Disable the write protect of rtc */
-       regmap_read(map, DS1347_CONTROL_REG, &data);
-       data = data & ~(1<<7);
-       regmap_write(map, DS1347_CONTROL_REG, data);
-
-       /* Enable the oscillator , disable the oscillator stop flag,
-        and glitch filter to reduce current consumption */
-       regmap_read(map, DS1347_STATUS_REG, &data);
-       data = data & 0x1B;
-       regmap_write(map, DS1347_STATUS_REG, data);
-
-       /* display the settings */
-       regmap_read(map, DS1347_CONTROL_REG, &data);
-       dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data);
-
-       regmap_read(map, DS1347_STATUS_REG, &data);
-       dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data);
-
-       rtc = devm_rtc_device_register(&spi->dev, "ds1347",
-                               &ds1347_rtc_ops, THIS_MODULE);
+       err = regmap_update_bits(map, DS1347_CONTROL_REG, DS1347_WP_BIT, 0);
+       if (err)
+               return err;
 
+       rtc = devm_rtc_allocate_device(&spi->dev);
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
 
-       return 0;
+       rtc->ops = &ds1347_rtc_ops;
+       rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;
+       rtc->range_max = RTC_TIMESTAMP_END_9999;
+
+       return rtc_register_device(rtc);
 }
 
 static struct spi_driver ds1347_driver = {
index 6e96916..6e9ddcd 100644 (file)
@@ -439,14 +439,13 @@ static void ds1374_wdt_ping(void)
 
 static void ds1374_wdt_disable(void)
 {
-       int ret = -ENOIOCTLCMD;
        int cr;
 
        cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR);
        /* Disable watchdog timer */
        cr &= ~DS1374_REG_CR_WACE;
 
-       ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+       i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
 }
 
 /*
index b6a4775..a63872c 100644 (file)
@@ -414,7 +414,6 @@ static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
 
 static int ds1511_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct rtc_plat_data *pdata;
        int ret = 0;
        struct nvmem_config ds1511_nvmem_cfg = {
@@ -431,8 +430,7 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ds1511_base = devm_ioremap_resource(&pdev->dev, res);
+       ds1511_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(ds1511_base))
                return PTR_ERR(ds1511_base);
        pdata->ioaddr = ds1511_base;
index 219d6b5..cdf5e05 100644 (file)
@@ -249,7 +249,6 @@ static int ds1553_nvram_write(void *priv, unsigned int pos, void *val,
 
 static int ds1553_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        unsigned int cen, sec;
        struct rtc_plat_data *pdata;
        void __iomem *ioaddr;
@@ -268,8 +267,7 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       ioaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(ioaddr))
                return PTR_ERR(ioaddr);
        pdata->ioaddr = ioaddr;
index 184e4a3..56c670a 100644 (file)
 
 
 /* ----------------------------------------------------------------------- */
-/* Standard read/write functions if platform does not provide overrides */
+/*
+ *  Standard read/write
+ *  all registers are mapped in CPU address space
+ */
 
 /**
  * ds1685_read - read a value from an rtc register.
@@ -59,6 +62,35 @@ ds1685_write(struct ds1685_priv *rtc, int reg, u8 value)
 }
 /* ----------------------------------------------------------------------- */
 
+/*
+ * Indirect read/write functions
+ * access happens via address and data register mapped in CPU address space
+ */
+
+/**
+ * ds1685_indirect_read - read a value from an rtc register.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @reg: the register address to read.
+ */
+static u8
+ds1685_indirect_read(struct ds1685_priv *rtc, int reg)
+{
+       writeb(reg, rtc->regs);
+       return readb(rtc->data);
+}
+
+/**
+ * ds1685_indirect_write - write a value to an rtc register.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @reg: the register address to write.
+ * @value: value to write to the register.
+ */
+static void
+ds1685_indirect_write(struct ds1685_priv *rtc, int reg, u8 value)
+{
+       writeb(reg, rtc->regs);
+       writeb(value, rtc->data);
+}
 
 /* ----------------------------------------------------------------------- */
 /* Inlined functions */
@@ -229,7 +261,7 @@ static int
 ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct ds1685_priv *rtc = dev_get_drvdata(dev);
-       u8 ctrlb, century;
+       u8 century;
        u8 seconds, minutes, hours, wday, mday, month, years;
 
        /* Fetch the time info from the RTC registers. */
@@ -242,7 +274,6 @@ ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm)
        month   = rtc->read(rtc, RTC_MONTH);
        years   = rtc->read(rtc, RTC_YEAR);
        century = rtc->read(rtc, RTC_CENTURY);
-       ctrlb   = rtc->read(rtc, RTC_CTRL_B);
        ds1685_rtc_end_data_access(rtc);
 
        /* bcd2bin if needed, perform fixups, and store to rtc_time. */
@@ -723,7 +754,7 @@ static int
 ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        struct ds1685_priv *rtc = dev_get_drvdata(dev);
-       u8 ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b, ssn[8];
+       u8 ctrla, ctrlb, ctrld, ctrl4a, ctrl4b, ssn[8];
        char *model;
 
        /* Read all the relevant data from the control registers. */
@@ -731,7 +762,6 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
        ds1685_rtc_get_ssn(rtc, ssn);
        ctrla = rtc->read(rtc, RTC_CTRL_A);
        ctrlb = rtc->read(rtc, RTC_CTRL_B);
-       ctrlc = rtc->read(rtc, RTC_CTRL_C);
        ctrld = rtc->read(rtc, RTC_CTRL_D);
        ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
        ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
@@ -1009,7 +1039,7 @@ ds1685_rtc_sysfs_serial_show(struct device *dev,
 }
 static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL);
 
-/**
+/*
  * struct ds1685_rtc_sysfs_misc_attrs - list for misc RTC features.
  */
 static struct attribute*
@@ -1020,7 +1050,7 @@ ds1685_rtc_sysfs_misc_attrs[] = {
        NULL,
 };
 
-/**
+/*
  * struct ds1685_rtc_sysfs_misc_grp - attr group for misc RTC features.
  */
 static const struct attribute_group
@@ -1040,7 +1070,6 @@ static int
 ds1685_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc_dev;
-       struct resource *res;
        struct ds1685_priv *rtc;
        struct ds1685_rtc_platform_data *pdata;
        u8 ctrla, ctrlb, hours;
@@ -1063,35 +1092,29 @@ ds1685_rtc_probe(struct platform_device *pdev)
        if (!rtc)
                return -ENOMEM;
 
-       /*
-        * Allocate/setup any IORESOURCE_MEM resources, if required.  Not all
-        * platforms put the RTC in an easy-access place.  Like the SGI Octane,
-        * which attaches the RTC to a "ByteBus", hooked to a SuperIO chip
-        * that sits behind the IOC3 PCI metadevice.
-        */
-       if (pdata->alloc_io_resources) {
-               /* Get the platform resources. */
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (!res)
-                       return -ENXIO;
-               rtc->size = resource_size(res);
-
-               /* Request a memory region. */
-               /* XXX: mmio-only for now. */
-               if (!devm_request_mem_region(&pdev->dev, res->start, rtc->size,
-                                            pdev->name))
-                       return -EBUSY;
-
-               /*
-                * Set the base address for the rtc, and ioremap its
-                * registers.
-                */
-               rtc->baseaddr = res->start;
-               rtc->regs = devm_ioremap(&pdev->dev, res->start, rtc->size);
-               if (!rtc->regs)
-                       return -ENOMEM;
+       /* Setup resources and access functions */
+       switch (pdata->access_type) {
+       case ds1685_reg_direct:
+               rtc->regs = devm_platform_ioremap_resource(pdev, 0);
+               if (IS_ERR(rtc->regs))
+                       return PTR_ERR(rtc->regs);
+               rtc->read = ds1685_read;
+               rtc->write = ds1685_write;
+               break;
+       case ds1685_reg_indirect:
+               rtc->regs = devm_platform_ioremap_resource(pdev, 0);
+               if (IS_ERR(rtc->regs))
+                       return PTR_ERR(rtc->regs);
+               rtc->data = devm_platform_ioremap_resource(pdev, 1);
+               if (IS_ERR(rtc->data))
+                       return PTR_ERR(rtc->data);
+               rtc->read = ds1685_indirect_read;
+               rtc->write = ds1685_indirect_write;
+               break;
        }
-       rtc->alloc_io_resources = pdata->alloc_io_resources;
+
+       if (!rtc->read || !rtc->write)
+               return -ENXIO;
 
        /* Get the register step size. */
        if (pdata->regstep > 0)
@@ -1099,24 +1122,6 @@ ds1685_rtc_probe(struct platform_device *pdev)
        else
                rtc->regstep = 1;
 
-       /* Platform read function, else default if mmio setup */
-       if (pdata->plat_read)
-               rtc->read = pdata->plat_read;
-       else
-               if (pdata->alloc_io_resources)
-                       rtc->read = ds1685_read;
-               else
-                       return -ENXIO;
-
-       /* Platform write function, else default if mmio setup */
-       if (pdata->plat_write)
-               rtc->write = pdata->plat_write;
-       else
-               if (pdata->alloc_io_resources)
-                       rtc->write = ds1685_write;
-               else
-                       return -ENXIO;
-
        /* Platform pre-shutdown function, if defined. */
        if (pdata->plat_prepare_poweroff)
                rtc->prepare_poweroff = pdata->plat_prepare_poweroff;
@@ -1271,7 +1276,6 @@ ds1685_rtc_probe(struct platform_device *pdev)
        /* See if the platform doesn't support UIE. */
        if (pdata->uie_unsupported)
                rtc_dev->uie_unsupported = 1;
-       rtc->uie_unsupported = pdata->uie_unsupported;
 
        rtc->dev = rtc_dev;
 
@@ -1351,7 +1355,7 @@ ds1685_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
-/**
+/*
  * ds1685_rtc_driver - rtc driver properties.
  */
 static struct platform_driver ds1685_rtc_driver = {
index 77cca13..9f176bc 100644 (file)
@@ -71,7 +71,7 @@ static int em3027_get_time(struct device *dev, struct rtc_time *tm)
        tm->tm_hour     = bcd2bin(buf[2]);
        tm->tm_mday     = bcd2bin(buf[3]);
        tm->tm_wday     = bcd2bin(buf[4]);
-       tm->tm_mon      = bcd2bin(buf[5]);
+       tm->tm_mon      = bcd2bin(buf[5]) - 1;
        tm->tm_year     = bcd2bin(buf[6]) + 100;
 
        return 0;
@@ -94,7 +94,7 @@ static int em3027_set_time(struct device *dev, struct rtc_time *tm)
        buf[3] = bin2bcd(tm->tm_hour);
        buf[4] = bin2bcd(tm->tm_mday);
        buf[5] = bin2bcd(tm->tm_wday);
-       buf[6] = bin2bcd(tm->tm_mon);
+       buf[6] = bin2bcd(tm->tm_mon + 1);
        buf[7] = bin2bcd(tm->tm_year % 100);
 
        /* write time/date registers */
index 1766496..8ec9ea1 100644 (file)
@@ -122,15 +122,13 @@ static const struct attribute_group ep93xx_rtc_sysfs_files = {
 static int ep93xx_rtc_probe(struct platform_device *pdev)
 {
        struct ep93xx_rtc *ep93xx_rtc;
-       struct resource *res;
        int err;
 
        ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
        if (!ep93xx_rtc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ep93xx_rtc->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+       ep93xx_rtc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(ep93xx_rtc->mmio_base))
                return PTR_ERR(ep93xx_rtc->mmio_base);
 
index 8df2075..9e6e994 100644 (file)
@@ -180,10 +180,7 @@ static int ftm_rtc_alarm_irq_enable(struct device *dev,
  */
 static int ftm_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-       struct timespec64 ts64;
-
-       ktime_get_real_ts64(&ts64);
-       rtc_time_to_tm(ts64.tv_sec, tm);
+       rtc_time64_to_tm(ktime_get_real_seconds(), tm);
 
        return 0;
 }
@@ -206,16 +203,14 @@ static int ftm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
  */
 static int ftm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-       struct rtc_time tm;
-       unsigned long now, alm_time, cycle;
+       time64_t alm_time;
+       unsigned long long cycle;
        struct ftm_rtc *rtc = dev_get_drvdata(dev);
 
-       ftm_rtc_read_time(dev, &tm);
-       rtc_tm_to_time(&tm, &now);
-       rtc_tm_to_time(&alm->time, &alm_time);
+       alm_time = rtc_tm_to_time64(&alm->time);
 
        ftm_clean_alarm(rtc);
-       cycle = (alm_time - now) * rtc->alarm_freq;
+       cycle = (alm_time - ktime_get_real_seconds()) * rtc->alarm_freq;
        if (cycle > MAX_COUNT_VAL) {
                pr_err("Out of alarm range {0~262} seconds.\n");
                return -ERANGE;
@@ -248,7 +243,6 @@ static const struct rtc_class_ops ftm_rtc_ops = {
 static int ftm_rtc_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct resource *r;
        int irq;
        int ret;
        struct ftm_rtc *rtc;
@@ -265,13 +259,7 @@ static int ftm_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(rtc->rtc_dev))
                return PTR_ERR(rtc->rtc_dev);
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r) {
-               dev_err(&pdev->dev, "cannot get resource for rtc\n");
-               return -ENODEV;
-       }
-
-       rtc->base = devm_ioremap_resource(&pdev->dev, r);
+       rtc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->base)) {
                dev_err(&pdev->dev, "cannot ioremap resource for rtc\n");
                return PTR_ERR(rtc->base);
index 1a3420e..cb6b0ad 100644 (file)
@@ -165,7 +165,6 @@ static const struct rtc_class_ops goldfish_rtc_ops = {
 static int goldfish_rtc_probe(struct platform_device *pdev)
 {
        struct goldfish_rtc *rtcdrv;
-       struct resource *r;
        int err;
 
        rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);
@@ -173,12 +172,7 @@ static int goldfish_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, rtcdrv);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -ENODEV;
-
-       rtcdrv->base = devm_ioremap_resource(&pdev->dev, r);
+       rtcdrv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtcdrv->base))
                return -ENODEV;
 
index 3089645..18023e4 100644 (file)
@@ -307,7 +307,6 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz4740_rtc *rtc;
-       struct resource *mem;
        const struct platform_device_id *id = platform_get_device_id(pdev);
        const struct of_device_id *of_id = of_match_device(
                        jz4740_rtc_of_match, &pdev->dev);
@@ -326,8 +325,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        if (rtc->irq < 0)
                return -ENOENT;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->base = devm_ioremap_resource(&pdev->dev, mem);
+       rtc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->base))
                return PTR_ERR(rtc->base);
 
index a8bb156..00ef16b 100644 (file)
@@ -194,15 +194,13 @@ static const struct rtc_class_ops lpc24xx_rtc_ops = {
 static int lpc24xx_rtc_probe(struct platform_device *pdev)
 {
        struct lpc24xx_rtc *rtc;
-       struct resource *res;
        int irq, ret;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res);
+       rtc->rtc_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->rtc_base))
                return PTR_ERR(rtc->rtc_base);
 
index ac39323..15d8abd 100644 (file)
@@ -185,7 +185,6 @@ static const struct rtc_class_ops lpc32xx_rtc_ops = {
 
 static int lpc32xx_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct lpc32xx_rtc *rtc;
        int err;
        u32 tmp;
@@ -194,8 +193,7 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
        if (unlikely(!rtc))
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res);
+       rtc->rtc_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->rtc_base))
                return PTR_ERR(rtc->rtc_base);
 
@@ -266,16 +264,6 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int lpc32xx_rtc_remove(struct platform_device *pdev)
-{
-       struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
-
-       if (rtc->irq >= 0)
-               device_init_wakeup(&pdev->dev, 0);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM
 static int lpc32xx_rtc_suspend(struct device *dev)
 {
@@ -357,7 +345,6 @@ MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
 
 static struct platform_driver lpc32xx_rtc_driver = {
        .probe          = lpc32xx_rtc_probe,
-       .remove         = lpc32xx_rtc_remove,
        .driver = {
                .name   = "rtc-lpc32xx",
                .pm     = LPC32XX_RTC_PM_OPS,
index f9fa4f0..9b70b37 100644 (file)
@@ -235,9 +235,6 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
        unsigned char buf[8];
        int err, flags;
 
-       if (tm->tm_year < 100 || tm->tm_year > 199)
-               return -EINVAL;
-
        buf[M41T80_REG_SSEC] = 0;
        buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
        buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
@@ -705,7 +702,6 @@ static ssize_t wdt_read(struct file *file, char __user *buf,
 
 /**
  *     wdt_ioctl:
- *     @inode: inode of the device
  *     @file: file handle to the device
  *     @cmd: watchdog command
  *     @arg: argument pointer
@@ -926,6 +922,8 @@ static int m41t80_probe(struct i2c_client *client,
        }
 
        m41t80_data->rtc->ops = &m41t80_rtc_ops;
+       m41t80_data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+       m41t80_data->rtc->range_max = RTC_TIMESTAMP_END_2099;
 
        if (client->irq <= 0) {
                /* We cannot support UIE mode if we do not have an IRQ line */
index 59b54ed..75a0e73 100644 (file)
@@ -218,7 +218,6 @@ static bool m48t86_verify_chip(struct platform_device *pdev)
 static int m48t86_rtc_probe(struct platform_device *pdev)
 {
        struct m48t86_rtc_info *info;
-       struct resource *res;
        unsigned char reg;
        int err;
        struct nvmem_config m48t86_nvmem_cfg = {
@@ -235,17 +234,11 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
        if (!info)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-       info->index_reg = devm_ioremap_resource(&pdev->dev, res);
+       info->index_reg = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(info->index_reg))
                return PTR_ERR(info->index_reg);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!res)
-               return -ENODEV;
-       info->data_reg = devm_ioremap_resource(&pdev->dev, res);
+       info->data_reg = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(info->data_reg))
                return PTR_ERR(info->data_reg);
 
index 2ecd875..df2829d 100644 (file)
@@ -172,7 +172,20 @@ int mc146818_set_time(struct rtc_time *time)
        save_control = CMOS_READ(RTC_CONTROL);
        CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
        save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+#ifdef CONFIG_X86
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+            boot_cpu_data.x86 == 0x17) ||
+            boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
+               CMOS_WRITE((save_freq_select & (~RTC_DIV_RESET2)),
+                       RTC_FREQ_SELECT);
+               save_freq_select &= ~RTC_DIV_RESET2;
+       } else
+               CMOS_WRITE((save_freq_select | RTC_DIV_RESET2),
+                       RTC_FREQ_SELECT);
+#else
+       CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT);
+#endif
 
 #ifdef CONFIG_MACH_DECSTATION
        CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
index e08b981..47ebcf8 100644 (file)
@@ -131,7 +131,7 @@ static u32 meson_rtc_get_data(struct meson_rtc *rtc)
 
 static int meson_rtc_get_bus(struct meson_rtc *rtc)
 {
-       int ret, retries = 3;
+       int ret, retries;
        u32 val;
 
        /* prepare bus for transfers, set all lines low */
@@ -292,7 +292,6 @@ static int meson_rtc_probe(struct platform_device *pdev)
        };
        struct device *dev = &pdev->dev;
        struct meson_rtc *rtc;
-       struct resource *res;
        void __iomem *base;
        int ret;
        u32 tm;
@@ -312,8 +311,7 @@ static int meson_rtc_probe(struct platform_device *pdev)
        rtc->rtc->ops = &meson_rtc_ops;
        rtc->rtc->range_max = U32_MAX;
 
-       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);
 
index 1c2d3c4..80e364b 100644 (file)
@@ -88,28 +88,16 @@ static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
        __raw_writel(val, &priv->regs[reg]);
 }
 
-static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val,
-                              unsigned int reg)
-{
-       msm6242_write(priv, msm6242_read(priv, reg) | val, reg);
-}
-
-static inline void msm6242_clear(struct msm6242_priv *priv, unsigned int val,
-                                unsigned int reg)
-{
-       msm6242_write(priv, msm6242_read(priv, reg) & ~val, reg);
-}
-
 static void msm6242_lock(struct msm6242_priv *priv)
 {
        int cnt = 5;
 
-       msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
+       msm6242_write(priv, MSM6242_CD_HOLD|MSM6242_CD_IRQ_FLAG, MSM6242_CD);
 
        while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt) {
-               msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
+               msm6242_write(priv, MSM6242_CD_IRQ_FLAG, MSM6242_CD);
                udelay(70);
-               msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
+               msm6242_write(priv, MSM6242_CD_HOLD|MSM6242_CD_IRQ_FLAG, MSM6242_CD);
                cnt--;
        }
 
@@ -120,7 +108,7 @@ static void msm6242_lock(struct msm6242_priv *priv)
 
 static void msm6242_unlock(struct msm6242_priv *priv)
 {
-       msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
+       msm6242_write(priv, MSM6242_CD_IRQ_FLAG, MSM6242_CD);
 }
 
 static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
@@ -133,7 +121,8 @@ static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
                      msm6242_read(priv, MSM6242_SECOND1);
        tm->tm_min  = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
                      msm6242_read(priv, MSM6242_MINUTE1);
-       tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 +
+       tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10) &
+                      MSM6242_HOUR10_HR_MASK) * 10 +
                      msm6242_read(priv, MSM6242_HOUR1);
        tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
                      msm6242_read(priv, MSM6242_DAY1);
index 16bd26b..f1e3563 100644 (file)
@@ -303,7 +303,6 @@ MODULE_DEVICE_TABLE(of, mtk_rtc_match);
 static int mtk_rtc_probe(struct platform_device *pdev)
 {
        struct mtk_rtc *hw;
-       struct resource *res;
        int ret;
 
        hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
@@ -312,8 +311,7 @@ static int mtk_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, hw);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->base = devm_ioremap_resource(&pdev->dev, res);
+       hw->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hw->base))
                return PTR_ERR(hw->base);
 
index ab9db57..d5f190e 100644 (file)
@@ -212,7 +212,6 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = {
 
 static int __init mv_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct rtc_plat_data *pdata;
        u32 rtc_time;
        int ret = 0;
@@ -221,8 +220,7 @@ static int __init mv_rtc_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       pdata->ioaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pdata->ioaddr))
                return PTR_ERR(pdata->ioaddr);
 
index a2941c8..988a4df 100644 (file)
@@ -727,7 +727,6 @@ static struct nvmem_config omap_rtc_nvmem_config = {
 static int omap_rtc_probe(struct platform_device *pdev)
 {
        struct omap_rtc *rtc;
-       struct resource *res;
        u8 reg, mask, new_ctrl;
        const struct platform_device_id *id_entry;
        const struct of_device_id *of_id;
@@ -764,8 +763,7 @@ static int omap_rtc_probe(struct platform_device *pdev)
        if (!IS_ERR(rtc->clk))
                clk_prepare_enable(rtc->clk);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->base = devm_ioremap_resource(&pdev->dev, res);
+       rtc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->base)) {
                clk_disable_unprepare(rtc->clk);
                return PTR_ERR(rtc->base);
index 02b069c..ba5baac 100644 (file)
@@ -417,6 +417,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
                        const char *name, bool has_nvmem)
 {
        struct pcf2127 *pcf2127;
+       u32 wdd_timeout;
        int ret = 0;
 
        dev_dbg(dev, "%s\n", __func__);
@@ -459,7 +460,6 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
        /*
         * Watchdog timer enabled and reset pin /RST activated when timed out.
         * Select 1Hz clock source for watchdog timer.
-        * Timer is not started until WD_VAL is loaded with a valid value.
         * Note: Countdown timer disabled and not available.
         */
        ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL,
@@ -475,6 +475,14 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
                return ret;
        }
 
+       /* Test if watchdog timer is started by bootloader */
+       ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout);
+       if (ret)
+               return ret;
+
+       if (wdd_timeout)
+               set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status);
+
 #ifdef CONFIG_WATCHDOG
        ret = devm_watchdog_register_device(dev, &pcf2127->wdd);
        if (ret)
index 2f435e5..b24c908 100644 (file)
 #define REG_OFFSET   0x0e
 #define REG_OFFSET_MODE BIT(7)
 
-struct pcf8523 {
-       struct rtc_device *rtc;
-};
-
 static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep)
 {
        struct i2c_msg msgs[2];
@@ -345,16 +341,12 @@ static const struct rtc_class_ops pcf8523_rtc_ops = {
 static int pcf8523_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       struct pcf8523 *pcf;
+       struct rtc_device *rtc;
        int err;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
-       pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL);
-       if (!pcf)
-               return -ENOMEM;
-
        err = pcf8523_load_capacitance(client);
        if (err < 0)
                dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
@@ -364,12 +356,10 @@ static int pcf8523_probe(struct i2c_client *client,
        if (err < 0)
                return err;
 
-       pcf->rtc = devm_rtc_device_register(&client->dev, DRIVER_NAME,
+       rtc = devm_rtc_device_register(&client->dev, DRIVER_NAME,
                                       &pcf8523_rtc_ops, THIS_MODULE);
-       if (IS_ERR(pcf->rtc))
-               return PTR_ERR(pcf->rtc);
-
-       i2c_set_clientdata(client, pcf);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
 
        return 0;
 }
index 24baa47..3c322f3 100644 (file)
@@ -390,7 +390,7 @@ static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
 
 #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw)
 
-static int clkout_rates[] = {
+static const int clkout_rates[] = {
        32768,
        1024,
        32,
index 17653ed..2b69467 100644 (file)
@@ -298,7 +298,6 @@ static int pic32_rtc_remove(struct platform_device *pdev)
 static int pic32_rtc_probe(struct platform_device *pdev)
 {
        struct pic32_rtc_dev *pdata;
-       struct resource *res;
        int ret;
 
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -311,8 +310,7 @@ static int pic32_rtc_probe(struct platform_device *pdev)
        if (pdata->alarm_irq < 0)
                return pdata->alarm_irq;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pdata->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       pdata->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pdata->reg_base))
                return PTR_ERR(pdata->reg_base);
 
index f5a30e0..07ea1be 100644 (file)
@@ -49,7 +49,7 @@ struct pm8xxx_rtc_regs {
  * @regmap:            regmap used to access RTC registers
  * @allow_set_time:    indicates whether writing to the RTC is allowed
  * @rtc_alarm_irq:     rtc alarm irq number.
- * @ctrl_reg:          rtc control register.
+ * @regs:              rtc registers description.
  * @rtc_dev:           device structure.
  * @ctrl_reg_lock:     spinlock protecting access to ctrl_reg.
  */
index 2498278..aaf1b95 100644 (file)
@@ -354,21 +354,16 @@ static void rtc7301_init(struct rtc7301_priv *priv)
 
 static int __init rtc7301_rtc_probe(struct platform_device *dev)
 {
-       struct resource *res;
        void __iomem *regs;
        struct rtc7301_priv *priv;
        struct rtc_device *rtc;
        int ret;
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       regs = devm_ioremap_resource(&dev->dev, res);
+       regs = devm_platform_ioremap_resource(dev, 0);
        if (IS_ERR(regs))
                return PTR_ERR(regs);
 
index b233559..bb98f2d 100644 (file)
@@ -167,7 +167,6 @@ static const struct of_device_id rtd119x_rtc_dt_ids[] = {
 static int rtd119x_rtc_probe(struct platform_device *pdev)
 {
        struct rtd119x_rtc *data;
-       struct resource *res;
        u32 val;
        int ret;
 
@@ -178,8 +177,7 @@ static int rtd119x_rtc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, data);
        data->base_year = 2014;
 
-       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);
 
index 2b31666..6b7b3a6 100644 (file)
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk-provider.h>
 #include <linux/bcd.h>
 #include <linux/bitops.h>
 #include <linux/i2c.h>
 #define RV3028_STATUS_CLKF             BIT(6)
 #define RV3028_STATUS_EEBUSY           BIT(7)
 
+#define RV3028_CLKOUT_FD_MASK          GENMASK(2, 0)
+#define RV3028_CLKOUT_PORIE            BIT(3)
+#define RV3028_CLKOUT_CLKSY            BIT(6)
+#define RV3028_CLKOUT_CLKOE            BIT(7)
+
 #define RV3028_CTRL1_EERD              BIT(3)
 #define RV3028_CTRL1_WADA              BIT(5)
 
@@ -84,6 +90,9 @@ struct rv3028_data {
        struct regmap *regmap;
        struct rtc_device *rtc;
        enum rv3028_type type;
+#ifdef CONFIG_COMMON_CLK
+       struct clk_hw clkout_hw;
+#endif
 };
 
 static u16 rv3028_trickle_resistors[] = {1000, 3000, 6000, 11000};
@@ -581,6 +590,140 @@ restore_eerd:
        return ret;
 }
 
+#ifdef CONFIG_COMMON_CLK
+#define clkout_hw_to_rv3028(hw) container_of(hw, struct rv3028_data, clkout_hw)
+
+static int clkout_rates[] = {
+       32768,
+       8192,
+       1024,
+       64,
+       32,
+       1,
+};
+
+static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate)
+{
+       int clkout, ret;
+       struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
+
+       ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout);
+       if (ret < 0)
+               return 0;
+
+       clkout &= RV3028_CLKOUT_FD_MASK;
+       return clkout_rates[clkout];
+}
+
+static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long *prate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
+               if (clkout_rates[i] <= rate)
+                       return clkout_rates[i];
+
+       return 0;
+}
+
+static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long parent_rate)
+{
+       int i, ret;
+       struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
+
+       ret = regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) {
+               if (clkout_rates[i] == rate) {
+                       ret = regmap_update_bits(rv3028->regmap,
+                                                RV3028_CLKOUT,
+                                                RV3028_CLKOUT_FD_MASK, i);
+                       if (ret < 0)
+                               return ret;
+
+                       return regmap_write(rv3028->regmap, RV3028_CLKOUT,
+                               RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE);
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int rv3028_clkout_prepare(struct clk_hw *hw)
+{
+       struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
+
+       return regmap_write(rv3028->regmap, RV3028_CLKOUT,
+                           RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE);
+}
+
+static void rv3028_clkout_unprepare(struct clk_hw *hw)
+{
+       struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
+
+       regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0);
+       regmap_update_bits(rv3028->regmap, RV3028_STATUS,
+                          RV3028_STATUS_CLKF, 0);
+}
+
+static int rv3028_clkout_is_prepared(struct clk_hw *hw)
+{
+       int clkout, ret;
+       struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
+
+       ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout);
+       if (ret < 0)
+               return ret;
+
+       return !!(clkout & RV3028_CLKOUT_CLKOE);
+}
+
+static const struct clk_ops rv3028_clkout_ops = {
+       .prepare = rv3028_clkout_prepare,
+       .unprepare = rv3028_clkout_unprepare,
+       .is_prepared = rv3028_clkout_is_prepared,
+       .recalc_rate = rv3028_clkout_recalc_rate,
+       .round_rate = rv3028_clkout_round_rate,
+       .set_rate = rv3028_clkout_set_rate,
+};
+
+static int rv3028_clkout_register_clk(struct rv3028_data *rv3028,
+                                     struct i2c_client *client)
+{
+       int ret;
+       struct clk *clk;
+       struct clk_init_data init;
+       struct device_node *node = client->dev.of_node;
+
+       ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
+                                RV3028_STATUS_CLKF, 0);
+       if (ret < 0)
+               return ret;
+
+       init.name = "rv3028-clkout";
+       init.ops = &rv3028_clkout_ops;
+       init.flags = 0;
+       init.parent_names = NULL;
+       init.num_parents = 0;
+       rv3028->clkout_hw.init = &init;
+
+       /* optional override of the clockname */
+       of_property_read_string(node, "clock-output-names", &init.name);
+
+       /* register the clock */
+       clk = devm_clk_register(&client->dev, &rv3028->clkout_hw);
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+       return 0;
+}
+#endif
+
 static struct rtc_class_ops rv3028_rtc_ops = {
        .read_time = rv3028_get_time,
        .set_time = rv3028_set_time,
@@ -708,6 +851,9 @@ static int rv3028_probe(struct i2c_client *client)
 
        rv3028->rtc->max_user_freq = 1;
 
+#ifdef CONFIG_COMMON_CLK
+       rv3028_clkout_register_clk(rv3028, client);
+#endif
        return 0;
 }
 
index 71e20a6..3a9eb70 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Driver for the Epson RTC module RX-6110 SA
  *
  * Copyright(C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
  * Copyright(C) SEIKO EPSON CORPORATION 2013. All rights reserved.
- *
- * This driver software is distributed as is, without any warranty of any kind,
- * either express or implied as further specified in the GNU Public License.
- * This software may be used and distributed according to the terms of the GNU
- * Public License, version 2 as published by the Free Software Foundation.
- * See the file COPYING in the main directory of this archive for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/bcd.h>
@@ -370,11 +362,6 @@ static int rx6110_probe(struct spi_device *spi)
        return 0;
 }
 
-static int rx6110_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static const struct spi_device_id rx6110_id[] = {
        { "rx6110", 0 },
        { }
@@ -393,7 +380,6 @@ static struct spi_driver rx6110_driver = {
                .of_match_table = of_match_ptr(rx6110_spi_of_match),
        },
        .probe          = rx6110_probe,
-       .remove         = rx6110_remove,
        .id_table       = rx6110_id,
 };
 
index da34cfd..03672a2 100644 (file)
@@ -423,8 +423,6 @@ static const struct rtc_class_ops s35390a_rtc_ops = {
        .ioctl          = s35390a_rtc_ioctl,
 };
 
-static struct i2c_driver s35390a_driver;
-
 static int s35390a_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -456,6 +454,10 @@ static int s35390a_probe(struct i2c_client *client,
                }
        }
 
+       s35390a->rtc = devm_rtc_allocate_device(dev);
+       if (IS_ERR(s35390a->rtc))
+               return PTR_ERR(s35390a->rtc);
+
        err_read = s35390a_read_status(s35390a, &status1);
        if (err_read < 0) {
                dev_err(dev, "error resetting chip\n");
@@ -485,11 +487,9 @@ static int s35390a_probe(struct i2c_client *client,
 
        device_set_wakeup_capable(dev, 1);
 
-       s35390a->rtc = devm_rtc_device_register(dev, s35390a_driver.driver.name,
-                                               &s35390a_rtc_ops, THIS_MODULE);
-
-       if (IS_ERR(s35390a->rtc))
-               return PTR_ERR(s35390a->rtc);
+       s35390a->rtc->ops = &s35390a_rtc_ops;
+       s35390a->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+       s35390a->rtc->range_max = RTC_TIMESTAMP_END_2099;
 
        /* supports per-minute alarms only, therefore set uie_unsupported */
        s35390a->rtc->uie_unsupported = 1;
@@ -497,7 +497,7 @@ static int s35390a_probe(struct i2c_client *client,
        if (status1 & S35390A_FLAG_INT2)
                rtc_update_irq(s35390a->rtc, 1, RTC_AF);
 
-       return 0;
+       return rtc_register_device(s35390a->rtc);
 }
 
 static struct i2c_driver s35390a_driver = {
index 7801249..e1b50e6 100644 (file)
@@ -444,7 +444,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 {
        struct s3c_rtc *info = NULL;
        struct rtc_time rtc_tm;
-       struct resource *res;
        int ret;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -475,8 +474,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                info->irq_tick, info->irq_alarm);
 
        /* get the memory region */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       info->base = devm_ioremap_resource(&pdev->dev, res);
+       info->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(info->base))
                return PTR_ERR(info->base);
 
index 86fa723..d37893f 100644 (file)
@@ -252,7 +252,6 @@ EXPORT_SYMBOL_GPL(sa1100_rtc_init);
 static int sa1100_rtc_probe(struct platform_device *pdev)
 {
        struct sa1100_rtc *info;
-       struct resource *iores;
        void __iomem *base;
        int irq_1hz, irq_alarm;
        int ret;
@@ -281,8 +280,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, iores);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index b956768..36810dd 100644 (file)
@@ -661,12 +661,6 @@ static int sprd_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int sprd_rtc_remove(struct platform_device *pdev)
-{
-       device_init_wakeup(&pdev->dev, 0);
-       return 0;
-}
-
 static const struct of_device_id sprd_rtc_of_match[] = {
        { .compatible = "sprd,sc2731-rtc", },
        { },
@@ -679,7 +673,6 @@ static struct platform_driver sprd_rtc_driver = {
                .of_match_table = sprd_rtc_of_match,
        },
        .probe  = sprd_rtc_probe,
-       .remove = sprd_rtc_remove,
 };
 module_platform_driver(sprd_rtc_driver);
 
index c759c55..a2c9c55 100644 (file)
@@ -365,13 +365,6 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int sirfsoc_rtc_remove(struct platform_device *pdev)
-{
-       device_init_wakeup(&pdev->dev, 0);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int sirfsoc_rtc_suspend(struct device *dev)
 {
@@ -450,7 +443,6 @@ static struct platform_driver sirfsoc_rtc_driver = {
                .of_match_table = sirfsoc_rtc_of_match,
        },
        .probe = sirfsoc_rtc_probe,
-       .remove = sirfsoc_rtc_remove,
 };
 module_platform_driver(sirfsoc_rtc_driver);
 
index 9f23b24..833daeb 100644 (file)
@@ -347,7 +347,6 @@ static const struct rtc_class_ops spear_rtc_ops = {
 
 static int spear_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct spear_rtc_config *config;
        int status = 0;
        int irq;
@@ -369,8 +368,7 @@ static int spear_rtc_probe(struct platform_device *pdev)
                return status;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       config->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       config->ioaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(config->ioaddr))
                return PTR_ERR(config->ioaddr);
 
index 49474a3..51041dc 100644 (file)
@@ -41,7 +41,6 @@
 struct st_rtc {
        struct rtc_device *rtc_dev;
        struct rtc_wkalrm alarm;
-       struct resource *res;
        struct clk *clk;
        unsigned long clkrate;
        void __iomem *ioaddr;
@@ -186,7 +185,6 @@ static int st_rtc_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct st_rtc *rtc;
-       struct resource *res;
        uint32_t mode;
        int ret = 0;
 
@@ -210,8 +208,7 @@ static int st_rtc_probe(struct platform_device *pdev)
 
        spin_lock_init(&rtc->lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       rtc->ioaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->ioaddr))
                return PTR_ERR(rtc->ioaddr);
 
index a833ebc..01a4504 100644 (file)
@@ -256,7 +256,6 @@ static int stk17ta8_nvram_write(void *priv, unsigned int pos, void *val,
 
 static int stk17ta8_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        unsigned int cal;
        unsigned int flags;
        struct rtc_plat_data *pdata;
@@ -275,8 +274,7 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       ioaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(ioaddr))
                return PTR_ERR(ioaddr);
        pdata->ioaddr = ioaddr;
index 2999e33..781cabb 100644 (file)
@@ -693,15 +693,13 @@ static int stm32_rtc_probe(struct platform_device *pdev)
 {
        struct stm32_rtc *rtc;
        const struct stm32_rtc_registers *regs;
-       struct resource *res;
        int ret;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rtc->base = devm_ioremap_resource(&pdev->dev, res);
+       rtc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rtc->base))
                return PTR_ERR(rtc->base);
 
index 5e2bd9f..8dcd20b 100644 (file)
@@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data {
 
 struct sun6i_rtc_dev {
        struct rtc_device *rtc;
-       struct device *dev;
        const struct sun6i_rtc_clk_data *data;
        void __iomem *base;
        int irq;
@@ -669,7 +668,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
                return -ENODEV;
 
        platform_set_drvdata(pdev, chip);
-       chip->dev = &pdev->dev;
 
        chip->irq = platform_get_irq(pdev, 0);
        if (chip->irq < 0)
index 9b6f248..f5d7f44 100644 (file)
@@ -422,7 +422,6 @@ MODULE_DEVICE_TABLE(of, sunxi_rtc_dt_ids);
 static int sunxi_rtc_probe(struct platform_device *pdev)
 {
        struct sunxi_rtc_dev *chip;
-       struct resource *res;
        int ret;
 
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
@@ -436,8 +435,7 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(chip->rtc))
                return PTR_ERR(chip->rtc);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       chip->base = devm_ioremap_resource(&pdev->dev, res);
+       chip->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(chip->base))
                return PTR_ERR(chip->base);
 
index 69d695b..7fbb174 100644 (file)
@@ -103,7 +103,7 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
        unsigned long flags;
-       u32 sec, msec;
+       u32 sec;
 
        /*
         * RTC hardware copies seconds to shadow seconds when a read of
@@ -111,7 +111,7 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
         */
        spin_lock_irqsave(&info->lock, flags);
 
-       msec = readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
+       readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
        sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS);
 
        spin_unlock_irqrestore(&info->lock, flags);
@@ -277,15 +277,13 @@ MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
 static int tegra_rtc_probe(struct platform_device *pdev)
 {
        struct tegra_rtc_info *info;
-       struct resource *res;
        int ret;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       info->base = devm_ioremap_resource(&pdev->dev, res);
+       info->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(info->base))
                return PTR_ERR(info->base);
 
index 2c0467a..e384038 100644 (file)
@@ -361,6 +361,13 @@ static const struct rtc_class_ops tps65910_rtc_ops = {
        .set_offset     = tps65910_set_offset,
 };
 
+static const struct rtc_class_ops tps65910_rtc_ops_noirq = {
+       .read_time      = tps65910_rtc_read_time,
+       .set_time       = tps65910_rtc_set_time,
+       .read_offset    = tps65910_read_offset,
+       .set_offset     = tps65910_set_offset,
+};
+
 static int tps65910_rtc_probe(struct platform_device *pdev)
 {
        struct tps65910 *tps65910 = NULL;
@@ -414,14 +421,16 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
                dev_name(&pdev->dev), &pdev->dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "IRQ is not free.\n");
-               return ret;
-       }
+       if (ret < 0)
+               irq = -1;
+
        tps_rtc->irq = irq;
-       device_set_wakeup_capable(&pdev->dev, 1);
+       if (irq != -1) {
+               device_set_wakeup_capable(&pdev->dev, 1);
+               tps_rtc->rtc->ops = &tps65910_rtc_ops;
+       } else
+               tps_rtc->rtc->ops = &tps65910_rtc_ops_noirq;
 
-       tps_rtc->rtc->ops = &tps65910_rtc_ops;
        tps_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
        tps_rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
 
index 5a29915..715b829 100644 (file)
@@ -236,7 +236,6 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct tx4939rtc_plat_data *pdata;
-       struct resource *res;
        int irq, ret;
        struct nvmem_config nvmem_cfg = {
                .name = "tx4939_nvram",
@@ -253,8 +252,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
        platform_set_drvdata(pdev, pdata);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pdata->rtcreg = devm_ioremap_resource(&pdev->dev, res);
+       pdata->rtcreg = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pdata->rtcreg))
                return PTR_ERR(pdata->rtcreg);
 
index 63ffba2..d2da921 100644 (file)
@@ -284,7 +284,6 @@ static int rtc_probe(struct platform_device *pdev)
        struct v3020 *chip;
        int retval = -EBUSY;
        int i;
-       int temp;
 
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -302,7 +301,7 @@ static int rtc_probe(struct platform_device *pdev)
        /* Make sure the v3020 expects a communication cycle
         * by reading 8 times */
        for (i = 0; i < 8; i++)
-               temp = chip->ops->read_bit(chip);
+               chip->ops->read_bit(chip);
 
        /* Test chip by doing a write/read sequence
         * to the chip ram */
index d5d14cf..e258862 100644 (file)
@@ -122,12 +122,6 @@ static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
 
-       if (tm->tm_year < 100) {
-               dev_warn(dev, "Only years 2000-2199 are supported by the "
-                             "hardware!\n");
-               return -EINVAL;
-       }
-
        writel((bin2bcd(tm->tm_year % 100) << DATE_YEAR_S)
                | (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S)
                | (bin2bcd(tm->tm_mday))
@@ -200,7 +194,6 @@ static const struct rtc_class_ops vt8500_rtc_ops = {
 static int vt8500_rtc_probe(struct platform_device *pdev)
 {
        struct vt8500_rtc *vt8500_rtc;
-       struct resource *res;
        int ret;
 
        vt8500_rtc = devm_kzalloc(&pdev->dev,
@@ -215,8 +208,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
        if (vt8500_rtc->irq_alarm < 0)
                return vt8500_rtc->irq_alarm;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res);
+       vt8500_rtc->regbase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(vt8500_rtc->regbase))
                return PTR_ERR(vt8500_rtc->regbase);
 
@@ -224,27 +216,23 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
        writel(VT8500_RTC_CR_ENABLE,
               vt8500_rtc->regbase + VT8500_RTC_CR);
 
-       vt8500_rtc->rtc = devm_rtc_device_register(&pdev->dev, "vt8500-rtc",
-                                             &vt8500_rtc_ops, THIS_MODULE);
-       if (IS_ERR(vt8500_rtc->rtc)) {
-               ret = PTR_ERR(vt8500_rtc->rtc);
-               dev_err(&pdev->dev,
-                       "Failed to register RTC device -> %d\n", ret);
-               goto err_return;
-       }
+       vt8500_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(vt8500_rtc->rtc))
+               return PTR_ERR(vt8500_rtc->rtc);
+
+       vt8500_rtc->rtc->ops = &vt8500_rtc_ops;
+       vt8500_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+       vt8500_rtc->rtc->range_max = RTC_TIMESTAMP_END_2199;
 
        ret = devm_request_irq(&pdev->dev, vt8500_rtc->irq_alarm,
                                vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "can't get irq %i, err %d\n",
                        vt8500_rtc->irq_alarm, ret);
-               goto err_return;
+               return ret;
        }
 
-       return 0;
-
-err_return:
-       return ret;
+       return rtc_register_device(vt8500_rtc->rtc);
 }
 
 static int vt8500_rtc_remove(struct platform_device *pdev)
index 8ad4c4e..ff46066 100644 (file)
@@ -110,10 +110,12 @@ static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm)
        tm->tm_mday     = rtc.day;
        tm->tm_mon      = rtc.month - 1;
        tm->tm_year     = rtc.year + (rtc.century * 100) - 1900;
-       tm->tm_yday     = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+       /* Ignore other tm fields, man rtc says userspace shouldn't use them. */
 
-       /* Don't compute day of week, we don't need it. */
-       tm->tm_wday = -1;
+       if (rtc_valid_tm(tm)) {
+               dev_err(dev, "Time from RTC is invalid: %ptRr\n", tm);
+               return -EIO;
+       }
 
        return 0;
 }
index 9683fbf..96db441 100644 (file)
@@ -34,7 +34,6 @@
 
 struct xgene_rtc_dev {
        struct rtc_device *rtc;
-       struct device *dev;
        void __iomem *csr_base;
        struct clk *clk;
        unsigned int irq_wake;
@@ -137,7 +136,6 @@ static irqreturn_t xgene_rtc_interrupt(int irq, void *id)
 static int xgene_rtc_probe(struct platform_device *pdev)
 {
        struct xgene_rtc_dev *pdata;
-       struct resource *res;
        int ret;
        int irq;
 
@@ -145,10 +143,8 @@ static int xgene_rtc_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
        platform_set_drvdata(pdev, pdata);
-       pdata->dev = &pdev->dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pdata->csr_base = devm_ioremap_resource(&pdev->dev, res);
+       pdata->csr_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pdata->csr_base))
                return PTR_ERR(pdata->csr_base);
 
index 2c76275..5396905 100644 (file)
@@ -44,7 +44,7 @@ struct xlnx_rtc_dev {
        void __iomem            *reg_base;
        int                     alarm_irq;
        int                     sec_irq;
-       int                     calibval;
+       unsigned int            calibval;
 };
 
 static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -195,7 +195,6 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
 static int xlnx_rtc_probe(struct platform_device *pdev)
 {
        struct xlnx_rtc_dev *xrtcdev;
-       struct resource *res;
        int ret;
 
        xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
@@ -211,9 +210,7 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
        xrtcdev->rtc->ops = &xlnx_rtc_ops;
        xrtcdev->rtc->range_max = U32_MAX;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       xrtcdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xrtcdev->reg_base))
                return PTR_ERR(xrtcdev->reg_base);
 
index be3531e..b7ca7d7 100644 (file)
@@ -103,8 +103,11 @@ static DEVICE_ATTR_RW(max_user_freq);
 
 /**
  * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time
+ * @dev: The device that the attribute belongs to.
+ * @attr: The attribute being read.
+ * @buf: The result buffer.
  *
- * Returns 1 if the system clock was set by this RTC at the last
+ * buf is "1" if the system clock was set by this RTC at the last
  * boot or resume event.
  */
 static ssize_t
index f34ee41..4f4dd9d 100644 (file)
@@ -61,6 +61,7 @@ struct error_hdr {
 #define REP82_ERROR_EVEN_MOD_IN_OPND       0x85
 #define REP82_ERROR_RESERVED_FIELD         0x88
 #define REP82_ERROR_INVALID_DOMAIN_PENDING  0x8A
+#define REP82_ERROR_FILTERED_BY_HYPERVISOR  0x8B
 #define REP82_ERROR_TRANSPORT_FAIL         0x90
 #define REP82_ERROR_PACKET_TRUNCATED       0xA0
 #define REP82_ERROR_ZERO_BUFFER_LEN        0xB0
@@ -91,6 +92,7 @@ static inline int convert_error(struct zcrypt_queue *zq,
        case REP82_ERROR_INVALID_DOMAIN_PRECHECK:
        case REP82_ERROR_INVALID_DOMAIN_PENDING:
        case REP82_ERROR_INVALID_SPECIAL_CMD:
+       case REP82_ERROR_FILTERED_BY_HYPERVISOR:
        //   REP88_ERROR_INVALID_KEY            // '82' CEX2A
        //   REP88_ERROR_OPERAND                // '84' CEX2A
        //   REP88_ERROR_OPERAND_EVEN_MOD       // '85' CEX2A
index 9dda431..352056e 100644 (file)
@@ -5,6 +5,6 @@
 
 zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_dbf.o zfcp_erp.o \
             zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \
-            zfcp_unit.o
+            zfcp_unit.o zfcp_diag.o
 
 obj-$(CONFIG_ZFCP) += zfcp.o
index e390f8c..09ec846 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Module interface and handling of zfcp data structures.
  *
- * Copyright IBM Corp. 2002, 2017
+ * Copyright IBM Corp. 2002, 2018
  */
 
 /*
@@ -25,6 +25,7 @@
  *            Martin Petermann
  *            Sven Schuetz
  *            Steffen Maier
+ *           Benjamin Block
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -36,6 +37,7 @@
 #include "zfcp_ext.h"
 #include "zfcp_fc.h"
 #include "zfcp_reqlist.h"
+#include "zfcp_diag.h"
 
 #define ZFCP_BUS_ID_SIZE       20
 
@@ -356,6 +358,9 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 
        adapter->erp_action.adapter = adapter;
 
+       if (zfcp_diag_adapter_setup(adapter))
+               goto failed;
+
        if (zfcp_qdio_setup(adapter))
                goto failed;
 
@@ -402,6 +407,9 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
                               &zfcp_sysfs_adapter_attrs))
                goto failed;
 
+       if (zfcp_diag_sysfs_setup(adapter))
+               goto failed;
+
        /* report size limit per scatter-gather segment */
        adapter->ccw_device->dev.dma_parms = &adapter->dma_parms;
 
@@ -426,6 +434,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
 
        zfcp_fc_wka_ports_force_offline(adapter->gs);
        zfcp_scsi_adapter_unregister(adapter);
+       zfcp_diag_sysfs_destroy(adapter);
        sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);
 
        zfcp_erp_thread_kill(adapter);
@@ -449,6 +458,7 @@ void zfcp_adapter_release(struct kref *ref)
        dev_set_drvdata(&adapter->ccw_device->dev, NULL);
        zfcp_fc_gs_destroy(adapter);
        zfcp_free_low_mem_buffers(adapter);
+       zfcp_diag_adapter_free(adapter);
        kfree(adapter->req_list);
        kfree(adapter->fc_stats);
        kfree(adapter->stats_reset_data);
index dccdb41..1234294 100644 (file)
@@ -95,11 +95,9 @@ void zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req)
        memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual,
               FSF_STATUS_QUALIFIER_SIZE);
 
-       if (q_head->fsf_command != FSF_QTCB_FCP_CMND) {
-               rec->pl_len = q_head->log_length;
-               zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
-                                 rec->pl_len, "fsf_res", req->req_id);
-       }
+       rec->pl_len = q_head->log_length;
+       zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
+                         rec->pl_len, "fsf_res", req->req_id);
 
        debug_event(dbf->hba, level, rec, sizeof(*rec));
        spin_unlock_irqrestore(&dbf->hba_lock, flags);
index 87d2f47..8cc0eef 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Global definitions for the zfcp device driver.
  *
- * Copyright IBM Corp. 2002, 2017
+ * Copyright IBM Corp. 2002, 2018
  */
 
 #ifndef ZFCP_DEF_H
@@ -86,6 +86,7 @@
 #define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED       0x00000080
 #define ZFCP_STATUS_FSFREQ_TMFUNCFAILED         0x00000200
 #define ZFCP_STATUS_FSFREQ_DISMISSED            0x00001000
+#define ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE     0x00020000
 
 /************************* STRUCTURE DEFINITIONS *****************************/
 
@@ -197,6 +198,7 @@ struct zfcp_adapter {
        struct device_dma_parameters dma_parms;
        struct zfcp_fc_events events;
        unsigned long           next_port_scan;
+       struct zfcp_diag_adapter        *diagnostics;
 };
 
 struct zfcp_port {
diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c
new file mode 100644 (file)
index 0000000..67a8f4e
--- /dev/null
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * zfcp device driver
+ *
+ * Functions to handle diagnostics.
+ *
+ * Copyright IBM Corp. 2018
+ */
+
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/kernfs.h>
+#include <linux/sysfs.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "zfcp_diag.h"
+#include "zfcp_ext.h"
+#include "zfcp_def.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(__zfcp_diag_publish_wait);
+
+/**
+ * zfcp_diag_adapter_setup() - Setup storage for adapter diagnostics.
+ * @adapter: the adapter to setup diagnostics for.
+ *
+ * Creates the data-structures to store the diagnostics for an adapter. This
+ * overwrites whatever was stored before at &zfcp_adapter->diagnostics!
+ *
+ * Return:
+ * * 0      - Everyting is OK
+ * * -ENOMEM - Could not allocate all/parts of the data-structures;
+ *            &zfcp_adapter->diagnostics remains unchanged
+ */
+int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter)
+{
+       struct zfcp_diag_adapter *diag;
+       struct zfcp_diag_header *hdr;
+
+       diag = kzalloc(sizeof(*diag), GFP_KERNEL);
+       if (diag == NULL)
+               return -ENOMEM;
+
+       diag->max_age = (5 * 1000); /* default value: 5 s */
+
+       /* setup header for port_data */
+       hdr = &diag->port_data.header;
+
+       spin_lock_init(&hdr->access_lock);
+       hdr->buffer = &diag->port_data.data;
+       hdr->buffer_size = sizeof(diag->port_data.data);
+       /* set the timestamp so that the first test on age will always fail */
+       hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age);
+
+       /* setup header for config_data */
+       hdr = &diag->config_data.header;
+
+       spin_lock_init(&hdr->access_lock);
+       hdr->buffer = &diag->config_data.data;
+       hdr->buffer_size = sizeof(diag->config_data.data);
+       /* set the timestamp so that the first test on age will always fail */
+       hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age);
+
+       adapter->diagnostics = diag;
+       return 0;
+}
+
+/**
+ * zfcp_diag_adapter_free() - Frees all adapter diagnostics allocations.
+ * @adapter: the adapter whose diagnostic structures should be freed.
+ *
+ * Frees all data-structures in the given adapter that store diagnostics
+ * information. Can savely be called with partially setup diagnostics.
+ */
+void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter)
+{
+       kfree(adapter->diagnostics);
+       adapter->diagnostics = NULL;
+}
+
+/**
+ * zfcp_diag_sysfs_setup() - Setup the sysfs-group for adapter-diagnostics.
+ * @adapter: target adapter to which the group should be added.
+ *
+ * Return: 0 on success; Something else otherwise (see sysfs_create_group()).
+ */
+int zfcp_diag_sysfs_setup(struct zfcp_adapter *const adapter)
+{
+       int rc = sysfs_create_group(&adapter->ccw_device->dev.kobj,
+                                   &zfcp_sysfs_diag_attr_group);
+       if (rc == 0)
+               adapter->diagnostics->sysfs_established = 1;
+
+       return rc;
+}
+
+/**
+ * zfcp_diag_sysfs_destroy() - Remove the sysfs-group for adapter-diagnostics.
+ * @adapter: target adapter from which the group should be removed.
+ */
+void zfcp_diag_sysfs_destroy(struct zfcp_adapter *const adapter)
+{
+       if (adapter->diagnostics == NULL ||
+           !adapter->diagnostics->sysfs_established)
+               return;
+
+       /*
+        * We need this state-handling so we can prevent warnings being printed
+        * on the kernel-console in case we have to abort a halfway done
+        * zfcp_adapter_enqueue(), in which the sysfs-group was not yet
+        * established. sysfs_remove_group() does this checking as well, but
+        * still prints a warning in case we try to remove a group that has not
+        * been established before
+        */
+       adapter->diagnostics->sysfs_established = 0;
+       sysfs_remove_group(&adapter->ccw_device->dev.kobj,
+                          &zfcp_sysfs_diag_attr_group);
+}
+
+
+/**
+ * zfcp_diag_update_xdata() - Update a diagnostics buffer.
+ * @hdr: the meta data to update.
+ * @data: data to use for the update.
+ * @incomplete: flag stating whether the data in @data is incomplete.
+ */
+void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr,
+                           const void *const data, const bool incomplete)
+{
+       const unsigned long capture_timestamp = jiffies;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdr->access_lock, flags);
+
+       /* make sure we never go into the past with an update */
+       if (!time_after_eq(capture_timestamp, hdr->timestamp))
+               goto out;
+
+       hdr->timestamp = capture_timestamp;
+       hdr->incomplete = incomplete;
+       memcpy(hdr->buffer, data, hdr->buffer_size);
+out:
+       spin_unlock_irqrestore(&hdr->access_lock, flags);
+}
+
+/**
+ * zfcp_diag_update_port_data_buffer() - Implementation of
+ *                                      &typedef zfcp_diag_update_buffer_func
+ *                                      to collect and update Port Data.
+ * @adapter: Adapter to collect Port Data from.
+ *
+ * This call is SYNCHRONOUS ! It blocks till the respective command has
+ * finished completely, or has failed in some way.
+ *
+ * Return:
+ * * 0         - Successfully retrieved new Diagnostics and Updated the buffer;
+ *               this also includes cases where data was retrieved, but
+ *               incomplete; you'll have to check the flag ``incomplete``
+ *               of &struct zfcp_diag_header.
+ * * see zfcp_fsf_exchange_port_data_sync() for possible error-codes (
+ *   excluding -EAGAIN)
+ */
+int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter)
+{
+       int rc;
+
+       rc = zfcp_fsf_exchange_port_data_sync(adapter->qdio, NULL);
+       if (rc == -EAGAIN)
+               rc = 0; /* signaling incomplete via struct zfcp_diag_header */
+
+       /* buffer-data was updated in zfcp_fsf_exchange_port_data_handler() */
+
+       return rc;
+}
+
+/**
+ * zfcp_diag_update_config_data_buffer() - Implementation of
+ *                                        &typedef zfcp_diag_update_buffer_func
+ *                                        to collect and update Config Data.
+ * @adapter: Adapter to collect Config Data from.
+ *
+ * This call is SYNCHRONOUS ! It blocks till the respective command has
+ * finished completely, or has failed in some way.
+ *
+ * Return:
+ * * 0         - Successfully retrieved new Diagnostics and Updated the buffer;
+ *               this also includes cases where data was retrieved, but
+ *               incomplete; you'll have to check the flag ``incomplete``
+ *               of &struct zfcp_diag_header.
+ * * see zfcp_fsf_exchange_config_data_sync() for possible error-codes (
+ *   excluding -EAGAIN)
+ */
+int zfcp_diag_update_config_data_buffer(struct zfcp_adapter *const adapter)
+{
+       int rc;
+
+       rc = zfcp_fsf_exchange_config_data_sync(adapter->qdio, NULL);
+       if (rc == -EAGAIN)
+               rc = 0; /* signaling incomplete via struct zfcp_diag_header */
+
+       /* buffer-data was updated in zfcp_fsf_exchange_config_data_handler() */
+
+       return rc;
+}
+
+static int __zfcp_diag_update_buffer(struct zfcp_adapter *const adapter,
+                                    struct zfcp_diag_header *const hdr,
+                                    zfcp_diag_update_buffer_func buffer_update,
+                                    unsigned long *const flags)
+       __must_hold(hdr->access_lock)
+{
+       int rc;
+
+       if (hdr->updating == 1) {
+               rc = wait_event_interruptible_lock_irq(__zfcp_diag_publish_wait,
+                                                      hdr->updating == 0,
+                                                      hdr->access_lock);
+               rc = (rc == 0 ? -EAGAIN : -EINTR);
+       } else {
+               hdr->updating = 1;
+               spin_unlock_irqrestore(&hdr->access_lock, *flags);
+
+               /* unlocked, because update function sleeps */
+               rc = buffer_update(adapter);
+
+               spin_lock_irqsave(&hdr->access_lock, *flags);
+               hdr->updating = 0;
+
+               /*
+                * every thread waiting here went via an interruptible wait,
+                * so its fine to only wake those
+                */
+               wake_up_interruptible_all(&__zfcp_diag_publish_wait);
+       }
+
+       return rc;
+}
+
+static bool
+__zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_adapter *const diag,
+                                   const struct zfcp_diag_header *const hdr)
+       __must_hold(hdr->access_lock)
+{
+       const unsigned long now = jiffies;
+
+       /*
+        * Should not happen (data is from the future).. if it does, still
+        * signal that it needs refresh
+        */
+       if (!time_after_eq(now, hdr->timestamp))
+               return false;
+
+       if (jiffies_to_msecs(now - hdr->timestamp) >= diag->max_age)
+               return false;
+
+       return true;
+}
+
+/**
+ * zfcp_diag_update_buffer_limited() - Collect diagnostics and update a
+ *                                    diagnostics buffer rate limited.
+ * @adapter: Adapter to collect the diagnostics from.
+ * @hdr: buffer-header for which to update with the collected diagnostics.
+ * @buffer_update: Specific implementation for collecting and updating.
+ *
+ * This function will cause an update of the given @hdr by calling the also
+ * given @buffer_update function. If called by multiple sources at the same
+ * time, it will synchornize the update by only allowing one source to call
+ * @buffer_update and the others to wait for that source to complete instead
+ * (the wait is interruptible).
+ *
+ * Additionally this version is rate-limited and will only exit if either the
+ * buffer is fresh enough (within the limit) - it will do nothing if the buffer
+ * is fresh enough to begin with -, or if the source/thread that started this
+ * update is the one that made the update (to prevent endless loops).
+ *
+ * Return:
+ * * 0         - If the update was successfully published and/or the buffer is
+ *               fresh enough
+ * * -EINTR    - If the thread went into the wait-state and was interrupted
+ * * whatever @buffer_update returns
+ */
+int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter,
+                                   struct zfcp_diag_header *const hdr,
+                                   zfcp_diag_update_buffer_func buffer_update)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&hdr->access_lock, flags);
+
+       for (rc = 0;
+            !__zfcp_diag_test_buffer_age_isfresh(adapter->diagnostics, hdr);
+            rc = 0) {
+               rc = __zfcp_diag_update_buffer(adapter, hdr, buffer_update,
+                                              &flags);
+               if (rc != -EAGAIN)
+                       break;
+       }
+
+       spin_unlock_irqrestore(&hdr->access_lock, flags);
+
+       return rc;
+}
diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h
new file mode 100644 (file)
index 0000000..b9c93d1
--- /dev/null
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * zfcp device driver
+ *
+ * Definitions for handling diagnostics in the the zfcp device driver.
+ *
+ * Copyright IBM Corp. 2018
+ */
+
+#ifndef ZFCP_DIAG_H
+#define ZFCP_DIAG_H
+
+#include <linux/spinlock.h>
+
+#include "zfcp_fsf.h"
+#include "zfcp_def.h"
+
+/**
+ * struct zfcp_diag_header - general part of a diagnostic buffer.
+ * @access_lock: lock protecting all the data in this buffer.
+ * @updating: flag showing that an update for this buffer is currently running.
+ * @incomplete: flag showing that the data in @buffer is incomplete.
+ * @timestamp: time in jiffies when the data of this buffer was last captured.
+ * @buffer: implementation-depending data of this buffer
+ * @buffer_size: size of @buffer
+ */
+struct zfcp_diag_header {
+       spinlock_t      access_lock;
+
+       /* Flags */
+       u64             updating        :1;
+       u64             incomplete      :1;
+
+       unsigned long   timestamp;
+
+       void            *buffer;
+       size_t          buffer_size;
+};
+
+/**
+ * struct zfcp_diag_adapter - central storage for all diagnostics concerning an
+ *                           adapter.
+ * @sysfs_established: flag showing that the associated sysfs-group was created
+ *                    during run of zfcp_adapter_enqueue().
+ * @max_age: maximum age of data in diagnostic buffers before they need to be
+ *          refreshed (in ms).
+ * @port_data: data retrieved using exchange port data.
+ * @port_data.header: header with metadata for the cache in @port_data.data.
+ * @port_data.data: cached QTCB Bottom of command exchange port data.
+ * @config_data: data retrieved using exchange config data.
+ * @config_data.header: header with metadata for the cache in @config_data.data.
+ * @config_data.data: cached QTCB Bottom of command exchange config data.
+ */
+struct zfcp_diag_adapter {
+       u64     sysfs_established       :1;
+
+       unsigned long   max_age;
+
+       struct {
+               struct zfcp_diag_header         header;
+               struct fsf_qtcb_bottom_port     data;
+       } port_data;
+       struct {
+               struct zfcp_diag_header         header;
+               struct fsf_qtcb_bottom_config   data;
+       } config_data;
+};
+
+int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter);
+void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter);
+
+int zfcp_diag_sysfs_setup(struct zfcp_adapter *const adapter);
+void zfcp_diag_sysfs_destroy(struct zfcp_adapter *const adapter);
+
+void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr,
+                           const void *const data, const bool incomplete);
+
+/*
+ * Function-Type used in zfcp_diag_update_buffer_limited() for the function
+ * that does the buffer-implementation dependent work.
+ */
+typedef int (*zfcp_diag_update_buffer_func)(struct zfcp_adapter *const adapter);
+
+int zfcp_diag_update_config_data_buffer(struct zfcp_adapter *const adapter);
+int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter);
+int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter,
+                                   struct zfcp_diag_header *const hdr,
+                                   zfcp_diag_update_buffer_func buffer_update);
+
+/**
+ * zfcp_diag_support_sfp() - Return %true if the @adapter supports reporting
+ *                          SFP Data.
+ * @adapter: adapter to test the availability of SFP Data reporting for.
+ */
+static inline bool
+zfcp_diag_support_sfp(const struct zfcp_adapter *const adapter)
+{
+       return !!(adapter->adapter_features & FSF_FEATURE_REPORT_SFP_DATA);
+}
+
+#endif /* ZFCP_DIAG_H */
index 96f0d34..93655b8 100644 (file)
@@ -174,7 +174,7 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
                        return 0;
                p_status = atomic_read(&port->status);
                if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
-                     p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
+                   p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
                        return 0;
                if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
                        need = ZFCP_ERP_ACTION_REOPEN_PORT;
@@ -190,7 +190,7 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
                        return 0;
                a_status = atomic_read(&adapter->status);
                if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
-                     a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
+                   a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
                        return 0;
                if (p_status & ZFCP_STATUS_COMMON_NOESC)
                        return need;
index 31e8a72..c855678 100644 (file)
@@ -167,6 +167,7 @@ extern const struct attribute_group *zfcp_port_attr_groups[];
 extern struct mutex zfcp_sysfs_port_units_mutex;
 extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
 extern struct device_attribute *zfcp_sysfs_shost_attrs[];
+extern const struct attribute_group zfcp_sysfs_diag_attr_group;
 bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port);
 
 /* zfcp_unit.c */
index cf63916..223a805 100644 (file)
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/blktrace_api.h>
+#include <linux/jiffies.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <scsi/fc/fc_els.h>
@@ -19,6 +20,7 @@
 #include "zfcp_dbf.h"
 #include "zfcp_qdio.h"
 #include "zfcp_reqlist.h"
+#include "zfcp_diag.h"
 
 /* timeout for FSF requests sent during scsi_eh: abort or FCP TMF */
 #define ZFCP_FSF_SCSI_ER_TIMEOUT (10*HZ)
@@ -554,6 +556,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
 static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
 {
        struct zfcp_adapter *adapter = req->adapter;
+       struct zfcp_diag_header *const diag_hdr =
+               &adapter->diagnostics->config_data.header;
        struct fsf_qtcb *qtcb = req->qtcb;
        struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
        struct Scsi_Host *shost = adapter->scsi_host;
@@ -570,6 +574,12 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
 
        switch (qtcb->header.fsf_status) {
        case FSF_GOOD:
+               /*
+                * usually we wait with an update till the cache is too old,
+                * but because we have the data available, update it anyway
+                */
+               zfcp_diag_update_xdata(diag_hdr, bottom, false);
+
                if (zfcp_fsf_exchange_config_evaluate(req))
                        return;
 
@@ -585,6 +595,9 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
                                &adapter->status);
                break;
        case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
+               zfcp_diag_update_xdata(diag_hdr, bottom, true);
+               req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE;
+
                fc_host_node_name(shost) = 0;
                fc_host_port_name(shost) = 0;
                fc_host_port_id(shost) = 0;
@@ -653,16 +666,28 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
 
 static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
 {
+       struct zfcp_diag_header *const diag_hdr =
+               &req->adapter->diagnostics->port_data.header;
        struct fsf_qtcb *qtcb = req->qtcb;
+       struct fsf_qtcb_bottom_port *bottom = &qtcb->bottom.port;
 
        if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
                return;
 
        switch (qtcb->header.fsf_status) {
        case FSF_GOOD:
+               /*
+                * usually we wait with an update till the cache is too old,
+                * but because we have the data available, update it anyway
+                */
+               zfcp_diag_update_xdata(diag_hdr, bottom, false);
+
                zfcp_fsf_exchange_port_evaluate(req);
                break;
        case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
+               zfcp_diag_update_xdata(diag_hdr, bottom, true);
+               req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE;
+
                zfcp_fsf_exchange_port_evaluate(req);
                zfcp_fsf_link_down_info_eval(req,
                        &qtcb->header.fsf_status_qual.link_down_info);
@@ -1261,7 +1286,8 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 
        req->qtcb->bottom.config.feature_selection =
                        FSF_FEATURE_NOTIFICATION_LOST |
-                       FSF_FEATURE_UPDATE_ALERT;
+                       FSF_FEATURE_UPDATE_ALERT |
+                       FSF_FEATURE_REQUEST_SFP_DATA;
        req->erp_action = erp_action;
        req->handler = zfcp_fsf_exchange_config_data_handler;
        erp_action->fsf_req_id = req->req_id;
@@ -1278,6 +1304,19 @@ out:
        return retval;
 }
 
+
+/**
+ * zfcp_fsf_exchange_config_data_sync() - Request information about FCP channel.
+ * @qdio: pointer to the QDIO-Queue to use for sending the command.
+ * @data: pointer to the QTCB-Bottom for storing the result of the command,
+ *       might be %NULL.
+ *
+ * Returns:
+ * * 0         - Exchange Config Data was successful, @data is complete
+ * * -EIO      - Exchange Config Data was not successful, @data is invalid
+ * * -EAGAIN   - @data contains incomplete data
+ * * -ENOMEM   - Some memory allocation failed along the way
+ */
 int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
                                       struct fsf_qtcb_bottom_config *data)
 {
@@ -1301,7 +1340,8 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
 
        req->qtcb->bottom.config.feature_selection =
                        FSF_FEATURE_NOTIFICATION_LOST |
-                       FSF_FEATURE_UPDATE_ALERT;
+                       FSF_FEATURE_UPDATE_ALERT |
+                       FSF_FEATURE_REQUEST_SFP_DATA;
 
        if (data)
                req->data = data;
@@ -1309,9 +1349,16 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
        zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
        retval = zfcp_fsf_req_send(req);
        spin_unlock_irq(&qdio->req_q_lock);
+
        if (!retval) {
                /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */
                wait_for_completion(&req->completion);
+
+               if (req->status &
+                   (ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_DISMISSED))
+                       retval = -EIO;
+               else if (req->status & ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE)
+                       retval = -EAGAIN;
        }
 
        zfcp_fsf_req_free(req);
@@ -1369,10 +1416,17 @@ out:
 }
 
 /**
- * zfcp_fsf_exchange_port_data_sync - request information about local port
- * @qdio: pointer to struct zfcp_qdio
- * @data: pointer to struct fsf_qtcb_bottom_port
- * Returns: 0 on success, error otherwise
+ * zfcp_fsf_exchange_port_data_sync() - Request information about local port.
+ * @qdio: pointer to the QDIO-Queue to use for sending the command.
+ * @data: pointer to the QTCB-Bottom for storing the result of the command,
+ *       might be %NULL.
+ *
+ * Returns:
+ * * 0         - Exchange Port Data was successful, @data is complete
+ * * -EIO      - Exchange Port Data was not successful, @data is invalid
+ * * -EAGAIN   - @data contains incomplete data
+ * * -ENOMEM   - Some memory allocation failed along the way
+ * * -EOPNOTSUPP       - This operation is not supported
  */
 int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
                                     struct fsf_qtcb_bottom_port *data)
@@ -1408,10 +1462,15 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
        if (!retval) {
                /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */
                wait_for_completion(&req->completion);
+
+               if (req->status &
+                   (ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_DISMISSED))
+                       retval = -EIO;
+               else if (req->status & ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE)
+                       retval = -EAGAIN;
        }
 
        zfcp_fsf_req_free(req);
-
        return retval;
 
 out_unlock:
index 2c658b6..2b1e4da 100644 (file)
 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS       0x00000020
 #define FSF_FEATURE_UPDATE_ALERT               0x00000100
 #define FSF_FEATURE_MEASUREMENT_DATA           0x00000200
+#define FSF_FEATURE_REQUEST_SFP_DATA           0x00000200
+#define FSF_FEATURE_REPORT_SFP_DATA            0x00000800
 #define FSF_FEATURE_DIF_PROT_TYPE1             0x00010000
 #define FSF_FEATURE_DIX_PROT_TCPIP             0x00020000
 
@@ -407,7 +409,24 @@ struct fsf_qtcb_bottom_port {
        u8 cp_util;
        u8 cb_util;
        u8 a_util;
-       u8 res2[253];
+       u8 res2;
+       u16 temperature;
+       u16 vcc;
+       u16 tx_bias;
+       u16 tx_power;
+       u16 rx_power;
+       union {
+               u16 raw;
+               struct {
+                       u16 fec_active          :1;
+                       u16:7;
+                       u16 connector_type      :2;
+                       u16 sfp_invalid         :1;
+                       u16 optical_port        :1;
+                       u16 port_tx_type        :4;
+               };
+       } sfp_flags;
+       u8 res3[240];
 } __attribute__ ((packed));
 
 union fsf_qtcb_bottom {
index e9ded2b..3910d52 100644 (file)
@@ -605,7 +605,7 @@ zfcp_scsi_get_fc_host_stats(struct Scsi_Host *host)
                return NULL;
 
        ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data);
-       if (ret) {
+       if (ret != 0 && ret != -EAGAIN) {
                kfree(data);
                return NULL;
        }
@@ -634,7 +634,7 @@ static void zfcp_scsi_reset_fc_host_stats(struct Scsi_Host *shost)
                return;
 
        ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data);
-       if (ret)
+       if (ret != 0 && ret != -EAGAIN)
                kfree(data);
        else {
                adapter->stats_reset = jiffies/HZ;
index af197e2..494b9fe 100644 (file)
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/slab.h>
+#include "zfcp_diag.h"
 #include "zfcp_ext.h"
 
 #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \
@@ -325,6 +326,50 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
 static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL,
                     zfcp_sysfs_port_remove_store);
 
+static ssize_t
+zfcp_sysfs_adapter_diag_max_age_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));
+       ssize_t rc;
+
+       if (!adapter)
+               return -ENODEV;
+
+       /* ceil(log(2^64 - 1) / log(10)) = 20 */
+       rc = scnprintf(buf, 20 + 2, "%lu\n", adapter->diagnostics->max_age);
+
+       zfcp_ccw_adapter_put(adapter);
+       return rc;
+}
+
+static ssize_t
+zfcp_sysfs_adapter_diag_max_age_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));
+       unsigned long max_age;
+       ssize_t rc;
+
+       if (!adapter)
+               return -ENODEV;
+
+       rc = kstrtoul(buf, 10, &max_age);
+       if (rc != 0)
+               goto out;
+
+       adapter->diagnostics->max_age = max_age;
+
+       rc = count;
+out:
+       zfcp_ccw_adapter_put(adapter);
+       return rc;
+}
+static ZFCP_DEV_ATTR(adapter, diag_max_age, 0644,
+                    zfcp_sysfs_adapter_diag_max_age_show,
+                    zfcp_sysfs_adapter_diag_max_age_store);
+
 static struct attribute *zfcp_adapter_attrs[] = {
        &dev_attr_adapter_failed.attr,
        &dev_attr_adapter_in_recovery.attr,
@@ -337,6 +382,7 @@ static struct attribute *zfcp_adapter_attrs[] = {
        &dev_attr_adapter_lic_version.attr,
        &dev_attr_adapter_status.attr,
        &dev_attr_adapter_hardware_version.attr,
+       &dev_attr_adapter_diag_max_age.attr,
        NULL
 };
 
@@ -577,7 +623,7 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev,
                return -ENOMEM;
 
        retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port);
-       if (!retval)
+       if (retval == 0 || retval == -EAGAIN)
                retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util,
                                 qtcb_port->cb_util, qtcb_port->a_util);
        kfree(qtcb_port);
@@ -603,7 +649,7 @@ static int zfcp_sysfs_adapter_ex_config(struct device *dev,
                return -ENOMEM;
 
        retval = zfcp_fsf_exchange_config_data_sync(adapter->qdio, qtcb_config);
-       if (!retval)
+       if (retval == 0 || retval == -EAGAIN)
                *stat_inf = qtcb_config->stat_info;
 
        kfree(qtcb_config);
@@ -664,3 +710,123 @@ struct device_attribute *zfcp_sysfs_shost_attrs[] = {
        &dev_attr_queue_full,
        NULL
 };
+
+static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show(
+       struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));
+       struct zfcp_diag_header *diag_hdr;
+       struct fc_els_flogi *nsp;
+       ssize_t rc = -ENOLINK;
+       unsigned long flags;
+       unsigned int status;
+
+       if (!adapter)
+               return -ENODEV;
+
+       status = atomic_read(&adapter->status);
+       if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||
+           0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||
+           0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED))
+               goto out;
+
+       diag_hdr = &adapter->diagnostics->config_data.header;
+
+       rc = zfcp_diag_update_buffer_limited(
+               adapter, diag_hdr, zfcp_diag_update_config_data_buffer);
+       if (rc != 0)
+               goto out;
+
+       spin_lock_irqsave(&diag_hdr->access_lock, flags);
+       /* nport_serv_param doesn't contain the ELS_Command code */
+       nsp = (struct fc_els_flogi *)((unsigned long)
+                                             adapter->diagnostics->config_data
+                                                     .data.nport_serv_param -
+                                     sizeof(u32));
+
+       rc = scnprintf(buf, 5 + 2, "%hu\n",
+                      be16_to_cpu(nsp->fl_csp.sp_bb_cred));
+       spin_unlock_irqrestore(&diag_hdr->access_lock, flags);
+
+out:
+       zfcp_ccw_adapter_put(adapter);
+       return rc;
+}
+static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400,
+                    zfcp_sysfs_adapter_diag_b2b_credit_show, NULL);
+
+#define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt)      \
+       static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show(             \
+               struct device *dev, struct device_attribute *attr, char *buf)  \
+       {                                                                      \
+               struct zfcp_adapter *const adapter =                           \
+                       zfcp_ccw_adapter_by_cdev(to_ccwdev(dev));              \
+               struct zfcp_diag_header *diag_hdr;                             \
+               ssize_t rc = -ENOLINK;                                         \
+               unsigned long flags;                                           \
+               unsigned int status;                                           \
+                                                                              \
+               if (!adapter)                                                  \
+                       return -ENODEV;                                        \
+                                                                              \
+               status = atomic_read(&adapter->status);                        \
+               if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||                 \
+                   0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||            \
+                   0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED))             \
+                       goto out;                                              \
+                                                                              \
+               if (!zfcp_diag_support_sfp(adapter)) {                         \
+                       rc = -EOPNOTSUPP;                                      \
+                       goto out;                                              \
+               }                                                              \
+                                                                              \
+               diag_hdr = &adapter->diagnostics->port_data.header;            \
+                                                                              \
+               rc = zfcp_diag_update_buffer_limited(                          \
+                       adapter, diag_hdr, zfcp_diag_update_port_data_buffer); \
+               if (rc != 0)                                                   \
+                       goto out;                                              \
+                                                                              \
+               spin_lock_irqsave(&diag_hdr->access_lock, flags);              \
+               rc = scnprintf(                                                \
+                       buf, (_prtsize) + 2, _prtfmt "\n",                     \
+                       adapter->diagnostics->port_data.data._qtcb_member);    \
+               spin_unlock_irqrestore(&diag_hdr->access_lock, flags);         \
+                                                                              \
+       out:                                                                   \
+               zfcp_ccw_adapter_put(adapter);                                 \
+               return rc;                                                     \
+       }                                                                      \
+       static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400,                    \
+                            zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL)
+
+ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, 2, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, 1, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, 1, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, 1, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, 1, "%hu");
+
+static struct attribute *zfcp_sysfs_diag_attrs[] = {
+       &dev_attr_adapter_diag_sfp_temperature.attr,
+       &dev_attr_adapter_diag_sfp_vcc.attr,
+       &dev_attr_adapter_diag_sfp_tx_bias.attr,
+       &dev_attr_adapter_diag_sfp_tx_power.attr,
+       &dev_attr_adapter_diag_sfp_rx_power.attr,
+       &dev_attr_adapter_diag_sfp_port_tx_type.attr,
+       &dev_attr_adapter_diag_sfp_optical_port.attr,
+       &dev_attr_adapter_diag_sfp_sfp_invalid.attr,
+       &dev_attr_adapter_diag_sfp_connector_type.attr,
+       &dev_attr_adapter_diag_sfp_fec_active.attr,
+       &dev_attr_adapter_diag_b2b_credit.attr,
+       NULL,
+};
+
+const struct attribute_group zfcp_sysfs_diag_attr_group = {
+       .name = "diagnostics",
+       .attrs = zfcp_sysfs_diag_attrs,
+};
index 536426f..f2f7e6e 100644 (file)
 #define NCR5380_release_dma_irq(x)
 #endif
 
+static unsigned int disconnect_mask = ~0;
+module_param(disconnect_mask, int, 0444);
+
 static int do_abort(struct Scsi_Host *);
 static void do_reset(struct Scsi_Host *);
 static void bus_reset_cleanup(struct Scsi_Host *);
@@ -172,6 +175,19 @@ static inline void advance_sg_buffer(struct scsi_cmnd *cmd)
        }
 }
 
+static inline void set_resid_from_SCp(struct scsi_cmnd *cmd)
+{
+       int resid = cmd->SCp.this_residual;
+       struct scatterlist *s = cmd->SCp.buffer;
+
+       if (s)
+               while (!sg_is_last(s)) {
+                       s = sg_next(s);
+                       resid += s->length;
+               }
+       scsi_set_resid(cmd, resid);
+}
+
 /**
  * NCR5380_poll_politely2 - wait for two chip register values
  * @hostdata: host private data
@@ -954,7 +970,8 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        int err;
        bool ret = true;
        bool can_disconnect = instance->irq != NO_IRQ &&
-                             cmd->cmnd[0] != REQUEST_SENSE;
+                             cmd->cmnd[0] != REQUEST_SENSE &&
+                             (disconnect_mask & BIT(scmd_id(cmd)));
 
        NCR5380_dprint(NDEBUG_ARBITRATION, instance);
        dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
@@ -1379,7 +1396,7 @@ static void do_reset(struct Scsi_Host *instance)
  * MESSAGE OUT phase and sending an ABORT message.
  * @instance: relevant scsi host instance
  *
- * Returns 0 on success, -1 on failure.
+ * Returns 0 on success, negative error code on failure.
  */
 
 static int do_abort(struct Scsi_Host *instance)
@@ -1404,7 +1421,7 @@ static int do_abort(struct Scsi_Host *instance)
 
        rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
        if (rc < 0)
-               goto timeout;
+               goto out;
 
        tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
 
@@ -1415,7 +1432,7 @@ static int do_abort(struct Scsi_Host *instance)
                              ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
                rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, 3 * HZ);
                if (rc < 0)
-                       goto timeout;
+                       goto out;
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
        }
 
@@ -1424,17 +1441,17 @@ static int do_abort(struct Scsi_Host *instance)
        len = 1;
        phase = PHASE_MSGOUT;
        NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
+       if (len)
+               rc = -ENXIO;
 
        /*
         * If we got here, and the command completed successfully,
         * we're about to go into bus free state.
         */
 
-       return len ? -1 : 0;
-
-timeout:
+out:
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-       return -1;
+       return rc;
 }
 
 /*
@@ -1803,6 +1820,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                        cmd->result |= cmd->SCp.Status;
                                        cmd->result |= cmd->SCp.Message << 8;
 
+                                       set_resid_from_SCp(cmd);
+
                                        if (cmd->cmnd[0] == REQUEST_SENSE)
                                                complete_cmd(instance, cmd);
                                        else {
@@ -2264,7 +2283,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
                dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
                hostdata->connected = NULL;
                hostdata->dma_len = 0;
-               if (do_abort(instance)) {
+               if (do_abort(instance) < 0) {
                        set_host_byte(cmd, DID_ERROR);
                        complete_cmd(instance, cmd);
                        result = FAILED;
index 0ed3f80..e36608c 100644 (file)
@@ -1477,6 +1477,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
        struct aac_srb * srbcmd;
        u32 flag;
        u32 timeout;
+       struct aac_dev *dev = fib->dev;
 
        aac_fib_init(fib);
        switch(cmd->sc_data_direction){
@@ -1503,7 +1504,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
        srbcmd->flags    = cpu_to_le32(flag);
        timeout = cmd->request->timeout/HZ;
        if (timeout == 0)
-               timeout = 1;
+               timeout = (dev->sa_firmware ? AAC_SA_TIMEOUT : AAC_ARC_TIMEOUT);
        srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
        srbcmd->retry_limit = 0; /* Obsolete parameter */
        srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len);
@@ -2467,13 +2468,13 @@ static int aac_read(struct scsi_cmnd * scsicmd)
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
                        SAM_STAT_CHECK_CONDITION;
                set_sense(&dev->fsa_dev[cid].sense_data,
-                         HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+                         ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE,
                          ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
                       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
                             SCSI_SENSE_BUFFERSIZE));
                scsicmd->scsi_done(scsicmd);
-               return 1;
+               return 0;
        }
 
        dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
@@ -2559,13 +2560,13 @@ static int aac_write(struct scsi_cmnd * scsicmd)
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
                        SAM_STAT_CHECK_CONDITION;
                set_sense(&dev->fsa_dev[cid].sense_data,
-                         HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+                         ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE,
                          ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
                       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
                             SCSI_SENSE_BUFFERSIZE));
                scsicmd->scsi_done(scsicmd);
-               return 1;
+               return 0;
        }
 
        dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
index 3fa0323..e3e4ecb 100644 (file)
@@ -85,7 +85,7 @@ enum {
 #define        PMC_GLOBAL_INT_BIT0             0x00000001
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 50877
+# define AAC_DRIVER_BUILD 50983
 # define AAC_DRIVER_BRANCH "-custom"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
@@ -108,6 +108,8 @@ enum {
 #define AAC_BUS_TARGET_LOOP            (AAC_MAX_BUSES * AAC_MAX_TARGETS)
 #define AAC_MAX_NATIVE_SIZE            2048
 #define FW_ERROR_BUFFER_SIZE           512
+#define AAC_SA_TIMEOUT                 180
+#define AAC_ARC_TIMEOUT                        60
 
 #define get_bus_number(x)      (x/AAC_MAX_TARGETS)
 #define get_target_number(x)   (x%AAC_MAX_TARGETS)
@@ -1328,7 +1330,7 @@ struct fib {
 #define AAC_DEVTYPE_ARC_RAW            2
 #define AAC_DEVTYPE_NATIVE_RAW         3
 
-#define AAC_SAFW_RESCAN_DELAY          (10 * HZ)
+#define AAC_RESCAN_DELAY               (10 * HZ)
 
 struct aac_hba_map_info {
        __le32  rmw_nexus;              /* nexus for native HBA devices */
@@ -1601,6 +1603,7 @@ struct aac_dev
        struct fsa_dev_info     *fsa_dev;
        struct task_struct      *thread;
        struct delayed_work     safw_rescan_work;
+       struct delayed_work     src_reinit_aif_worker;
        int                     cardtype;
        /*
         *This lock will protect the two 32-bit
@@ -1673,6 +1676,7 @@ struct aac_dev
        u8                      adapter_shutdown;
        u32                     handle_pci_error;
        bool                    init_reset;
+       u8                      soft_reset_support;
 };
 
 #define aac_adapter_interrupt(dev) \
@@ -2644,7 +2648,12 @@ int aac_scan_host(struct aac_dev *dev);
 
 static inline void aac_schedule_safw_scan_worker(struct aac_dev *dev)
 {
-       schedule_delayed_work(&dev->safw_rescan_work, AAC_SAFW_RESCAN_DELAY);
+       schedule_delayed_work(&dev->safw_rescan_work, AAC_RESCAN_DELAY);
+}
+
+static inline void aac_schedule_src_reinit_aif_worker(struct aac_dev *dev)
+{
+       schedule_delayed_work(&dev->src_reinit_aif_worker, AAC_RESCAN_DELAY);
 }
 
 static inline void aac_safw_rescan_worker(struct work_struct *work)
@@ -2658,10 +2667,10 @@ static inline void aac_safw_rescan_worker(struct work_struct *work)
        aac_scan_host(dev);
 }
 
-static inline void aac_cancel_safw_rescan_worker(struct aac_dev *dev)
+static inline void aac_cancel_rescan_worker(struct aac_dev *dev)
 {
-       if (dev->sa_firmware)
-               cancel_delayed_work_sync(&dev->safw_rescan_work);
+       cancel_delayed_work_sync(&dev->safw_rescan_work);
+       cancel_delayed_work_sync(&dev->src_reinit_aif_worker);
 }
 
 /* SCp.phase values */
@@ -2671,6 +2680,7 @@ static inline void aac_cancel_safw_rescan_worker(struct aac_dev *dev)
 #define AAC_OWNER_FIRMWARE     0x106
 
 void aac_safw_rescan_worker(struct work_struct *work);
+void aac_src_reinit_aif_worker(struct work_struct *work);
 int aac_acquire_irq(struct aac_dev *dev);
 void aac_free_irq(struct aac_dev *dev);
 int aac_setup_safw_adapter(struct aac_dev *dev);
@@ -2728,6 +2738,7 @@ int aac_probe_container(struct aac_dev *dev, int cid);
 int _aac_rx_init(struct aac_dev *dev);
 int aac_rx_select_comm(struct aac_dev *dev, int comm);
 int aac_rx_deliver_producer(struct fib * fib);
+void aac_reinit_aif(struct aac_dev *aac, unsigned int index);
 
 static inline int aac_is_src(struct aac_dev *dev)
 {
index d4fcfa1..f75878d 100644 (file)
@@ -571,6 +571,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
                else
                        dev->sa_firmware = 0;
 
+               if (status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET))
+                       dev->soft_reset_support = 1;
+               else
+                       dev->soft_reset_support = 0;
+
                if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
                    (status[2] > dev->base_size)) {
                        aac_adapter_ioremap(dev, 0);
index 2142a64..5a8a999 100644 (file)
@@ -232,6 +232,7 @@ struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd)
        fibptr->type = FSAFS_NTC_FIB_CONTEXT;
        fibptr->callback_data = NULL;
        fibptr->callback = NULL;
+       fibptr->flags = 0;
 
        return fibptr;
 }
@@ -1463,6 +1464,14 @@ retry_next:
        }
 }
 
+static void aac_schedule_bus_scan(struct aac_dev *aac)
+{
+       if (aac->sa_firmware)
+               aac_schedule_safw_scan_worker(aac);
+       else
+               aac_schedule_src_reinit_aif_worker(aac);
+}
+
 static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
 {
        int index, quirks;
@@ -1638,7 +1647,7 @@ out:
         */
        if (!retval && !is_kdump_kernel()) {
                dev_info(&aac->pdev->dev, "Scheduling bus rescan\n");
-               aac_schedule_safw_scan_worker(aac);
+               aac_schedule_bus_scan(aac);
        }
 
        if (jafo) {
@@ -1959,6 +1968,16 @@ int aac_scan_host(struct aac_dev *dev)
        return rcode;
 }
 
+void aac_src_reinit_aif_worker(struct work_struct *work)
+{
+       struct aac_dev *dev = container_of(to_delayed_work(work),
+                               struct aac_dev, src_reinit_aif_worker);
+
+       wait_event(dev->scsi_host_ptr->host_wait,
+                       !scsi_host_in_recovery(dev->scsi_host_ptr));
+       aac_reinit_aif(dev, dev->cardtype);
+}
+
 /**
  *     aac_handle_sa_aif       Handle a message from the firmware
  *     @dev: Which adapter this fib is from
index 4a85878..ee6bc2f 100644 (file)
@@ -391,6 +391,7 @@ static int aac_slave_configure(struct scsi_device *sdev)
        int chn, tid;
        unsigned int depth = 0;
        unsigned int set_timeout = 0;
+       int timeout = 0;
        bool set_qd_dev_type = false;
        u8 devtype = 0;
 
@@ -483,10 +484,13 @@ common_config:
 
        /*
         * Firmware has an individual device recovery time typically
-        * of 35 seconds, give us a margin.
+        * of 35 seconds, give us a margin. Thor devices can take longer in
+        * error recovery, hence different value.
         */
-       if (set_timeout && sdev->request_queue->rq_timeout < (45 * HZ))
-               blk_queue_rq_timeout(sdev->request_queue, 45*HZ);
+       if (set_timeout) {
+               timeout = aac->sa_firmware ? AAC_SA_TIMEOUT : AAC_ARC_TIMEOUT;
+               blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
+       }
 
        if (depth > 256)
                depth = 256;
@@ -608,9 +612,13 @@ static struct device_attribute *aac_dev_attrs[] = {
 static int aac_ioctl(struct scsi_device *sdev, unsigned int cmd,
                     void __user *arg)
 {
+       int retval;
        struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
+       retval = aac_adapter_check_health(dev);
+       if (retval)
+               return -EBUSY;
        return aac_do_ioctl(dev, cmd, arg);
 }
 
@@ -1585,6 +1593,19 @@ static void aac_init_char(void)
        }
 }
 
+void aac_reinit_aif(struct aac_dev *aac, unsigned int index)
+{
+       /*
+        * Firmware may send a AIF messages very early and the Driver may have
+        * ignored as it is not fully ready to process the messages. Send
+        * AIF to firmware so that if there are any unprocessed events they
+        * can be processed now.
+        */
+       if (aac_drivers[index].quirks & AAC_QUIRK_SRC)
+               aac_intr_normal(aac, 0, 2, 0, NULL);
+
+}
+
 static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        unsigned index = id->driver_data;
@@ -1682,6 +1703,8 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        mutex_init(&aac->scan_mutex);
 
        INIT_DELAYED_WORK(&aac->safw_rescan_work, aac_safw_rescan_worker);
+       INIT_DELAYED_WORK(&aac->src_reinit_aif_worker,
+                               aac_src_reinit_aif_worker);
        /*
         *      Map in the registers from the adapter.
         */
@@ -1872,7 +1895,7 @@ static int aac_suspend(struct pci_dev *pdev, pm_message_t state)
        struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
 
        scsi_block_requests(shost);
-       aac_cancel_safw_rescan_worker(aac);
+       aac_cancel_rescan_worker(aac);
        aac_send_shutdown(aac);
 
        aac_release_resources(aac);
@@ -1931,7 +1954,7 @@ static void aac_remove_one(struct pci_dev *pdev)
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
 
-       aac_cancel_safw_rescan_worker(aac);
+       aac_cancel_rescan_worker(aac);
        scsi_remove_host(shost);
 
        __aac_shutdown(aac);
@@ -1989,7 +2012,7 @@ static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev,
                aac->handle_pci_error = 1;
 
                scsi_block_requests(aac->scsi_host_ptr);
-               aac_cancel_safw_rescan_worker(aac);
+               aac_cancel_rescan_worker(aac);
                aac_flush_ios(aac);
                aac_release_resources(aac);
 
index 3b66e06..787ec9b 100644 (file)
@@ -733,10 +733,20 @@ static bool aac_is_ctrl_up_and_running(struct aac_dev *dev)
        return ctrl_up;
 }
 
+static void aac_src_drop_io(struct aac_dev *dev)
+{
+       if (!dev->soft_reset_support)
+               return;
+
+       aac_adapter_sync_cmd(dev, DROP_IO,
+                       0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
+}
+
 static void aac_notify_fw_of_iop_reset(struct aac_dev *dev)
 {
        aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 0, 0, 0, 0, 0, 0, NULL,
                                                NULL, NULL, NULL, NULL);
+       aac_src_drop_io(dev);
 }
 
 static void aac_send_iop_reset(struct aac_dev *dev)
index 88053b1..db687ef 100644 (file)
@@ -1400,7 +1400,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma
                                , pCCB->acb
                                , pCCB->startdone
                                , atomic_read(&acb->ccboutstandingcount));
-                 return;
+               return;
        }
        arcmsr_report_ccb_state(acb, pCCB, error);
 }
@@ -3476,8 +3476,8 @@ polling_hbc_ccb_retry:
                                        , pCCB->pcmd->device->id
                                        , (u32)pCCB->pcmd->device->lun
                                        , pCCB);
-                                       pCCB->pcmd->result = DID_ABORT << 16;
-                                       arcmsr_ccb_complete(pCCB);
+                               pCCB->pcmd->result = DID_ABORT << 16;
+                               arcmsr_ccb_complete(pCCB);
                                continue;
                        }
                        printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
index d12dd89..ddb52e7 100644 (file)
@@ -1067,7 +1067,7 @@ void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
  * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
  * Params  : host - host to finish
  * Notes   : This is called when a command is:
- *             terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT
+ *             terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONNECT
  *        : This must not return until all transfers are completed.
  */
 static
@@ -1816,7 +1816,7 @@ int acornscsi_reconnect(AS_Host *host)
 }
 
 /*
- * Function: int acornscsi_reconect_finish(AS_Host *host)
+ * Function: int acornscsi_reconnect_finish(AS_Host *host)
  * Purpose : finish reconnecting a command
  * Params  : host - host to complete
  * Returns : 0 if failed
index e809493..a82b63a 100644 (file)
@@ -742,7 +742,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
                atari_scsi_template.sg_tablesize = SG_ALL;
        } else {
                atari_scsi_template.can_queue    = 1;
-               atari_scsi_template.sg_tablesize = SG_NONE;
+               atari_scsi_template.sg_tablesize = 1;
        }
 
        if (setup_can_queue > 0)
@@ -751,8 +751,8 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
        if (setup_cmd_per_lun > 0)
                atari_scsi_template.cmd_per_lun = setup_cmd_per_lun;
 
-       /* Leave sg_tablesize at 0 on a Falcon! */
-       if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
+       /* Don't increase sg_tablesize on Falcon! */
+       if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize > 0)
                atari_scsi_template.sg_tablesize = setup_sg_tablesize;
 
        if (setup_hostid >= 0) {
index e41f0bb..c6a7523 100644 (file)
@@ -1680,7 +1680,7 @@ static struct scsi_host_template atp870u_template = {
      .bios_param               = atp870u_biosparam     /* biosparm */,
      .can_queue                = qcnt                  /* can_queue */,
      .this_id                  = 7                     /* SCSI ID */,
-     .sg_tablesize             = ATP870U_SCATTER       /*SG_ALL*/ /*SG_NONE*/,
+     .sg_tablesize             = ATP870U_SCATTER       /*SG_ALL*/,
      .max_sectors              = ATP870U_MAX_SECTORS,
 };
 
index 2f9213b..eb0c763 100644 (file)
@@ -1487,8 +1487,7 @@ bfad_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
        return ret;
 }
 
-int
-restart_bfa(struct bfad_s *bfad)
+static int restart_bfa(struct bfad_s *bfad)
 {
        unsigned long flags;
        struct pci_dev *pdev = bfad->pcidev;
index 29ab81d..fbfce02 100644 (file)
@@ -275,8 +275,10 @@ bfad_im_get_stats(struct Scsi_Host *shost)
        rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa),
                                fcstats, bfad_hcb_comp, &fcomp);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
-       if (rc != BFA_STATUS_OK)
+       if (rc != BFA_STATUS_OK) {
+               kfree(fcstats);
                return NULL;
+       }
 
        wait_for_completion(&fcomp.comp);
 
index e4469df..698f5eb 100644 (file)
@@ -813,7 +813,7 @@ struct fcoe_confqe {
 
 
 /*
- * FCoE conection data base
+ * FCoE connection data base
  */
 struct fcoe_conn_db {
 #if defined(__BIG_ENDIAN)
index 401743e..4c8122a 100644 (file)
@@ -1242,7 +1242,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
 
        /* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */
        time_left = wait_for_completion_timeout(&io_req->abts_done,
-                                               (2 * rp->r_a_tov + 1) * HZ);
+                                       msecs_to_jiffies(2 * rp->r_a_tov + 1));
        if (time_left)
                BNX2FC_IO_DBG(io_req,
                              "Timed out in eh_abort waiting for abts_done");
index c5fa5f3..0b28d44 100644 (file)
@@ -915,12 +915,12 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
        INIT_LIST_HEAD(&hba->ep_ofld_list);
        INIT_LIST_HEAD(&hba->ep_active_list);
        INIT_LIST_HEAD(&hba->ep_destroy_list);
-       pci_dev_put(hba->pcidev);
 
        if (hba->regview) {
                pci_iounmap(hba->pcidev, hba->regview);
                hba->regview = NULL;
        }
+       pci_dev_put(hba->pcidev);
        bnx2i_free_mp_bdt(hba);
        bnx2i_release_free_cid_que(hba);
        iscsi_host_free(shost);
index e519238..950f9cd 100644 (file)
@@ -793,10 +793,10 @@ csio_hw_get_flash_params(struct csio_hw *hw)
                        goto found;
                }
 
-       /* Decode Flash part size.  The code below looks repetative with
+       /* Decode Flash part size.  The code below looks repetitive with
         * common encodings, but that's not guaranteed in the JEDEC
-        * specification for the Read JADEC ID command.  The only thing that
-        * we're guaranteed by the JADEC specification is where the
+        * specification for the Read JEDEC ID command.  The only thing that
+        * we're guaranteed by the JEDEC specification is where the
         * Manufacturer ID is in the returned result.  After that each
         * Manufacturer ~could~ encode things completely differently.
         * Note, all Flash parts must have 64KB sectors.
@@ -983,8 +983,8 @@ retry:
                        waiting -= 50;
 
                        /*
-                        * If neither Error nor Initialialized are indicated
-                        * by the firmware keep waiting till we exaust our
+                        * If neither Error nor Initialized are indicated
+                        * by the firmware keep waiting till we exhaust our
                         * timeout ... and then retry if we haven't exhausted
                         * our retries ...
                         */
@@ -1738,7 +1738,7 @@ static void csio_link_l1cfg(struct link_config *lc, uint16_t fw_caps,
         * Convert Common Code Forward Error Control settings into the
         * Firmware's API.  If the current Requested FEC has "Automatic"
         * (IEEE 802.3) specified, then we use whatever the Firmware
-        * sent us as part of it's IEEE 802.3-based interpratation of
+        * sent us as part of it's IEEE 802.3-based interpretation of
         * the Transceiver Module EPROM FEC parameters.  Otherwise we
         * use whatever is in the current Requested FEC settings.
         */
@@ -2834,7 +2834,7 @@ csio_hws_configuring(struct csio_hw *hw, enum csio_hw_ev evt)
 }
 
 /*
- * csio_hws_initializing - Initialiazing state
+ * csio_hws_initializing - Initializing state
  * @hw - HW module
  * @evt - Event
  *
@@ -3049,7 +3049,7 @@ csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt)
                if (!csio_is_hw_master(hw))
                        break;
                /*
-                * The BYE should have alerady been issued, so we cant
+                * The BYE should have already been issued, so we can't
                 * use the mailbox interface. Hence we use the PL_RST
                 * register directly.
                 */
@@ -3104,7 +3104,7 @@ csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt)
  *
  *     A table driven interrupt handler that applies a set of masks to an
  *     interrupt status word and performs the corresponding actions if the
- *     interrupts described by the mask have occured.  The actions include
+ *     interrupts described by the mask have occurred.  The actions include
  *     optionally emitting a warning or alert message. The table is terminated
  *     by an entry specifying mask 0.  Returns the number of fatal interrupt
  *     conditions.
@@ -4219,7 +4219,7 @@ csio_mgmtm_exit(struct csio_mgmtm *mgmtm)
  * @hw:                Pointer to HW module.
  *
  * It is assumed that the initialization is a synchronous operation.
- * So when we return afer posting the event, the HW SM should be in
+ * So when we return after posting the event, the HW SM should be in
  * the ready state, if there were no errors during init.
  */
 int
index a6dd704..2e8a3ac 100644 (file)
@@ -154,13 +154,10 @@ csio_dfs_create(struct csio_hw *hw)
 /*
  * csio_dfs_destroy - Destroys per-hw debugfs.
  */
-static int
+static void
 csio_dfs_destroy(struct csio_hw *hw)
 {
-       if (hw->debugfs_root)
-               debugfs_remove_recursive(hw->debugfs_root);
-
-       return 0;
+       debugfs_remove_recursive(hw->debugfs_root);
 }
 
 /*
index 66e58f0..74ff8ad 100644 (file)
@@ -301,6 +301,7 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
        struct fc_fdmi_port_name *port_name;
        uint8_t buf[64];
        uint8_t *fc4_type;
+       unsigned long flags;
 
        if (fdmi_req->wr_status != FW_SUCCESS) {
                csio_ln_dbg(ln, "WR error:%x in processing fdmi rhba cmd\n",
@@ -385,13 +386,13 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
        len = (uint32_t)(pld - (uint8_t *)cmd);
 
        /* Submit FDMI RPA request */
-       spin_lock_irq(&hw->lock);
+       spin_lock_irqsave(&hw->lock, flags);
        if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done,
                                FCOE_CT, &fdmi_req->dma_buf, len)) {
                CSIO_INC_STATS(ln, n_fdmi_err);
                csio_ln_dbg(ln, "Failed to issue fdmi rpa req\n");
        }
-       spin_unlock_irq(&hw->lock);
+       spin_unlock_irqrestore(&hw->lock, flags);
 }
 
 /*
@@ -412,6 +413,7 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
        struct fc_fdmi_rpl *reg_pl;
        struct fs_fdmi_attrs *attrib_blk;
        uint8_t buf[64];
+       unsigned long flags;
 
        if (fdmi_req->wr_status != FW_SUCCESS) {
                csio_ln_dbg(ln, "WR error:%x in processing fdmi dprt cmd\n",
@@ -491,13 +493,13 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
        attrib_blk->numattrs = htonl(numattrs);
 
        /* Submit FDMI RHBA request */
-       spin_lock_irq(&hw->lock);
+       spin_lock_irqsave(&hw->lock, flags);
        if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn,
                                FCOE_CT, &fdmi_req->dma_buf, len)) {
                CSIO_INC_STATS(ln, n_fdmi_err);
                csio_ln_dbg(ln, "Failed to issue fdmi rhba req\n");
        }
-       spin_unlock_irq(&hw->lock);
+       spin_unlock_irqrestore(&hw->lock, flags);
 }
 
 /*
@@ -512,6 +514,7 @@ csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
        void *cmd;
        struct fc_fdmi_port_name *port_name;
        uint32_t len;
+       unsigned long flags;
 
        if (fdmi_req->wr_status != FW_SUCCESS) {
                csio_ln_dbg(ln, "WR error:%x in processing fdmi dhba cmd\n",
@@ -542,13 +545,13 @@ csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
        len += sizeof(*port_name);
 
        /* Submit FDMI request */
-       spin_lock_irq(&hw->lock);
+       spin_lock_irqsave(&hw->lock, flags);
        if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn,
                                FCOE_CT, &fdmi_req->dma_buf, len)) {
                CSIO_INC_STATS(ln, n_fdmi_err);
                csio_ln_dbg(ln, "Failed to issue fdmi dprt req\n");
        }
-       spin_unlock_irq(&hw->lock);
+       spin_unlock_irqrestore(&hw->lock, flags);
 }
 
 /**
@@ -1989,7 +1992,7 @@ static int
 csio_ln_init(struct csio_lnode *ln)
 {
        int rv = -EINVAL;
-       struct csio_lnode *rln, *pln;
+       struct csio_lnode *pln;
        struct csio_hw *hw = csio_lnode_to_hw(ln);
 
        csio_init_state(&ln->sm, csio_lns_uninit);
@@ -2019,7 +2022,6 @@ csio_ln_init(struct csio_lnode *ln)
                 * THe rest is common for non-root physical and NPIV lnodes.
                 * Just get references to all other modules
                 */
-               rln = csio_root_lnode(ln);
 
                if (csio_is_npiv_ln(ln)) {
                        /* NPIV */
index 6f13673..94810b1 100644 (file)
@@ -1210,7 +1210,7 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
                   !csio_is_hw_intr_enabled(hw)) {
                csio_err(hw, "Cannot issue mailbox in interrupt mode 0x%x\n",
                         *((uint8_t *)mbp->mb));
-                       goto error_out;
+               goto error_out;
        }
 
        if (mbm->mcurrent != NULL) {
index da50e87..bc1086a 100644 (file)
@@ -2073,7 +2073,6 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
        struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
        struct net_device *ndev = cdev->ports[0];
        struct cxgbi_tag_format tformat;
-       unsigned int ppmax;
        int i, err;
 
        if (!lldi->vr->iscsi.size) {
@@ -2082,7 +2081,6 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
        }
 
        cdev->flags |= CXGBI_FLAG_USE_PPOD_OFLDQ;
-       ppmax = lldi->vr->iscsi.size >> PPOD_SIZE_SHIFT;
 
        memset(&tformat, 0, sizeof(struct cxgbi_tag_format));
        for (i = 0; i < 4; i++)
index 3e17af8..0d044c1 100644 (file)
@@ -2284,34 +2284,6 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn,
 }
 EXPORT_SYMBOL_GPL(cxgbi_set_conn_param);
 
-static inline int csk_print_port(struct cxgbi_sock *csk, char *buf)
-{
-       int len;
-
-       cxgbi_sock_get(csk);
-       len = sprintf(buf, "%hu\n", ntohs(csk->daddr.sin_port));
-       cxgbi_sock_put(csk);
-
-       return len;
-}
-
-static inline int csk_print_ip(struct cxgbi_sock *csk, char *buf)
-{
-       int len;
-
-       cxgbi_sock_get(csk);
-       if (csk->csk_family == AF_INET)
-               len = sprintf(buf, "%pI4",
-                             &csk->daddr.sin_addr.s_addr);
-       else
-               len = sprintf(buf, "%pI6",
-                             &csk->daddr6.sin6_addr);
-
-       cxgbi_sock_put(csk);
-
-       return len;
-}
-
 int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param,
                       char *buf)
 {
index 2dbf35f..fbd2ae4 100644 (file)
@@ -44,14 +44,12 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp)
        struct afu *afu = cmd->parent;
        struct cxlflash_cfg *cfg = afu->parent;
        struct device *dev = &cfg->dev->dev;
-       struct sisl_ioarcb *ioarcb;
        struct sisl_ioasa *ioasa;
        u32 resid;
 
        if (unlikely(!cmd))
                return;
 
-       ioarcb = &(cmd->rcb);
        ioasa = &(cmd->sa);
 
        if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) {
index 7bd376d..b02ac38 100644 (file)
@@ -1197,6 +1197,7 @@ bool esas2r_nvram_read_direct(struct esas2r_adapter *a)
        if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR,
                                     sizeof(struct esas2r_sas_nvram))) {
                esas2r_hdebug("NVRAM read failed, using defaults");
+               up(&a->nvram_semaphore);
                return false;
        }
 
index 80608b5..8ef150d 100644 (file)
@@ -1024,7 +1024,8 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic,
                atomic64_inc(&fnic_stats->io_stats.io_completions);
 
 
-       io_duration_time = jiffies_to_msecs(jiffies) - jiffies_to_msecs(io_req->start_time);
+       io_duration_time = jiffies_to_msecs(jiffies) -
+                                               jiffies_to_msecs(start_time);
 
        if(io_duration_time <= 10)
                atomic64_inc(&fnic_stats->io_stats.io_btw_0_to_10_msec);
index 78af9cc..1f55b9e 100644 (file)
@@ -259,7 +259,7 @@ int vnic_dev_cmd1(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, int wait)
        struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
        int delay;
        u32 status;
-       int dev_cmd_err[] = {
+       static const int dev_cmd_err[] = {
                /* convert from fw's version of error.h to host's version */
                0,      /* ERR_SUCCESS */
                EINVAL, /* ERR_EINVAL */
index 720c4d6..233c73e 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
+#include <linux/timer.h>
 #include <scsi/sas_ata.h>
 #include <scsi/libsas.h>
 
@@ -84,6 +85,7 @@
 #define HISI_SAS_PROT_MASK (HISI_SAS_DIF_PROT_MASK | HISI_SAS_DIX_PROT_MASK)
 
 #define HISI_SAS_WAIT_PHYUP_TIMEOUT 20
+#define CLEAR_ITCT_TIMEOUT     20
 
 struct hisi_hba;
 
@@ -167,6 +169,7 @@ struct hisi_sas_phy {
        enum sas_linkrate       minimum_linkrate;
        enum sas_linkrate       maximum_linkrate;
        int enable;
+       atomic_t down_cnt;
 };
 
 struct hisi_sas_port {
@@ -296,8 +299,8 @@ struct hisi_sas_hw {
        void (*phy_set_linkrate)(struct hisi_hba *hisi_hba, int phy_no,
                        struct sas_phy_linkrates *linkrates);
        enum sas_linkrate (*phy_get_max_linkrate)(void);
-       void (*clear_itct)(struct hisi_hba *hisi_hba,
-                           struct hisi_sas_device *dev);
+       int (*clear_itct)(struct hisi_hba *hisi_hba,
+                         struct hisi_sas_device *dev);
        void (*free_device)(struct hisi_sas_device *sas_dev);
        int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
        void (*dereg_device)(struct hisi_hba *hisi_hba,
@@ -321,6 +324,44 @@ struct hisi_sas_hw {
        const struct hisi_sas_debugfs_reg *debugfs_reg_port;
 };
 
+#define HISI_SAS_MAX_DEBUGFS_DUMP (50)
+
+struct hisi_sas_debugfs_cq {
+       struct hisi_sas_cq *cq;
+       void *complete_hdr;
+};
+
+struct hisi_sas_debugfs_dq {
+       struct hisi_sas_dq *dq;
+       struct hisi_sas_cmd_hdr *hdr;
+};
+
+struct hisi_sas_debugfs_regs {
+       struct hisi_hba *hisi_hba;
+       u32 *data;
+};
+
+struct hisi_sas_debugfs_port {
+       struct hisi_sas_phy *phy;
+       u32 *data;
+};
+
+struct hisi_sas_debugfs_iost {
+       struct hisi_sas_iost *iost;
+};
+
+struct hisi_sas_debugfs_itct {
+       struct hisi_sas_itct *itct;
+};
+
+struct hisi_sas_debugfs_iost_cache {
+       struct hisi_sas_iost_itct_cache *cache;
+};
+
+struct hisi_sas_debugfs_itct_cache {
+       struct hisi_sas_iost_itct_cache *cache;
+};
+
 struct hisi_hba {
        /* This must be the first element, used by SHOST_TO_SAS_HA */
        struct sas_ha_struct *p;
@@ -402,19 +443,20 @@ struct hisi_hba {
 
        /* debugfs memories */
        /* Put Global AXI and RAS Register into register array */
-       u32 *debugfs_regs[DEBUGFS_REGS_NUM];
-       u32 *debugfs_port_reg[HISI_SAS_MAX_PHYS];
-       void *debugfs_complete_hdr[HISI_SAS_MAX_QUEUES];
-       struct hisi_sas_cmd_hdr *debugfs_cmd_hdr[HISI_SAS_MAX_QUEUES];
-       struct hisi_sas_iost *debugfs_iost;
-       struct hisi_sas_itct *debugfs_itct;
-       u64 *debugfs_iost_cache;
-       u64 *debugfs_itct_cache;
-
+       struct hisi_sas_debugfs_regs debugfs_regs[HISI_SAS_MAX_DEBUGFS_DUMP][DEBUGFS_REGS_NUM];
+       struct hisi_sas_debugfs_port debugfs_port_reg[HISI_SAS_MAX_DEBUGFS_DUMP][HISI_SAS_MAX_PHYS];
+       struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_DEBUGFS_DUMP][HISI_SAS_MAX_QUEUES];
+       struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_DEBUGFS_DUMP][HISI_SAS_MAX_QUEUES];
+       struct hisi_sas_debugfs_iost debugfs_iost[HISI_SAS_MAX_DEBUGFS_DUMP];
+       struct hisi_sas_debugfs_itct debugfs_itct[HISI_SAS_MAX_DEBUGFS_DUMP];
+       struct hisi_sas_debugfs_iost_cache debugfs_iost_cache[HISI_SAS_MAX_DEBUGFS_DUMP];
+       struct hisi_sas_debugfs_itct_cache debugfs_itct_cache[HISI_SAS_MAX_DEBUGFS_DUMP];
+
+       u64 debugfs_timestamp[HISI_SAS_MAX_DEBUGFS_DUMP];
+       int debugfs_dump_index;
        struct dentry *debugfs_dir;
        struct dentry *debugfs_dump_dentry;
        struct dentry *debugfs_bist_dentry;
-       bool debugfs_snapshot;
 };
 
 /* Generic HW DMA host memory structures */
@@ -556,6 +598,7 @@ struct hisi_sas_slot_dif_buf_table {
 extern struct scsi_transport_template *hisi_sas_stt;
 
 extern bool hisi_sas_debugfs_enable;
+extern u32 hisi_sas_debugfs_dump_count;
 extern struct dentry *hisi_sas_debugfs_dir;
 
 extern void hisi_sas_stop_phys(struct hisi_hba *hisi_hba);
index 0847e68..03588ec 100644 (file)
@@ -587,7 +587,13 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
        dev = hisi_hba->dev;
 
        if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
-               if (in_softirq())
+               /*
+                * For IOs from upper layer, it may already disable preempt
+                * in the IO path, if disable preempt again in down(),
+                * function schedule() will report schedule_bug(), so check
+                * preemptible() before goto down().
+                */
+               if (!preemptible())
                        return -EINVAL;
 
                down(&hisi_hba->sem);
@@ -968,12 +974,13 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
        struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
        struct hisi_sas_phy *phy = sas_phy->lldd_phy;
        struct asd_sas_port *sas_port = sas_phy->port;
-       struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+       struct hisi_sas_port *port;
        unsigned long flags;
 
        if (!sas_port)
                return;
 
+       port = to_hisi_sas_port(sas_port);
        spin_lock_irqsave(&hisi_hba->lock, flags);
        port->port_attached = 1;
        port->id = phy->port_id;
@@ -1045,6 +1052,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
        struct device *dev = hisi_hba->dev;
+       int ret = 0;
 
        dev_info(dev, "dev[%d:%x] is gone\n",
                 sas_dev->device_id, sas_dev->dev_type);
@@ -1056,13 +1064,16 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 
                hisi_sas_dereg_device(hisi_hba, device);
 
-               hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+               ret = hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
                device->lldd_dev = NULL;
        }
 
        if (hisi_hba->hw->free_device)
                hisi_hba->hw->free_device(sas_dev);
-       sas_dev->dev_type = SAS_PHY_UNUSED;
+
+       /* Don't mark it as SAS_PHY_UNUSED if failed to clear ITCT */
+       if (!ret)
+               sas_dev->dev_type = SAS_PHY_UNUSED;
        sas_dev->sas_device = NULL;
        up(&hisi_hba->sem);
 }
@@ -1402,7 +1413,7 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state)
                struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
                struct asd_sas_phy *sas_phy = &phy->sas_phy;
                struct asd_sas_port *sas_port = sas_phy->port;
-               bool do_port_check = !!(_sas_port != sas_port);
+               bool do_port_check = _sas_port != sas_port;
 
                if (!sas_phy->phy->enabled)
                        continue;
@@ -1563,7 +1574,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
        struct Scsi_Host *shost = hisi_hba->shost;
        int rc;
 
-       if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct)
+       if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
                queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
 
        if (!hisi_hba->hw->soft_reset)
@@ -2055,7 +2066,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
 
        /* Internal abort timed out */
        if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-               if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct)
+               if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
                        queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
 
                if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
@@ -2676,6 +2687,7 @@ int hisi_sas_probe(struct platform_device *pdev,
 err_out_register_ha:
        scsi_remove_host(shost);
 err_out_ha:
+       hisi_sas_debugfs_exit(hisi_hba);
        hisi_sas_free(hisi_hba);
        scsi_host_put(shost);
        return rc;
@@ -2687,10 +2699,11 @@ struct dentry *hisi_sas_debugfs_dir;
 static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba)
 {
        int queue_entry_size = hisi_hba->hw->complete_hdr_size;
+       int dump_index = hisi_hba->debugfs_dump_index;
        int i;
 
        for (i = 0; i < hisi_hba->queue_count; i++)
-               memcpy(hisi_hba->debugfs_complete_hdr[i],
+               memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr,
                       hisi_hba->complete_hdr[i],
                       HISI_SAS_QUEUE_SLOTS * queue_entry_size);
 }
@@ -2698,13 +2711,14 @@ static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba)
 static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba)
 {
        int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr);
+       int dump_index = hisi_hba->debugfs_dump_index;
        int i;
 
        for (i = 0; i < hisi_hba->queue_count; i++) {
-               struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
+               struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
                int j;
 
-               debugfs_cmd_hdr = hisi_hba->debugfs_cmd_hdr[i];
+               debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr;
                cmd_hdr = hisi_hba->cmd_hdr[i];
 
                for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
@@ -2715,6 +2729,7 @@ static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba)
 {
+       int dump_index = hisi_hba->debugfs_dump_index;
        const struct hisi_sas_debugfs_reg *port =
                hisi_hba->hw->debugfs_reg_port;
        int i, phy_cnt;
@@ -2722,7 +2737,7 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba)
        u32 *databuf;
 
        for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) {
-               databuf = (u32 *)hisi_hba->debugfs_port_reg[phy_cnt];
+               databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data;
                for (i = 0; i < port->count; i++, databuf++) {
                        offset = port->base_off + 4 * i;
                        *databuf = port->read_port_reg(hisi_hba, phy_cnt,
@@ -2733,7 +2748,8 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba)
 {
-       u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_GLOBAL];
+       int dump_index = hisi_hba->debugfs_dump_index;
+       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const struct hisi_sas_debugfs_reg *global =
                        hw->debugfs_reg_array[DEBUGFS_GLOBAL];
@@ -2745,7 +2761,8 @@ static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba)
 {
-       u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_AXI];
+       int dump_index = hisi_hba->debugfs_dump_index;
+       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const struct hisi_sas_debugfs_reg *axi =
                        hw->debugfs_reg_array[DEBUGFS_AXI];
@@ -2758,7 +2775,8 @@ static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba)
 {
-       u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_RAS];
+       int dump_index = hisi_hba->debugfs_dump_index;
+       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const struct hisi_sas_debugfs_reg *ras =
                        hw->debugfs_reg_array[DEBUGFS_RAS];
@@ -2771,8 +2789,9 @@ static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
 {
-       void *cachebuf = hisi_hba->debugfs_itct_cache;
-       void *databuf = hisi_hba->debugfs_itct;
+       int dump_index = hisi_hba->debugfs_dump_index;
+       void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache;
+       void *databuf = hisi_hba->debugfs_itct[dump_index].itct;
        struct hisi_sas_itct *itct;
        int i;
 
@@ -2789,9 +2808,10 @@ static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
 
 static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba)
 {
+       int dump_index = hisi_hba->debugfs_dump_index;
        int max_command_entries = HISI_SAS_MAX_COMMANDS;
-       void *cachebuf = hisi_hba->debugfs_iost_cache;
-       void *databuf = hisi_hba->debugfs_iost;
+       void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache;
+       void *databuf = hisi_hba->debugfs_iost[dump_index].iost;
        struct hisi_sas_iost *iost;
        int i;
 
@@ -2842,11 +2862,12 @@ static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr,
 
 static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p)
 {
-       struct hisi_hba *hisi_hba = s->private;
+       struct hisi_sas_debugfs_regs *global = s->private;
+       struct hisi_hba *hisi_hba = global->hisi_hba;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL];
 
-       hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_GLOBAL],
+       hisi_sas_debugfs_print_reg(global->data,
                                   reg_global, s);
 
        return 0;
@@ -2868,11 +2889,12 @@ static const struct file_operations hisi_sas_debugfs_global_fops = {
 
 static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p)
 {
-       struct hisi_hba *hisi_hba = s->private;
+       struct hisi_sas_debugfs_regs *axi = s->private;
+       struct hisi_hba *hisi_hba = axi->hisi_hba;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI];
 
-       hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_AXI],
+       hisi_sas_debugfs_print_reg(axi->data,
                                   reg_axi, s);
 
        return 0;
@@ -2894,11 +2916,12 @@ static const struct file_operations hisi_sas_debugfs_axi_fops = {
 
 static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p)
 {
-       struct hisi_hba *hisi_hba = s->private;
+       struct hisi_sas_debugfs_regs *ras = s->private;
+       struct hisi_hba *hisi_hba = ras->hisi_hba;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS];
 
-       hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_RAS],
+       hisi_sas_debugfs_print_reg(ras->data,
                                   reg_ras, s);
 
        return 0;
@@ -2920,13 +2943,13 @@ static const struct file_operations hisi_sas_debugfs_ras_fops = {
 
 static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p)
 {
-       struct hisi_sas_phy *phy = s->private;
+       struct hisi_sas_debugfs_port *port = s->private;
+       struct hisi_sas_phy *phy = port->phy;
        struct hisi_hba *hisi_hba = phy->hisi_hba;
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port;
-       u32 *databuf = hisi_hba->debugfs_port_reg[phy->sas_phy.id];
 
-       hisi_sas_debugfs_print_reg(databuf, reg_port, s);
+       hisi_sas_debugfs_print_reg(port->data, reg_port, s);
 
        return 0;
 }
@@ -2975,13 +2998,13 @@ static void hisi_sas_show_row_32(struct seq_file *s, int index,
        seq_puts(s, "\n");
 }
 
-static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr)
+static void hisi_sas_cq_show_slot(struct seq_file *s, int slot,
+                                 struct hisi_sas_debugfs_cq *debugfs_cq)
 {
-       struct hisi_sas_cq *cq = cq_ptr;
+       struct hisi_sas_cq *cq = debugfs_cq->cq;
        struct hisi_hba *hisi_hba = cq->hisi_hba;
-       void *complete_queue = hisi_hba->debugfs_complete_hdr[cq->id];
-       __le32 *complete_hdr = complete_queue +
-                       (hisi_hba->hw->complete_hdr_size * slot);
+       __le32 *complete_hdr = debugfs_cq->complete_hdr +
+                              (hisi_hba->hw->complete_hdr_size * slot);
 
        hisi_sas_show_row_32(s, slot,
                             hisi_hba->hw->complete_hdr_size,
@@ -2990,11 +3013,11 @@ static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr)
 
 static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p)
 {
-       struct hisi_sas_cq *cq = s->private;
+       struct hisi_sas_debugfs_cq *debugfs_cq = s->private;
        int slot;
 
        for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
-               hisi_sas_cq_show_slot(s, slot, cq);
+               hisi_sas_cq_show_slot(s, slot, debugfs_cq);
        }
        return 0;
 }
@@ -3014,9 +3037,8 @@ static const struct file_operations hisi_sas_debugfs_cq_fops = {
 
 static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr)
 {
-       struct hisi_sas_dq *dq = dq_ptr;
-       struct hisi_hba *hisi_hba = dq->hisi_hba;
-       void *cmd_queue = hisi_hba->debugfs_cmd_hdr[dq->id];
+       struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr;
+       void *cmd_queue = debugfs_dq->hdr;
        __le32 *cmd_hdr = cmd_queue +
                sizeof(struct hisi_sas_cmd_hdr) * slot;
 
@@ -3048,14 +3070,14 @@ static const struct file_operations hisi_sas_debugfs_dq_fops = {
 
 static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p)
 {
-       struct hisi_hba *hisi_hba = s->private;
-       struct hisi_sas_iost *debugfs_iost = hisi_hba->debugfs_iost;
+       struct hisi_sas_debugfs_iost *debugfs_iost = s->private;
+       struct hisi_sas_iost *iost = debugfs_iost->iost;
        int i, max_command_entries = HISI_SAS_MAX_COMMANDS;
 
-       for (i = 0; i < max_command_entries; i++, debugfs_iost++) {
-               __le64 *iost = &debugfs_iost->qw0;
+       for (i = 0; i < max_command_entries; i++, iost++) {
+               __le64 *data = &iost->qw0;
 
-               hisi_sas_show_row_64(s, i, sizeof(*debugfs_iost), iost);
+               hisi_sas_show_row_64(s, i, sizeof(*iost), data);
        }
 
        return 0;
@@ -3076,9 +3098,8 @@ static const struct file_operations hisi_sas_debugfs_iost_fops = {
 
 static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p)
 {
-       struct hisi_hba *hisi_hba = s->private;
-       struct hisi_sas_iost_itct_cache *iost_cache =
-               (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_iost_cache;
+       struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private;
+       struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache;
        u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
        int i, tab_idx;
        __le64 *iost;
@@ -3117,13 +3138,13 @@ static const struct file_operations hisi_sas_debugfs_iost_cache_fops = {
 static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p)
 {
        int i;
-       struct hisi_hba *hisi_hba = s->private;
-       struct hisi_sas_itct *debugfs_itct = hisi_hba->debugfs_itct;
+       struct hisi_sas_debugfs_itct *debugfs_itct = s->private;
+       struct hisi_sas_itct *itct = debugfs_itct->itct;
 
-       for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, debugfs_itct++) {
-               __le64 *itct = &debugfs_itct->qw0;
+       for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
+               __le64 *data = &itct->qw0;
 
-               hisi_sas_show_row_64(s, i, sizeof(*debugfs_itct), itct);
+               hisi_sas_show_row_64(s, i, sizeof(*itct), data);
        }
 
        return 0;
@@ -3144,9 +3165,8 @@ static const struct file_operations hisi_sas_debugfs_itct_fops = {
 
 static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p)
 {
-       struct hisi_hba *hisi_hba = s->private;
-       struct hisi_sas_iost_itct_cache *itct_cache =
-               (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_itct_cache;
+       struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private;
+       struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache;
        u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
        int i, tab_idx;
        __le64 *itct;
@@ -3184,6 +3204,8 @@ static const struct file_operations hisi_sas_debugfs_itct_cache_fops = {
 
 static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
 {
+       u64 *debugfs_timestamp;
+       int dump_index = hisi_hba->debugfs_dump_index;
        struct dentry *dump_dentry;
        struct dentry *dentry;
        char name[256];
@@ -3191,19 +3213,26 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
        int c;
        int d;
 
-       /* Create dump dir inside device dir */
-       dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir);
-       hisi_hba->debugfs_dump_dentry = dump_dentry;
+       snprintf(name, 256, "%d", dump_index);
+
+       dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry);
 
-       debugfs_create_file("global", 0400, dump_dentry, hisi_hba,
-                           &hisi_sas_debugfs_global_fops);
+       debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index];
+
+       debugfs_create_u64("timestamp", 0400, dump_dentry,
+                          debugfs_timestamp);
+
+       debugfs_create_file("global", 0400, dump_dentry,
+                          &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL],
+                          &hisi_sas_debugfs_global_fops);
 
        /* Create port dir and files */
        dentry = debugfs_create_dir("port", dump_dentry);
        for (p = 0; p < hisi_hba->n_phy; p++) {
                snprintf(name, 256, "%d", p);
 
-               debugfs_create_file(name, 0400, dentry, &hisi_hba->phy[p],
+               debugfs_create_file(name, 0400, dentry,
+                                   &hisi_hba->debugfs_port_reg[dump_index][p],
                                    &hisi_sas_debugfs_port_fops);
        }
 
@@ -3212,7 +3241,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
        for (c = 0; c < hisi_hba->queue_count; c++) {
                snprintf(name, 256, "%d", c);
 
-               debugfs_create_file(name, 0400, dentry, &hisi_hba->cq[c],
+               debugfs_create_file(name, 0400, dentry,
+                                   &hisi_hba->debugfs_cq[dump_index][c],
                                    &hisi_sas_debugfs_cq_fops);
        }
 
@@ -3221,26 +3251,33 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
        for (d = 0; d < hisi_hba->queue_count; d++) {
                snprintf(name, 256, "%d", d);
 
-               debugfs_create_file(name, 0400, dentry, &hisi_hba->dq[d],
+               debugfs_create_file(name, 0400, dentry,
+                                   &hisi_hba->debugfs_dq[dump_index][d],
                                    &hisi_sas_debugfs_dq_fops);
        }
 
-       debugfs_create_file("iost", 0400, dump_dentry, hisi_hba,
+       debugfs_create_file("iost", 0400, dump_dentry,
+                           &hisi_hba->debugfs_iost[dump_index],
                            &hisi_sas_debugfs_iost_fops);
 
-       debugfs_create_file("iost_cache", 0400, dump_dentry, hisi_hba,
+       debugfs_create_file("iost_cache", 0400, dump_dentry,
+                           &hisi_hba->debugfs_iost_cache[dump_index],
                            &hisi_sas_debugfs_iost_cache_fops);
 
-       debugfs_create_file("itct", 0400, dump_dentry, hisi_hba,
+       debugfs_create_file("itct", 0400, dump_dentry,
+                           &hisi_hba->debugfs_itct[dump_index],
                            &hisi_sas_debugfs_itct_fops);
 
-       debugfs_create_file("itct_cache", 0400, dump_dentry, hisi_hba,
+       debugfs_create_file("itct_cache", 0400, dump_dentry,
+                           &hisi_hba->debugfs_itct_cache[dump_index],
                            &hisi_sas_debugfs_itct_cache_fops);
 
-       debugfs_create_file("axi", 0400, dump_dentry, hisi_hba,
+       debugfs_create_file("axi", 0400, dump_dentry,
+                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI],
                            &hisi_sas_debugfs_axi_fops);
 
-       debugfs_create_file("ras", 0400, dump_dentry, hisi_hba,
+       debugfs_create_file("ras", 0400, dump_dentry,
+                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS],
                            &hisi_sas_debugfs_ras_fops);
 
        return;
@@ -3271,8 +3308,7 @@ static ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file,
        struct hisi_hba *hisi_hba = file->f_inode->i_private;
        char buf[8];
 
-       /* A bit racy, but don't care too much since it's only debugfs */
-       if (hisi_hba->debugfs_snapshot)
+       if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count)
                return -EFAULT;
 
        if (count > 8)
@@ -3539,7 +3575,7 @@ static const struct {
        int             value;
        char            *name;
 } hisi_sas_debugfs_loop_modes[] = {
-       { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digial" },
+       { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" },
        { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" },
        { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" },
 };
@@ -3670,132 +3706,201 @@ static const struct file_operations hisi_sas_debugfs_bist_enable_ops = {
        .owner = THIS_MODULE,
 };
 
+static ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp,
+                                                  const char __user *buf,
+                                                  size_t count, loff_t *ppos)
+{
+       struct seq_file *s = filp->private_data;
+       struct hisi_sas_phy *phy = s->private;
+       unsigned int set_val;
+       int res;
+
+       res = kstrtouint_from_user(buf, count, 0, &set_val);
+       if (res)
+               return res;
+
+       if (set_val > 0)
+               return -EINVAL;
+
+       atomic_set(&phy->down_cnt, 0);
+
+       return count;
+}
+
+static int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p)
+{
+       struct hisi_sas_phy *phy = s->private;
+
+       seq_printf(s, "%d\n", atomic_read(&phy->down_cnt));
+
+       return 0;
+}
+
+static int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode,
+                                             struct file *filp)
+{
+       return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show,
+                          inode->i_private);
+}
+
+static const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = {
+       .open = hisi_sas_debugfs_phy_down_cnt_open,
+       .read = seq_read,
+       .write = hisi_sas_debugfs_phy_down_cnt_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
 void hisi_sas_debugfs_work_handler(struct work_struct *work)
 {
        struct hisi_hba *hisi_hba =
                container_of(work, struct hisi_hba, debugfs_work);
+       int debugfs_dump_index = hisi_hba->debugfs_dump_index;
+       struct device *dev = hisi_hba->dev;
+       u64 timestamp = local_clock();
 
-       if (hisi_hba->debugfs_snapshot)
+       if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) {
+               dev_warn(dev, "dump count exceeded!\n");
                return;
-       hisi_hba->debugfs_snapshot = true;
+       }
+
+       do_div(timestamp, NSEC_PER_MSEC);
+       hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp;
 
        hisi_sas_debugfs_snapshot_regs(hisi_hba);
+       hisi_hba->debugfs_dump_index++;
 }
 EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler);
 
-static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba)
+static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index)
 {
        struct device *dev = hisi_hba->dev;
        int i;
 
-       devm_kfree(dev, hisi_hba->debugfs_iost_cache);
-       devm_kfree(dev, hisi_hba->debugfs_itct_cache);
-       devm_kfree(dev, hisi_hba->debugfs_iost);
+       devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache);
+       devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache);
+       devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost);
+       devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct);
 
        for (i = 0; i < hisi_hba->queue_count; i++)
-               devm_kfree(dev, hisi_hba->debugfs_cmd_hdr[i]);
+               devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr);
 
        for (i = 0; i < hisi_hba->queue_count; i++)
-               devm_kfree(dev, hisi_hba->debugfs_complete_hdr[i]);
+               devm_kfree(dev,
+                          hisi_hba->debugfs_cq[dump_index][i].complete_hdr);
 
        for (i = 0; i < DEBUGFS_REGS_NUM; i++)
-               devm_kfree(dev, hisi_hba->debugfs_regs[i]);
+               devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data);
 
        for (i = 0; i < hisi_hba->n_phy; i++)
-               devm_kfree(dev, hisi_hba->debugfs_port_reg[i]);
+               devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data);
 }
 
-static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba)
+static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index)
 {
        const struct hisi_sas_hw *hw = hisi_hba->hw;
        struct device *dev = hisi_hba->dev;
-       int p, c, d;
+       int p, c, d, r, i;
        size_t sz;
 
-       hisi_hba->debugfs_dump_dentry =
-                       debugfs_create_dir("dump", hisi_hba->debugfs_dir);
+       for (r = 0; r < DEBUGFS_REGS_NUM; r++) {
+               struct hisi_sas_debugfs_regs *regs =
+                               &hisi_hba->debugfs_regs[dump_index][r];
 
-       sz = hw->debugfs_reg_array[DEBUGFS_GLOBAL]->count * 4;
-       hisi_hba->debugfs_regs[DEBUGFS_GLOBAL] =
-                               devm_kmalloc(dev, sz, GFP_KERNEL);
-
-       if (!hisi_hba->debugfs_regs[DEBUGFS_GLOBAL])
-               goto fail;
+               sz = hw->debugfs_reg_array[r]->count * 4;
+               regs->data = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!regs->data)
+                       goto fail;
+               regs->hisi_hba = hisi_hba;
+       }
 
        sz = hw->debugfs_reg_port->count * 4;
        for (p = 0; p < hisi_hba->n_phy; p++) {
-               hisi_hba->debugfs_port_reg[p] =
-                       devm_kmalloc(dev, sz, GFP_KERNEL);
+               struct hisi_sas_debugfs_port *port =
+                               &hisi_hba->debugfs_port_reg[dump_index][p];
 
-               if (!hisi_hba->debugfs_port_reg[p])
+               port->data = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!port->data)
                        goto fail;
+               port->phy = &hisi_hba->phy[p];
        }
 
-       sz = hw->debugfs_reg_array[DEBUGFS_AXI]->count * 4;
-       hisi_hba->debugfs_regs[DEBUGFS_AXI] =
-               devm_kmalloc(dev, sz, GFP_KERNEL);
-
-       if (!hisi_hba->debugfs_regs[DEBUGFS_AXI])
-               goto fail;
-
-       sz = hw->debugfs_reg_array[DEBUGFS_RAS]->count * 4;
-       hisi_hba->debugfs_regs[DEBUGFS_RAS] =
-               devm_kmalloc(dev, sz, GFP_KERNEL);
-
-       if (!hisi_hba->debugfs_regs[DEBUGFS_RAS])
-               goto fail;
-
        sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
        for (c = 0; c < hisi_hba->queue_count; c++) {
-               hisi_hba->debugfs_complete_hdr[c] =
-                       devm_kmalloc(dev, sz, GFP_KERNEL);
+               struct hisi_sas_debugfs_cq *cq =
+                               &hisi_hba->debugfs_cq[dump_index][c];
 
-               if (!hisi_hba->debugfs_complete_hdr[c])
+               cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!cq->complete_hdr)
                        goto fail;
+               cq->cq = &hisi_hba->cq[c];
        }
 
        sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
        for (d = 0; d < hisi_hba->queue_count; d++) {
-               hisi_hba->debugfs_cmd_hdr[d] =
-                       devm_kmalloc(dev, sz, GFP_KERNEL);
+               struct hisi_sas_debugfs_dq *dq =
+                               &hisi_hba->debugfs_dq[dump_index][d];
 
-               if (!hisi_hba->debugfs_cmd_hdr[d])
+               dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!dq->hdr)
                        goto fail;
+               dq->dq = &hisi_hba->dq[d];
        }
 
        sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost);
 
-       hisi_hba->debugfs_iost = devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_iost)
+       hisi_hba->debugfs_iost[dump_index].iost =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_iost[dump_index].iost)
                goto fail;
 
        sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
             sizeof(struct hisi_sas_iost_itct_cache);
 
-       hisi_hba->debugfs_iost_cache = devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_iost_cache)
+       hisi_hba->debugfs_iost_cache[dump_index].cache =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_iost_cache[dump_index].cache)
                goto fail;
 
        sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
             sizeof(struct hisi_sas_iost_itct_cache);
 
-       hisi_hba->debugfs_itct_cache = devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_itct_cache)
+       hisi_hba->debugfs_itct_cache[dump_index].cache =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_itct_cache[dump_index].cache)
                goto fail;
 
        /* New memory allocation must be locate before itct */
        sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
 
-       hisi_hba->debugfs_itct = devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_itct)
+       hisi_hba->debugfs_itct[dump_index].itct =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_itct[dump_index].itct)
                goto fail;
 
        return 0;
 fail:
-       hisi_sas_debugfs_release(hisi_hba);
+       for (i = 0; i < hisi_sas_debugfs_dump_count; i++)
+               hisi_sas_debugfs_release(hisi_hba, i);
        return -ENOMEM;
 }
 
+static void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba)
+{
+       struct dentry *dir = debugfs_create_dir("phy_down_cnt",
+                                               hisi_hba->debugfs_dir);
+       char name[16];
+       int phy_no;
+
+       for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+               snprintf(name, 16, "%d", phy_no);
+               debugfs_create_file(name, 0600, dir,
+                                   &hisi_hba->phy[phy_no],
+                                   &hisi_sas_debugfs_phy_down_cnt_ops);
+       }
+}
+
 static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba)
 {
        hisi_hba->debugfs_bist_dentry =
@@ -3827,6 +3932,7 @@ static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba)
 void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
 {
        struct device *dev = hisi_hba->dev;
+       int i;
 
        hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
                                                   hisi_sas_debugfs_dir);
@@ -3838,9 +3944,17 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
        /* create bist structures */
        hisi_sas_debugfs_bist_init(hisi_hba);
 
-       if (hisi_sas_debugfs_alloc(hisi_hba)) {
-               debugfs_remove_recursive(hisi_hba->debugfs_dir);
-               dev_dbg(dev, "failed to init debugfs!\n");
+       hisi_hba->debugfs_dump_dentry =
+                       debugfs_create_dir("dump", hisi_hba->debugfs_dir);
+
+       hisi_sas_debugfs_phy_down_cnt_init(hisi_hba);
+
+       for (i = 0; i < hisi_sas_debugfs_dump_count; i++) {
+               if (hisi_sas_debugfs_alloc(hisi_hba, i)) {
+                       debugfs_remove_recursive(hisi_hba->debugfs_dir);
+                       dev_dbg(dev, "failed to init debugfs!\n");
+                       break;
+               }
        }
 }
 EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init);
@@ -3874,14 +3988,24 @@ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable);
 module_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444);
 MODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)");
 
+u32 hisi_sas_debugfs_dump_count = 1;
+EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count);
+module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444);
+MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow");
+
 static __init int hisi_sas_init(void)
 {
        hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
        if (!hisi_sas_stt)
                return -ENOMEM;
 
-       if (hisi_sas_debugfs_enable)
+       if (hisi_sas_debugfs_enable) {
                hisi_sas_debugfs_dir = debugfs_create_dir("hisi_sas", NULL);
+               if (hisi_sas_debugfs_dump_count > HISI_SAS_MAX_DEBUGFS_DUMP) {
+                       pr_info("hisi_sas: Limiting debugfs dump count\n");
+                       hisi_sas_debugfs_dump_count = HISI_SAS_MAX_DEBUGFS_DUMP;
+               }
+       }
 
        return 0;
 }
index b861a0f..3af53cc 100644 (file)
@@ -531,8 +531,8 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
                                (0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF));
 }
 
-static void clear_itct_v1_hw(struct hisi_hba *hisi_hba,
-                             struct hisi_sas_device *sas_dev)
+static int clear_itct_v1_hw(struct hisi_hba *hisi_hba,
+                           struct hisi_sas_device *sas_dev)
 {
        u64 dev_id = sas_dev->device_id;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
@@ -551,6 +551,8 @@ static void clear_itct_v1_hw(struct hisi_hba *hisi_hba,
        qw0 = le64_to_cpu(itct->qw0);
        qw0 &= ~ITCT_HDR_VALID_MSK;
        itct->qw0 = cpu_to_le64(qw0);
+
+       return 0;
 }
 
 static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
index 8e96a25..61b1e26 100644 (file)
@@ -974,13 +974,14 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
                                        (0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void clear_itct_v2_hw(struct hisi_hba *hisi_hba,
-                             struct hisi_sas_device *sas_dev)
+static int clear_itct_v2_hw(struct hisi_hba *hisi_hba,
+                           struct hisi_sas_device *sas_dev)
 {
        DECLARE_COMPLETION_ONSTACK(completion);
        u64 dev_id = sas_dev->device_id;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
        u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+       struct device *dev = hisi_hba->dev;
        int i;
 
        sas_dev->completion = &completion;
@@ -990,13 +991,19 @@ static void clear_itct_v2_hw(struct hisi_hba *hisi_hba,
                hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
                                 ENT_INT_SRC3_ITC_INT_MSK);
 
+       /* need to set register twice to clear ITCT for v2 hw */
        for (i = 0; i < 2; i++) {
                reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
                hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
-               wait_for_completion(sas_dev->completion);
+               if (!wait_for_completion_timeout(sas_dev->completion,
+                                                CLEAR_ITCT_TIMEOUT * HZ)) {
+                       dev_warn(dev, "failed to clear ITCT\n");
+                       return -ETIMEDOUT;
+               }
 
                memset(itct, 0, sizeof(struct hisi_sas_itct));
        }
+       return 0;
 }
 
 static void free_device_v2_hw(struct hisi_sas_device *sas_dev)
index cb8d087..bf5d5f1 100644 (file)
@@ -795,13 +795,14 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
                                        (0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void clear_itct_v3_hw(struct hisi_hba *hisi_hba,
-                             struct hisi_sas_device *sas_dev)
+static int clear_itct_v3_hw(struct hisi_hba *hisi_hba,
+                           struct hisi_sas_device *sas_dev)
 {
        DECLARE_COMPLETION_ONSTACK(completion);
        u64 dev_id = sas_dev->device_id;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
        u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+       struct device *dev = hisi_hba->dev;
 
        sas_dev->completion = &completion;
 
@@ -814,8 +815,14 @@ static void clear_itct_v3_hw(struct hisi_hba *hisi_hba,
        reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
        hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
 
-       wait_for_completion(sas_dev->completion);
+       if (!wait_for_completion_timeout(sas_dev->completion,
+                                        CLEAR_ITCT_TIMEOUT * HZ)) {
+               dev_warn(dev, "failed to clear ITCT\n");
+               return -ETIMEDOUT;
+       }
+
        memset(itct, 0, sizeof(struct hisi_sas_itct));
+       return 0;
 }
 
 static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
@@ -1542,6 +1549,8 @@ static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
        u32 phy_state, sl_ctrl, txid_auto;
        struct device *dev = hisi_hba->dev;
 
+       atomic_inc(&phy->down_cnt);
+
        del_timer(&phy->timer);
        hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
@@ -3022,11 +3031,6 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable)
                hisi_sas_phy_write32(hisi_hba, phy_id,
                                     SAS_PHY_BIST_CTRL, reg_val);
 
-               mdelay(100);
-               reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK);
-               hisi_sas_phy_write32(hisi_hba, phy_id,
-                                    SAS_PHY_BIST_CTRL, reg_val);
-
                /* set the bist init value */
                hisi_sas_phy_write32(hisi_hba, phy_id,
                                     SAS_PHY_BIST_CODE,
@@ -3035,6 +3039,11 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable)
                                     SAS_PHY_BIST_CODE1,
                                     SAS_PHY_BIST_CODE1_INIT);
 
+               mdelay(100);
+               reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK);
+               hisi_sas_phy_write32(hisi_hba, phy_id,
+                                    SAS_PHY_BIST_CTRL, reg_val);
+
                /* clear error bit */
                mdelay(100);
                hisi_sas_phy_read32(hisi_hba, phy_id, SAS_BIST_ERR_CNT);
@@ -3259,6 +3268,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 err_out_register_ha:
        scsi_remove_host(shost);
 err_out_ha:
+       hisi_sas_debugfs_exit(hisi_hba);
        scsi_host_put(shost);
 err_out_regions:
        pci_release_regions(pdev);
@@ -3292,8 +3302,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
        struct hisi_hba *hisi_hba = sha->lldd_ha;
        struct Scsi_Host *shost = sha->core.shost;
 
-       hisi_sas_debugfs_exit(hisi_hba);
-
        if (timer_pending(&hisi_hba->timer))
                del_timer(&hisi_hba->timer);
 
@@ -3305,6 +3313,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        hisi_sas_free(hisi_hba);
+       hisi_sas_debugfs_exit(hisi_hba);
        scsi_host_put(shost);
 }
 
@@ -3422,6 +3431,7 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev)
        if (rc) {
                scsi_remove_host(shost);
                pci_disable_device(pdev);
+               return rc;
        }
        hisi_hba->hw->phys_init(hisi_hba);
        sas_resume_ha(sha);
index 55522b7..1d669e4 100644 (file)
@@ -38,6 +38,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
+#include <scsi/scsi_cmnd.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -554,13 +555,29 @@ struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL(scsi_host_get);
 
+static bool scsi_host_check_in_flight(struct request *rq, void *data,
+                                     bool reserved)
+{
+       int *count = data;
+       struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
+
+       if (test_bit(SCMD_STATE_INFLIGHT, &cmd->state))
+               (*count)++;
+
+       return true;
+}
+
 /**
  * scsi_host_busy - Return the host busy counter
  * @shost:     Pointer to Scsi_Host to inc.
  **/
 int scsi_host_busy(struct Scsi_Host *shost)
 {
-       return atomic_read(&shost->host_busy);
+       int cnt = 0;
+
+       blk_mq_tagset_busy_iter(&shost->tag_set,
+                               scsi_host_check_in_flight, &cnt);
+       return cnt;
 }
 EXPORT_SYMBOL(scsi_host_busy);
 
index e8bc8d3..f256729 100644 (file)
@@ -498,7 +498,7 @@ ips_setup(char *ips_str)
        int i;
        char *key;
        char *value;
-       IPS_OPTION options[] = {
+       static const IPS_OPTION options[] = {
                {"noi2o", &ips_force_i2o, 0},
                {"nommap", &ips_force_memio, 0},
                {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
index 9e8de14..b1c1975 100644 (file)
@@ -147,7 +147,7 @@ static struct isci_port *sci_port_configuration_agent_find_port(
 /**
  *
  * @controller: This is the controller object that contains the port agent
- * @port_agent: This is the port configruation agent for the controller.
+ * @port_agent: This is the port configuration agent for the controller.
  *
  * This routine will validate the port configuration is correct for the SCU
  * hardware.  The SCU hardware allows for port configurations as follows. LP0
index 49aa4e6..cd1e4b4 100644 (file)
@@ -1504,7 +1504,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
  * This function builds the isci_remote_device when a libsas dev_found message
  *    is received.
  * @isci_host: This parameter specifies the isci host object.
- * @port: This parameter specifies the isci_port conected to this device.
+ * @port: This parameter specifies the isci_port connected to this device.
  *
  * pointer to new isci_remote_device.
  */
index 7bedbe8..0bc63a7 100644 (file)
@@ -369,8 +369,16 @@ static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task)
 {
        struct iscsi_conn *conn = task->conn;
        unsigned int noreclaim_flag;
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
        int rc = 0;
 
+       if (!tcp_sw_conn->sock) {
+               iscsi_conn_printk(KERN_ERR, conn,
+                                 "Transport not bound to socket!\n");
+               return -EINVAL;
+       }
+
        noreclaim_flag = memalloc_noreclaim_save();
 
        while (iscsi_sw_tcp_xmit_qlen(conn)) {
index 691acbd..935f988 100644 (file)
@@ -605,6 +605,12 @@ struct lpfc_epd_pool {
        spinlock_t lock;        /* lock for expedite pool */
 };
 
+enum ras_state {
+       INACTIVE,
+       REG_INPROGRESS,
+       ACTIVE
+};
+
 struct lpfc_ras_fwlog {
        uint8_t *fwlog_buff;
        uint32_t fw_buffcount; /* Buffer size posted to FW */
@@ -621,7 +627,7 @@ struct lpfc_ras_fwlog {
        bool ras_enabled;   /* Ras Enabled for the function */
 #define LPFC_RAS_DISABLE_LOGGING 0x00
 #define LPFC_RAS_ENABLE_LOGGING 0x01
-       bool ras_active;    /* RAS logging running state */
+       enum ras_state state;    /* RAS logging running state */
 };
 
 struct lpfc_hba {
@@ -725,6 +731,7 @@ struct lpfc_hba {
 #define HBA_FCOE_MODE          0x4 /* HBA function in FCoE Mode */
 #define HBA_SP_QUEUE_EVT       0x8 /* Slow-path qevt posted to worker thread*/
 #define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
+#define HBA_PERSISTENT_TOPO    0x20 /* Persistent topology support in hba */
 #define ELS_XRI_ABORT_EVENT    0x40
 #define ASYNC_EVENT            0x80
 #define LINK_DISABLED          0x100 /* Link disabled by user */
@@ -830,6 +837,7 @@ struct lpfc_hba {
        uint32_t cfg_fcp_mq_threshold;
        uint32_t cfg_hdw_queue;
        uint32_t cfg_irq_chann;
+       uint32_t cfg_irq_numa;
        uint32_t cfg_suppress_rsp;
        uint32_t cfg_nvme_oas;
        uint32_t cfg_nvme_embed_cmd;
@@ -872,7 +880,6 @@ struct lpfc_hba {
        uint32_t cfg_aer_support;
        uint32_t cfg_sriov_nr_virtfn;
        uint32_t cfg_request_firmware_upgrade;
-       uint32_t cfg_iocb_cnt;
        uint32_t cfg_suppress_link_up;
        uint32_t cfg_rrq_xri_bitmap_sz;
        uint32_t cfg_delay_discovery;
@@ -990,7 +997,6 @@ struct lpfc_hba {
        struct dma_pool *lpfc_drb_pool; /* data receive buffer pool */
        struct dma_pool *lpfc_nvmet_drb_pool; /* data receive buffer pool */
        struct dma_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */
-       struct dma_pool *txrdy_payload_pool;
        struct dma_pool *lpfc_cmd_rsp_buf_pool;
        struct lpfc_dma_pool lpfc_mbuf_safety_pool;
 
@@ -1055,6 +1061,7 @@ struct lpfc_hba {
 #ifdef LPFC_HDWQ_LOCK_STAT
        struct dentry *debug_lockstat;
 #endif
+       struct dentry *debug_ras_log;
        atomic_t nvmeio_trc_cnt;
        uint32_t nvmeio_trc_size;
        uint32_t nvmeio_trc_output_idx;
@@ -1209,6 +1216,13 @@ struct lpfc_hba {
        uint64_t ktime_seg10_min;
        uint64_t ktime_seg10_max;
 #endif
+
+       struct hlist_node cpuhp;        /* used for cpuhp per hba callback */
+       struct timer_list cpuhp_poll_timer;
+       struct list_head poll_list;     /* slowpath eq polling list */
+#define LPFC_POLL_HB   1               /* slowpath heartbeat */
+#define LPFC_POLL_FASTPATH     0       /* called from fastpath */
+#define LPFC_POLL_SLOWPATH     1       /* called from slowpath */
 };
 
 static inline struct Scsi_Host *
@@ -1298,6 +1312,26 @@ lpfc_phba_elsring(struct lpfc_hba *phba)
        return &phba->sli.sli3_ring[LPFC_ELS_RING];
 }
 
+/**
+ * lpfc_next_online_numa_cpu - Finds next online CPU on NUMA node
+ * @numa_mask: Pointer to phba's numa_mask member.
+ * @start: starting cpu index
+ *
+ * Note: If no valid cpu found, then nr_cpu_ids is returned.
+ *
+ **/
+static inline unsigned int
+lpfc_next_online_numa_cpu(const struct cpumask *numa_mask, unsigned int start)
+{
+       unsigned int cpu_it;
+
+       for_each_cpu_wrap(cpu_it, numa_mask, start) {
+               if (cpu_online(cpu_it))
+                       break;
+       }
+
+       return cpu_it;
+}
 /**
  * lpfc_sli4_mod_hba_eq_delay - update EQ delay
  * @phba: Pointer to HBA context object.
index 25aa7a5..4ff82b3 100644 (file)
@@ -176,7 +176,6 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
        int i;
        int len = 0;
        char tmp[LPFC_MAX_NVME_INFO_TMP_LEN] = {0};
-       unsigned long iflags = 0;
 
        if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
                len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n");
@@ -347,7 +346,6 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
        if (strlcat(buf, "\nNVME Initiator Enabled\n", PAGE_SIZE) >= PAGE_SIZE)
                goto buffer_done;
 
-       rcu_read_lock();
        scnprintf(tmp, sizeof(tmp),
                  "XRI Dist lpfc%d Total %d IO %d ELS %d\n",
                  phba->brd_no,
@@ -355,7 +353,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
                  phba->sli4_hba.io_xri_max,
                  lpfc_sli4_get_els_iocb_cnt(phba));
        if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-               goto rcu_unlock_buf_done;
+               goto buffer_done;
 
        /* Port state is only one of two values for now. */
        if (localport->port_id)
@@ -371,15 +369,17 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
                  wwn_to_u64(vport->fc_nodename.u.wwn),
                  localport->port_id, statep);
        if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-               goto rcu_unlock_buf_done;
+               goto buffer_done;
+
+       spin_lock_irq(shost->host_lock);
 
        list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
                nrport = NULL;
-               spin_lock_irqsave(&vport->phba->hbalock, iflags);
+               spin_lock(&vport->phba->hbalock);
                rport = lpfc_ndlp_get_nrport(ndlp);
                if (rport)
                        nrport = rport->remoteport;
-               spin_unlock_irqrestore(&vport->phba->hbalock, iflags);
+               spin_unlock(&vport->phba->hbalock);
                if (!nrport)
                        continue;
 
@@ -398,39 +398,39 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 
                /* Tab in to show lport ownership. */
                if (strlcat(buf, "NVME RPORT       ", PAGE_SIZE) >= PAGE_SIZE)
-                       goto rcu_unlock_buf_done;
+                       goto unlock_buf_done;
                if (phba->brd_no >= 10) {
                        if (strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE)
-                               goto rcu_unlock_buf_done;
+                               goto unlock_buf_done;
                }
 
                scnprintf(tmp, sizeof(tmp), "WWPN x%llx ",
                          nrport->port_name);
                if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-                       goto rcu_unlock_buf_done;
+                       goto unlock_buf_done;
 
                scnprintf(tmp, sizeof(tmp), "WWNN x%llx ",
                          nrport->node_name);
                if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-                       goto rcu_unlock_buf_done;
+                       goto unlock_buf_done;
 
                scnprintf(tmp, sizeof(tmp), "DID x%06x ",
                          nrport->port_id);
                if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-                       goto rcu_unlock_buf_done;
+                       goto unlock_buf_done;
 
                /* An NVME rport can have multiple roles. */
                if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) {
                        if (strlcat(buf, "INITIATOR ", PAGE_SIZE) >= PAGE_SIZE)
-                               goto rcu_unlock_buf_done;
+                               goto unlock_buf_done;
                }
                if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) {
                        if (strlcat(buf, "TARGET ", PAGE_SIZE) >= PAGE_SIZE)
-                               goto rcu_unlock_buf_done;
+                               goto unlock_buf_done;
                }
                if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) {
                        if (strlcat(buf, "DISCSRVC ", PAGE_SIZE) >= PAGE_SIZE)
-                               goto rcu_unlock_buf_done;
+                               goto unlock_buf_done;
                }
                if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
                                          FC_PORT_ROLE_NVME_TARGET |
@@ -438,14 +438,14 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
                        scnprintf(tmp, sizeof(tmp), "UNKNOWN ROLE x%x",
                                  nrport->port_role);
                        if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-                               goto rcu_unlock_buf_done;
+                               goto unlock_buf_done;
                }
 
                scnprintf(tmp, sizeof(tmp), "%s\n", statep);
                if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
-                       goto rcu_unlock_buf_done;
+                       goto unlock_buf_done;
        }
-       rcu_read_unlock();
+       spin_unlock_irq(shost->host_lock);
 
        if (!lport)
                goto buffer_done;
@@ -505,11 +505,11 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
                  atomic_read(&lport->cmpl_fcp_err));
        strlcat(buf, tmp, PAGE_SIZE);
 
-       /* RCU is already unlocked. */
+       /* host_lock is already unlocked. */
        goto buffer_done;
 
rcu_unlock_buf_done:
-       rcu_read_unlock();
+ unlock_buf_done:
+       spin_unlock_irq(shost->host_lock);
 
  buffer_done:
        len = strnlen(buf, PAGE_SIZE);
@@ -1475,8 +1475,9 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
        int i;
 
        msleep(100);
-       lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
-                  &portstat_reg.word0);
+       if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+                      &portstat_reg.word0))
+               return -EIO;
 
        /* verify if privileged for the request operation */
        if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) &&
@@ -1486,8 +1487,9 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
        /* wait for the SLI port firmware ready after firmware reset */
        for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
                msleep(10);
-               lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
-                          &portstat_reg.word0);
+               if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+                              &portstat_reg.word0))
+                       continue;
                if (!bf_get(lpfc_sliport_status_err, &portstat_reg))
                        continue;
                if (!bf_get(lpfc_sliport_status_rn, &portstat_reg))
@@ -1642,7 +1644,7 @@ lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out)
 {
        LPFC_MBOXQ_t *mbox = NULL;
        unsigned long val = 0;
-       char *pval = 0;
+       char *pval = NULL;
        int rc = 0;
 
        if (!strncmp("enable", buff_out,
@@ -3533,6 +3535,31 @@ LPFC_ATTR_R(enable_rrq, 2, 0, 2,
 LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK,
                LPFC_DELAY_INIT_LINK_INDEFINITELY,
                "Suppress Link Up at initialization");
+
+static ssize_t
+lpfc_pls_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host  *shost = class_to_shost(dev);
+       struct lpfc_hba   *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        phba->sli4_hba.pc_sli4_params.pls);
+}
+static DEVICE_ATTR(pls, 0444,
+                        lpfc_pls_show, NULL);
+
+static ssize_t
+lpfc_pt_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host  *shost = class_to_shost(dev);
+       struct lpfc_hba   *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        (phba->hba_flag & HBA_PERSISTENT_TOPO) ? 1 : 0);
+}
+static DEVICE_ATTR(pt, 0444,
+                        lpfc_pt_show, NULL);
+
 /*
 # lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS
 #       1 - (1024)
@@ -3580,9 +3607,6 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
                         lpfc_txcmplq_hw_show, NULL);
 
-LPFC_ATTR_R(iocb_cnt, 2, 1, 5,
-       "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs");
-
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
 # until the timer expires. Value range is [0,255]. Default value is 30.
@@ -4096,7 +4120,16 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
                                val);
                        return -EINVAL;
                }
-               if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC ||
+               /*
+                * The 'topology' is not a configurable parameter if :
+                *   - persistent topology enabled
+                *   - G7 adapters
+                *   - G6 with no private loop support
+                */
+
+               if (((phba->hba_flag & HBA_PERSISTENT_TOPO) ||
+                    (!phba->sli4_hba.pc_sli4_params.pls &&
+                    phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC) ||
                     phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) &&
                    val == 4) {
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
@@ -5298,7 +5331,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
                        len += scnprintf(buf + len, PAGE_SIZE - len,
                                        "CPU %02d not present\n",
                                        phba->sli4_hba.curr_disp_cpu);
-               else if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) {
+               else if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
                        if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY)
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
@@ -5311,10 +5344,10 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
                        else
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
-                                       "CPU %02d EQ %04d hdwq %04d "
+                                       "CPU %02d EQ None hdwq %04d "
                                        "physid %d coreid %d ht %d ua %d\n",
                                        phba->sli4_hba.curr_disp_cpu,
-                                       cpup->eq, cpup->hdwq, cpup->phys_id,
+                                       cpup->hdwq, cpup->phys_id,
                                        cpup->core_id,
                                        (cpup->flag & LPFC_CPU_MAP_HYPER),
                                        (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
@@ -5329,7 +5362,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
                                        cpup->core_id,
                                        (cpup->flag & LPFC_CPU_MAP_HYPER),
                                        (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
-                                       cpup->irq);
+                                       lpfc_get_irq(cpup->eq));
                        else
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
@@ -5340,7 +5373,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
                                        cpup->core_id,
                                        (cpup->flag & LPFC_CPU_MAP_HYPER),
                                        (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
-                                       cpup->irq);
+                                       lpfc_get_irq(cpup->eq));
                }
 
                phba->sli4_hba.curr_disp_cpu++;
@@ -5711,7 +5744,7 @@ LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2,
  * the driver will advertise it supports to the SCSI layer.
  *
  *      0    = Set nr_hw_queues by the number of CPUs or HW queues.
- *      1,128 = Manually specify the maximum nr_hw_queue value to be set,
+ *      1,256 = Manually specify nr_hw_queue value to be advertised,
  *
  * Value range is [0,256]. Default value is 8.
  */
@@ -5729,30 +5762,130 @@ LPFC_ATTR_R(fcp_mq_threshold, LPFC_FCP_MQ_THRESHOLD_DEF,
  * A hardware IO queue maps (qidx) to a specific driver CQ/WQ.
  *
  *      0    = Configure the number of hdw queues to the number of active CPUs.
- *      1,128 = Manually specify how many hdw queues to use.
+ *      1,256 = Manually specify how many hdw queues to use.
  *
- * Value range is [0,128]. Default value is 0.
+ * Value range is [0,256]. Default value is 0.
  */
 LPFC_ATTR_R(hdw_queue,
            LPFC_HBA_HDWQ_DEF,
            LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX,
            "Set the number of I/O Hardware Queues");
 
+static inline void
+lpfc_assign_default_irq_numa(struct lpfc_hba *phba)
+{
+#if IS_ENABLED(CONFIG_X86)
+       /* If AMD architecture, then default is LPFC_IRQ_CHANN_NUMA */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+               phba->cfg_irq_numa = 1;
+       else
+               phba->cfg_irq_numa = 0;
+#else
+       phba->cfg_irq_numa = 0;
+#endif
+}
+
 /*
  * lpfc_irq_chann: Set the number of IRQ vectors that are available
  * for Hardware Queues to utilize.  This also will map to the number
  * of EQ / MSI-X vectors the driver will create. This should never be
  * more than the number of Hardware Queues
  *
- *      0     = Configure number of IRQ Channels to the number of active CPUs.
- *      1,128 = Manually specify how many IRQ Channels to use.
+ *     0               = Configure number of IRQ Channels to:
+ *                       if AMD architecture, number of CPUs on HBA's NUMA node
+ *                       otherwise, number of active CPUs.
+ *     [1,256]         = Manually specify how many IRQ Channels to use.
  *
- * Value range is [0,128]. Default value is 0.
+ * Value range is [0,256]. Default value is [0].
  */
-LPFC_ATTR_R(irq_chann,
-           LPFC_HBA_HDWQ_DEF,
-           LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX,
-           "Set the number of I/O IRQ Channels");
+static uint lpfc_irq_chann = LPFC_IRQ_CHANN_DEF;
+module_param(lpfc_irq_chann, uint, 0444);
+MODULE_PARM_DESC(lpfc_irq_chann, "Set number of interrupt vectors to allocate");
+
+/* lpfc_irq_chann_init - Set the hba irq_chann initial value
+ * @phba: lpfc_hba pointer.
+ * @val: contains the initial value
+ *
+ * Description:
+ * Validates the initial value is within range and assigns it to the
+ * adapter. If not in range, an error message is posted and the
+ * default value is assigned.
+ *
+ * Returns:
+ * zero if value is in range and is set
+ * -EINVAL if value was out of range
+ **/
+static int
+lpfc_irq_chann_init(struct lpfc_hba *phba, uint32_t val)
+{
+       const struct cpumask *numa_mask;
+
+       if (phba->cfg_use_msi != 2) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "8532 use_msi = %u ignoring cfg_irq_numa\n",
+                               phba->cfg_use_msi);
+               phba->cfg_irq_numa = 0;
+               phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN;
+               return 0;
+       }
+
+       /* Check if default setting was passed */
+       if (val == LPFC_IRQ_CHANN_DEF)
+               lpfc_assign_default_irq_numa(phba);
+
+       if (phba->cfg_irq_numa) {
+               numa_mask = &phba->sli4_hba.numa_mask;
+
+               if (cpumask_empty(numa_mask)) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "8533 Could not identify NUMA node, "
+                                       "ignoring cfg_irq_numa\n");
+                       phba->cfg_irq_numa = 0;
+                       phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN;
+               } else {
+                       phba->cfg_irq_chann = cpumask_weight(numa_mask);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "8543 lpfc_irq_chann set to %u "
+                                       "(numa)\n", phba->cfg_irq_chann);
+               }
+       } else {
+               if (val > LPFC_IRQ_CHANN_MAX) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "8545 lpfc_irq_chann attribute cannot "
+                                       "be set to %u, allowed range is "
+                                       "[%u,%u]\n",
+                                       val,
+                                       LPFC_IRQ_CHANN_MIN,
+                                       LPFC_IRQ_CHANN_MAX);
+                       phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN;
+                       return -EINVAL;
+               }
+               phba->cfg_irq_chann = val;
+       }
+
+       return 0;
+}
+
+/**
+ * lpfc_irq_chann_show - Display value of irq_chann
+ * @dev: class converted to a Scsi_host structure.
+ * @attr: device attribute, not used.
+ * @buf: on return contains a string with the list sizes
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_irq_chann_show(struct device *dev, struct device_attribute *attr,
+                   char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+       struct lpfc_hba *phba = vport->phba;
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", phba->cfg_irq_chann);
+}
+
+static DEVICE_ATTR_RO(lpfc_irq_chann);
 
 /*
 # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
@@ -5933,7 +6066,53 @@ LPFC_ATTR_RW(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics");
  *     [1-4] = Multiple of 1/4th Mb of host memory for FW logging
  * Value range [0..4]. Default value is 0
  */
-LPFC_ATTR_RW(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging");
+LPFC_ATTR(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging");
+lpfc_param_show(ras_fwlog_buffsize);
+
+static ssize_t
+lpfc_ras_fwlog_buffsize_set(struct lpfc_hba  *phba, uint val)
+{
+       int ret = 0;
+       enum ras_state state;
+
+       if (!lpfc_rangecheck(val, 0, 4))
+               return -EINVAL;
+
+       if (phba->cfg_ras_fwlog_buffsize == val)
+               return 0;
+
+       if (phba->cfg_ras_fwlog_func != PCI_FUNC(phba->pcidev->devfn))
+               return -EINVAL;
+
+       spin_lock_irq(&phba->hbalock);
+       state = phba->ras_fwlog.state;
+       spin_unlock_irq(&phba->hbalock);
+
+       if (state == REG_INPROGRESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "6147 RAS Logging "
+                               "registration is in progress\n");
+               return -EBUSY;
+       }
+
+       /* For disable logging: stop the logs and free the DMA.
+        * For ras_fwlog_buffsize size change we still need to free and
+        * reallocate the DMA in lpfc_sli4_ras_fwlog_init.
+        */
+       phba->cfg_ras_fwlog_buffsize = val;
+       if (state == ACTIVE) {
+               lpfc_ras_stop_fwlog(phba);
+               lpfc_sli4_ras_dma_free(phba);
+       }
+
+       lpfc_sli4_ras_init(phba);
+       if (phba->ras_fwlog.ras_enabled)
+               ret = lpfc_sli4_ras_fwlog_init(phba, phba->cfg_ras_fwlog_level,
+                                              LPFC_RAS_ENABLE_LOGGING);
+       return ret;
+}
+
+lpfc_param_store(ras_fwlog_buffsize);
+static DEVICE_ATTR_RW(lpfc_ras_fwlog_buffsize);
 
 /*
  * lpfc_ras_fwlog_level: Firmware logging verbosity level
@@ -6071,8 +6250,9 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_sriov_nr_virtfn,
        &dev_attr_lpfc_req_fw_upgrade,
        &dev_attr_lpfc_suppress_link_up,
-       &dev_attr_lpfc_iocb_cnt,
        &dev_attr_iocb_hw,
+       &dev_attr_pls,
+       &dev_attr_pt,
        &dev_attr_txq_hw,
        &dev_attr_txcmplq_hw,
        &dev_attr_lpfc_fips_level,
@@ -7085,11 +7265,22 @@ struct fc_function_template lpfc_vport_transport_functions = {
 static void
 lpfc_get_hba_function_mode(struct lpfc_hba *phba)
 {
-       /* If it's a SkyHawk FCoE adapter */
-       if (phba->pcidev->device == PCI_DEVICE_ID_SKYHAWK)
+       /* If the adapter supports FCoE mode */
+       switch (phba->pcidev->device) {
+       case PCI_DEVICE_ID_SKYHAWK:
+       case PCI_DEVICE_ID_SKYHAWK_VF:
+       case PCI_DEVICE_ID_LANCER_FCOE:
+       case PCI_DEVICE_ID_LANCER_FCOE_VF:
+       case PCI_DEVICE_ID_ZEPHYR_DCSP:
+       case PCI_DEVICE_ID_HORNET:
+       case PCI_DEVICE_ID_TIGERSHARK:
+       case PCI_DEVICE_ID_TOMCAT:
                phba->hba_flag |= HBA_FCOE_MODE;
-       else
+               break;
+       default:
+       /* for others, clear the flag */
                phba->hba_flag &= ~HBA_FCOE_MODE;
+       }
 }
 
 /**
@@ -7099,6 +7290,7 @@ lpfc_get_hba_function_mode(struct lpfc_hba *phba)
 void
 lpfc_get_cfgparam(struct lpfc_hba *phba)
 {
+       lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
        lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched);
        lpfc_ns_query_init(phba, lpfc_ns_query);
        lpfc_fcp2_no_tgt_reset_init(phba, lpfc_fcp2_no_tgt_reset);
@@ -7205,12 +7397,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        phba->cfg_soft_wwpn = 0L;
        lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
        lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
-       lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
        lpfc_aer_support_init(phba, lpfc_aer_support);
        lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn);
        lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade);
        lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
-       lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
        lpfc_delay_discovery_init(phba, lpfc_delay_discovery);
        lpfc_sli_mode_init(phba, lpfc_sli_mode);
        phba->cfg_enable_dss = 1;
@@ -7256,11 +7446,11 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba)
                }
 
                if (!phba->cfg_nvmet_mrq)
-                       phba->cfg_nvmet_mrq = phba->cfg_irq_chann;
+                       phba->cfg_nvmet_mrq = phba->cfg_hdw_queue;
 
                /* Adjust lpfc_nvmet_mrq to avoid running out of WQE slots */
-               if (phba->cfg_nvmet_mrq > phba->cfg_irq_chann) {
-                       phba->cfg_nvmet_mrq = phba->cfg_irq_chann;
+               if (phba->cfg_nvmet_mrq > phba->cfg_hdw_queue) {
+                       phba->cfg_nvmet_mrq = phba->cfg_hdw_queue;
                        lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC,
                                        "6018 Adjust lpfc_nvmet_mrq to %d\n",
                                        phba->cfg_nvmet_mrq);
index 39a736b..d4e1b12 100644 (file)
@@ -5435,10 +5435,12 @@ lpfc_bsg_get_ras_config(struct bsg_job *job)
                bsg_reply->reply_data.vendor_reply.vendor_rsp;
 
        /* Current logging state */
-       if (ras_fwlog->ras_active == true)
+       spin_lock_irq(&phba->hbalock);
+       if (ras_fwlog->state == ACTIVE)
                ras_reply->state = LPFC_RASLOG_STATE_RUNNING;
        else
                ras_reply->state = LPFC_RASLOG_STATE_STOPPED;
+       spin_unlock_irq(&phba->hbalock);
 
        ras_reply->log_level = phba->ras_fwlog.fw_loglevel;
        ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize;
@@ -5495,10 +5497,13 @@ lpfc_bsg_set_ras_config(struct bsg_job *job)
 
        if (action == LPFC_RASACTION_STOP_LOGGING) {
                /* Check if already disabled */
-               if (ras_fwlog->ras_active == false) {
+               spin_lock_irq(&phba->hbalock);
+               if (ras_fwlog->state != ACTIVE) {
+                       spin_unlock_irq(&phba->hbalock);
                        rc = -ESRCH;
                        goto ras_job_error;
                }
+               spin_unlock_irq(&phba->hbalock);
 
                /* Disable logging */
                lpfc_ras_stop_fwlog(phba);
@@ -5509,8 +5514,10 @@ lpfc_bsg_set_ras_config(struct bsg_job *job)
                 * FW-logging with new log-level. Return status
                 * "Logging already Running" to caller.
                 **/
-               if (ras_fwlog->ras_active)
+               spin_lock_irq(&phba->hbalock);
+               if (ras_fwlog->state != INACTIVE)
                        action_status = -EINPROGRESS;
+               spin_unlock_irq(&phba->hbalock);
 
                /* Enable logging */
                rc = lpfc_sli4_ras_fwlog_init(phba, log_level,
@@ -5626,10 +5633,13 @@ lpfc_bsg_get_ras_fwlog(struct bsg_job *job)
                goto ras_job_error;
 
        /* Logging to be stopped before reading */
-       if (ras_fwlog->ras_active == true) {
+       spin_lock_irq(&phba->hbalock);
+       if (ras_fwlog->state == ACTIVE) {
+               spin_unlock_irq(&phba->hbalock);
                rc = -EINPROGRESS;
                goto ras_job_error;
        }
+       spin_unlock_irq(&phba->hbalock);
 
        if (job->request_len <
            sizeof(struct fc_bsg_request) +
index b2ad8c7..ee353c8 100644 (file)
@@ -215,6 +215,12 @@ irqreturn_t lpfc_sli_fp_intr_handler(int, void *);
 irqreturn_t lpfc_sli4_intr_handler(int, void *);
 irqreturn_t lpfc_sli4_hba_intr_handler(int, void *);
 
+void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba);
+int lpfc_sli4_poll_eq(struct lpfc_queue *q, uint8_t path);
+void lpfc_sli4_poll_hbtimer(struct timer_list *t);
+void lpfc_sli4_start_polling(struct lpfc_queue *q);
+void lpfc_sli4_stop_polling(struct lpfc_queue *q);
+
 void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
@@ -586,6 +592,7 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd,
 void lpfc_nvme_cmd_template(void);
 void lpfc_nvmet_cmd_template(void);
 void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn);
+void lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt);
 extern int lpfc_enable_nvmet_cnt;
 extern unsigned long long lpfc_enable_nvmet[];
 extern int lpfc_no_hba_reset_cnt;
index 25e8670..99c9bb2 100644 (file)
@@ -763,9 +763,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                    cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
                        lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
                                         "0208 NameServer Rsp Data: x%x x%x "
-                                        "sz x%x\n",
+                                        "x%x x%x sz x%x\n",
                                         vport->fc_flag,
                                         CTreq->un.gid.Fc4Type,
+                                        vport->num_disc_nodes,
+                                        vport->gidft_inp,
                                         irsp->un.genreq64.bdl.bdeSize);
 
                        lpfc_ns_rsp(vport,
@@ -961,9 +963,13 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                if (CTrsp->CommandResponse.bits.CmdRsp ==
                    cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
                        lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                                        "4105 NameServer Rsp Data: x%x x%x\n",
+                                        "4105 NameServer Rsp Data: x%x x%x "
+                                        "x%x x%x sz x%x\n",
                                         vport->fc_flag,
-                                        CTreq->un.gid.Fc4Type);
+                                        CTreq->un.gid.Fc4Type,
+                                        vport->num_disc_nodes,
+                                        vport->gidft_inp,
+                                        irsp->un.genreq64.bdl.bdeSize);
 
                        lpfc_ns_rsp(vport,
                                    outp,
@@ -1025,6 +1031,11 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
                vport->gidft_inp--;
        }
+
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "6450 GID_PT cmpl inp %d disc %d\n",
+                        vport->gidft_inp, vport->num_disc_nodes);
+
        /* Link up / RSCN discovery */
        if ((vport->num_disc_nodes == 0) &&
            (vport->gidft_inp == 0)) {
@@ -1159,6 +1170,11 @@ out:
        /* Link up / RSCN discovery */
        if (vport->num_disc_nodes)
                vport->num_disc_nodes--;
+
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "6451 GFF_ID cmpl inp %d disc %d\n",
+                        vport->gidft_inp, vport->num_disc_nodes);
+
        if (vport->num_disc_nodes == 0) {
                /*
                 * The driver has cycled through all Nports in the RSCN payload.
@@ -1868,6 +1884,12 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
                        switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
                        case IOERR_SLI_ABORTED:
+                       case IOERR_SLI_DOWN:
+                               /* Driver aborted this IO.  No retry as error
+                                * is likely Offline->Online or some adapter
+                                * error.  Recovery will try again.
+                                */
+                               break;
                        case IOERR_ABORT_IN_PROGRESS:
                        case IOERR_SEQUENCE_TIMEOUT:
                        case IOERR_ILLEGAL_FRAME:
index 8d34be6..2e6a68d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/ctype.h>
+#include <linux/vmalloc.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -2078,6 +2079,96 @@ lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf,
 }
 #endif
 
+static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba,
+                                    char *buffer, int size)
+{
+       int copied = 0;
+       struct lpfc_dmabuf *dmabuf, *next;
+
+       spin_lock_irq(&phba->hbalock);
+       if (phba->ras_fwlog.state != ACTIVE) {
+               spin_unlock_irq(&phba->hbalock);
+               return -EINVAL;
+       }
+       spin_unlock_irq(&phba->hbalock);
+
+       list_for_each_entry_safe(dmabuf, next,
+                                &phba->ras_fwlog.fwlog_buff_list, list) {
+               memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE);
+               copied += LPFC_RAS_MAX_ENTRY_SIZE;
+               if (size > copied)
+                       break;
+       }
+       return copied;
+}
+
+static int
+lpfc_debugfs_ras_log_release(struct inode *inode, struct file *file)
+{
+       struct lpfc_debug *debug = file->private_data;
+
+       vfree(debug->buffer);
+       kfree(debug);
+
+       return 0;
+}
+
+/**
+ * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer
+ * @inode: The inode pointer that contains a vport pointer.
+ * @file: The file pointer to attach the log output.
+ *
+ * Description:
+ * This routine is the entry point for the debugfs open file operation. It gets
+ * the vport from the i_private field in @inode, allocates the necessary buffer
+ * for the log, fills the buffer from the in-memory log for this vport, and then
+ * returns a pointer to that log in the private_data field in @file.
+ *
+ * Returns:
+ * This function returns zero if successful. On error it will return a negative
+ * error value.
+ **/
+static int
+lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file)
+{
+       struct lpfc_hba *phba = inode->i_private;
+       struct lpfc_debug *debug;
+       int size;
+       int rc = -ENOMEM;
+
+       spin_lock_irq(&phba->hbalock);
+       if (phba->ras_fwlog.state != ACTIVE) {
+               spin_unlock_irq(&phba->hbalock);
+               rc = -EINVAL;
+               goto out;
+       }
+       spin_unlock_irq(&phba->hbalock);
+       debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+       if (!debug)
+               goto out;
+
+       size = LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize;
+       debug->buffer = vmalloc(size);
+       if (!debug->buffer)
+               goto free_debug;
+
+       debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size);
+       if (debug->len < 0) {
+               rc = -EINVAL;
+               goto free_buffer;
+       }
+       file->private_data = debug;
+
+       return 0;
+
+free_buffer:
+       vfree(debug->buffer);
+free_debug:
+       kfree(debug);
+out:
+       return rc;
+}
+
 /**
  * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer
  * @inode: The inode pointer that contains a vport pointer.
@@ -5286,6 +5377,16 @@ static const struct file_operations lpfc_debugfs_op_lockstat = {
 };
 #endif
 
+#undef lpfc_debugfs_ras_log
+static const struct file_operations lpfc_debugfs_ras_log = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_ras_log_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_ras_log_release,
+};
+#endif
+
 #undef lpfc_debugfs_op_dumpHBASlim
 static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
        .owner =        THIS_MODULE,
@@ -5457,7 +5558,6 @@ static const struct file_operations lpfc_idiag_op_extAcc = {
        .release =      lpfc_idiag_cmd_release,
 };
 
-#endif
 
 /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command
  * @phba: Pointer to HBA context object.
@@ -5707,6 +5807,19 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                        goto debug_failed;
                }
 
+               /* RAS log */
+               snprintf(name, sizeof(name), "ras_log");
+               phba->debug_ras_log =
+                       debugfs_create_file(name, 0644,
+                                           phba->hba_debugfs_root,
+                                           phba, &lpfc_debugfs_ras_log);
+               if (!phba->debug_ras_log) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                        "6148 Cannot create debugfs"
+                                        " ras_log\n");
+                       goto debug_failed;
+               }
+
                /* Setup hbqinfo */
                snprintf(name, sizeof(name), "hbqinfo");
                phba->debug_hbqinfo =
@@ -6117,6 +6230,9 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
                phba->debug_hbqinfo = NULL;
 
+               debugfs_remove(phba->debug_ras_log);
+               phba->debug_ras_log = NULL;
+
 #ifdef LPFC_HDWQ_LOCK_STAT
                debugfs_remove(phba->debug_lockstat); /* lockstat */
                phba->debug_lockstat = NULL;
index d530399..42a2bf3 100644 (file)
@@ -2236,6 +2236,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
        IOCB_t *irsp;
        struct lpfc_nodelist *ndlp;
+       char *mode;
 
        /* we pass cmdiocb to state machine which needs rspiocb as well */
        cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -2273,8 +2274,17 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        goto out;
                }
 
+               /* If we don't send GFT_ID to Fabric, a PRLI error
+                * could be expected.
+                */
+               if ((vport->fc_flag & FC_FABRIC) ||
+                   (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH))
+                       mode = KERN_ERR;
+               else
+                       mode = KERN_INFO;
+
                /* PRLI failed */
-               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+               lpfc_printf_vlog(vport, mode, LOG_ELS,
                                 "2754 PRLI failure DID:%06X Status:x%x/x%x, "
                                 "data: x%x\n",
                                 ndlp->nlp_DID, irsp->ulpStatus,
@@ -4291,6 +4301,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        irsp = &rspiocb->iocb;
 
+       if (!vport) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+                               "3177 ELS response failed\n");
+               goto out;
+       }
        if (cmdiocb->context_un.mbox)
                mbox = cmdiocb->context_un.mbox;
 
@@ -4430,7 +4445,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                mempool_free(mbox, phba->mbox_mem_pool);
        }
 out:
-       if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
+       if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) {
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
                spin_unlock_irq(shost->host_lock);
@@ -5260,6 +5275,11 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
                        }
                }
        }
+
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "6452 Discover PLOGI %d flag x%x\n",
+                        sentplogi, vport->fc_flag);
+
        if (sentplogi) {
                lpfc_set_disctmo(vport);
        }
@@ -6455,7 +6475,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        uint32_t payload_len, length, nportid, *cmd;
        int rscn_cnt;
        int rscn_id = 0, hba_id = 0;
-       int i;
+       int i, tmo;
 
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
@@ -6561,6 +6581,13 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_RSCN_DEFERRED;
+
+               /* Restart disctmo if its already running */
+               if (vport->fc_flag & FC_DISC_TMO) {
+                       tmo = ((phba->fc_ratov * 3) + 3);
+                       mod_timer(&vport->fc_disctmo,
+                                 jiffies + msecs_to_jiffies(1000 * tmo));
+               }
                if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
                    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
                        vport->fc_flag |= FC_RSCN_MODE;
@@ -6663,9 +6690,10 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
 
        /* RSCN processed */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                        "0215 RSCN processed Data: x%x x%x x%x x%x\n",
+                        "0215 RSCN processed Data: x%x x%x x%x x%x x%x x%x\n",
                         vport->fc_flag, 0, vport->fc_rscn_id_cnt,
-                        vport->port_state);
+                        vport->port_state, vport->num_disc_nodes,
+                        vport->gidft_inp);
 
        /* To process RSCN, first compare RSCN data with NameServer */
        vport->fc_ns_retry = 0;
@@ -7986,20 +8014,22 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
+       unsigned long iflags = 0;
 
        lpfc_fabric_abort_vport(vport);
+
        /*
         * For SLI3, only the hbalock is required.  But SLI4 needs to coordinate
         * with the ring insert operation.  Because lpfc_sli_issue_abort_iotag
         * ultimately grabs the ring_lock, the driver must splice the list into
         * a working list and release the locks before calling the abort.
         */
-       spin_lock_irq(&phba->hbalock);
+       spin_lock_irqsave(&phba->hbalock, iflags);
        pring = lpfc_phba_elsring(phba);
 
        /* Bail out if we've no ELS wq, like in PCI error recovery case. */
        if (unlikely(!pring)) {
-               spin_unlock_irq(&phba->hbalock);
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
                return;
        }
 
@@ -8014,6 +8044,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
                if (piocb->vport != vport)
                        continue;
 
+               if (piocb->iocb_flag & LPFC_DRIVER_ABORTED)
+                       continue;
+
                /* On the ELS ring we can have ELS_REQUESTs or
                 * GEN_REQUESTs waiting for a response.
                 */
@@ -8037,21 +8070,21 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
 
        if (phba->sli_rev == LPFC_SLI_REV4)
                spin_unlock(&pring->ring_lock);
-       spin_unlock_irq(&phba->hbalock);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
 
        /* Abort each txcmpl iocb on aborted list and remove the dlist links. */
        list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
-               spin_lock_irq(&phba->hbalock);
+               spin_lock_irqsave(&phba->hbalock, iflags);
                list_del_init(&piocb->dlist);
                lpfc_sli_issue_abort_iotag(phba, pring, piocb);
-               spin_unlock_irq(&phba->hbalock);
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
        }
        if (!list_empty(&abort_list))
                lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
                                 "3387 abort list for txq not empty\n");
        INIT_LIST_HEAD(&abort_list);
 
-       spin_lock_irq(&phba->hbalock);
+       spin_lock_irqsave(&phba->hbalock, iflags);
        if (phba->sli_rev == LPFC_SLI_REV4)
                spin_lock(&pring->ring_lock);
 
@@ -8091,7 +8124,7 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
 
        if (phba->sli_rev == LPFC_SLI_REV4)
                spin_unlock(&pring->ring_lock);
-       spin_unlock_irq(&phba->hbalock);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
 
        /* Cancel all the IOCBs from the completions list */
        lpfc_sli_cancel_iocbs(phba, &abort_list,
index 749286a..85ada3d 100644 (file)
@@ -700,7 +700,10 @@ lpfc_work_done(struct lpfc_hba *phba)
                        if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
                                set_bit(LPFC_DATA_READY, &phba->data_flags);
                } else {
-                       if (phba->link_state >= LPFC_LINK_UP ||
+                       /* Driver could have abort request completed in queue
+                        * when link goes down.  Allow for this transition.
+                        */
+                       if (phba->link_state >= LPFC_LINK_DOWN ||
                            phba->link_flag & LS_MDS_LOOPBACK) {
                                pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
                                lpfc_sli_handle_slow_ring_event(phba, pring,
@@ -1135,7 +1138,6 @@ void
 lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
-       uint8_t bbscn = 0;
 
        if (pmb->u.mb.mbxStatus)
                goto out;
@@ -1162,17 +1164,11 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        /* Start discovery by sending a FLOGI. port_state is identically
         * LPFC_FLOGI while waiting for FLOGI cmpl
         */
-       if (vport->port_state != LPFC_FLOGI) {
-               if (phba->bbcredit_support && phba->cfg_enable_bbcr) {
-                       bbscn = bf_get(lpfc_bbscn_def,
-                                      &phba->sli4_hba.bbscn_params);
-                       vport->fc_sparam.cmn.bbRcvSizeMsb &= 0xf;
-                       vport->fc_sparam.cmn.bbRcvSizeMsb |= (bbscn << 4);
-               }
+       if (vport->port_state != LPFC_FLOGI)
                lpfc_initial_flogi(vport);
-       } else if (vport->fc_flag & FC_PT2PT) {
+       else if (vport->fc_flag & FC_PT2PT)
                lpfc_disc_start(vport);
-       }
+
        return;
 
 out:
@@ -3456,8 +3452,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                                phba->pport->port_state, vport->fc_flag);
                else if (attn_type == LPFC_ATT_UNEXP_WWPN)
                        lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
-                               "1313 Link Down UNEXP WWPN Event x%x received "
-                               "Data: x%x x%x x%x x%x x%x\n",
+                               "1313 Link Down Unexpected FA WWPN Event x%x "
+                               "received Data: x%x x%x x%x x%x x%x\n",
                                la->eventTag, phba->fc_eventTag,
                                phba->pport->port_state, vport->fc_flag,
                                bf_get(lpfc_mbx_read_top_mm, la),
@@ -4046,7 +4042,7 @@ out:
        ndlp->nlp_flag |= NLP_RPI_REGISTERED;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
-       lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY,
                         "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n",
                         ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
                         kref_read(&ndlp->kref),
@@ -4575,8 +4571,10 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        return ndlp;
 
 free_rpi:
-       if (phba->sli_rev == LPFC_SLI_REV4)
+       if (phba->sli_rev == LPFC_SLI_REV4) {
                lpfc_sli4_free_rpi(vport->phba, rpi);
+               ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
+       }
        return NULL;
 }
 
@@ -4835,11 +4833,50 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
                        lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
                        ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
+                       ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
                }
                ndlp->nlp_flag &= ~NLP_UNREG_INP;
        }
 }
 
+/*
+ * Sets the mailbox completion handler to be used for the
+ * unreg_rpi command. The handler varies based on the state of
+ * the port and what will be happening to the rpi next.
+ */
+static void
+lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport,
+       struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox)
+{
+       unsigned long iflags;
+
+       if (ndlp->nlp_flag & NLP_ISSUE_LOGO) {
+               mbox->ctx_ndlp = ndlp;
+               mbox->mbox_cmpl = lpfc_nlp_logo_unreg;
+
+       } else if (phba->sli_rev == LPFC_SLI_REV4 &&
+                  (!(vport->load_flag & FC_UNLOADING)) &&
+                   (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
+                                     LPFC_SLI_INTF_IF_TYPE_2) &&
+                   (kref_read(&ndlp->kref) > 0)) {
+               mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
+               mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr;
+       } else {
+               if (vport->load_flag & FC_UNLOADING) {
+                       if (phba->sli_rev == LPFC_SLI_REV4) {
+                               spin_lock_irqsave(&vport->phba->ndlp_lock,
+                                                 iflags);
+                               ndlp->nlp_flag |= NLP_RELEASE_RPI;
+                               spin_unlock_irqrestore(&vport->phba->ndlp_lock,
+                                                      iflags);
+                       }
+                       lpfc_nlp_get(ndlp);
+               }
+               mbox->ctx_ndlp = ndlp;
+               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       }
+}
+
 /*
  * Free rpi associated with LPFC_NODELIST entry.
  * This routine is called from lpfc_freenode(), when we are removing
@@ -4860,7 +4897,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        if (ndlp->nlp_flag & NLP_RPI_REGISTERED ||
            ndlp->nlp_flag & NLP_REG_LOGIN_SEND) {
                if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
-                       lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+                       lpfc_printf_vlog(vport, KERN_INFO,
+                                        LOG_NODE | LOG_DISCOVERY,
                                         "3366 RPI x%x needs to be "
                                         "unregistered nlp_flag x%x "
                                         "did x%x\n",
@@ -4871,7 +4909,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                 * no need to queue up another one.
                 */
                if (ndlp->nlp_flag & NLP_UNREG_INP) {
-                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                       lpfc_printf_vlog(vport, KERN_INFO,
+                                        LOG_NODE | LOG_DISCOVERY,
                                         "1436 unreg_rpi SKIP UNREG x%x on "
                                         "NPort x%x deferred x%x  flg x%x "
                                         "Data: x%px\n",
@@ -4890,39 +4929,19 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 
                        lpfc_unreg_login(phba, vport->vpi, rpi, mbox);
                        mbox->vport = vport;
-                       if (ndlp->nlp_flag & NLP_ISSUE_LOGO) {
-                               mbox->ctx_ndlp = ndlp;
-                               mbox->mbox_cmpl = lpfc_nlp_logo_unreg;
-                       } else {
-                               if (phba->sli_rev == LPFC_SLI_REV4 &&
-                                   (!(vport->load_flag & FC_UNLOADING)) &&
-                                   (bf_get(lpfc_sli_intf_if_type,
-                                    &phba->sli4_hba.sli_intf) >=
-                                     LPFC_SLI_INTF_IF_TYPE_2) &&
-                                   (kref_read(&ndlp->kref) > 0)) {
-                                       mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
-                                       mbox->mbox_cmpl =
-                                               lpfc_sli4_unreg_rpi_cmpl_clr;
-                                       /*
-                                        * accept PLOGIs after unreg_rpi_cmpl
-                                        */
-                                       acc_plogi = 0;
-                               } else if (vport->load_flag & FC_UNLOADING) {
-                                       mbox->ctx_ndlp = NULL;
-                                       mbox->mbox_cmpl =
-                                               lpfc_sli_def_mbox_cmpl;
-                               } else {
-                                       mbox->ctx_ndlp = ndlp;
-                                       mbox->mbox_cmpl =
-                                               lpfc_sli_def_mbox_cmpl;
-                               }
-                       }
+                       lpfc_set_unreg_login_mbx_cmpl(phba, vport, ndlp, mbox);
+                       if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr)
+                               /*
+                                * accept PLOGIs after unreg_rpi_cmpl
+                                */
+                               acc_plogi = 0;
                        if (((ndlp->nlp_DID & Fabric_DID_MASK) !=
                            Fabric_DID_MASK) &&
                            (!(vport->fc_flag & FC_OFFLINE_MODE)))
                                ndlp->nlp_flag |= NLP_UNREG_INP;
 
-                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                       lpfc_printf_vlog(vport, KERN_INFO,
+                                        LOG_NODE | LOG_DISCOVERY,
                                         "1433 unreg_rpi UNREG x%x on "
                                         "NPort x%x deferred flg x%x "
                                         "Data:x%px\n",
@@ -5057,6 +5076,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        struct lpfc_hba  *phba = vport->phba;
        LPFC_MBOXQ_t *mb, *nextmb;
        struct lpfc_dmabuf *mp;
+       unsigned long iflags;
 
        /* Cleanup node for NPort <nlp_DID> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
@@ -5138,8 +5158,20 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        lpfc_cleanup_vports_rrqs(vport, ndlp);
        if (phba->sli_rev == LPFC_SLI_REV4)
                ndlp->nlp_flag |= NLP_RELEASE_RPI;
-       lpfc_unreg_rpi(vport, ndlp);
-
+       if (!lpfc_unreg_rpi(vport, ndlp)) {
+               /* Clean up unregistered and non freed rpis */
+               if ((ndlp->nlp_flag & NLP_RELEASE_RPI) &&
+                   !(ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR)) {
+                       lpfc_sli4_free_rpi(vport->phba,
+                                          ndlp->nlp_rpi);
+                       spin_lock_irqsave(&vport->phba->ndlp_lock,
+                                         iflags);
+                       ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
+                       ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
+                       spin_unlock_irqrestore(&vport->phba->ndlp_lock,
+                                              iflags);
+               }
+       }
        return 0;
 }
 
@@ -5165,8 +5197,10 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                /* For this case we need to cleanup the default rpi
                 * allocated by the firmware.
                 */
-               lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
-                                "0005 rpi:%x DID:%x flg:%x %d map:%x x%px\n",
+               lpfc_printf_vlog(vport, KERN_INFO,
+                                LOG_NODE | LOG_DISCOVERY,
+                                "0005 Cleanup Default rpi:x%x DID:x%x flg:x%x "
+                                "ref %d map:x%x ndlp x%px\n",
                                 ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
                                 kref_read(&ndlp->kref),
                                 ndlp->nlp_usg_map, ndlp);
@@ -5203,8 +5237,9 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                 */
                lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
                                "0940 removed node x%px DID x%x "
-                               " rport not null x%px\n",
-                               ndlp, ndlp->nlp_DID, ndlp->rport);
+                               "rpi %d rport not null x%px\n",
+                                ndlp, ndlp->nlp_DID, ndlp->nlp_rpi,
+                                ndlp->rport);
                rport = ndlp->rport;
                rdata = rport->dd_data;
                rdata->pnode = NULL;
@@ -5362,6 +5397,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
                if (!ndlp)
                        return NULL;
                lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "6453 Setup New Node 2B_DISC x%x "
+                                "Data:x%x x%x x%x\n",
+                                ndlp->nlp_DID, ndlp->nlp_flag,
+                                ndlp->nlp_state, vport->fc_flag);
+
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
                spin_unlock_irq(shost->host_lock);
@@ -5375,6 +5417,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
                                         "0014 Could not enable ndlp\n");
                        return NULL;
                }
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "6454 Setup Enabled Node 2B_DISC x%x "
+                                "Data:x%x x%x x%x\n",
+                                ndlp->nlp_DID, ndlp->nlp_flag,
+                                ndlp->nlp_state, vport->fc_flag);
+
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
                spin_unlock_irq(shost->host_lock);
@@ -5394,6 +5442,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
                         */
                        lpfc_cancel_retry_delay_tmo(vport, ndlp);
 
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                        "6455 Setup RSCN Node 2B_DISC x%x "
+                                        "Data:x%x x%x x%x\n",
+                                        ndlp->nlp_DID, ndlp->nlp_flag,
+                                        ndlp->nlp_state, vport->fc_flag);
+
                        /* NVME Target mode waits until rport is known to be
                         * impacted by the RSCN before it transitions.  No
                         * active management - just go to NPR provided the
@@ -5405,15 +5459,32 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
                        /* If we've already received a PLOGI from this NPort
                         * we don't need to try to discover it again.
                         */
-                       if (ndlp->nlp_flag & NLP_RCV_PLOGI)
+                       if (ndlp->nlp_flag & NLP_RCV_PLOGI &&
+                           !(ndlp->nlp_type &
+                            (NLP_FCP_TARGET | NLP_NVME_TARGET)))
                                return NULL;
 
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+
                        spin_lock_irq(shost->host_lock);
                        ndlp->nlp_flag |= NLP_NPR_2B_DISC;
                        spin_unlock_irq(shost->host_lock);
-               } else
+               } else {
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                        "6456 Skip Setup RSCN Node x%x "
+                                        "Data:x%x x%x x%x\n",
+                                        ndlp->nlp_DID, ndlp->nlp_flag,
+                                        ndlp->nlp_state, vport->fc_flag);
                        ndlp = NULL;
+               }
        } else {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "6457 Setup Active Node 2B_DISC x%x "
+                                "Data:x%x x%x x%x\n",
+                                ndlp->nlp_DID, ndlp->nlp_flag,
+                                ndlp->nlp_state, vport->fc_flag);
+
                /* If the initiator received a PLOGI from this NPort or if the
                 * initiator is already in the process of discovery on it,
                 * there's no need to try to discover it again.
@@ -5565,10 +5636,10 @@ lpfc_disc_start(struct lpfc_vport *vport)
 
        /* Start Discovery state <hba_state> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                        "0202 Start Discovery hba state x%x "
-                        "Data: x%x x%x x%x\n",
+                        "0202 Start Discovery port state x%x "
+                        "flg x%x Data: x%x x%x x%x\n",
                         vport->port_state, vport->fc_flag, vport->fc_plogi_cnt,
-                        vport->fc_adisc_cnt);
+                        vport->fc_adisc_cnt, vport->fc_npr_cnt);
 
        /* First do ADISCs - if any */
        num_sent = lpfc_els_disc_adisc(vport);
@@ -5996,7 +6067,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        ndlp->nlp_flag |= NLP_RPI_REGISTERED;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
-       lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY,
                         "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n",
                         ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
                         kref_read(&ndlp->kref),
@@ -6185,12 +6256,12 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did)
        INIT_LIST_HEAD(&ndlp->nlp_listp);
        if (vport->phba->sli_rev == LPFC_SLI_REV4) {
                ndlp->nlp_rpi = rpi;
-               lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
-                                "0007 rpi:%x DID:%x flg:%x refcnt:%d "
-                                "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID,
-                                ndlp->nlp_flag,
-                                kref_read(&ndlp->kref),
-                                ndlp->nlp_usg_map, ndlp);
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY,
+                                "0007 Init New ndlp x%px, rpi:x%x DID:%x "
+                                "flg:x%x refcnt:%d map:x%x\n",
+                                ndlp, ndlp->nlp_rpi, ndlp->nlp_DID,
+                                ndlp->nlp_flag, kref_read(&ndlp->kref),
+                                ndlp->nlp_usg_map);
 
                ndlp->active_rrqs_xri_bitmap =
                                mempool_alloc(vport->phba->active_rrq_pool,
@@ -6419,7 +6490,8 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
                                goto out;
                        } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
                                ret = 1;
-                               lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                               lpfc_printf_log(phba, KERN_INFO,
+                                               LOG_NODE | LOG_DISCOVERY,
                                                "2624 RPI %x DID %x flag %x "
                                                "still logged in\n",
                                                ndlp->nlp_rpi, ndlp->nlp_DID,
index bd53347..25cdcbc 100644 (file)
@@ -210,7 +210,6 @@ struct lpfc_sli_intf {
 #define LPFC_MAX_IMAX          5000000
 #define LPFC_DEF_IMAX          0
 
-#define LPFC_IMAX_THRESHOLD    1000
 #define LPFC_MAX_AUTO_EQ_DELAY 120
 #define LPFC_EQ_DELAY_STEP     15
 #define LPFC_EQD_ISR_TRIGGER   20000
@@ -2320,6 +2319,7 @@ struct lpfc_mbx_redisc_fcf_tbl {
 #define ADD_STATUS_OPERATION_ALREADY_ACTIVE            0x67
 #define ADD_STATUS_FW_NOT_SUPPORTED                    0xEB
 #define ADD_STATUS_INVALID_REQUEST                     0x4B
+#define ADD_STATUS_FW_DOWNLOAD_HW_DISABLED              0x58
 
 struct lpfc_mbx_sli4_config {
        struct mbox_header header;
@@ -2809,6 +2809,15 @@ struct lpfc_mbx_read_config {
 #define lpfc_mbx_rd_conf_trunk_SHIFT           12
 #define lpfc_mbx_rd_conf_trunk_MASK            0x0000000F
 #define lpfc_mbx_rd_conf_trunk_WORD            word2
+#define lpfc_mbx_rd_conf_pt_SHIFT              20
+#define lpfc_mbx_rd_conf_pt_MASK               0x00000003
+#define lpfc_mbx_rd_conf_pt_WORD               word2
+#define lpfc_mbx_rd_conf_tf_SHIFT              22
+#define lpfc_mbx_rd_conf_tf_MASK               0x00000001
+#define lpfc_mbx_rd_conf_tf_WORD               word2
+#define lpfc_mbx_rd_conf_ptv_SHIFT             23
+#define lpfc_mbx_rd_conf_ptv_MASK              0x00000001
+#define lpfc_mbx_rd_conf_ptv_WORD              word2
 #define lpfc_mbx_rd_conf_topology_SHIFT                24
 #define lpfc_mbx_rd_conf_topology_MASK         0x000000FF
 #define lpfc_mbx_rd_conf_topology_WORD         word2
@@ -3479,6 +3488,9 @@ struct lpfc_sli4_parameters {
 #define cfg_bv1s_SHIFT                          10
 #define cfg_bv1s_MASK                           0x00000001
 #define cfg_bv1s_WORD                           word19
+#define cfg_pvl_SHIFT                          13
+#define cfg_pvl_MASK                           0x00000001
+#define cfg_pvl_WORD                           word19
 
 #define cfg_nsler_SHIFT                         12
 #define cfg_nsler_MASK                          0x00000001
@@ -3518,6 +3530,7 @@ struct lpfc_sli4_parameters {
 
 #define LPFC_SET_UE_RECOVERY           0x10
 #define LPFC_SET_MDS_DIAGS             0x11
+#define LPFC_SET_DUAL_DUMP             0x1e
 struct lpfc_mbx_set_feature {
        struct mbox_header header;
        uint32_t feature;
@@ -3532,6 +3545,15 @@ struct lpfc_mbx_set_feature {
 #define lpfc_mbx_set_feature_mds_deep_loopbk_SHIFT  1
 #define lpfc_mbx_set_feature_mds_deep_loopbk_MASK   0x00000001
 #define lpfc_mbx_set_feature_mds_deep_loopbk_WORD   word6
+#define lpfc_mbx_set_feature_dd_SHIFT          0
+#define lpfc_mbx_set_feature_dd_MASK           0x00000001
+#define lpfc_mbx_set_feature_dd_WORD           word6
+#define lpfc_mbx_set_feature_ddquery_SHIFT     1
+#define lpfc_mbx_set_feature_ddquery_MASK      0x00000001
+#define lpfc_mbx_set_feature_ddquery_WORD      word6
+#define LPFC_DISABLE_DUAL_DUMP         0
+#define LPFC_ENABLE_DUAL_DUMP          1
+#define LPFC_QUERY_OP_DUAL_DUMP                2
        uint32_t word7;
 #define lpfc_mbx_set_feature_UERP_SHIFT 0
 #define lpfc_mbx_set_feature_UERP_MASK  0x0000ffff
@@ -4261,6 +4283,8 @@ struct lpfc_acqe_sli {
 #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP          0x5
 #define LPFC_SLI_EVENT_TYPE_MISCONFIGURED      0x9
 #define LPFC_SLI_EVENT_TYPE_REMOTE_DPORT       0xA
+#define LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN      0xF
+#define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE     0x10
 };
 
 /*
@@ -4659,6 +4683,7 @@ struct create_xri_wqe {
        uint32_t rsvd_12_15[4];         /* word 12-15 */
 };
 
+#define INHIBIT_ABORT 1
 #define T_REQUEST_TAG 3
 #define T_XRI_TAG 1
 
@@ -4807,8 +4832,8 @@ union lpfc_wqe128 {
        struct send_frame_wqe send_frame;
 };
 
-#define MAGIC_NUMER_G6 0xFEAA0003
-#define MAGIC_NUMER_G7 0xFEAA0005
+#define MAGIC_NUMBER_G6 0xFEAA0003
+#define MAGIC_NUMBER_G7 0xFEAA0005
 
 struct lpfc_grp_hdr {
        uint32_t size;
index e8813d2..dc6f7c4 100644 (file)
@@ -40,6 +40,8 @@
 #include <linux/irq.h>
 #include <linux/bitops.h>
 #include <linux/crash_dump.h>
+#include <linux/cpu.h>
+#include <linux/cpuhotplug.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include "lpfc_version.h"
 #include "lpfc_ids.h"
 
+static enum cpuhp_state lpfc_cpuhp_state;
 /* Used when mapping IRQ vectors in a driver centric manner */
 static uint32_t lpfc_present_cpu;
 
+static void __lpfc_cpuhp_remove(struct lpfc_hba *phba);
+static void lpfc_cpuhp_remove(struct lpfc_hba *phba);
+static void lpfc_cpuhp_add(struct lpfc_hba *phba);
 static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
 static int lpfc_post_rcv_buf(struct lpfc_hba *);
 static int lpfc_sli4_queue_verify(struct lpfc_hba *);
@@ -1235,10 +1241,9 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
                                             struct lpfc_hba, eq_delay_work);
        struct lpfc_eq_intr_info *eqi, *eqi_new;
        struct lpfc_queue *eq, *eq_next;
-       unsigned char *eqcnt = NULL;
+       unsigned char *ena_delay = NULL;
        uint32_t usdelay;
        int i;
-       bool update = false;
 
        if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING)
                return;
@@ -1247,44 +1252,36 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
            phba->pport->fc_flag & FC_OFFLINE_MODE)
                goto requeue;
 
-       eqcnt = kcalloc(num_possible_cpus(), sizeof(unsigned char),
-                       GFP_KERNEL);
-       if (!eqcnt)
+       ena_delay = kcalloc(phba->sli4_hba.num_possible_cpu, sizeof(*ena_delay),
+                           GFP_KERNEL);
+       if (!ena_delay)
                goto requeue;
 
-       if (phba->cfg_irq_chann > 1) {
-               /* Loop thru all IRQ vectors */
-               for (i = 0; i < phba->cfg_irq_chann; i++) {
-                       /* Get the EQ corresponding to the IRQ vector */
-                       eq = phba->sli4_hba.hba_eq_hdl[i].eq;
-                       if (!eq)
-                               continue;
-                       if (eq->q_mode) {
-                               update = true;
-                               break;
-                       }
-                       if (eqcnt[eq->last_cpu] < 2)
-                               eqcnt[eq->last_cpu]++;
+       for (i = 0; i < phba->cfg_irq_chann; i++) {
+               /* Get the EQ corresponding to the IRQ vector */
+               eq = phba->sli4_hba.hba_eq_hdl[i].eq;
+               if (!eq)
+                       continue;
+               if (eq->q_mode || eq->q_flag & HBA_EQ_DELAY_CHK) {
+                       eq->q_flag &= ~HBA_EQ_DELAY_CHK;
+                       ena_delay[eq->last_cpu] = 1;
                }
-       } else
-               update = true;
+       }
 
        for_each_present_cpu(i) {
                eqi = per_cpu_ptr(phba->sli4_hba.eq_info, i);
-               if (!update && eqcnt[i] < 2) {
-                       eqi->icnt = 0;
-                       continue;
+               if (ena_delay[i]) {
+                       usdelay = (eqi->icnt >> 10) * LPFC_EQ_DELAY_STEP;
+                       if (usdelay > LPFC_MAX_AUTO_EQ_DELAY)
+                               usdelay = LPFC_MAX_AUTO_EQ_DELAY;
+               } else {
+                       usdelay = 0;
                }
 
-               usdelay = (eqi->icnt / LPFC_IMAX_THRESHOLD) *
-                          LPFC_EQ_DELAY_STEP;
-               if (usdelay > LPFC_MAX_AUTO_EQ_DELAY)
-                       usdelay = LPFC_MAX_AUTO_EQ_DELAY;
-
                eqi->icnt = 0;
 
                list_for_each_entry_safe(eq, eq_next, &eqi->list, cpu_list) {
-                       if (eq->last_cpu != i) {
+                       if (unlikely(eq->last_cpu != i)) {
                                eqi_new = per_cpu_ptr(phba->sli4_hba.eq_info,
                                                      eq->last_cpu);
                                list_move_tail(&eq->cpu_list, &eqi_new->list);
@@ -1296,7 +1293,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
                }
        }
 
-       kfree(eqcnt);
+       kfree(ena_delay);
 
 requeue:
        queue_delayed_work(phba->wq, &phba->eq_delay_work,
@@ -3053,11 +3050,12 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba)
                                continue;
                        }
                        ndlp->nlp_rpi = rpi;
-                       lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
-                                        "0009 rpi:%x DID:%x "
-                                        "flg:%x map:%x x%px\n", ndlp->nlp_rpi,
-                                        ndlp->nlp_DID, ndlp->nlp_flag,
-                                        ndlp->nlp_usg_map, ndlp);
+                       lpfc_printf_vlog(ndlp->vport, KERN_INFO,
+                                        LOG_NODE | LOG_DISCOVERY,
+                                        "0009 Assign RPI x%x to ndlp x%px "
+                                        "DID:x%06x flg:x%x map:x%x\n",
+                                        ndlp->nlp_rpi, ndlp, ndlp->nlp_DID,
+                                        ndlp->nlp_flag, ndlp->nlp_usg_map);
                }
        }
        lpfc_destroy_vport_work_array(phba, vports);
@@ -3387,6 +3385,8 @@ lpfc_online(struct lpfc_hba *phba)
        if (phba->cfg_xri_rebalancing)
                lpfc_create_multixri_pools(phba);
 
+       lpfc_cpuhp_add(phba);
+
        lpfc_unblock_mgmt_io(phba);
        return 0;
 }
@@ -3453,10 +3453,15 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
                        list_for_each_entry_safe(ndlp, next_ndlp,
                                                 &vports[i]->fc_nodes,
                                                 nlp_listp) {
-                               if (!NLP_CHK_NODE_ACT(ndlp))
-                                       continue;
-                               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+                               if ((!NLP_CHK_NODE_ACT(ndlp)) ||
+                                   ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
+                                       /* Driver must assume RPI is invalid for
+                                        * any unused or inactive node.
+                                        */
+                                       ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
                                        continue;
+                               }
+
                                if (ndlp->nlp_type & NLP_FABRIC) {
                                        lpfc_disc_state_machine(vports[i], ndlp,
                                                NULL, NLP_EVT_DEVICE_RECOVERY);
@@ -3472,16 +3477,16 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
                                 * comes back online.
                                 */
                                if (phba->sli_rev == LPFC_SLI_REV4) {
-                                       lpfc_printf_vlog(ndlp->vport,
-                                                        KERN_INFO, LOG_NODE,
-                                                        "0011 lpfc_offline: "
-                                                        "ndlp:x%px did %x "
-                                                        "usgmap:x%x rpi:%x\n",
-                                                        ndlp, ndlp->nlp_DID,
-                                                        ndlp->nlp_usg_map,
-                                                        ndlp->nlp_rpi);
-
+                                       lpfc_printf_vlog(ndlp->vport, KERN_INFO,
+                                                LOG_NODE | LOG_DISCOVERY,
+                                                "0011 Free RPI x%x on "
+                                                "ndlp:x%px did x%x "
+                                                "usgmap:x%x\n",
+                                                ndlp->nlp_rpi, ndlp,
+                                                ndlp->nlp_DID,
+                                                ndlp->nlp_usg_map);
                                        lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
+                                       ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
                                }
                                lpfc_unreg_rpi(vports[i], ndlp);
                        }
@@ -3545,6 +3550,7 @@ lpfc_offline(struct lpfc_hba *phba)
                        spin_unlock_irq(shost->host_lock);
                }
        lpfc_destroy_vport_work_array(phba, vports);
+       __lpfc_cpuhp_remove(phba);
 
        if (phba->cfg_xri_rebalancing)
                lpfc_destroy_multixri_pools(phba);
@@ -5283,10 +5289,10 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
        evt_type = bf_get(lpfc_trailer_type, acqe_sli);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                       "2901 Async SLI event - Event Data1:x%08x Event Data2:"
-                       "x%08x SLI Event Type:%d\n",
+                       "2901 Async SLI event - Type:%d, Event Data: x%08x "
+                       "x%08x x%08x x%08x\n", evt_type,
                        acqe_sli->event_data1, acqe_sli->event_data2,
-                       evt_type);
+                       acqe_sli->reserved, acqe_sli->trailer);
 
        port_name = phba->Port[0];
        if (port_name == 0x00)
@@ -5433,11 +5439,26 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
                                "Event Data1:x%08x Event Data2: x%08x\n",
                                acqe_sli->event_data1, acqe_sli->event_data2);
                break;
+       case LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN:
+               /* Misconfigured WWN. Reports that the SLI Port is configured
+                * to use FA-WWN, but the attached device doesn’t support it.
+                * No driver action is required.
+                * Event Data1 - N.A, Event Data2 - N.A
+                */
+               lpfc_log_msg(phba, KERN_WARNING, LOG_SLI,
+                            "2699 Misconfigured FA-WWN - Attached device does "
+                            "not support FA-WWN\n");
+               break;
+       case LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE:
+               /* EEPROM failure. No driver action is required */
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                            "2518 EEPROM failure - "
+                            "Event Data1: x%08x Event Data2: x%08x\n",
+                            acqe_sli->event_data1, acqe_sli->event_data2);
+               break;
        default:
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               "3193 Async SLI event - Event Data1:x%08x Event Data2:"
-                               "x%08x SLI Event Type:%d\n",
-                               acqe_sli->event_data1, acqe_sli->event_data2,
+                               "3193 Unrecognized SLI event, type: 0x%x",
                                evt_type);
                break;
        }
@@ -5975,6 +5996,29 @@ static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
        return;
 }
 
+/**
+ * lpfc_cpumask_of_node_init - initalizes cpumask of phba's NUMA node
+ * @phba: Pointer to HBA context object.
+ *
+ **/
+static void
+lpfc_cpumask_of_node_init(struct lpfc_hba *phba)
+{
+       unsigned int cpu, numa_node;
+       struct cpumask *numa_mask = &phba->sli4_hba.numa_mask;
+
+       cpumask_clear(numa_mask);
+
+       /* Check if we're a NUMA architecture */
+       numa_node = dev_to_node(&phba->pcidev->dev);
+       if (numa_node == NUMA_NO_NODE)
+               return;
+
+       for_each_possible_cpu(cpu)
+               if (cpu_to_node(cpu) == numa_node)
+                       cpumask_set_cpu(cpu, numa_mask);
+}
+
 /**
  * lpfc_enable_pci_dev - Enable a generic PCI device.
  * @phba: pointer to lpfc hba data structure.
@@ -6418,6 +6462,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        phba->sli4_hba.num_present_cpu = lpfc_present_cpu;
        phba->sli4_hba.num_possible_cpu = num_possible_cpus();
        phba->sli4_hba.curr_disp_cpu = 0;
+       lpfc_cpumask_of_node_init(phba);
 
        /* Get all the module params for configuring this host */
        lpfc_get_cfgparam(phba);
@@ -6953,6 +6998,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
        phba->sli4_hba.num_possible_cpu = 0;
        phba->sli4_hba.num_present_cpu = 0;
        phba->sli4_hba.curr_disp_cpu = 0;
+       cpumask_clear(&phba->sli4_hba.numa_mask);
 
        /* Free memory allocated for fast-path work queue handles */
        kfree(phba->sli4_hba.hba_eq_hdl);
@@ -7126,7 +7172,7 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count)
                if (iocbq_entry == NULL) {
                        printk(KERN_ERR "%s: only allocated %d iocbs of "
                                "expected %d count. Unloading driver.\n",
-                               __func__, i, LPFC_IOCB_LIST_CNT);
+                               __func__, i, iocb_count);
                        goto out_free_iocbq;
                }
 
@@ -7545,18 +7591,10 @@ lpfc_create_shost(struct lpfc_hba *phba)
 
        if (phba->nvmet_support) {
                /* Only 1 vport (pport) will support NVME target */
-               if (phba->txrdy_payload_pool == NULL) {
-                       phba->txrdy_payload_pool = dma_pool_create(
-                               "txrdy_pool", &phba->pcidev->dev,
-                               TXRDY_PAYLOAD_LEN, 16, 0);
-                       if (phba->txrdy_payload_pool) {
-                               phba->targetport = NULL;
-                               phba->cfg_enable_fc4_type = LPFC_ENABLE_NVME;
-                               lpfc_printf_log(phba, KERN_INFO,
-                                               LOG_INIT | LOG_NVME_DISC,
-                                               "6076 NVME Target Found\n");
-                       }
-               }
+               phba->targetport = NULL;
+               phba->cfg_enable_fc4_type = LPFC_ENABLE_NVME;
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME_DISC,
+                               "6076 NVME Target Found\n");
        }
 
        lpfc_debugfs_initialize(vport);
@@ -8235,6 +8273,94 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba)
        memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx));
 }
 
+static const char * const lpfc_topo_to_str[] = {
+       "Loop then P2P",
+       "Loopback",
+       "P2P Only",
+       "Unsupported",
+       "Loop Only",
+       "Unsupported",
+       "P2P then Loop",
+};
+
+/**
+ * lpfc_map_topology - Map the topology read from READ_CONFIG
+ * @phba: pointer to lpfc hba data structure.
+ * @rdconf: pointer to read config data
+ *
+ * This routine is invoked to map the topology values as read
+ * from the read config mailbox command. If the persistent
+ * topology feature is supported, the firmware will provide the
+ * saved topology information to be used in INIT_LINK
+ *
+ **/
+#define        LINK_FLAGS_DEF  0x0
+#define        LINK_FLAGS_P2P  0x1
+#define        LINK_FLAGS_LOOP 0x2
+static void
+lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config)
+{
+       u8 ptv, tf, pt;
+
+       ptv = bf_get(lpfc_mbx_rd_conf_ptv, rd_config);
+       tf = bf_get(lpfc_mbx_rd_conf_tf, rd_config);
+       pt = bf_get(lpfc_mbx_rd_conf_pt, rd_config);
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "2027 Read Config Data : ptv:0x%x, tf:0x%x pt:0x%x",
+                        ptv, tf, pt);
+       if (!ptv) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "2019 FW does not support persistent topology "
+                               "Using driver parameter defined value [%s]",
+                               lpfc_topo_to_str[phba->cfg_topology]);
+               return;
+       }
+       /* FW supports persistent topology - override module parameter value */
+       phba->hba_flag |= HBA_PERSISTENT_TOPO;
+       switch (phba->pcidev->device) {
+       case PCI_DEVICE_ID_LANCER_G7_FC:
+               if (tf || (pt == LINK_FLAGS_LOOP)) {
+                       /* Invalid values from FW - use driver params */
+                       phba->hba_flag &= ~HBA_PERSISTENT_TOPO;
+               } else {
+                       /* Prism only supports PT2PT topology */
+                       phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT;
+               }
+               break;
+       case PCI_DEVICE_ID_LANCER_G6_FC:
+               if (!tf) {
+                       phba->cfg_topology = ((pt == LINK_FLAGS_LOOP)
+                                       ? FLAGS_TOPOLOGY_MODE_LOOP
+                                       : FLAGS_TOPOLOGY_MODE_PT_PT);
+               } else {
+                       phba->hba_flag &= ~HBA_PERSISTENT_TOPO;
+               }
+               break;
+       default:        /* G5 */
+               if (tf) {
+                       /* If topology failover set - pt is '0' or '1' */
+                       phba->cfg_topology = (pt ? FLAGS_TOPOLOGY_MODE_PT_LOOP :
+                                             FLAGS_TOPOLOGY_MODE_LOOP_PT);
+               } else {
+                       phba->cfg_topology = ((pt == LINK_FLAGS_P2P)
+                                       ? FLAGS_TOPOLOGY_MODE_PT_PT
+                                       : FLAGS_TOPOLOGY_MODE_LOOP);
+               }
+               break;
+       }
+       if (phba->hba_flag & HBA_PERSISTENT_TOPO) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                               "2020 Using persistent topology value [%s]",
+                               lpfc_topo_to_str[phba->cfg_topology]);
+       } else {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "2021 Invalid topology values from FW "
+                               "Using driver parameter defined value [%s]",
+                               lpfc_topo_to_str[phba->cfg_topology]);
+       }
+}
+
 /**
  * lpfc_sli4_read_config - Get the config parameters.
  * @phba: pointer to lpfc hba data structure.
@@ -8346,6 +8472,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ?
                                (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
                phba->max_vports = phba->max_vpi;
+               lpfc_map_topology(phba, rd_config);
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
                                "2003 cfg params Extents? %d "
                                "XRI(B:%d M:%d), "
@@ -8619,8 +8746,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
         */
 
        if (phba->nvmet_support) {
-               if (phba->cfg_irq_chann < phba->cfg_nvmet_mrq)
-                       phba->cfg_nvmet_mrq = phba->cfg_irq_chann;
+               if (phba->cfg_hdw_queue < phba->cfg_nvmet_mrq)
+                       phba->cfg_nvmet_mrq = phba->cfg_hdw_queue;
                if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX)
                        phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX;
        }
@@ -9160,6 +9287,8 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
        }
        spin_unlock_irq(&phba->hbalock);
 
+       lpfc_sli4_cleanup_poll_list(phba);
+
        /* Release HBA eqs */
        if (phba->sli4_hba.hdwq)
                lpfc_sli4_release_hdwq(phba);
@@ -10581,7 +10710,6 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
                 */
                if ((match == LPFC_FIND_BY_EQ) &&
                    (cpup->flag & LPFC_CPU_FIRST_IRQ) &&
-                   (cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
                    (cpup->eq == id))
                        return cpu;
 
@@ -10619,6 +10747,75 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu,
 }
 #endif
 
+/*
+ * lpfc_assign_eq_map_info - Assigns eq for vector_map structure
+ * @phba: pointer to lpfc hba data structure.
+ * @eqidx: index for eq and irq vector
+ * @flag: flags to set for vector_map structure
+ * @cpu: cpu used to index vector_map structure
+ *
+ * The routine assigns eq info into vector_map structure
+ */
+static inline void
+lpfc_assign_eq_map_info(struct lpfc_hba *phba, uint16_t eqidx, uint16_t flag,
+                       unsigned int cpu)
+{
+       struct lpfc_vector_map_info *cpup = &phba->sli4_hba.cpu_map[cpu];
+       struct lpfc_hba_eq_hdl *eqhdl = lpfc_get_eq_hdl(eqidx);
+
+       cpup->eq = eqidx;
+       cpup->flag |= flag;
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "3336 Set Affinity: CPU %d irq %d eq %d flag x%x\n",
+                       cpu, eqhdl->irq, cpup->eq, cpup->flag);
+}
+
+/**
+ * lpfc_cpu_map_array_init - Initialize cpu_map structure
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * The routine initializes the cpu_map array structure
+ */
+static void
+lpfc_cpu_map_array_init(struct lpfc_hba *phba)
+{
+       struct lpfc_vector_map_info *cpup;
+       struct lpfc_eq_intr_info *eqi;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+               cpup->phys_id = LPFC_VECTOR_MAP_EMPTY;
+               cpup->core_id = LPFC_VECTOR_MAP_EMPTY;
+               cpup->hdwq = LPFC_VECTOR_MAP_EMPTY;
+               cpup->eq = LPFC_VECTOR_MAP_EMPTY;
+               cpup->flag = 0;
+               eqi = per_cpu_ptr(phba->sli4_hba.eq_info, cpu);
+               INIT_LIST_HEAD(&eqi->list);
+               eqi->icnt = 0;
+       }
+}
+
+/**
+ * lpfc_hba_eq_hdl_array_init - Initialize hba_eq_hdl structure
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * The routine initializes the hba_eq_hdl array structure
+ */
+static void
+lpfc_hba_eq_hdl_array_init(struct lpfc_hba *phba)
+{
+       struct lpfc_hba_eq_hdl *eqhdl;
+       int i;
+
+       for (i = 0; i < phba->cfg_irq_chann; i++) {
+               eqhdl = lpfc_get_eq_hdl(i);
+               eqhdl->irq = LPFC_VECTOR_MAP_EMPTY;
+               eqhdl->phba = phba;
+       }
+}
+
 /**
  * lpfc_cpu_affinity_check - Check vector CPU affinity mappings
  * @phba: pointer to lpfc hba data structure.
@@ -10637,22 +10834,10 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
        int max_core_id, min_core_id;
        struct lpfc_vector_map_info *cpup;
        struct lpfc_vector_map_info *new_cpup;
-       const struct cpumask *maskp;
 #ifdef CONFIG_X86
        struct cpuinfo_x86 *cpuinfo;
 #endif
 
-       /* Init cpu_map array */
-       for_each_possible_cpu(cpu) {
-               cpup = &phba->sli4_hba.cpu_map[cpu];
-               cpup->phys_id = LPFC_VECTOR_MAP_EMPTY;
-               cpup->core_id = LPFC_VECTOR_MAP_EMPTY;
-               cpup->hdwq = LPFC_VECTOR_MAP_EMPTY;
-               cpup->eq = LPFC_VECTOR_MAP_EMPTY;
-               cpup->irq = LPFC_VECTOR_MAP_EMPTY;
-               cpup->flag = 0;
-       }
-
        max_phys_id = 0;
        min_phys_id = LPFC_VECTOR_MAP_EMPTY;
        max_core_id = 0;
@@ -10688,65 +10873,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
                        min_core_id = cpup->core_id;
        }
 
-       for_each_possible_cpu(i) {
-               struct lpfc_eq_intr_info *eqi =
-                       per_cpu_ptr(phba->sli4_hba.eq_info, i);
-
-               INIT_LIST_HEAD(&eqi->list);
-               eqi->icnt = 0;
-       }
-
-       /* This loop sets up all CPUs that are affinitized with a
-        * irq vector assigned to the driver. All affinitized CPUs
-        * will get a link to that vectors IRQ and EQ.
-        *
-        * NULL affinity mask handling:
-        * If irq count is greater than one, log an error message.
-        * If the null mask is received for the first irq, find the
-        * first present cpu, and assign the eq index to ensure at
-        * least one EQ is assigned.
-        */
-       for (idx = 0; idx <  phba->cfg_irq_chann; idx++) {
-               /* Get a CPU mask for all CPUs affinitized to this vector */
-               maskp = pci_irq_get_affinity(phba->pcidev, idx);
-               if (!maskp) {
-                       if (phba->cfg_irq_chann > 1)
-                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                               "3329 No affinity mask found "
-                                               "for vector %d (%d)\n",
-                                               idx, phba->cfg_irq_chann);
-                       if (!idx) {
-                               cpu = cpumask_first(cpu_present_mask);
-                               cpup = &phba->sli4_hba.cpu_map[cpu];
-                               cpup->eq = idx;
-                               cpup->irq = pci_irq_vector(phba->pcidev, idx);
-                               cpup->flag |= LPFC_CPU_FIRST_IRQ;
-                       }
-                       break;
-               }
-
-               i = 0;
-               /* Loop through all CPUs associated with vector idx */
-               for_each_cpu_and(cpu, maskp, cpu_present_mask) {
-                       /* Set the EQ index and IRQ for that vector */
-                       cpup = &phba->sli4_hba.cpu_map[cpu];
-                       cpup->eq = idx;
-                       cpup->irq = pci_irq_vector(phba->pcidev, idx);
-
-                       /* If this is the first CPU thats assigned to this
-                        * vector, set LPFC_CPU_FIRST_IRQ.
-                        */
-                       if (!i)
-                               cpup->flag |= LPFC_CPU_FIRST_IRQ;
-                       i++;
-
-                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                                       "3336 Set Affinity: CPU %d "
-                                       "irq %d eq %d flag x%x\n",
-                                       cpu, cpup->irq, cpup->eq, cpup->flag);
-               }
-       }
-
        /* After looking at each irq vector assigned to this pcidev, its
         * possible to see that not ALL CPUs have been accounted for.
         * Next we will set any unassigned (unaffinitized) cpu map
@@ -10772,7 +10898,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
                        for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
                                new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
                                if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
-                                   (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
+                                   (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY) &&
                                    (new_cpup->phys_id == cpup->phys_id))
                                        goto found_same;
                                new_cpu = cpumask_next(
@@ -10785,7 +10911,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
 found_same:
                        /* We found a matching phys_id, so copy the IRQ info */
                        cpup->eq = new_cpup->eq;
-                       cpup->irq = new_cpup->irq;
 
                        /* Bump start_cpu to the next slot to minmize the
                         * chance of having multiple unassigned CPU entries
@@ -10797,9 +10922,10 @@ found_same:
 
                        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                        "3337 Set Affinity: CPU %d "
-                                       "irq %d from id %d same "
+                                       "eq %d from peer cpu %d same "
                                        "phys_id (%d)\n",
-                                       cpu, cpup->irq, new_cpu, cpup->phys_id);
+                                       cpu, cpup->eq, new_cpu,
+                                       cpup->phys_id);
                }
        }
 
@@ -10823,7 +10949,7 @@ found_same:
                        for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
                                new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
                                if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
-                                   (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY))
+                                   (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY))
                                        goto found_any;
                                new_cpu = cpumask_next(
                                        new_cpu, cpu_present_mask);
@@ -10833,13 +10959,12 @@ found_same:
                        /* We should never leave an entry unassigned */
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "3339 Set Affinity: CPU %d "
-                                       "irq %d UNASSIGNED\n",
-                                       cpup->hdwq, cpup->irq);
+                                       "eq %d UNASSIGNED\n",
+                                       cpup->hdwq, cpup->eq);
                        continue;
 found_any:
                        /* We found an available entry, copy the IRQ info */
                        cpup->eq = new_cpup->eq;
-                       cpup->irq = new_cpup->irq;
 
                        /* Bump start_cpu to the next slot to minmize the
                         * chance of having multiple unassigned CPU entries
@@ -10851,8 +10976,8 @@ found_any:
 
                        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                        "3338 Set Affinity: CPU %d "
-                                       "irq %d from id %d (%d/%d)\n",
-                                       cpu, cpup->irq, new_cpu,
+                                       "eq %d from peer cpu %d (%d/%d)\n",
+                                       cpu, cpup->eq, new_cpu,
                                        new_cpup->phys_id, new_cpup->core_id);
                }
        }
@@ -10873,11 +10998,11 @@ found_any:
                idx++;
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "3333 Set Affinity: CPU %d (phys %d core %d): "
-                               "hdwq %d eq %d irq %d flg x%x\n",
+                               "hdwq %d eq %d flg x%x\n",
                                cpu, cpup->phys_id, cpup->core_id,
-                               cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
+                               cpup->hdwq, cpup->eq, cpup->flag);
        }
-       /* Finally we need to associate a hdwq with each cpu_map entry
+       /* Associate a hdwq with each cpu_map entry
         * This will be 1 to 1 - hdwq to cpu, unless there are less
         * hardware queues then CPUs. For that case we will just round-robin
         * the available hardware queues as they get assigned to CPUs.
@@ -10951,9 +11076,26 @@ found_any:
  logit:
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "3335 Set Affinity: CPU %d (phys %d core %d): "
-                               "hdwq %d eq %d irq %d flg x%x\n",
+                               "hdwq %d eq %d flg x%x\n",
                                cpu, cpup->phys_id, cpup->core_id,
-                               cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
+                               cpup->hdwq, cpup->eq, cpup->flag);
+       }
+
+       /*
+        * Initialize the cpu_map slots for not-present cpus in case
+        * a cpu is hot-added. Perform a simple hdwq round robin assignment.
+        */
+       idx = 0;
+       for_each_possible_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+               if (cpup->hdwq != LPFC_VECTOR_MAP_EMPTY)
+                       continue;
+
+               cpup->hdwq = idx++ % phba->cfg_hdw_queue;
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "3340 Set Affinity: not present "
+                               "CPU %d hdwq %d\n",
+                               cpu, cpup->hdwq);
        }
 
        /* The cpu_map array will be used later during initialization
@@ -10962,12 +11104,281 @@ found_any:
        return;
 }
 
+/**
+ * lpfc_cpuhp_get_eq
+ *
+ * @phba:   pointer to lpfc hba data structure.
+ * @cpu:    cpu going offline
+ * @eqlist:
+ */
+static void
+lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu,
+                 struct list_head *eqlist)
+{
+       const struct cpumask *maskp;
+       struct lpfc_queue *eq;
+       cpumask_t tmp;
+       u16 idx;
+
+       for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+               maskp = pci_irq_get_affinity(phba->pcidev, idx);
+               if (!maskp)
+                       continue;
+               /*
+                * if irq is not affinitized to the cpu going
+                * then we don't need to poll the eq attached
+                * to it.
+                */
+               if (!cpumask_and(&tmp, maskp, cpumask_of(cpu)))
+                       continue;
+               /* get the cpus that are online and are affini-
+                * tized to this irq vector.  If the count is
+                * more than 1 then cpuhp is not going to shut-
+                * down this vector.  Since this cpu has not
+                * gone offline yet, we need >1.
+                */
+               cpumask_and(&tmp, maskp, cpu_online_mask);
+               if (cpumask_weight(&tmp) > 1)
+                       continue;
+
+               /* Now that we have an irq to shutdown, get the eq
+                * mapped to this irq.  Note: multiple hdwq's in
+                * the software can share an eq, but eventually
+                * only eq will be mapped to this vector
+                */
+               eq = phba->sli4_hba.hba_eq_hdl[idx].eq;
+               list_add(&eq->_poll_list, eqlist);
+       }
+}
+
+static void __lpfc_cpuhp_remove(struct lpfc_hba *phba)
+{
+       if (phba->sli_rev != LPFC_SLI_REV4)
+               return;
+
+       cpuhp_state_remove_instance_nocalls(lpfc_cpuhp_state,
+                                           &phba->cpuhp);
+       /*
+        * unregistering the instance doesn't stop the polling
+        * timer. Wait for the poll timer to retire.
+        */
+       synchronize_rcu();
+       del_timer_sync(&phba->cpuhp_poll_timer);
+}
+
+static void lpfc_cpuhp_remove(struct lpfc_hba *phba)
+{
+       if (phba->pport->fc_flag & FC_OFFLINE_MODE)
+               return;
+
+       __lpfc_cpuhp_remove(phba);
+}
+
+static void lpfc_cpuhp_add(struct lpfc_hba *phba)
+{
+       if (phba->sli_rev != LPFC_SLI_REV4)
+               return;
+
+       rcu_read_lock();
+
+       if (!list_empty(&phba->poll_list)) {
+               timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
+               mod_timer(&phba->cpuhp_poll_timer,
+                         jiffies + msecs_to_jiffies(LPFC_POLL_HB));
+       }
+
+       rcu_read_unlock();
+
+       cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state,
+                                        &phba->cpuhp);
+}
+
+static int __lpfc_cpuhp_checks(struct lpfc_hba *phba, int *retval)
+{
+       if (phba->pport->load_flag & FC_UNLOADING) {
+               *retval = -EAGAIN;
+               return true;
+       }
+
+       if (phba->sli_rev != LPFC_SLI_REV4) {
+               *retval = 0;
+               return true;
+       }
+
+       /* proceed with the hotplug */
+       return false;
+}
+
+/**
+ * lpfc_irq_set_aff - set IRQ affinity
+ * @eqhdl: EQ handle
+ * @cpu: cpu to set affinity
+ *
+ **/
+static inline void
+lpfc_irq_set_aff(struct lpfc_hba_eq_hdl *eqhdl, unsigned int cpu)
+{
+       cpumask_clear(&eqhdl->aff_mask);
+       cpumask_set_cpu(cpu, &eqhdl->aff_mask);
+       irq_set_status_flags(eqhdl->irq, IRQ_NO_BALANCING);
+       irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask);
+}
+
+/**
+ * lpfc_irq_clear_aff - clear IRQ affinity
+ * @eqhdl: EQ handle
+ *
+ **/
+static inline void
+lpfc_irq_clear_aff(struct lpfc_hba_eq_hdl *eqhdl)
+{
+       cpumask_clear(&eqhdl->aff_mask);
+       irq_clear_status_flags(eqhdl->irq, IRQ_NO_BALANCING);
+       irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask);
+}
+
+/**
+ * lpfc_irq_rebalance - rebalances IRQ affinity according to cpuhp event
+ * @phba: pointer to HBA context object.
+ * @cpu: cpu going offline/online
+ * @offline: true, cpu is going offline. false, cpu is coming online.
+ *
+ * If cpu is going offline, we'll try our best effort to find the next
+ * online cpu on the phba's NUMA node and migrate all offlining IRQ affinities.
+ *
+ * If cpu is coming online, reaffinitize the IRQ back to the onlineng cpu.
+ *
+ * Note: Call only if cfg_irq_numa is enabled, otherwise rely on
+ *      PCI_IRQ_AFFINITY to auto-manage IRQ affinity.
+ *
+ **/
+static void
+lpfc_irq_rebalance(struct lpfc_hba *phba, unsigned int cpu, bool offline)
+{
+       struct lpfc_vector_map_info *cpup;
+       struct cpumask *aff_mask;
+       unsigned int cpu_select, cpu_next, idx;
+       const struct cpumask *numa_mask;
+
+       if (!phba->cfg_irq_numa)
+               return;
+
+       numa_mask = &phba->sli4_hba.numa_mask;
+
+       if (!cpumask_test_cpu(cpu, numa_mask))
+               return;
+
+       cpup = &phba->sli4_hba.cpu_map[cpu];
+
+       if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
+               return;
+
+       if (offline) {
+               /* Find next online CPU on NUMA node */
+               cpu_next = cpumask_next_wrap(cpu, numa_mask, cpu, true);
+               cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu_next);
+
+               /* Found a valid CPU */
+               if ((cpu_select < nr_cpu_ids) && (cpu_select != cpu)) {
+                       /* Go through each eqhdl and ensure offlining
+                        * cpu aff_mask is migrated
+                        */
+                       for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+                               aff_mask = lpfc_get_aff_mask(idx);
+
+                               /* Migrate affinity */
+                               if (cpumask_test_cpu(cpu, aff_mask))
+                                       lpfc_irq_set_aff(lpfc_get_eq_hdl(idx),
+                                                        cpu_select);
+                       }
+               } else {
+                       /* Rely on irqbalance if no online CPUs left on NUMA */
+                       for (idx = 0; idx < phba->cfg_irq_chann; idx++)
+                               lpfc_irq_clear_aff(lpfc_get_eq_hdl(idx));
+               }
+       } else {
+               /* Migrate affinity back to this CPU */
+               lpfc_irq_set_aff(lpfc_get_eq_hdl(cpup->eq), cpu);
+       }
+}
+
+static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node)
+{
+       struct lpfc_hba *phba = hlist_entry_safe(node, struct lpfc_hba, cpuhp);
+       struct lpfc_queue *eq, *next;
+       LIST_HEAD(eqlist);
+       int retval;
+
+       if (!phba) {
+               WARN_ONCE(!phba, "cpu: %u. phba:NULL", raw_smp_processor_id());
+               return 0;
+       }
+
+       if (__lpfc_cpuhp_checks(phba, &retval))
+               return retval;
+
+       lpfc_irq_rebalance(phba, cpu, true);
+
+       lpfc_cpuhp_get_eq(phba, cpu, &eqlist);
+
+       /* start polling on these eq's */
+       list_for_each_entry_safe(eq, next, &eqlist, _poll_list) {
+               list_del_init(&eq->_poll_list);
+               lpfc_sli4_start_polling(eq);
+       }
+
+       return 0;
+}
+
+static int lpfc_cpu_online(unsigned int cpu, struct hlist_node *node)
+{
+       struct lpfc_hba *phba = hlist_entry_safe(node, struct lpfc_hba, cpuhp);
+       struct lpfc_queue *eq, *next;
+       unsigned int n;
+       int retval;
+
+       if (!phba) {
+               WARN_ONCE(!phba, "cpu: %u. phba:NULL", raw_smp_processor_id());
+               return 0;
+       }
+
+       if (__lpfc_cpuhp_checks(phba, &retval))
+               return retval;
+
+       lpfc_irq_rebalance(phba, cpu, false);
+
+       list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list) {
+               n = lpfc_find_cpu_handle(phba, eq->hdwq, LPFC_FIND_BY_HDWQ);
+               if (n == cpu)
+                       lpfc_sli4_stop_polling(eq);
+       }
+
+       return 0;
+}
+
 /**
  * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to enable the MSI-X interrupt vectors to device
- * with SLI-4 interface spec.
+ * with SLI-4 interface spec.  It also allocates MSI-X vectors and maps them
+ * to cpus on the system.
+ *
+ * When cfg_irq_numa is enabled, the adapter will only allocate vectors for
+ * the number of cpus on the same numa node as this adapter.  The vectors are
+ * allocated without requesting OS affinity mapping.  A vector will be
+ * allocated and assigned to each online and offline cpu.  If the cpu is
+ * online, then affinity will be set to that cpu.  If the cpu is offline, then
+ * affinity will be set to the nearest peer cpu within the numa node that is
+ * online.  If there are no online cpus within the numa node, affinity is not
+ * assigned and the OS may do as it pleases. Note: cpu vector affinity mapping
+ * is consistent with the way cpu online/offline is handled when cfg_irq_numa is
+ * configured.
+ *
+ * If numa mode is not enabled and there is more than 1 vector allocated, then
+ * the driver relies on the managed irq interface where the OS assigns vector to
+ * cpu affinity.  The driver will then use that affinity mapping to setup its
+ * cpu mapping table.
  *
  * Return codes
  * 0 - successful
@@ -10978,13 +11389,31 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 {
        int vectors, rc, index;
        char *name;
+       const struct cpumask *numa_mask = NULL;
+       unsigned int cpu = 0, cpu_cnt = 0, cpu_select = nr_cpu_ids;
+       struct lpfc_hba_eq_hdl *eqhdl;
+       const struct cpumask *maskp;
+       bool first;
+       unsigned int flags = PCI_IRQ_MSIX;
 
        /* Set up MSI-X multi-message vectors */
        vectors = phba->cfg_irq_chann;
 
-       rc = pci_alloc_irq_vectors(phba->pcidev,
-                               1,
-                               vectors, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
+       if (phba->cfg_irq_numa) {
+               numa_mask = &phba->sli4_hba.numa_mask;
+               cpu_cnt = cpumask_weight(numa_mask);
+               vectors = min(phba->cfg_irq_chann, cpu_cnt);
+
+               /* cpu: iterates over numa_mask including offline or online
+                * cpu_select: iterates over online numa_mask to set affinity
+                */
+               cpu = cpumask_first(numa_mask);
+               cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu);
+       } else {
+               flags |= PCI_IRQ_AFFINITY;
+       }
+
+       rc = pci_alloc_irq_vectors(phba->pcidev, 1, vectors, flags);
        if (rc < 0) {
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                "0484 PCI enable MSI-X failed (%d)\n", rc);
@@ -10994,23 +11423,61 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 
        /* Assign MSI-X vectors to interrupt handlers */
        for (index = 0; index < vectors; index++) {
-               name = phba->sli4_hba.hba_eq_hdl[index].handler_name;
+               eqhdl = lpfc_get_eq_hdl(index);
+               name = eqhdl->handler_name;
                memset(name, 0, LPFC_SLI4_HANDLER_NAME_SZ);
                snprintf(name, LPFC_SLI4_HANDLER_NAME_SZ,
                         LPFC_DRIVER_HANDLER_NAME"%d", index);
 
-               phba->sli4_hba.hba_eq_hdl[index].idx = index;
-               phba->sli4_hba.hba_eq_hdl[index].phba = phba;
+               eqhdl->idx = index;
                rc = request_irq(pci_irq_vector(phba->pcidev, index),
                         &lpfc_sli4_hba_intr_handler, 0,
-                        name,
-                        &phba->sli4_hba.hba_eq_hdl[index]);
+                        name, eqhdl);
                if (rc) {
                        lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
                                        "0486 MSI-X fast-path (%d) "
                                        "request_irq failed (%d)\n", index, rc);
                        goto cfg_fail_out;
                }
+
+               eqhdl->irq = pci_irq_vector(phba->pcidev, index);
+
+               if (phba->cfg_irq_numa) {
+                       /* If found a neighboring online cpu, set affinity */
+                       if (cpu_select < nr_cpu_ids)
+                               lpfc_irq_set_aff(eqhdl, cpu_select);
+
+                       /* Assign EQ to cpu_map */
+                       lpfc_assign_eq_map_info(phba, index,
+                                               LPFC_CPU_FIRST_IRQ,
+                                               cpu);
+
+                       /* Iterate to next offline or online cpu in numa_mask */
+                       cpu = cpumask_next(cpu, numa_mask);
+
+                       /* Find next online cpu in numa_mask to set affinity */
+                       cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu);
+               } else if (vectors == 1) {
+                       cpu = cpumask_first(cpu_present_mask);
+                       lpfc_assign_eq_map_info(phba, index, LPFC_CPU_FIRST_IRQ,
+                                               cpu);
+               } else {
+                       maskp = pci_irq_get_affinity(phba->pcidev, index);
+
+                       first = true;
+                       /* Loop through all CPUs associated with vector index */
+                       for_each_cpu_and(cpu, maskp, cpu_present_mask) {
+                               /* If this is the first CPU thats assigned to
+                                * this vector, set LPFC_CPU_FIRST_IRQ.
+                                */
+                               lpfc_assign_eq_map_info(phba, index,
+                                                       first ?
+                                                       LPFC_CPU_FIRST_IRQ : 0,
+                                                       cpu);
+                               if (first)
+                                       first = false;
+                       }
+               }
        }
 
        if (vectors != phba->cfg_irq_chann) {
@@ -11020,17 +11487,18 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
                                phba->cfg_irq_chann, vectors);
                if (phba->cfg_irq_chann > vectors)
                        phba->cfg_irq_chann = vectors;
-               if (phba->nvmet_support && (phba->cfg_nvmet_mrq > vectors))
-                       phba->cfg_nvmet_mrq = vectors;
        }
 
        return rc;
 
 cfg_fail_out:
        /* free the irq already requested */
-       for (--index; index >= 0; index--)
-               free_irq(pci_irq_vector(phba->pcidev, index),
-                               &phba->sli4_hba.hba_eq_hdl[index]);
+       for (--index; index >= 0; index--) {
+               eqhdl = lpfc_get_eq_hdl(index);
+               lpfc_irq_clear_aff(eqhdl);
+               irq_set_affinity_hint(eqhdl->irq, NULL);
+               free_irq(eqhdl->irq, eqhdl);
+       }
 
        /* Unconfigure MSI-X capability structure */
        pci_free_irq_vectors(phba->pcidev);
@@ -11057,6 +11525,8 @@ static int
 lpfc_sli4_enable_msi(struct lpfc_hba *phba)
 {
        int rc, index;
+       unsigned int cpu;
+       struct lpfc_hba_eq_hdl *eqhdl;
 
        rc = pci_alloc_irq_vectors(phba->pcidev, 1, 1,
                                   PCI_IRQ_MSI | PCI_IRQ_AFFINITY);
@@ -11078,9 +11548,15 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
                return rc;
        }
 
+       eqhdl = lpfc_get_eq_hdl(0);
+       eqhdl->irq = pci_irq_vector(phba->pcidev, 0);
+
+       cpu = cpumask_first(cpu_present_mask);
+       lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, cpu);
+
        for (index = 0; index < phba->cfg_irq_chann; index++) {
-               phba->sli4_hba.hba_eq_hdl[index].idx = index;
-               phba->sli4_hba.hba_eq_hdl[index].phba = phba;
+               eqhdl = lpfc_get_eq_hdl(index);
+               eqhdl->idx = index;
        }
 
        return 0;
@@ -11138,15 +11614,21 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
                                     IRQF_SHARED, LPFC_DRIVER_NAME, phba);
                if (!retval) {
                        struct lpfc_hba_eq_hdl *eqhdl;
+                       unsigned int cpu;
 
                        /* Indicate initialization to INTx mode */
                        phba->intr_type = INTx;
                        intr_mode = 0;
 
+                       eqhdl = lpfc_get_eq_hdl(0);
+                       eqhdl->irq = pci_irq_vector(phba->pcidev, 0);
+
+                       cpu = cpumask_first(cpu_present_mask);
+                       lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ,
+                                               cpu);
                        for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
-                               eqhdl = &phba->sli4_hba.hba_eq_hdl[idx];
+                               eqhdl = lpfc_get_eq_hdl(idx);
                                eqhdl->idx = idx;
-                               eqhdl->phba = phba;
                        }
                }
        }
@@ -11168,14 +11650,14 @@ lpfc_sli4_disable_intr(struct lpfc_hba *phba)
        /* Disable the currently initialized interrupt mode */
        if (phba->intr_type == MSIX) {
                int index;
+               struct lpfc_hba_eq_hdl *eqhdl;
 
                /* Free up MSI-X multi-message vectors */
                for (index = 0; index < phba->cfg_irq_chann; index++) {
-                       irq_set_affinity_hint(
-                               pci_irq_vector(phba->pcidev, index),
-                               NULL);
-                       free_irq(pci_irq_vector(phba->pcidev, index),
-                                       &phba->sli4_hba.hba_eq_hdl[index]);
+                       eqhdl = lpfc_get_eq_hdl(index);
+                       lpfc_irq_clear_aff(eqhdl);
+                       irq_set_affinity_hint(eqhdl->irq, NULL);
+                       free_irq(eqhdl->irq, eqhdl);
                }
        } else {
                free_irq(phba->pcidev->irq, phba);
@@ -11367,6 +11849,9 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
        /* Wait for completion of device XRI exchange busy */
        lpfc_sli4_xri_exchange_busy_wait(phba);
 
+       /* per-phba callback de-registration for hotplug event */
+       lpfc_cpuhp_remove(phba);
+
        /* Disable PCI subsystem interrupt */
        lpfc_sli4_disable_intr(phba);
 
@@ -11538,6 +12023,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters);
        sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
        sli4_params->bv1s = bf_get(cfg_bv1s, mbx_sli4_parameters);
+       sli4_params->pls = bf_get(cfg_pvl, mbx_sli4_parameters);
        sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
                                            mbx_sli4_parameters);
        sli4_params->wqpcnt = bf_get(cfg_wqpcnt, mbx_sli4_parameters);
@@ -11589,13 +12075,10 @@ fcponly:
        }
 
        /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to
-        * accommodate 512K and 1M IOs in a single nvme buf and supply
-        * enough NVME LS iocb buffers for larger connectivity counts.
+        * accommodate 512K and 1M IOs in a single nvme buf.
         */
-       if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
+       if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
                phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT;
-               phba->cfg_iocb_cnt = 5;
-       }
 
        /* Only embed PBDE for if_type 6, PBDE support requires xib be set */
        if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
@@ -12312,35 +12795,57 @@ lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba)
 }
 
 
-static void
+static int
 lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset,
        uint32_t magic_number, uint32_t ftype, uint32_t fid, uint32_t fsize,
        const struct firmware *fw)
 {
-       if ((offset == ADD_STATUS_FW_NOT_SUPPORTED) ||
+       int rc;
+
+       /* Three cases:  (1) FW was not supported on the detected adapter.
+        * (2) FW update has been locked out administratively.
+        * (3) Some other error during FW update.
+        * In each case, an unmaskable message is written to the console
+        * for admin diagnosis.
+        */
+       if (offset == ADD_STATUS_FW_NOT_SUPPORTED ||
            (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC &&
-            magic_number != MAGIC_NUMER_G6) ||
+            magic_number != MAGIC_NUMBER_G6) ||
            (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC &&
-            magic_number != MAGIC_NUMER_G7))
+            magic_number != MAGIC_NUMBER_G7)) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "3030 This firmware version is not supported on "
-                       "this HBA model. Device:%x Magic:%x Type:%x "
-                       "ID:%x Size %d %zd\n",
-                       phba->pcidev->device, magic_number, ftype, fid,
-                       fsize, fw->size);
-       else
+                               "3030 This firmware version is not supported on"
+                               " this HBA model. Device:%x Magic:%x Type:%x "
+                               "ID:%x Size %d %zd\n",
+                               phba->pcidev->device, magic_number, ftype, fid,
+                               fsize, fw->size);
+               rc = -EINVAL;
+       } else if (offset == ADD_STATUS_FW_DOWNLOAD_HW_DISABLED) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "3022 FW Download failed. Device:%x Magic:%x Type:%x "
-                       "ID:%x Size %d %zd\n",
-                       phba->pcidev->device, magic_number, ftype, fid,
-                       fsize, fw->size);
+                               "3021 Firmware downloads have been prohibited "
+                               "by a system configuration setting on "
+                               "Device:%x Magic:%x Type:%x ID:%x Size %d "
+                               "%zd\n",
+                               phba->pcidev->device, magic_number, ftype, fid,
+                               fsize, fw->size);
+               rc = -EACCES;
+       } else {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3022 FW Download failed. Add Status x%x "
+                               "Device:%x Magic:%x Type:%x ID:%x Size %d "
+                               "%zd\n",
+                               offset, phba->pcidev->device, magic_number,
+                               ftype, fid, fsize, fw->size);
+               rc = -EIO;
+       }
+       return rc;
 }
 
-
 /**
  * lpfc_write_firmware - attempt to write a firmware image to the port
  * @fw: pointer to firmware image returned from request_firmware.
- * @phba: pointer to lpfc hba data structure.
+ * @context: pointer to firmware image returned from request_firmware.
+ * @ret: return value this routine provides to the caller.
  *
  **/
 static void
@@ -12409,8 +12914,12 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
                        rc = lpfc_wr_object(phba, &dma_buffer_list,
                                    (fw->size - offset), &offset);
                        if (rc) {
-                               lpfc_log_write_firmware_error(phba, offset,
-                                       magic_number, ftype, fid, fsize, fw);
+                               rc = lpfc_log_write_firmware_error(phba, offset,
+                                                                  magic_number,
+                                                                  ftype,
+                                                                  fid,
+                                                                  fsize,
+                                                                  fw);
                                goto release_out;
                        }
                }
@@ -12430,9 +12939,12 @@ release_out:
        }
        release_firmware(fw);
 out:
-       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "3024 Firmware update done: %d.\n", rc);
-       return;
+       if (rc < 0)
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3062 Firmware update error, status %d.\n", rc);
+       else
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3024 Firmware update success: size %d.\n", rc);
 }
 
 /**
@@ -12551,6 +13063,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        phba->pport = NULL;
        lpfc_stop_port(phba);
 
+       /* Init cpu_map array */
+       lpfc_cpu_map_array_init(phba);
+
+       /* Init hba_eq_hdl array */
+       lpfc_hba_eq_hdl_array_init(phba);
+
        /* Configure and enable interrupt */
        intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode);
        if (intr_mode == LPFC_INTR_ERROR) {
@@ -12632,6 +13150,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        /* Enable RAS FW log support */
        lpfc_sli4_ras_setup(phba);
 
+       INIT_LIST_HEAD(&phba->poll_list);
+       cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp);
+
        return 0;
 
 out_free_sysfs_attr:
@@ -13344,8 +13865,7 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba)
                phba->cfg_fof = 1;
        } else {
                phba->cfg_fof = 0;
-               if (phba->device_data_mem_pool)
-                       mempool_destroy(phba->device_data_mem_pool);
+               mempool_destroy(phba->device_data_mem_pool);
                phba->device_data_mem_pool = NULL;
        }
 
@@ -13450,11 +13970,24 @@ lpfc_init(void)
        /* Initialize in case vector mapping is needed */
        lpfc_present_cpu = num_present_cpus();
 
+       error = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+                                       "lpfc/sli4:online",
+                                       lpfc_cpu_online, lpfc_cpu_offline);
+       if (error < 0)
+               goto cpuhp_failure;
+       lpfc_cpuhp_state = error;
+
        error = pci_register_driver(&lpfc_driver);
-       if (error) {
-               fc_release_transport(lpfc_transport_template);
-               fc_release_transport(lpfc_vport_transport_template);
-       }
+       if (error)
+               goto unwind;
+
+       return error;
+
+unwind:
+       cpuhp_remove_multi_state(lpfc_cpuhp_state);
+cpuhp_failure:
+       fc_release_transport(lpfc_transport_template);
+       fc_release_transport(lpfc_vport_transport_template);
 
        return error;
 }
@@ -13471,6 +14004,7 @@ lpfc_exit(void)
 {
        misc_deregister(&lpfc_mgmt_dev);
        pci_unregister_driver(&lpfc_driver);
+       cpuhp_remove_multi_state(lpfc_cpuhp_state);
        fc_release_transport(lpfc_transport_template);
        fc_release_transport(lpfc_vport_transport_template);
        idr_destroy(&lpfc_hba_index);
index ea10f03..148d02a 100644 (file)
 #define LOG_NVME_IOERR  0x00800000      /* NVME IO Error events. */
 #define LOG_ALL_MSG    0xffffffff      /* LOG all messages */
 
+/* generate message by verbose log setting or severity */
+#define lpfc_vlog_msg(vport, level, mask, fmt, arg...) \
+{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '4')) \
+       dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
+                  fmt, (vport)->phba->brd_no, vport->vpi, ##arg); }
+
+#define lpfc_log_msg(phba, level, mask, fmt, arg...) \
+do { \
+       { uint32_t log_verbose = (phba)->pport ? \
+                                (phba)->pport->cfg_log_verbose : \
+                                (phba)->cfg_log_verbose; \
+       if (((mask) & log_verbose) || (level[1] <= '4')) \
+               dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
+                          fmt, phba->brd_no, ##arg); \
+       } \
+} while (0)
+
 #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
 do { \
        { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \
index 8abe933..d1773c0 100644 (file)
@@ -515,6 +515,7 @@ lpfc_init_link(struct lpfc_hba * phba,
 
        if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC ||
             phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) &&
+           !(phba->sli4_hba.pc_sli4_params.pls) &&
            mb->un.varInitLnk.link_flags & FLAGS_TOPOLOGY_MODE_LOOP) {
                mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
                phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT;
index ae09bb8..7082279 100644 (file)
@@ -230,9 +230,6 @@ lpfc_mem_free(struct lpfc_hba *phba)
        dma_pool_destroy(phba->lpfc_hrb_pool);
        phba->lpfc_hrb_pool = NULL;
 
-       dma_pool_destroy(phba->txrdy_payload_pool);
-       phba->txrdy_payload_pool = NULL;
-
        dma_pool_destroy(phba->lpfc_hbq_pool);
        phba->lpfc_hbq_pool = NULL;
 
index fc6e454..ae43590 100644 (file)
@@ -279,6 +279,55 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
        lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
 }
 
+/* lpfc_defer_pt2pt_acc - Complete SLI3 pt2pt processing on link up
+ * @phba: pointer to lpfc hba data structure.
+ * @link_mbox: pointer to CONFIG_LINK mailbox object
+ *
+ * This routine is only called if we are SLI3, direct connect pt2pt
+ * mode and the remote NPort issues the PLOGI after link up.
+ */
+static void
+lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox)
+{
+       LPFC_MBOXQ_t *login_mbox;
+       MAILBOX_t *mb = &link_mbox->u.mb;
+       struct lpfc_iocbq *save_iocb;
+       struct lpfc_nodelist *ndlp;
+       int rc;
+
+       ndlp = link_mbox->ctx_ndlp;
+       login_mbox = link_mbox->context3;
+       save_iocb = login_mbox->context3;
+       link_mbox->context3 = NULL;
+       login_mbox->context3 = NULL;
+
+       /* Check for CONFIG_LINK error */
+       if (mb->mbxStatus) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "4575 CONFIG_LINK fails pt2pt discovery: %x\n",
+                               mb->mbxStatus);
+               mempool_free(login_mbox, phba->mbox_mem_pool);
+               mempool_free(link_mbox, phba->mbox_mem_pool);
+               lpfc_sli_release_iocbq(phba, save_iocb);
+               return;
+       }
+
+       /* Now that CONFIG_LINK completed, and our SID is configured,
+        * we can now proceed with sending the PLOGI ACC.
+        */
+       rc = lpfc_els_rsp_acc(link_mbox->vport, ELS_CMD_PLOGI,
+                             save_iocb, ndlp, login_mbox);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "4576 PLOGI ACC fails pt2pt discovery: %x\n",
+                               rc);
+               mempool_free(login_mbox, phba->mbox_mem_pool);
+       }
+
+       mempool_free(link_mbox, phba->mbox_mem_pool);
+       lpfc_sli_release_iocbq(phba, save_iocb);
+}
+
 static int
 lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
               struct lpfc_iocbq *cmdiocb)
@@ -291,10 +340,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        IOCB_t *icmd;
        struct serv_parm *sp;
        uint32_t ed_tov;
-       LPFC_MBOXQ_t *mbox;
+       LPFC_MBOXQ_t *link_mbox;
+       LPFC_MBOXQ_t *login_mbox;
+       struct lpfc_iocbq *save_iocb;
        struct ls_rjt stat;
        uint32_t vid, flag;
-       int rc;
+       int rc, defer_acc;
 
        memset(&stat, 0, sizeof (struct ls_rjt));
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -343,6 +394,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        else
                ndlp->nlp_fcp_info |= CLASS3;
 
+       defer_acc = 0;
        ndlp->nlp_class_sup = 0;
        if (sp->cls1.classValid)
                ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -354,7 +406,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                ndlp->nlp_class_sup |= FC_COS_CLASS4;
        ndlp->nlp_maxframe =
                ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
-
        /* if already logged in, do implicit logout */
        switch (ndlp->nlp_state) {
        case  NLP_STE_NPR_NODE:
@@ -396,6 +447,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
        ndlp->nlp_flag &= ~NLP_FIRSTBURST;
 
+       login_mbox = NULL;
+       link_mbox = NULL;
+       save_iocb = NULL;
+
        /* Check for Nport to NPort pt2pt protocol */
        if ((vport->fc_flag & FC_PT2PT) &&
            !(vport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -423,17 +478,22 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                if (phba->sli_rev == LPFC_SLI_REV4)
                        lpfc_issue_reg_vfi(vport);
                else {
-                       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-                       if (mbox == NULL)
+                       defer_acc = 1;
+                       link_mbox = mempool_alloc(phba->mbox_mem_pool,
+                                                 GFP_KERNEL);
+                       if (!link_mbox)
                                goto out;
-                       lpfc_config_link(phba, mbox);
-                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-                       mbox->vport = vport;
-                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-                       if (rc == MBX_NOT_FINISHED) {
-                               mempool_free(mbox, phba->mbox_mem_pool);
+                       lpfc_config_link(phba, link_mbox);
+                       link_mbox->mbox_cmpl = lpfc_defer_pt2pt_acc;
+                       link_mbox->vport = vport;
+                       link_mbox->ctx_ndlp = ndlp;
+
+                       save_iocb = lpfc_sli_get_iocbq(phba);
+                       if (!save_iocb)
                                goto out;
-                       }
+                       /* Save info from cmd IOCB used in rsp */
+                       memcpy((uint8_t *)save_iocb, (uint8_t *)cmdiocb,
+                              sizeof(struct lpfc_iocbq));
                }
 
                lpfc_can_disctmo(vport);
@@ -448,8 +508,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        ndlp->nlp_flag |= NLP_SUPPRESS_RSP;
        }
 
-       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mbox)
+       login_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!login_mbox)
                goto out;
 
        /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
@@ -457,21 +517,19 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                lpfc_unreg_rpi(vport, ndlp);
 
        rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
-                           (uint8_t *) sp, mbox, ndlp->nlp_rpi);
-       if (rc) {
-               mempool_free(mbox, phba->mbox_mem_pool);
+                           (uint8_t *)sp, login_mbox, ndlp->nlp_rpi);
+       if (rc)
                goto out;
-       }
 
        /* ACC PLOGI rsp command needs to execute first,
-        * queue this mbox command to be processed later.
+        * queue this login_mbox command to be processed later.
         */
-       mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+       login_mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
        /*
-        * mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox
+        * login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox
         * command issued in lpfc_cmpl_els_acc().
         */
-       mbox->vport = vport;
+       login_mbox->vport = vport;
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
        spin_unlock_irq(shost->host_lock);
@@ -484,8 +542,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
         * single discovery thread, this will cause a huge delay in
         * discovery. Also this will cause multiple state machines
         * running in parallel for this node.
+        * This only applies to a fabric environment.
         */
-       if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+       if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) &&
+           (vport->fc_flag & FC_FABRIC)) {
                /* software abort outstanding PLOGI */
                lpfc_els_abort(phba, ndlp);
        }
@@ -504,16 +564,47 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
                stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
                rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
-                       ndlp, mbox);
+                       ndlp, login_mbox);
                if (rc)
-                       mempool_free(mbox, phba->mbox_mem_pool);
+                       mempool_free(login_mbox, phba->mbox_mem_pool);
+               return 1;
+       }
+       if (defer_acc) {
+               /* So the order here should be:
+                * Issue CONFIG_LINK mbox
+                * CONFIG_LINK cmpl
+                * Issue PLOGI ACC
+                * PLOGI ACC cmpl
+                * Issue REG_LOGIN mbox
+                */
+
+               /* Save the REG_LOGIN mbox for and rcv IOCB copy later */
+               link_mbox->context3 = login_mbox;
+               login_mbox->context3 = save_iocb;
+
+               /* Start the ball rolling by issuing CONFIG_LINK here */
+               rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT);
+               if (rc == MBX_NOT_FINISHED)
+                       goto out;
                return 1;
        }
-       rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
+
+       rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, login_mbox);
        if (rc)
-               mempool_free(mbox, phba->mbox_mem_pool);
+               mempool_free(login_mbox, phba->mbox_mem_pool);
        return 1;
 out:
+       if (defer_acc)
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "4577 pt2pt discovery failure: %p %p %p\n",
+                               save_iocb, link_mbox, login_mbox);
+       if (save_iocb)
+               lpfc_sli_release_iocbq(phba, save_iocb);
+       if (link_mbox)
+               mempool_free(link_mbox, phba->mbox_mem_pool);
+       if (login_mbox)
+               mempool_free(login_mbox, phba->mbox_mem_pool);
+
        stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
        stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
        lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
@@ -2030,7 +2121,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                if (bf_get_be32(prli_init, nvpr))
                        ndlp->nlp_type |= NLP_NVME_INITIATOR;
 
-               if (phba->nsler && bf_get_be32(prli_nsler, nvpr))
+               if (phba->nsler && bf_get_be32(prli_nsler, nvpr) &&
+                   bf_get_be32(prli_conf, nvpr))
+
                        ndlp->nlp_nvme_info |= NLP_NVME_NSLER;
                else
                        ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER;
index a227e36..db4a04a 100644 (file)
@@ -195,6 +195,46 @@ lpfc_nvme_cmd_template(void)
        /* Word 12, 13, 14, 15 - is zero */
 }
 
+/**
+ * lpfc_nvme_prep_abort_wqe - set up 'abort' work queue entry.
+ * @pwqeq: Pointer to command iocb.
+ * @xritag: Tag that  uniqely identifies the local exchange resource.
+ * @opt: Option bits -
+ *             bit 0 = inhibit sending abts on the link
+ *
+ * This function is called with hbalock held.
+ **/
+void
+lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt)
+{
+       union lpfc_wqe128 *wqe = &pwqeq->wqe;
+
+       /* WQEs are reused.  Clear stale data and set key fields to
+        * zero like ia, iaab, iaar, xri_tag, and ctxt_tag.
+        */
+       memset(wqe, 0, sizeof(*wqe));
+
+       if (opt & INHIBIT_ABORT)
+               bf_set(abort_cmd_ia, &wqe->abort_cmd, 1);
+       /* Abort specified xri tag, with the mask deliberately zeroed */
+       bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
+
+       bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
+
+       /* Abort the IO associated with this outstanding exchange ID. */
+       wqe->abort_cmd.wqe_com.abort_tag = xritag;
+
+       /* iotag for the wqe completion. */
+       bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, pwqeq->iotag);
+
+       bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1);
+       bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE);
+
+       bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND);
+       bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1);
+       bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+}
+
 /**
  * lpfc_nvme_create_queue -
  * @lpfc_pnvme: Pointer to the driver's nvme instance data
@@ -1791,7 +1831,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
        struct lpfc_iocbq *abts_buf;
        struct lpfc_iocbq *nvmereq_wqe;
        struct lpfc_nvme_fcpreq_priv *freqpriv;
-       union lpfc_wqe128 *abts_wqe;
        unsigned long flags;
        int ret_val;
 
@@ -1912,37 +1951,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
        /* Ready - mark outstanding as aborted by driver. */
        nvmereq_wqe->iocb_flag |= LPFC_DRIVER_ABORTED;
 
-       /* Complete prepping the abort wqe and issue to the FW. */
-       abts_wqe = &abts_buf->wqe;
-
-       /* WQEs are reused.  Clear stale data and set key fields to
-        * zero like ia, iaab, iaar, xri_tag, and ctxt_tag.
-        */
-       memset(abts_wqe, 0, sizeof(*abts_wqe));
-       bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG);
-
-       /* word 7 */
-       bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
-       bf_set(wqe_class, &abts_wqe->abort_cmd.wqe_com,
-              nvmereq_wqe->iocb.ulpClass);
-
-       /* word 8 - tell the FW to abort the IO associated with this
-        * outstanding exchange ID.
-        */
-       abts_wqe->abort_cmd.wqe_com.abort_tag = nvmereq_wqe->sli4_xritag;
-
-       /* word 9 - this is the iotag for the abts_wqe completion. */
-       bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com,
-              abts_buf->iotag);
-
-       /* word 10 */
-       bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1);
-       bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE);
-
-       /* word 11 */
-       bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND);
-       bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1);
-       bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+       lpfc_nvme_prep_abort_wqe(abts_buf, nvmereq_wqe->sli4_xritag, 0);
 
        /* ABTS WQE must go to the same WQ as the WQE to be aborted */
        abts_buf->iocb_flag |= LPFC_IO_NVME;
@@ -2084,7 +2093,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd)
        lpfc_ncmd->flags &= ~LPFC_SBUF_BUMP_QDEPTH;
 
        qp = lpfc_ncmd->hdwq;
-       if (lpfc_ncmd->flags & LPFC_SBUF_XBUSY) {
+       if (unlikely(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) {
                lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
                                "6310 XB release deferred for "
                                "ox_id x%x on reqtag x%x\n",
@@ -2139,12 +2148,10 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
         */
        lpfc_nvme_template.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1;
 
-       /* Advertise how many hw queues we support based on fcp_io_sched */
-       if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ)
-               lpfc_nvme_template.max_hw_queues = phba->cfg_hdw_queue;
-       else
-               lpfc_nvme_template.max_hw_queues =
-                       phba->sli4_hba.num_present_cpu;
+       /* Advertise how many hw queues we support based on cfg_hdw_queue,
+        * which will not exceed cpu count.
+        */
+       lpfc_nvme_template.max_hw_queues = phba->cfg_hdw_queue;
 
        if (!IS_ENABLED(CONFIG_NVME_FC))
                return ret;
index 9884228..9dc9afe 100644 (file)
@@ -378,13 +378,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
        int cpu;
        unsigned long iflag;
 
-       if (ctxp->txrdy) {
-               dma_pool_free(phba->txrdy_payload_pool, ctxp->txrdy,
-                             ctxp->txrdy_phys);
-               ctxp->txrdy = NULL;
-               ctxp->txrdy_phys = 0;
-       }
-
        if (ctxp->state == LPFC_NVMET_STE_FREE) {
                lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
                                "6411 NVMET free, already free IO x%x: %d %d\n",
@@ -430,7 +423,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
 
                ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context;
                ctxp->wqeq = NULL;
-               ctxp->txrdy = NULL;
                ctxp->offset = 0;
                ctxp->phba = phba;
                ctxp->size = size;
@@ -1958,12 +1950,10 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        uint32_t *payload;
        uint32_t size, oxid, sid, rc;
 
-       fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt);
-       oxid = be16_to_cpu(fc_hdr->fh_ox_id);
 
-       if (!phba->targetport) {
+       if (!nvmebuf || !phba->targetport) {
                lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
-                               "6154 LS Drop IO x%x\n", oxid);
+                               "6154 LS Drop IO\n");
                oxid = 0;
                size = 0;
                sid = 0;
@@ -1971,6 +1961,9 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                goto dropit;
        }
 
+       fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt);
+       oxid = be16_to_cpu(fc_hdr->fh_ox_id);
+
        tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
        payload = (uint32_t *)(nvmebuf->dbuf.virt);
        size = bf_get(lpfc_rcqe_length,  &nvmebuf->cq_event.cqe.rcqe_cmpl);
@@ -2326,7 +2319,6 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
                                ctxp->state, ctxp->entry_cnt, ctxp->oxid);
        }
        ctxp->wqeq = NULL;
-       ctxp->txrdy = NULL;
        ctxp->offset = 0;
        ctxp->phba = phba;
        ctxp->size = size;
@@ -2401,6 +2393,11 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        d_buf = piocb->context2;
        nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 
+       if (!nvmebuf) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
+                               "3015 LS Drop IO\n");
+               return;
+       }
        if (phba->nvmet_support == 0) {
                lpfc_in_buf_free(phba, &nvmebuf->dbuf);
                return;
@@ -2429,6 +2426,11 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba,
                           uint64_t isr_timestamp,
                           uint8_t cqflag)
 {
+       if (!nvmebuf) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
+                               "3167 NVMET FCP Drop IO\n");
+               return;
+       }
        if (phba->nvmet_support == 0) {
                lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
                return;
@@ -2595,7 +2597,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
        struct scatterlist *sgel;
        union lpfc_wqe128 *wqe;
        struct ulp_bde64 *bde;
-       uint32_t *txrdy;
        dma_addr_t physaddr;
        int i, cnt;
        int do_pbde;
@@ -2757,23 +2758,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
                       &lpfc_treceive_cmd_template.words[3],
                       sizeof(uint32_t) * 9);
 
-               /* Words 0 - 2 : The first sg segment */
-               txrdy = dma_pool_alloc(phba->txrdy_payload_pool,
-                                      GFP_KERNEL, &physaddr);
-               if (!txrdy) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
-                                       "6041 Bad txrdy buffer: oxid x%x\n",
-                                       ctxp->oxid);
-                       return NULL;
-               }
-               ctxp->txrdy = txrdy;
-               ctxp->txrdy_phys = physaddr;
-               wqe->fcp_treceive.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-               wqe->fcp_treceive.bde.tus.f.bdeSize = TXRDY_PAYLOAD_LEN;
-               wqe->fcp_treceive.bde.addrLow =
-                       cpu_to_le32(putPaddrLow(physaddr));
-               wqe->fcp_treceive.bde.addrHigh =
-                       cpu_to_le32(putPaddrHigh(physaddr));
+               /* Words 0 - 2 : First SGE is skipped, set invalid BDE type */
+               wqe->fcp_treceive.bde.tus.f.bdeFlags = LPFC_SGE_TYPE_SKIP;
+               wqe->fcp_treceive.bde.tus.f.bdeSize = 0;
+               wqe->fcp_treceive.bde.addrLow = 0;
+               wqe->fcp_treceive.bde.addrHigh = 0;
 
                /* Word 4 */
                wqe->fcp_treceive.relative_offset = ctxp->offset;
@@ -2808,17 +2797,13 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
                /* Word 12 */
                wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
 
-               /* Setup 1 TXRDY and 1 SKIP SGE */
-               txrdy[0] = 0;
-               txrdy[1] = cpu_to_be32(rsp->transfer_length);
-               txrdy[2] = 0;
-
-               sgl->addr_hi = putPaddrHigh(physaddr);
-               sgl->addr_lo = putPaddrLow(physaddr);
+               /* Setup 2 SKIP SGEs */
+               sgl->addr_hi = 0;
+               sgl->addr_lo = 0;
                sgl->word2 = 0;
-               bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA);
+               bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_SKIP);
                sgl->word2 = cpu_to_le32(sgl->word2);
-               sgl->sge_len = cpu_to_le32(TXRDY_PAYLOAD_LEN);
+               sgl->sge_len = 0;
                sgl++;
                sgl->addr_hi = 0;
                sgl->addr_lo = 0;
@@ -3239,9 +3224,9 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba,
 {
        struct lpfc_nvmet_tgtport *tgtp;
        struct lpfc_iocbq *abts_wqeq;
-       union lpfc_wqe128 *abts_wqe;
        struct lpfc_nodelist *ndlp;
        unsigned long flags;
+       u8 opt;
        int rc;
 
        tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
@@ -3280,8 +3265,8 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba,
                return 0;
        }
        abts_wqeq = ctxp->abort_wqeq;
-       abts_wqe = &abts_wqeq->wqe;
        ctxp->state = LPFC_NVMET_STE_ABORT;
+       opt = (ctxp->flag & LPFC_NVMET_ABTS_RCV) ? INHIBIT_ABORT : 0;
        spin_unlock_irqrestore(&ctxp->ctxlock, flags);
 
        /* Announce entry to new IO submit field. */
@@ -3327,40 +3312,12 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba,
        /* Ready - mark outstanding as aborted by driver. */
        abts_wqeq->iocb_flag |= LPFC_DRIVER_ABORTED;
 
-       /* WQEs are reused.  Clear stale data and set key fields to
-        * zero like ia, iaab, iaar, xri_tag, and ctxt_tag.
-        */
-       memset(abts_wqe, 0, sizeof(*abts_wqe));
-
-       /* word 3 */
-       bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG);
-
-       /* word 7 */
-       bf_set(wqe_ct, &abts_wqe->abort_cmd.wqe_com, 0);
-       bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
-
-       /* word 8 - tell the FW to abort the IO associated with this
-        * outstanding exchange ID.
-        */
-       abts_wqe->abort_cmd.wqe_com.abort_tag = ctxp->wqeq->sli4_xritag;
-
-       /* word 9 - this is the iotag for the abts_wqe completion. */
-       bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com,
-              abts_wqeq->iotag);
-
-       /* word 10 */
-       bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1);
-       bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE);
-
-       /* word 11 */
-       bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND);
-       bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1);
-       bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+       lpfc_nvme_prep_abort_wqe(abts_wqeq, ctxp->wqeq->sli4_xritag, opt);
 
        /* ABTS WQE must go to the same WQ as the WQE to be aborted */
        abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx;
        abts_wqeq->wqe_cmpl = lpfc_nvmet_sol_fcp_abort_cmp;
-       abts_wqeq->iocb_cmpl = 0;
+       abts_wqeq->iocb_cmpl = NULL;
        abts_wqeq->iocb_flag |= LPFC_IO_NVME;
        abts_wqeq->context2 = ctxp;
        abts_wqeq->vport = phba->pport;
@@ -3495,7 +3452,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba,
 
        spin_lock_irqsave(&phba->hbalock, flags);
        abts_wqeq->wqe_cmpl = lpfc_nvmet_xmt_ls_abort_cmp;
-       abts_wqeq->iocb_cmpl = 0;
+       abts_wqeq->iocb_cmpl = NULL;
        abts_wqeq->iocb_flag |=  LPFC_IO_NVME_LS;
        rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, abts_wqeq);
        spin_unlock_irqrestore(&phba->hbalock, flags);
index 8ff67de..b80b163 100644 (file)
@@ -112,9 +112,7 @@ struct lpfc_nvmet_rcv_ctx {
        struct lpfc_hba *phba;
        struct lpfc_iocbq *wqeq;
        struct lpfc_iocbq *abort_wqeq;
-       dma_addr_t txrdy_phys;
        spinlock_t ctxlock; /* protect flag access */
-       uint32_t *txrdy;
        uint32_t sid;
        uint32_t offset;
        uint16_t oxid;
index 6822cd9..b138d9f 100644 (file)
@@ -134,21 +134,21 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba,
 
 /**
  * lpfc_update_stats - Update statistical data for the command completion
- * @phba: Pointer to HBA object.
+ * @vport: The virtual port on which this call is executing.
  * @lpfc_cmd: lpfc scsi command object pointer.
  *
  * This function is called when there is a command completion and this
  * function updates the statistical data for the command completion.
  **/
 static void
-lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
+lpfc_update_stats(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd)
 {
+       struct lpfc_hba *phba = vport->phba;
        struct lpfc_rport_data *rdata;
        struct lpfc_nodelist *pnode;
        struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
        unsigned long flags;
-       struct Scsi_Host  *shost = cmd->device->host;
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        unsigned long latency;
        int i;
 
@@ -526,7 +526,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
                &qp->lpfc_abts_io_buf_list, list) {
                if (psb->cur_iocbq.sli4_xritag == xri) {
                        list_del_init(&psb->list);
-                       psb->exch_busy = 0;
+                       psb->flags &= ~LPFC_SBUF_XBUSY;
                        psb->status = IOSTAT_SUCCESS;
                        if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) {
                                qp->abts_nvme_io_bufs--;
@@ -566,7 +566,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
                if (iocbq->sli4_xritag != xri)
                        continue;
                psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq);
-               psb->exch_busy = 0;
+               psb->flags &= ~LPFC_SBUF_XBUSY;
                spin_unlock_irqrestore(&phba->hbalock, iflag);
                if (!list_empty(&pring->txq))
                        lpfc_worker_wake_up(phba);
@@ -786,7 +786,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb)
        psb->prot_seg_cnt = 0;
 
        qp = psb->hdwq;
-       if (psb->exch_busy) {
+       if (psb->flags & LPFC_SBUF_XBUSY) {
                spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag);
                psb->pCmd = NULL;
                list_add_tail(&psb->list, &qp->lpfc_abts_io_buf_list);
@@ -3812,7 +3812,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 
        /* Sanity check on return of outstanding command */
        cmd = lpfc_cmd->pCmd;
-       if (!cmd) {
+       if (!cmd || !phba) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
                                 "2621 IO completion: Not an active IO\n");
                spin_unlock(&lpfc_cmd->buf_lock);
@@ -3824,7 +3824,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) {
+       if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) {
                cpu = raw_smp_processor_id();
                if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq)
                        phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++;
@@ -3835,7 +3835,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
        lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
        /* pick up SLI4 exhange busy status from HBA */
-       lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY;
+       if (pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY)
+               lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
+       else
+               lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        if (lpfc_cmd->prot_data_type) {
@@ -3869,7 +3872,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        }
 #endif
 
-       if (lpfc_cmd->status) {
+       if (unlikely(lpfc_cmd->status)) {
                if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
                    (lpfc_cmd->result & IOERR_DRVR_MASK))
                        lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
@@ -4002,7 +4005,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                                 scsi_get_resid(cmd));
        }
 
-       lpfc_update_stats(phba, lpfc_cmd);
+       lpfc_update_stats(vport, lpfc_cmd);
        if (vport->cfg_max_scsicmpl_time &&
           time_after(jiffies, lpfc_cmd->start_time +
                msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) {
@@ -4610,17 +4613,18 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
                err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd);
        }
 
-       if (err == 2) {
-               cmnd->result = DID_ERROR << 16;
-               goto out_fail_command_release_buf;
-       } else if (err) {
+       if (unlikely(err)) {
+               if (err == 2) {
+                       cmnd->result = DID_ERROR << 16;
+                       goto out_fail_command_release_buf;
+               }
                goto out_host_busy_free_buf;
        }
 
        lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) {
+       if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) {
                cpu = raw_smp_processor_id();
                if (cpu < LPFC_CHECK_CPU_CNT) {
                        struct lpfc_sli4_hdw_queue *hdwq =
@@ -4843,20 +4847,21 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
                ret_val = __lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,
                                                abtsiocb, 0);
        }
-       /* no longer need the lock after this point */
-       spin_unlock_irqrestore(&phba->hbalock, flags);
 
        if (ret_val == IOCB_ERROR) {
                /* Indicate the IO is not being aborted by the driver. */
                iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
                lpfc_cmd->waitq = NULL;
                spin_unlock(&lpfc_cmd->buf_lock);
+               spin_unlock_irqrestore(&phba->hbalock, flags);
                lpfc_sli_release_iocbq(phba, abtsiocb);
                ret = FAILED;
                goto out;
        }
 
+       /* no longer need the lock after this point */
        spin_unlock(&lpfc_cmd->buf_lock);
+       spin_unlock_irqrestore(&phba->hbalock, flags);
 
        if (phba->cfg_poll & DISABLE_FCP_RING_INT)
                lpfc_sli_handle_fast_ring_event(phba,
index 614f78d..c82b579 100644 (file)
@@ -87,6 +87,10 @@ static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba,
                                     struct lpfc_eqe *eqe);
 static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba);
 static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba);
+static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q);
+static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba,
+                                   struct lpfc_queue *cq,
+                                   struct lpfc_cqe *cqe);
 
 static IOCB_t *
 lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
@@ -467,25 +471,52 @@ __lpfc_sli4_consume_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq,
 }
 
 static void
-lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
+lpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
 {
-       struct lpfc_eqe *eqe;
-       uint32_t count = 0;
+       struct lpfc_eqe *eqe = NULL;
+       u32 eq_count = 0, cq_count = 0;
+       struct lpfc_cqe *cqe = NULL;
+       struct lpfc_queue *cq = NULL, *childq = NULL;
+       int cqid = 0;
 
        /* walk all the EQ entries and drop on the floor */
        eqe = lpfc_sli4_eq_get(eq);
        while (eqe) {
+               /* Get the reference to the corresponding CQ */
+               cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
+               cq = NULL;
+
+               list_for_each_entry(childq, &eq->child_list, list) {
+                       if (childq->queue_id == cqid) {
+                               cq = childq;
+                               break;
+                       }
+               }
+               /* If CQ is valid, iterate through it and drop all the CQEs */
+               if (cq) {
+                       cqe = lpfc_sli4_cq_get(cq);
+                       while (cqe) {
+                               __lpfc_sli4_consume_cqe(phba, cq, cqe);
+                               cq_count++;
+                               cqe = lpfc_sli4_cq_get(cq);
+                       }
+                       /* Clear and re-arm the CQ */
+                       phba->sli4_hba.sli4_write_cq_db(phba, cq, cq_count,
+                           LPFC_QUEUE_REARM);
+                       cq_count = 0;
+               }
                __lpfc_sli4_consume_eqe(phba, eq, eqe);
-               count++;
+               eq_count++;
                eqe = lpfc_sli4_eq_get(eq);
        }
 
        /* Clear and re-arm the EQ */
-       phba->sli4_hba.sli4_write_eq_db(phba, eq, count, LPFC_QUEUE_REARM);
+       phba->sli4_hba.sli4_write_eq_db(phba, eq, eq_count, LPFC_QUEUE_REARM);
 }
 
 static int
-lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq)
+lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq,
+                    uint8_t rearm)
 {
        struct lpfc_eqe *eqe;
        int count = 0, consumed = 0;
@@ -519,8 +550,8 @@ lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq)
        eq->queue_claimed = 0;
 
 rearm_and_exit:
-       /* Always clear and re-arm the EQ */
-       phba->sli4_hba.sli4_write_eq_db(phba, eq, consumed, LPFC_QUEUE_REARM);
+       /* Always clear the EQ. */
+       phba->sli4_hba.sli4_write_eq_db(phba, eq, consumed, rearm);
 
        return count;
 }
@@ -2526,6 +2557,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                        } else {
                                __lpfc_sli_rpi_release(vport, ndlp);
                        }
+                       if (vport->load_flag & FC_UNLOADING)
+                               lpfc_nlp_put(ndlp);
                        pmb->ctx_ndlp = NULL;
                }
        }
@@ -2672,7 +2705,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
                        lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
                                        "(%d):0323 Unknown Mailbox command "
                                        "x%x (x%x/x%x) Cmpl\n",
-                                       pmb->vport ? pmb->vport->vpi : 0,
+                                       pmb->vport ? pmb->vport->vpi :
+                                       LPFC_VPORT_UNKNOWN,
                                        pmbox->mbxCommand,
                                        lpfc_sli_config_mbox_subsys_get(phba,
                                                                        pmb),
@@ -2693,7 +2727,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
                                        "(%d):0305 Mbox cmd cmpl "
                                        "error - RETRYing Data: x%x "
                                        "(x%x/x%x) x%x x%x x%x\n",
-                                       pmb->vport ? pmb->vport->vpi : 0,
+                                       pmb->vport ? pmb->vport->vpi :
+                                       LPFC_VPORT_UNKNOWN,
                                        pmbox->mbxCommand,
                                        lpfc_sli_config_mbox_subsys_get(phba,
                                                                        pmb),
@@ -2701,7 +2736,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
                                                                        pmb),
                                        pmbox->mbxStatus,
                                        pmbox->un.varWords[0],
-                                       pmb->vport->port_state);
+                                       pmb->vport ? pmb->vport->port_state :
+                                       LPFC_VPORT_UNKNOWN);
                                pmbox->mbxStatus = 0;
                                pmbox->mbxOwner = OWN_HOST;
                                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
@@ -6167,6 +6203,14 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
                mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS;
                mbox->u.mqe.un.set_feature.param_len = 8;
                break;
+       case LPFC_SET_DUAL_DUMP:
+               bf_set(lpfc_mbx_set_feature_dd,
+                      &mbox->u.mqe.un.set_feature, LPFC_ENABLE_DUAL_DUMP);
+               bf_set(lpfc_mbx_set_feature_ddquery,
+                      &mbox->u.mqe.un.set_feature, 0);
+               mbox->u.mqe.un.set_feature.feature = LPFC_SET_DUAL_DUMP;
+               mbox->u.mqe.un.set_feature.param_len = 4;
+               break;
        }
 
        return;
@@ -6184,11 +6228,16 @@ lpfc_ras_stop_fwlog(struct lpfc_hba *phba)
 {
        struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
 
-       ras_fwlog->ras_active = false;
+       spin_lock_irq(&phba->hbalock);
+       ras_fwlog->state = INACTIVE;
+       spin_unlock_irq(&phba->hbalock);
 
        /* Disable FW logging to host memory */
        writel(LPFC_CTL_PDEV_CTL_DDL_RAS,
               phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
+
+       /* Wait 10ms for firmware to stop using DMA buffer */
+       usleep_range(10 * 1000, 20 * 1000);
 }
 
 /**
@@ -6224,7 +6273,9 @@ lpfc_sli4_ras_dma_free(struct lpfc_hba *phba)
                ras_fwlog->lwpd.virt = NULL;
        }
 
-       ras_fwlog->ras_active = false;
+       spin_lock_irq(&phba->hbalock);
+       ras_fwlog->state = INACTIVE;
+       spin_unlock_irq(&phba->hbalock);
 }
 
 /**
@@ -6326,7 +6377,9 @@ lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                goto disable_ras;
        }
 
-       ras_fwlog->ras_active = true;
+       spin_lock_irq(&phba->hbalock);
+       ras_fwlog->state = ACTIVE;
+       spin_unlock_irq(&phba->hbalock);
        mempool_free(pmb, phba->mbox_mem_pool);
 
        return;
@@ -6358,6 +6411,10 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba,
        uint32_t len = 0, fwlog_buffsize, fwlog_entry_count;
        int rc = 0;
 
+       spin_lock_irq(&phba->hbalock);
+       ras_fwlog->state = INACTIVE;
+       spin_unlock_irq(&phba->hbalock);
+
        fwlog_buffsize = (LPFC_RAS_MIN_BUFF_POST_SIZE *
                          phba->cfg_ras_fwlog_buffsize);
        fwlog_entry_count = (fwlog_buffsize/LPFC_RAS_MAX_ENTRY_SIZE);
@@ -6417,6 +6474,9 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba,
        mbx_fwlog->u.request.lwpd.addr_lo = putPaddrLow(ras_fwlog->lwpd.phys);
        mbx_fwlog->u.request.lwpd.addr_hi = putPaddrHigh(ras_fwlog->lwpd.phys);
 
+       spin_lock_irq(&phba->hbalock);
+       ras_fwlog->state = REG_INPROGRESS;
+       spin_unlock_irq(&phba->hbalock);
        mbox->vport = phba->pport;
        mbox->mbox_cmpl = lpfc_sli4_ras_mbox_cmpl;
 
@@ -7148,7 +7208,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 int
 lpfc_sli4_hba_setup(struct lpfc_hba *phba)
 {
-       int rc, i, cnt, len;
+       int rc, i, cnt, len, dd;
        LPFC_MBOXQ_t *mboxq;
        struct lpfc_mqe *mqe;
        uint8_t *vpd;
@@ -7399,6 +7459,23 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
        phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED);
        spin_unlock_irq(&phba->hbalock);
 
+       /* Always try to enable dual dump feature if we can */
+       lpfc_set_features(phba, mboxq, LPFC_SET_DUAL_DUMP);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       dd = bf_get(lpfc_mbx_set_feature_dd, &mboxq->u.mqe.un.set_feature);
+       if ((rc == MBX_SUCCESS) && (dd == LPFC_ENABLE_DUAL_DUMP))
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_INIT,
+                               "6448 Dual Dump is enabled\n");
+       else
+               lpfc_printf_log(phba, KERN_INFO, LOG_SLI | LOG_INIT,
+                               "6447 Dual Dump Mailbox x%x (x%x/x%x) failed, "
+                               "rc:x%x dd:x%x\n",
+                               bf_get(lpfc_mqe_command, &mboxq->u.mqe),
+                               lpfc_sli_config_mbox_subsys_get(
+                                       phba, mboxq),
+                               lpfc_sli_config_mbox_opcode_get(
+                                       phba, mboxq),
+                               rc, dd);
        /*
         * Allocate all resources (xri,rpi,vpi,vfi) now.  Subsequent
         * calls depends on these resources to complete port setup.
@@ -7523,9 +7600,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                }
                phba->sli4_hba.nvmet_xri_cnt = rc;
 
-               cnt = phba->cfg_iocb_cnt * 1024;
-               /* We need 1 iocbq for every SGL, for IO processing */
-               cnt += phba->sli4_hba.nvmet_xri_cnt;
+               /* We allocate an iocbq for every receive context SGL.
+                * The additional allocation is for abort and ls handling.
+                */
+               cnt = phba->sli4_hba.nvmet_xri_cnt +
+                       phba->sli4_hba.max_cfg_param.max_xri;
        } else {
                /* update host common xri-sgl sizes and mappings */
                rc = lpfc_sli4_io_sgl_update(phba);
@@ -7547,14 +7626,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                        rc = -ENODEV;
                        goto out_destroy_queue;
                }
-               cnt = phba->cfg_iocb_cnt * 1024;
+               /* Each lpfc_io_buf job structure has an iocbq element.
+                * This cnt provides for abort, els, ct and ls requests.
+                */
+               cnt = phba->sli4_hba.max_cfg_param.max_xri;
        }
 
        if (!phba->sli.iocbq_lookup) {
                /* Initialize and populate the iocb list per host */
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                               "2821 initialize iocb list %d total %d\n",
-                               phba->cfg_iocb_cnt, cnt);
+                               "2821 initialize iocb list with %d entries\n",
+                               cnt);
                rc = lpfc_init_iocb_list(phba, cnt);
                if (rc) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -7892,7 +7974,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 
        if (mbox_pending)
                /* process and rearm the EQ */
-               lpfc_sli4_process_eq(phba, fpeq);
+               lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM);
        else
                /* Always clear and re-arm the EQ */
                sli4_hba->sli4_write_eq_db(phba, fpeq, 0, LPFC_QUEUE_REARM);
@@ -8964,7 +9046,8 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
  * @pring: Pointer to driver SLI ring object.
  * @piocb: Pointer to address of newly added command iocb.
  *
- * This function is called with hbalock held to add a command
+ * This function is called with hbalock held for SLI3 ports or
+ * the ring lock held for SLI4 ports to add a command
  * iocb to the txq when SLI layer cannot submit the command iocb
  * to the ring.
  **/
@@ -8972,7 +9055,10 @@ void
 __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                    struct lpfc_iocbq *piocb)
 {
-       lockdep_assert_held(&phba->hbalock);
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               lockdep_assert_held(&pring->ring_lock);
+       else
+               lockdep_assert_held(&phba->hbalock);
        /* Insert the caller's iocb in the txq tail for later processing. */
        list_add_tail(&piocb->list, &pring->txq);
 }
@@ -9863,7 +9949,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
  * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue
  * an iocb command to an HBA with SLI-4 interface spec.
  *
- * This function is called with hbalock held. The function will return success
+ * This function is called with ringlock held. The function will return success
  * after it successfully submit the iocb to firmware or after adding to the
  * txq.
  **/
@@ -10053,10 +10139,13 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
                    struct lpfc_iocbq *piocb, uint32_t flag)
 {
        struct lpfc_sli_ring *pring;
+       struct lpfc_queue *eq;
        unsigned long iflags;
        int rc;
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
+               eq = phba->sli4_hba.hdwq[piocb->hba_wqidx].hba_eq;
+
                pring = lpfc_sli4_calc_ring(phba, piocb);
                if (unlikely(pring == NULL))
                        return IOCB_ERROR;
@@ -10064,6 +10153,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
                spin_lock_irqsave(&pring->ring_lock, iflags);
                rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
                spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+               lpfc_sli4_poll_eq(eq, LPFC_POLL_FASTPATH);
        } else {
                /* For now, SLI2/3 will still use hbalock */
                spin_lock_irqsave(&phba->hbalock, iflags);
@@ -10678,14 +10769,14 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
                                set_bit(LPFC_DATA_READY, &phba->data_flags);
                        }
                        prev_pring_flag = pring->flag;
-                       spin_lock_irq(&pring->ring_lock);
+                       spin_lock(&pring->ring_lock);
                        list_for_each_entry_safe(iocb, next_iocb,
                                                 &pring->txq, list) {
                                if (iocb->vport != vport)
                                        continue;
                                list_move_tail(&iocb->list, &completions);
                        }
-                       spin_unlock_irq(&pring->ring_lock);
+                       spin_unlock(&pring->ring_lock);
                        list_for_each_entry_safe(iocb, next_iocb,
                                                 &pring->txcmplq, list) {
                                if (iocb->vport != vport)
@@ -11050,9 +11141,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                irsp->ulpStatus, irsp->un.ulpWord[4]);
 
                spin_unlock_irq(&phba->hbalock);
-               if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT &&
-                   irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)
-                       lpfc_sli_release_iocbq(phba, abort_iocb);
        }
 release_iocb:
        lpfc_sli_release_iocbq(phba, cmdiocb);
@@ -11736,7 +11824,10 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
                !(cmdiocbq->iocb_flag & LPFC_IO_LIBDFC)) {
                lpfc_cmd = container_of(cmdiocbq, struct lpfc_io_buf,
                        cur_iocbq);
-               lpfc_cmd->exch_busy = rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY;
+               if (rspiocbq && (rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY))
+                       lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
+               else
+                       lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
        }
 
        pdone_q = cmdiocbq->context_un.wait_queue;
@@ -13158,13 +13249,19 @@ send_current_mbox:
        phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
        /* Setting active mailbox pointer need to be in sync to flag clear */
        phba->sli.mbox_active = NULL;
+       if (bf_get(lpfc_trailer_consumed, mcqe))
+               lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
        spin_unlock_irqrestore(&phba->hbalock, iflags);
        /* Wake up worker thread to post the next pending mailbox command */
        lpfc_worker_wake_up(phba);
+       return workposted;
+
 out_no_mqe_complete:
+       spin_lock_irqsave(&phba->hbalock, iflags);
        if (bf_get(lpfc_trailer_consumed, mcqe))
                lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
-       return workposted;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       return false;
 }
 
 /**
@@ -13217,7 +13314,6 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
        struct lpfc_sli_ring *pring = cq->pring;
        int txq_cnt = 0;
        int txcmplq_cnt = 0;
-       int fcp_txcmplq_cnt = 0;
 
        /* Check for response status */
        if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) {
@@ -13239,9 +13335,8 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
                        txcmplq_cnt++;
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                        "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
-                       "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
+                       "els_txcmplq_cnt=%d\n",
                        txq_cnt, phba->iocb_cnt,
-                       fcp_txcmplq_cnt,
                        txcmplq_cnt);
                return false;
        }
@@ -13592,6 +13687,7 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
                        phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed,
                                                LPFC_QUEUE_NOARM);
                        consumed = 0;
+                       cq->assoc_qp->q_flag |= HBA_EQ_DELAY_CHK;
                }
 
                if (count == LPFC_NVMET_CQ_NOTIFY)
@@ -14220,7 +14316,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
                spin_lock_irqsave(&phba->hbalock, iflag);
                if (phba->link_state < LPFC_LINK_DOWN)
                        /* Flush, clear interrupt, and rearm the EQ */
-                       lpfc_sli4_eq_flush(phba, fpeq);
+                       lpfc_sli4_eqcq_flush(phba, fpeq);
                spin_unlock_irqrestore(&phba->hbalock, iflag);
                return IRQ_NONE;
        }
@@ -14230,14 +14326,14 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
        fpeq->last_cpu = raw_smp_processor_id();
 
        if (icnt > LPFC_EQD_ISR_TRIGGER &&
-           phba->cfg_irq_chann == 1 &&
+           fpeq->q_flag & HBA_EQ_DELAY_CHK &&
            phba->cfg_auto_imax &&
            fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY &&
            phba->sli.sli_flag & LPFC_SLI_USE_EQDR)
                lpfc_sli4_mod_hba_eq_delay(phba, fpeq, LPFC_MAX_AUTO_EQ_DELAY);
 
        /* process and rearm the EQ */
-       ecount = lpfc_sli4_process_eq(phba, fpeq);
+       ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM);
 
        if (unlikely(ecount == 0)) {
                fpeq->EQ_no_entry++;
@@ -14297,6 +14393,147 @@ lpfc_sli4_intr_handler(int irq, void *dev_id)
        return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE;
 } /* lpfc_sli4_intr_handler */
 
+void lpfc_sli4_poll_hbtimer(struct timer_list *t)
+{
+       struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer);
+       struct lpfc_queue *eq;
+       int i = 0;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(eq, &phba->poll_list, _poll_list)
+               i += lpfc_sli4_poll_eq(eq, LPFC_POLL_SLOWPATH);
+       if (!list_empty(&phba->poll_list))
+               mod_timer(&phba->cpuhp_poll_timer,
+                         jiffies + msecs_to_jiffies(LPFC_POLL_HB));
+
+       rcu_read_unlock();
+}
+
+inline int lpfc_sli4_poll_eq(struct lpfc_queue *eq, uint8_t path)
+{
+       struct lpfc_hba *phba = eq->phba;
+       int i = 0;
+
+       /*
+        * Unlocking an irq is one of the entry point to check
+        * for re-schedule, but we are good for io submission
+        * path as midlayer does a get_cpu to glue us in. Flush
+        * out the invalidate queue so we can see the updated
+        * value for flag.
+        */
+       smp_rmb();
+
+       if (READ_ONCE(eq->mode) == LPFC_EQ_POLL)
+               /* We will not likely get the completion for the caller
+                * during this iteration but i guess that's fine.
+                * Future io's coming on this eq should be able to
+                * pick it up.  As for the case of single io's, they
+                * will be handled through a sched from polling timer
+                * function which is currently triggered every 1msec.
+                */
+               i = lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM);
+
+       return i;
+}
+
+static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq)
+{
+       struct lpfc_hba *phba = eq->phba;
+
+       if (list_empty(&phba->poll_list)) {
+               timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
+               /* kickstart slowpath processing for this eq */
+               mod_timer(&phba->cpuhp_poll_timer,
+                         jiffies + msecs_to_jiffies(LPFC_POLL_HB));
+       }
+
+       list_add_rcu(&eq->_poll_list, &phba->poll_list);
+       synchronize_rcu();
+}
+
+static inline void lpfc_sli4_remove_from_poll_list(struct lpfc_queue *eq)
+{
+       struct lpfc_hba *phba = eq->phba;
+
+       /* Disable slowpath processing for this eq.  Kick start the eq
+        * by RE-ARMING the eq's ASAP
+        */
+       list_del_rcu(&eq->_poll_list);
+       synchronize_rcu();
+
+       if (list_empty(&phba->poll_list))
+               del_timer_sync(&phba->cpuhp_poll_timer);
+}
+
+void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba)
+{
+       struct lpfc_queue *eq, *next;
+
+       list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list)
+               list_del(&eq->_poll_list);
+
+       INIT_LIST_HEAD(&phba->poll_list);
+       synchronize_rcu();
+}
+
+static inline void
+__lpfc_sli4_switch_eqmode(struct lpfc_queue *eq, uint8_t mode)
+{
+       if (mode == eq->mode)
+               return;
+       /*
+        * currently this function is only called during a hotplug
+        * event and the cpu on which this function is executing
+        * is going offline.  By now the hotplug has instructed
+        * the scheduler to remove this cpu from cpu active mask.
+        * So we don't need to work about being put aside by the
+        * scheduler for a high priority process.  Yes, the inte-
+        * rrupts could come but they are known to retire ASAP.
+        */
+
+       /* Disable polling in the fastpath */
+       WRITE_ONCE(eq->mode, mode);
+       /* flush out the store buffer */
+       smp_wmb();
+
+       /*
+        * Add this eq to the polling list and start polling. For
+        * a grace period both interrupt handler and poller will
+        * try to process the eq _but_ that's fine.  We have a
+        * synchronization mechanism in place (queue_claimed) to
+        * deal with it.  This is just a draining phase for int-
+        * errupt handler (not eq's) as we have guranteed through
+        * barrier that all the CPUs have seen the new CQ_POLLED
+        * state. which will effectively disable the REARMING of
+        * the EQ.  The whole idea is eq's die off eventually as
+        * we are not rearming EQ's anymore.
+        */
+       mode ? lpfc_sli4_add_to_poll_list(eq) :
+              lpfc_sli4_remove_from_poll_list(eq);
+}
+
+void lpfc_sli4_start_polling(struct lpfc_queue *eq)
+{
+       __lpfc_sli4_switch_eqmode(eq, LPFC_EQ_POLL);
+}
+
+void lpfc_sli4_stop_polling(struct lpfc_queue *eq)
+{
+       struct lpfc_hba *phba = eq->phba;
+
+       __lpfc_sli4_switch_eqmode(eq, LPFC_EQ_INTERRUPT);
+
+       /* Kick start for the pending io's in h/w.
+        * Once we switch back to interrupt processing on a eq
+        * the io path completion will only arm eq's when it
+        * receives a completion.  But since eq's are in disa-
+        * rmed state it doesn't receive a completion.  This
+        * creates a deadlock scenaro.
+        */
+       phba->sli4_hba.sli4_write_eq_db(phba, eq, 0, LPFC_QUEUE_REARM);
+}
+
 /**
  * lpfc_sli4_queue_free - free a queue structure and associated memory
  * @queue: The queue structure to free.
@@ -14371,6 +14608,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
                return NULL;
 
        INIT_LIST_HEAD(&queue->list);
+       INIT_LIST_HEAD(&queue->_poll_list);
        INIT_LIST_HEAD(&queue->wq_list);
        INIT_LIST_HEAD(&queue->wqfull_list);
        INIT_LIST_HEAD(&queue->page_list);
@@ -18124,8 +18362,9 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
                phba->sli4_hba.max_cfg_param.rpi_used++;
                phba->sli4_hba.rpi_count++;
        }
-       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                       "0001 rpi:%x max:%x lim:%x\n",
+       lpfc_printf_log(phba, KERN_INFO,
+                       LOG_NODE | LOG_DISCOVERY,
+                       "0001 Allocated rpi:x%x max:x%x lim:x%x\n",
                        (int) rpi, max_rpi, rpi_limit);
 
        /*
@@ -18181,11 +18420,19 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
 static void
 __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
 {
+       /*
+        * if the rpi value indicates a prior unreg has already
+        * been done, skip the unreg.
+        */
+       if (rpi == LPFC_RPI_ALLOC_ERROR)
+               return;
+
        if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
                phba->sli4_hba.rpi_count--;
                phba->sli4_hba.max_cfg_param.rpi_used--;
        } else {
-               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+               lpfc_printf_log(phba, KERN_INFO,
+                               LOG_NODE | LOG_DISCOVERY,
                                "2016 rpi %x not inuse\n",
                                rpi);
        }
@@ -19683,6 +19930,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
 
                lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
                spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+               lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH);
                return 0;
        }
 
@@ -19703,6 +19952,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
                }
                lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
                spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+               lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH);
                return 0;
        }
 
@@ -19731,6 +19982,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
                }
                lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
                spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+               lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH);
                return 0;
        }
        return WQE_ERROR;
@@ -20093,6 +20346,13 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd,
        lpfc_ncmd->cur_iocbq.wqe_cmpl = NULL;
        lpfc_ncmd->cur_iocbq.iocb_cmpl = NULL;
 
+       if (phba->cfg_xpsgl && !phba->nvmet_support &&
+           !list_empty(&lpfc_ncmd->dma_sgl_xtra_list))
+               lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd);
+
+       if (!list_empty(&lpfc_ncmd->dma_cmd_rsp_list))
+               lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd);
+
        if (phba->cfg_xri_rebalancing) {
                if (lpfc_ncmd->expedite) {
                        /* Return to expedite pool */
@@ -20157,13 +20417,6 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd,
                spin_unlock_irqrestore(&qp->io_buf_list_put_lock,
                                       iflag);
        }
-
-       if (phba->cfg_xpsgl && !phba->nvmet_support &&
-           !list_empty(&lpfc_ncmd->dma_sgl_xtra_list))
-               lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd);
-
-       if (!list_empty(&lpfc_ncmd->dma_cmd_rsp_list))
-               lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd);
 }
 
 /**
@@ -20399,8 +20652,9 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
        struct sli4_hybrid_sgl *allocated_sgl = NULL;
        struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
        struct list_head *buf_list = &hdwq->sgl_list;
+       unsigned long iflags;
 
-       spin_lock_irq(&hdwq->hdwq_lock);
+       spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
 
        if (likely(!list_empty(buf_list))) {
                /* break off 1 chunk from the sgl_list */
@@ -20412,9 +20666,9 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
                }
        } else {
                /* allocate more */
-               spin_unlock_irq(&hdwq->hdwq_lock);
+               spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
                tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC,
-                                  cpu_to_node(smp_processor_id()));
+                                  cpu_to_node(hdwq->io_wq->chann));
                if (!tmp) {
                        lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
                                        "8353 error kmalloc memory for HDWQ "
@@ -20434,7 +20688,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
                        return NULL;
                }
 
-               spin_lock_irq(&hdwq->hdwq_lock);
+               spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
                list_add_tail(&tmp->list_node, &lpfc_buf->dma_sgl_xtra_list);
        }
 
@@ -20442,7 +20696,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
                                        struct sli4_hybrid_sgl,
                                        list_node);
 
-       spin_unlock_irq(&hdwq->hdwq_lock);
+       spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
 
        return allocated_sgl;
 }
@@ -20466,8 +20720,9 @@ lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
        struct sli4_hybrid_sgl *tmp = NULL;
        struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
        struct list_head *buf_list = &hdwq->sgl_list;
+       unsigned long iflags;
 
-       spin_lock_irq(&hdwq->hdwq_lock);
+       spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
 
        if (likely(!list_empty(&lpfc_buf->dma_sgl_xtra_list))) {
                list_for_each_entry_safe(list_entry, tmp,
@@ -20480,7 +20735,7 @@ lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf)
                rc = -EINVAL;
        }
 
-       spin_unlock_irq(&hdwq->hdwq_lock);
+       spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
        return rc;
 }
 
@@ -20501,8 +20756,9 @@ lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba,
        struct list_head *buf_list = &hdwq->sgl_list;
        struct sli4_hybrid_sgl *list_entry = NULL;
        struct sli4_hybrid_sgl *tmp = NULL;
+       unsigned long iflags;
 
-       spin_lock_irq(&hdwq->hdwq_lock);
+       spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
 
        /* Free sgl pool */
        list_for_each_entry_safe(list_entry, tmp,
@@ -20514,7 +20770,7 @@ lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba,
                kfree(list_entry);
        }
 
-       spin_unlock_irq(&hdwq->hdwq_lock);
+       spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
 }
 
 /**
@@ -20538,8 +20794,9 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
        struct fcp_cmd_rsp_buf *allocated_buf = NULL;
        struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
        struct list_head *buf_list = &hdwq->cmd_rsp_buf_list;
+       unsigned long iflags;
 
-       spin_lock_irq(&hdwq->hdwq_lock);
+       spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
 
        if (likely(!list_empty(buf_list))) {
                /* break off 1 chunk from the list */
@@ -20552,9 +20809,9 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
                }
        } else {
                /* allocate more */
-               spin_unlock_irq(&hdwq->hdwq_lock);
+               spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
                tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC,
-                                  cpu_to_node(smp_processor_id()));
+                                  cpu_to_node(hdwq->io_wq->chann));
                if (!tmp) {
                        lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
                                        "8355 error kmalloc memory for HDWQ "
@@ -20579,7 +20836,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
                tmp->fcp_rsp = (struct fcp_rsp *)((uint8_t *)tmp->fcp_cmnd +
                                sizeof(struct fcp_cmnd));
 
-               spin_lock_irq(&hdwq->hdwq_lock);
+               spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
                list_add_tail(&tmp->list_node, &lpfc_buf->dma_cmd_rsp_list);
        }
 
@@ -20587,7 +20844,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
                                        struct fcp_cmd_rsp_buf,
                                        list_node);
 
-       spin_unlock_irq(&hdwq->hdwq_lock);
+       spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
 
        return allocated_buf;
 }
@@ -20612,8 +20869,9 @@ lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
        struct fcp_cmd_rsp_buf *tmp = NULL;
        struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq;
        struct list_head *buf_list = &hdwq->cmd_rsp_buf_list;
+       unsigned long iflags;
 
-       spin_lock_irq(&hdwq->hdwq_lock);
+       spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
 
        if (likely(!list_empty(&lpfc_buf->dma_cmd_rsp_list))) {
                list_for_each_entry_safe(list_entry, tmp,
@@ -20626,7 +20884,7 @@ lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
                rc = -EINVAL;
        }
 
-       spin_unlock_irq(&hdwq->hdwq_lock);
+       spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
        return rc;
 }
 
@@ -20647,8 +20905,9 @@ lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
        struct list_head *buf_list = &hdwq->cmd_rsp_buf_list;
        struct fcp_cmd_rsp_buf *list_entry = NULL;
        struct fcp_cmd_rsp_buf *tmp = NULL;
+       unsigned long iflags;
 
-       spin_lock_irq(&hdwq->hdwq_lock);
+       spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
 
        /* Free cmd_rsp buf pool */
        list_for_each_entry_safe(list_entry, tmp,
@@ -20661,5 +20920,5 @@ lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
                kfree(list_entry);
        }
 
-       spin_unlock_irq(&hdwq->hdwq_lock);
+       spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags);
 }
index 37fbcb4..7bcf922 100644 (file)
@@ -384,14 +384,13 @@ struct lpfc_io_buf {
 
        struct lpfc_nodelist *ndlp;
        uint32_t timeout;
-       uint16_t flags;  /* TBD convert exch_busy to flags */
+       uint16_t flags;
 #define LPFC_SBUF_XBUSY                0x1     /* SLI4 hba reported XB on WCQE cmpl */
 #define LPFC_SBUF_BUMP_QDEPTH  0x2     /* bumped queue depth counter */
                                        /* External DIF device IO conversions */
 #define LPFC_SBUF_NORMAL_DIF   0x4     /* normal mode to insert/strip */
 #define LPFC_SBUF_PASS_DIF     0x8     /* insert/strip mode to passthru */
 #define LPFC_SBUF_NOT_POSTED    0x10    /* SGL failed post to FW. */
-       uint16_t exch_busy;     /* SLI4 hba reported XB on complete WCQE */
        uint16_t status;        /* From IOCB Word 7- ulpStatus */
        uint32_t result;        /* From IOCB Word 4. */
 
index 0d4882a..d963ca8 100644 (file)
 
 /* Multi-queue arrangement for FCP EQ/CQ/WQ tuples */
 #define LPFC_HBA_HDWQ_MIN      0
-#define LPFC_HBA_HDWQ_MAX      128
-#define LPFC_HBA_HDWQ_DEF      0
+#define LPFC_HBA_HDWQ_MAX      256
+#define LPFC_HBA_HDWQ_DEF      LPFC_HBA_HDWQ_MIN
+
+/* irq_chann range, values */
+#define LPFC_IRQ_CHANN_MIN     0
+#define LPFC_IRQ_CHANN_MAX     256
+#define LPFC_IRQ_CHANN_DEF     LPFC_IRQ_CHANN_MIN
 
 /* FCP MQ queue count limiting */
 #define LPFC_FCP_MQ_THRESHOLD_MIN      0
@@ -133,6 +138,23 @@ struct lpfc_rqb {
 struct lpfc_queue {
        struct list_head list;
        struct list_head wq_list;
+
+       /*
+        * If interrupts are in effect on _all_ the eq's the footprint
+        * of polling code is zero (except mode). This memory is chec-
+        * ked for every io to see if the io needs to be polled and
+        * while completion to check if the eq's needs to be rearmed.
+        * Keep in same cacheline as the queue ptr to avoid cpu fetch
+        * stalls. Using 1B memory will leave us with 7B hole. Fill
+        * it with other frequently used members.
+        */
+       uint16_t last_cpu;      /* most recent cpu */
+       uint16_t hdwq;
+       uint8_t  qe_valid;
+       uint8_t  mode;  /* interrupt or polling */
+#define LPFC_EQ_INTERRUPT      0
+#define LPFC_EQ_POLL           1
+
        struct list_head wqfull_list;
        enum lpfc_sli4_queue_type type;
        enum lpfc_sli4_queue_subtype subtype;
@@ -199,6 +221,7 @@ struct lpfc_queue {
        uint8_t q_flag;
 #define HBA_NVMET_WQFULL       0x1 /* We hit WQ Full condition for NVMET */
 #define HBA_NVMET_CQ_NOTIFY    0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */
+#define HBA_EQ_DELAY_CHK       0x2 /* EQ is a candidate for coalescing */
 #define LPFC_NVMET_CQ_NOTIFY   4
        void __iomem *db_regaddr;
        uint16_t dpp_enable;
@@ -239,10 +262,8 @@ struct lpfc_queue {
        struct delayed_work     sched_spwork;
 
        uint64_t isr_timestamp;
-       uint16_t hdwq;
-       uint16_t last_cpu;      /* most recent cpu */
-       uint8_t qe_valid;
        struct lpfc_queue *assoc_qp;
+       struct list_head _poll_list;
        void **q_pgs;   /* array to index entries per page */
 };
 
@@ -451,11 +472,17 @@ struct lpfc_hba;
 #define LPFC_SLI4_HANDLER_NAME_SZ      16
 struct lpfc_hba_eq_hdl {
        uint32_t idx;
+       uint16_t irq;
        char handler_name[LPFC_SLI4_HANDLER_NAME_SZ];
        struct lpfc_hba *phba;
        struct lpfc_queue *eq;
+       struct cpumask aff_mask;
 };
 
+#define lpfc_get_eq_hdl(eqidx) (&phba->sli4_hba.hba_eq_hdl[eqidx])
+#define lpfc_get_aff_mask(eqidx) (&phba->sli4_hba.hba_eq_hdl[eqidx].aff_mask)
+#define lpfc_get_irq(eqidx) (phba->sli4_hba.hba_eq_hdl[eqidx].irq)
+
 /*BB Credit recovery value*/
 struct lpfc_bbscn_params {
        uint32_t word0;
@@ -513,6 +540,7 @@ struct lpfc_pc_sli4_params {
        uint8_t cqav;
        uint8_t wqsize;
        uint8_t bv1s;
+       uint8_t pls;
 #define LPFC_WQ_SZ64_SUPPORT   1
 #define LPFC_WQ_SZ128_SUPPORT  2
        uint8_t wqpcnt;
@@ -544,11 +572,10 @@ struct lpfc_sli4_lnk_info {
 #define LPFC_SLI4_HANDLER_CNT          (LPFC_HBA_IO_CHAN_MAX+ \
                                         LPFC_FOF_IO_CHAN_NUM)
 
-/* Used for IRQ vector to CPU mapping */
+/* Used for tracking CPU mapping attributes */
 struct lpfc_vector_map_info {
        uint16_t        phys_id;
        uint16_t        core_id;
-       uint16_t        irq;
        uint16_t        eq;
        uint16_t        hdwq;
        uint16_t        flag;
@@ -891,6 +918,7 @@ struct lpfc_sli4_hba {
        struct lpfc_vector_map_info *cpu_map;
        uint16_t num_possible_cpu;
        uint16_t num_present_cpu;
+       struct cpumask numa_mask;
        uint16_t curr_disp_cpu;
        struct lpfc_eq_intr_info __percpu *eq_info;
        uint32_t conf_trunk;
index b8aae31..9e5ff58 100644 (file)
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "12.4.0.0"
+#define LPFC_DRIVER_VERSION "12.6.0.2"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index 9c55662..b5dde9d 100644 (file)
@@ -464,7 +464,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
                mac_scsi_template.can_queue = setup_can_queue;
        if (setup_cmd_per_lun > 0)
                mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
-       if (setup_sg_tablesize >= 0)
+       if (setup_sg_tablesize > 0)
                mac_scsi_template.sg_tablesize = setup_sg_tablesize;
        if (setup_hostid >= 0)
                mac_scsi_template.this_id = setup_hostid & 7;
index a6e788c..bd81840 100644 (file)
@@ -24,6 +24,8 @@
 #define MEGASAS_VERSION                                "07.710.50.00-rc1"
 #define MEGASAS_RELDATE                                "June 28, 2019"
 
+#define MEGASAS_MSIX_NAME_LEN                  32
+
 /*
  * Device IDs
  */
@@ -2203,6 +2205,7 @@ struct megasas_aen_event {
 };
 
 struct megasas_irq_context {
+       char name[MEGASAS_MSIX_NAME_LEN];
        struct megasas_instance *instance;
        u32 MSIxIndex;
        u32 os_irq;
index 42cf38c..c40fbea 100644 (file)
@@ -5546,9 +5546,11 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance)
        pdev = instance->pdev;
        instance->irq_context[0].instance = instance;
        instance->irq_context[0].MSIxIndex = 0;
+       snprintf(instance->irq_context->name, MEGASAS_MSIX_NAME_LEN, "%s%u",
+               "megasas", instance->host->host_no);
        if (request_irq(pci_irq_vector(pdev, 0),
                        instance->instancet->service_isr, IRQF_SHARED,
-                       "megasas", &instance->irq_context[0])) {
+                       instance->irq_context->name, &instance->irq_context[0])) {
                dev_err(&instance->pdev->dev,
                                "Failed to register IRQ from %s %d\n",
                                __func__, __LINE__);
@@ -5580,8 +5582,10 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
        for (i = 0; i < instance->msix_vectors; i++) {
                instance->irq_context[i].instance = instance;
                instance->irq_context[i].MSIxIndex = i;
+               snprintf(instance->irq_context[i].name, MEGASAS_MSIX_NAME_LEN, "%s%u-msix%u",
+                       "megasas", instance->host->host_no, i);
                if (request_irq(pci_irq_vector(pdev, i),
-                       instance->instancet->service_isr, 0, "megasas",
+                       instance->instancet->service_isr, 0, instance->irq_context[i].name,
                        &instance->irq_context[i])) {
                        dev_err(&instance->pdev->dev,
                                "Failed to register IRQ for vector %d.\n", i);
index 50b8c1b..89c3685 100644 (file)
@@ -386,9 +386,8 @@ u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
                                le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart),
                                le32_to_cpu(quad->diff))) == 0) {
                                if (span_blk != NULL) {
-                                       u64  blk, debugBlk;
+                                       u64  blk;
                                        blk =  mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff));
-                                       debugBlk = blk;
 
                                        blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift;
                                        *span_blk = blk;
@@ -699,9 +698,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
        __le16  *pDevHandle = &io_info->devHandle;
        u8      *pPdInterface = &io_info->pd_interface;
        u32     logArm, rowMod, armQ, arm;
-       struct fusion_context *fusion;
 
-       fusion = instance->ctrl_context;
        *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID);
 
        /*Get row and span from io_info for Uneven Span IO.*/
@@ -801,9 +798,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
        u64         *pdBlock = &io_info->pdBlock;
        __le16      *pDevHandle = &io_info->devHandle;
        u8          *pPdInterface = &io_info->pd_interface;
-       struct fusion_context *fusion;
 
-       fusion = instance->ctrl_context;
        *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID);
 
        row =  mega_div64_32(stripRow, raid->rowDataSize);
index fea3cb6..848fbec 100644 (file)
@@ -3044,11 +3044,11 @@ _base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc)
                descp = NULL;
 
        ioc_info(ioc, " %d %d\n", ioc->high_iops_queues,
-           ioc->msix_vector_count);
+           ioc->reply_queue_count);
 
        i = pci_alloc_irq_vectors_affinity(ioc->pdev,
            ioc->high_iops_queues,
-           ioc->msix_vector_count, irq_flags, descp);
+           ioc->reply_queue_count, irq_flags, descp);
 
        return i;
 }
@@ -4242,10 +4242,12 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
        static int
 _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
 {
-       Mpi2FWImageHeader_t *FWImgHdr;
+       Mpi2FWImageHeader_t *fw_img_hdr;
+       Mpi26ComponentImageHeader_t *cmp_img_hdr;
        Mpi25FWUploadRequest_t *mpi_request;
        Mpi2FWUploadReply_t mpi_reply;
        int r = 0;
+       u32  package_version = 0;
        void *fwpkg_data = NULL;
        dma_addr_t fwpkg_data_dma;
        u16 smid, ioc_status;
@@ -4302,14 +4304,26 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
                        ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                                                MPI2_IOCSTATUS_MASK;
                        if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
-                               FWImgHdr = (Mpi2FWImageHeader_t *)fwpkg_data;
-                               if (FWImgHdr->PackageVersion.Word) {
-                                       ioc_info(ioc, "FW Package Version (%02d.%02d.%02d.%02d)\n",
-                                                FWImgHdr->PackageVersion.Struct.Major,
-                                                FWImgHdr->PackageVersion.Struct.Minor,
-                                                FWImgHdr->PackageVersion.Struct.Unit,
-                                                FWImgHdr->PackageVersion.Struct.Dev);
-                               }
+                               fw_img_hdr = (Mpi2FWImageHeader_t *)fwpkg_data;
+                               if (le32_to_cpu(fw_img_hdr->Signature) ==
+                                   MPI26_IMAGE_HEADER_SIGNATURE0_MPI26) {
+                                       cmp_img_hdr =
+                                           (Mpi26ComponentImageHeader_t *)
+                                           (fwpkg_data);
+                                       package_version =
+                                           le32_to_cpu(
+                                           cmp_img_hdr->ApplicationSpecific);
+                               } else
+                                       package_version =
+                                           le32_to_cpu(
+                                           fw_img_hdr->PackageVersion.Word);
+                               if (package_version)
+                                       ioc_info(ioc,
+                                       "FW Package Ver(%02d.%02d.%02d.%02d)\n",
+                                       ((package_version) & 0xFF000000) >> 24,
+                                       ((package_version) & 0x00FF0000) >> 16,
+                                       ((package_version) & 0x0000FF00) >> 8,
+                                       (package_version) & 0x000000FF);
                        } else {
                                _debug_dump_mf(&mpi_reply,
                                                sizeof(Mpi2FWUploadReply_t)/4);
index faca0a5..4ebf81e 100644 (file)
@@ -76,8 +76,8 @@
 #define MPT3SAS_DRIVER_NAME            "mpt3sas"
 #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
 #define MPT3SAS_DESCRIPTION    "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION         "31.100.00.00"
-#define MPT3SAS_MAJOR_VERSION          31
+#define MPT3SAS_DRIVER_VERSION         "32.100.00.00"
+#define MPT3SAS_MAJOR_VERSION          32
 #define MPT3SAS_MINOR_VERSION          100
 #define MPT3SAS_BUILD_VERSION          0
 #define MPT3SAS_RELEASE_VERSION        00
@@ -303,6 +303,8 @@ struct mpt3sas_nvme_cmd {
 #define MPT3_DIAG_BUFFER_IS_REGISTERED (0x01)
 #define MPT3_DIAG_BUFFER_IS_RELEASED   (0x02)
 #define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04)
+#define MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED (0x08)
+#define MPT3_DIAG_BUFFER_IS_APP_OWNED (0x10)
 
 /*
  * HP HBA branding
@@ -391,9 +393,12 @@ struct Mpi2ManufacturingPage11_t {
        u8      Reserved6;                      /* 2Fh */
        __le32  Reserved7[7];                   /* 30h - 4Bh */
        u8      NVMeAbortTO;                    /* 4Ch */
-       u8      Reserved8;                      /* 4Dh */
-       u16     Reserved9;                      /* 4Eh */
-       __le32  Reserved10[4];                  /* 50h - 60h */
+       u8      NumPerDevEvents;                /* 4Dh */
+       u8      HostTraceBufferDecrementSizeKB; /* 4Eh */
+       u8      HostTraceBufferFlags;           /* 4Fh */
+       u16     HostTraceBufferMaxSizeKB;       /* 50h */
+       u16     HostTraceBufferMinSizeKB;       /* 52h */
+       __le32  Reserved10[2];                  /* 54h - 5Bh */
 };
 
 /**
index 7d69695..6874cf0 100644 (file)
@@ -466,6 +466,13 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
                if ((ioc->diag_buffer_status[i] &
                     MPT3_DIAG_BUFFER_IS_RELEASED))
                        continue;
+
+               /*
+                * add a log message to indicate the release
+                */
+               ioc_info(ioc,
+                   "%s: Releasing the trace buffer due to adapter reset.",
+                   __func__);
                mpt3sas_send_diag_release(ioc, i, &issue_reset);
        }
 }
@@ -778,6 +785,18 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
        case MPI2_FUNCTION_NVME_ENCAPSULATED:
        {
                nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request;
+               if (!ioc->pcie_sg_lookup) {
+                       dtmprintk(ioc, ioc_info(ioc,
+                           "HBA doesn't support NVMe. Rejecting NVMe Encapsulated request.\n"
+                           ));
+
+                       if (ioc->logging_level & MPT_DEBUG_TM)
+                               _debug_dump_mf(nvme_encap_request,
+                                   ioc->request_sz/4);
+                       mpt3sas_base_free_smid(ioc, smid);
+                       ret = -EINVAL;
+                       goto out;
+               }
                /*
                 * Get the Physical Address of the sense buffer.
                 * Use Error Response buffer address field to hold the sense
@@ -1484,6 +1503,26 @@ _ctl_diag_capability(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type)
        return rc;
 }
 
+/**
+ * _ctl_diag_get_bufftype - return diag buffer type
+ *              either TRACE, SNAPSHOT, or EXTENDED
+ * @ioc: per adapter object
+ * @unique_id: specifies the unique_id for the buffer
+ *
+ * returns MPT3_DIAG_UID_NOT_FOUND if the id not found
+ */
+static u8
+_ctl_diag_get_bufftype(struct MPT3SAS_ADAPTER *ioc, u32 unique_id)
+{
+       u8  index;
+
+       for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) {
+               if (ioc->unique_id[index] == unique_id)
+                       return index;
+       }
+
+       return MPT3_DIAG_UID_NOT_FOUND;
+}
 
 /**
  * _ctl_diag_register_2 - wrapper for registering diag buffer support
@@ -1531,11 +1570,88 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
                return -EPERM;
        }
 
+       if (diag_register->unique_id == 0) {
+               ioc_err(ioc,
+                   "%s: Invalid UID(0x%08x), buffer_type(0x%02x)\n", __func__,
+                   diag_register->unique_id, buffer_type);
+               return -EINVAL;
+       }
+
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_APP_OWNED) &&
+           !(ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_RELEASED)) {
+               ioc_err(ioc,
+                   "%s: buffer_type(0x%02x) is already registered by application with UID(0x%08x)\n",
+                   __func__, buffer_type, ioc->unique_id[buffer_type]);
+               return -EINVAL;
+       }
+
        if (ioc->diag_buffer_status[buffer_type] &
            MPT3_DIAG_BUFFER_IS_REGISTERED) {
-               ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n",
-                       __func__, buffer_type);
-               return -EINVAL;
+               /*
+                * If driver posts buffer initially, then an application wants
+                * to Register that buffer (own it) without Releasing first,
+                * the application Register command MUST have the same buffer
+                * type and size in the Register command (obtained from the
+                * Query command). Otherwise that Register command will be
+                * failed. If the application has released the buffer but wants
+                * to re-register it, it should be allowed as long as the
+                * Unique-Id/Size match.
+                */
+
+               if (ioc->unique_id[buffer_type] == MPT3DIAGBUFFUNIQUEID &&
+                   ioc->diag_buffer_sz[buffer_type] ==
+                   diag_register->requested_buffer_size) {
+
+                       if (!(ioc->diag_buffer_status[buffer_type] &
+                            MPT3_DIAG_BUFFER_IS_RELEASED)) {
+                               dctlprintk(ioc, ioc_info(ioc,
+                                   "%s: diag_buffer (%d) ownership changed. old-ID(0x%08x), new-ID(0x%08x)\n",
+                                   __func__, buffer_type,
+                                   ioc->unique_id[buffer_type],
+                                   diag_register->unique_id));
+
+                               /*
+                                * Application wants to own the buffer with
+                                * the same size.
+                                */
+                               ioc->unique_id[buffer_type] =
+                                   diag_register->unique_id;
+                               rc = 0; /* success */
+                               goto out;
+                       }
+               } else if (ioc->unique_id[buffer_type] !=
+                   MPT3DIAGBUFFUNIQUEID) {
+                       if (ioc->unique_id[buffer_type] !=
+                           diag_register->unique_id ||
+                           ioc->diag_buffer_sz[buffer_type] !=
+                           diag_register->requested_buffer_size ||
+                           !(ioc->diag_buffer_status[buffer_type] &
+                           MPT3_DIAG_BUFFER_IS_RELEASED)) {
+                               ioc_err(ioc,
+                                   "%s: already has a registered buffer for buffer_type(0x%02x)\n",
+                                   __func__, buffer_type);
+                               return -EINVAL;
+                       }
+               } else {
+                       ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n",
+                           __func__, buffer_type);
+                       return -EINVAL;
+               }
+       } else if (ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) {
+
+               if (ioc->unique_id[buffer_type] != MPT3DIAGBUFFUNIQUEID ||
+                   ioc->diag_buffer_sz[buffer_type] !=
+                   diag_register->requested_buffer_size) {
+
+                       ioc_err(ioc,
+                           "%s: already a buffer is allocated for buffer_type(0x%02x) of size %d bytes, so please try registering again with same size\n",
+                            __func__, buffer_type,
+                           ioc->diag_buffer_sz[buffer_type]);
+                       return -EINVAL;
+               }
        }
 
        if (diag_register->requested_buffer_size % 4)  {
@@ -1560,7 +1676,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
        request_data = ioc->diag_buffer[buffer_type];
        request_data_sz = diag_register->requested_buffer_size;
        ioc->unique_id[buffer_type] = diag_register->unique_id;
-       ioc->diag_buffer_status[buffer_type] = 0;
+       ioc->diag_buffer_status[buffer_type] &=
+           MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
        memcpy(ioc->product_specific[buffer_type],
            diag_register->product_specific, MPT3_PRODUCT_SPECIFIC_DWORDS);
        ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags;
@@ -1584,7 +1701,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
                        ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n",
                                __func__, request_data_sz);
                        mpt3sas_base_free_smid(ioc, smid);
-                       return -ENOMEM;
+                       rc = -ENOMEM;
+                       goto out;
                }
                ioc->diag_buffer[buffer_type] = request_data;
                ioc->diag_buffer_sz[buffer_type] = request_data_sz;
@@ -1649,9 +1767,12 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
 
  out:
 
-       if (rc && request_data)
+       if (rc && request_data) {
                dma_free_coherent(&ioc->pdev->dev, request_data_sz,
                    request_data, request_data_dma);
+               ioc->diag_buffer_status[buffer_type] &=
+                   ~MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
+       }
 
        ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
        return rc;
@@ -1669,6 +1790,10 @@ void
 mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
 {
        struct mpt3_diag_register diag_register;
+       u32 ret_val;
+       u32 trace_buff_size = ioc->manu_pg11.HostTraceBufferMaxSizeKB<<10;
+       u32 min_trace_buff_size = 0;
+       u32 decr_trace_buff_size = 0;
 
        memset(&diag_register, 0, sizeof(struct mpt3_diag_register));
 
@@ -1677,10 +1802,68 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
                ioc->diag_trigger_master.MasterData =
                    (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
                diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
-               /* register for 2MB buffers  */
-               diag_register.requested_buffer_size = 2 * (1024 * 1024);
-               diag_register.unique_id = 0x7075900;
-               _ctl_diag_register_2(ioc,  &diag_register);
+               diag_register.unique_id =
+                   (ioc->hba_mpi_version_belonged == MPI2_VERSION) ?
+                   (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID);
+
+               if (trace_buff_size != 0) {
+                       diag_register.requested_buffer_size = trace_buff_size;
+                       min_trace_buff_size =
+                           ioc->manu_pg11.HostTraceBufferMinSizeKB<<10;
+                       decr_trace_buff_size =
+                           ioc->manu_pg11.HostTraceBufferDecrementSizeKB<<10;
+
+                       if (min_trace_buff_size > trace_buff_size) {
+                               /* The buff size is not set correctly */
+                               ioc_err(ioc,
+                                   "Min Trace Buff size (%d KB) greater than Max Trace Buff size (%d KB)\n",
+                                    min_trace_buff_size>>10,
+                                    trace_buff_size>>10);
+                               ioc_err(ioc,
+                                   "Using zero Min Trace Buff Size\n");
+                               min_trace_buff_size = 0;
+                       }
+
+                       if (decr_trace_buff_size == 0) {
+                               /*
+                                * retry the min size if decrement
+                                * is not available.
+                                */
+                               decr_trace_buff_size =
+                                   trace_buff_size - min_trace_buff_size;
+                       }
+               } else {
+                       /* register for 2MB buffers  */
+                       diag_register.requested_buffer_size = 2 * (1024 * 1024);
+               }
+
+               do {
+                       ret_val = _ctl_diag_register_2(ioc,  &diag_register);
+
+                       if (ret_val == -ENOMEM && min_trace_buff_size &&
+                           (trace_buff_size - decr_trace_buff_size) >=
+                           min_trace_buff_size) {
+                               /* adjust the buffer size */
+                               trace_buff_size -= decr_trace_buff_size;
+                               diag_register.requested_buffer_size =
+                                   trace_buff_size;
+                       } else
+                               break;
+               } while (true);
+
+               if (ret_val == -ENOMEM)
+                       ioc_err(ioc,
+                           "Cannot allocate trace buffer memory. Last memory tried = %d KB\n",
+                           diag_register.requested_buffer_size>>10);
+               else if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE]
+                   & MPT3_DIAG_BUFFER_IS_REGISTERED) {
+                       ioc_err(ioc, "Trace buffer memory %d KB allocated\n",
+                           diag_register.requested_buffer_size>>10);
+                       if (ioc->hba_mpi_version_belonged != MPI2_VERSION)
+                               ioc->diag_buffer_status[
+                                   MPI2_DIAG_BUF_TYPE_TRACE] |=
+                                   MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
+               }
        }
 
        if (bits_to_register & 2) {
@@ -1723,6 +1906,12 @@ _ctl_diag_register(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        }
 
        rc = _ctl_diag_register_2(ioc, &karg);
+
+       if (!rc && (ioc->diag_buffer_status[karg.buffer_type] &
+           MPT3_DIAG_BUFFER_IS_REGISTERED))
+               ioc->diag_buffer_status[karg.buffer_type] |=
+                   MPT3_DIAG_BUFFER_IS_APP_OWNED;
+
        return rc;
 }
 
@@ -1752,7 +1941,13 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        dctlprintk(ioc, ioc_info(ioc, "%s\n",
                                 __func__));
 
-       buffer_type = karg.unique_id & 0x000000ff;
+       buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id);
+       if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) {
+               ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n",
+                   __func__, karg.unique_id);
+               return -EINVAL;
+       }
+
        if (!_ctl_diag_capability(ioc, buffer_type)) {
                ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
                        __func__, buffer_type);
@@ -1785,12 +1980,21 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
                return -ENOMEM;
        }
 
-       request_data_sz = ioc->diag_buffer_sz[buffer_type];
-       request_data_dma = ioc->diag_buffer_dma[buffer_type];
-       dma_free_coherent(&ioc->pdev->dev, request_data_sz,
-                       request_data, request_data_dma);
-       ioc->diag_buffer[buffer_type] = NULL;
-       ioc->diag_buffer_status[buffer_type] = 0;
+       if (ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) {
+               ioc->unique_id[buffer_type] = MPT3DIAGBUFFUNIQUEID;
+               ioc->diag_buffer_status[buffer_type] &=
+                   ~MPT3_DIAG_BUFFER_IS_APP_OWNED;
+               ioc->diag_buffer_status[buffer_type] &=
+                   ~MPT3_DIAG_BUFFER_IS_REGISTERED;
+       } else {
+               request_data_sz = ioc->diag_buffer_sz[buffer_type];
+               request_data_dma = ioc->diag_buffer_dma[buffer_type];
+               dma_free_coherent(&ioc->pdev->dev, request_data_sz,
+                               request_data, request_data_dma);
+               ioc->diag_buffer[buffer_type] = NULL;
+               ioc->diag_buffer_status[buffer_type] = 0;
+       }
        return 0;
 }
 
@@ -1829,14 +2033,17 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
                return -EPERM;
        }
 
-       if ((ioc->diag_buffer_status[buffer_type] &
-           MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
-               ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
-                       __func__, buffer_type);
-               return -EINVAL;
+       if (!(ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) {
+               if ((ioc->diag_buffer_status[buffer_type] &
+                   MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
+                       ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
+                               __func__, buffer_type);
+                       return -EINVAL;
+               }
        }
 
-       if (karg.unique_id & 0xffffff00) {
+       if (karg.unique_id) {
                if (karg.unique_id != ioc->unique_id[buffer_type]) {
                        ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
                                __func__, karg.unique_id);
@@ -1851,13 +2058,21 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
                return -ENOMEM;
        }
 
-       if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED)
-               karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED |
-                   MPT3_APP_FLAGS_BUFFER_VALID);
-       else
-               karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED |
-                   MPT3_APP_FLAGS_BUFFER_VALID |
-                   MPT3_APP_FLAGS_FW_BUFFER_ACCESS);
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_REGISTERED))
+               karg.application_flags |= MPT3_APP_FLAGS_BUFFER_VALID;
+
+       if (!(ioc->diag_buffer_status[buffer_type] &
+            MPT3_DIAG_BUFFER_IS_RELEASED))
+               karg.application_flags |= MPT3_APP_FLAGS_FW_BUFFER_ACCESS;
+
+       if (!(ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED))
+               karg.application_flags |= MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC;
+
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT3_DIAG_BUFFER_IS_APP_OWNED))
+               karg.application_flags |= MPT3_APP_FLAGS_APP_OWNED;
 
        for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++)
                karg.product_specific[i] =
@@ -2002,7 +2217,13 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        dctlprintk(ioc, ioc_info(ioc, "%s\n",
                                 __func__));
 
-       buffer_type = karg.unique_id & 0x000000ff;
+       buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id);
+       if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) {
+               ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n",
+                   __func__, karg.unique_id);
+               return -EINVAL;
+       }
+
        if (!_ctl_diag_capability(ioc, buffer_type)) {
                ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
                        __func__, buffer_type);
@@ -2026,7 +2247,7 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
            MPT3_DIAG_BUFFER_IS_RELEASED) {
                ioc_err(ioc, "%s: buffer_type(0x%02x) is already released\n",
                        __func__, buffer_type);
-               return 0;
+               return -EINVAL;
        }
 
        request_data = ioc->diag_buffer[buffer_type];
@@ -2086,7 +2307,13 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        dctlprintk(ioc, ioc_info(ioc, "%s\n",
                                 __func__));
 
-       buffer_type = karg.unique_id & 0x000000ff;
+       buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id);
+       if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) {
+               ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n",
+                   __func__, karg.unique_id);
+               return -EINVAL;
+       }
+
        if (!_ctl_diag_capability(ioc, buffer_type)) {
                ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
                        __func__, buffer_type);
@@ -2210,6 +2437,8 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
                ioc->diag_buffer_status[buffer_type] |=
                    MPT3_DIAG_BUFFER_IS_REGISTERED;
+               ioc->diag_buffer_status[buffer_type] &=
+                   ~MPT3_DIAG_BUFFER_IS_RELEASED;
                dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
        } else {
                ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
@@ -3130,10 +3359,49 @@ host_trace_buffer_enable_store(struct device *cdev,
                memset(&diag_register, 0, sizeof(struct mpt3_diag_register));
                ioc_info(ioc, "posting host trace buffers\n");
                diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
-               diag_register.requested_buffer_size = (1024 * 1024);
-               diag_register.unique_id = 0x7075900;
+
+               if (ioc->manu_pg11.HostTraceBufferMaxSizeKB != 0 &&
+                   ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0) {
+                       /* post the same buffer allocated previously */
+                       diag_register.requested_buffer_size =
+                           ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE];
+               } else {
+                       /*
+                        * Free the diag buffer memory which was previously
+                        * allocated by an application.
+                        */
+                       if ((ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0)
+                           &&
+                           (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+                           MPT3_DIAG_BUFFER_IS_APP_OWNED)) {
+                               pci_free_consistent(ioc->pdev,
+                                   ioc->diag_buffer_sz[
+                                   MPI2_DIAG_BUF_TYPE_TRACE],
+                                   ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE],
+                                   ioc->diag_buffer_dma[
+                                   MPI2_DIAG_BUF_TYPE_TRACE]);
+                               ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE] =
+                                   NULL;
+                       }
+
+                       diag_register.requested_buffer_size = (1024 * 1024);
+               }
+
+               diag_register.unique_id =
+                   (ioc->hba_mpi_version_belonged == MPI2_VERSION) ?
+                   (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID);
                ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
                _ctl_diag_register_2(ioc,  &diag_register);
+               if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+                   MPT3_DIAG_BUFFER_IS_REGISTERED) {
+                       ioc_info(ioc,
+                           "Trace buffer %d KB allocated through sysfs\n",
+                           diag_register.requested_buffer_size>>10);
+                       if (ioc->hba_mpi_version_belonged != MPI2_VERSION)
+                               ioc->diag_buffer_status[
+                                   MPI2_DIAG_BUF_TYPE_TRACE] |=
+                                   MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
+               }
        } else if (!strcmp(str, "release")) {
                /* exit out if host buffers are already released */
                if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
@@ -3702,12 +3970,6 @@ mpt3sas_ctl_exit(ushort hbas_to_enumerate)
                for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
                        if (!ioc->diag_buffer[i])
                                continue;
-                       if (!(ioc->diag_buffer_status[i] &
-                           MPT3_DIAG_BUFFER_IS_REGISTERED))
-                               continue;
-                       if ((ioc->diag_buffer_status[i] &
-                           MPT3_DIAG_BUFFER_IS_RELEASED))
-                               continue;
                        dma_free_coherent(&ioc->pdev->dev,
                                          ioc->diag_buffer_sz[i],
                                          ioc->diag_buffer[i],
index 18b46fa..0f7aa4d 100644 (file)
 #define MPT3DIAGREADBUFFER _IOWR(MPT3_MAGIC_NUMBER, 30, \
        struct mpt3_diag_read_buffer)
 
+/* Trace Buffer default UniqueId */
+#define MPT2DIAGBUFFUNIQUEID (0x07075900)
+#define MPT3DIAGBUFFUNIQUEID (0x4252434D)
+
+/* UID not found */
+#define MPT3_DIAG_UID_NOT_FOUND (0xFF)
+
+
 /**
  * struct mpt3_ioctl_header - main header structure
  * @ioc_number -  IOC unit number
@@ -310,6 +318,7 @@ struct mpt3_ioctl_btdh_mapping {
 #define MPT3_APP_FLAGS_APP_OWNED       (0x0001)
 #define MPT3_APP_FLAGS_BUFFER_VALID    (0x0002)
 #define MPT3_APP_FLAGS_FW_BUFFER_ACCESS        (0x0004)
+#define MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC (0x0008)
 
 /* flags for mpt3_diag_read_buffer */
 #define MPT3_FLAGS_REREGISTER          (0x0001)
index c8e512b..a038be8 100644 (file)
@@ -5161,7 +5161,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        /* insert into event log */
        sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
             sizeof(Mpi2EventDataSasDeviceStatusChange_t);
-       event_reply = kzalloc(sz, GFP_KERNEL);
+       event_reply = kzalloc(sz, GFP_ATOMIC);
        if (!event_reply) {
                ioc_err(ioc, "failure at %s:%d/%s()!\n",
                        __FILE__, __LINE__, __func__);
@@ -10193,6 +10193,8 @@ scsih_scan_start(struct Scsi_Host *shost)
        int rc;
        if (diag_buffer_enable != -1 && diag_buffer_enable != 0)
                mpt3sas_enable_diag_buffer(ioc, diag_buffer_enable);
+       else if (ioc->manu_pg11.HostTraceBufferMaxSizeKB != 0)
+               mpt3sas_enable_diag_buffer(ioc, 1);
 
        if (disable_discovery > 0)
                return;
index 6ac453f..8ec9bab 100644 (file)
@@ -113,15 +113,21 @@ mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc,
        struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
 {
        u8 issue_reset = 0;
+       u32 *trig_data = (u32 *)&event_data->u.master;
 
        dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
 
        /* release the diag buffer trace */
        if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
            MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
-               dTriggerDiagPrintk(ioc,
-                                  ioc_info(ioc, "%s: release trace diag buffer\n",
-                                           __func__));
+               /*
+                * add a log message so that user knows which event caused
+                * the release
+                */
+               ioc_info(ioc,
+                   "%s: Releasing the trace buffer. Trigger_Type 0x%08x, Data[0] 0x%08x, Data[1] 0x%08x\n",
+                   __func__, event_data->trigger_type,
+                   trig_data[0], trig_data[1]);
                mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
                    &issue_reset);
        }
index 3e0b8eb..a920ece 100644 (file)
@@ -1541,7 +1541,7 @@ out:
 
 int mvs_abort_task_set(struct domain_device *dev, u8 *lun)
 {
-       int rc = TMF_RESP_FUNC_FAILED;
+       int rc;
        struct mvs_tmf_task tmf_task;
 
        tmf_task.tmf = TMF_ABORT_TASK_SET;
index e0b427f..11a2cb8 100644 (file)
@@ -1722,7 +1722,7 @@ struct ncb {
        **      Miscellaneous configuration and status parameters.
        **----------------------------------------------------------------
        */
-       u_char          disc;           /* Diconnection allowed         */
+       u_char          disc;           /* Disconnection allowed        */
        u_char          scsi_mode;      /* Current SCSI BUS mode        */
        u_char          order;          /* Tag order to use             */
        u_char          verbose;        /* Verbosity for this controller*/
index 70db792..b6e04d1 100644 (file)
@@ -1542,7 +1542,7 @@ static void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
  * with ACK reply when below condition is matched:
  *     MsgIn 00: Command Complete.
  *     MsgIn 02: Save Data Pointer.
- *     MsgIn 04: Diconnect.
+ *     MsgIn 04: Disconnect.
  * In other case, unexpected BUSFREE is detected.
  */
 static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
index 2368f34..dc9b74c 100644 (file)
@@ -32,7 +32,7 @@ config PCMCIA_FDOMAIN
 
 config PCMCIA_NINJA_SCSI
        tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
-       depends on !64BIT
+       depends on !64BIT || COMPILE_TEST
        help
          If you intend to attach this type of PCMCIA SCSI host adapter to
          your computer, say Y here and read
index 97416e1..93616f9 100644 (file)
@@ -56,9 +56,7 @@
 MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
 MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
 MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
-#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
-#endif
 
 #include "nsp_io.h"
 
index 6b85016..7c6be2e 100644 (file)
@@ -69,6 +69,25 @@ static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev,
 static
 DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);
 
+/**
+ * controller_fatal_error_show - check controller is under fatal err
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read only' shost attribute.
+ */
+static ssize_t controller_fatal_error_show(struct device *cdev,
+               struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       pm8001_ha->controller_fatal_error);
+}
+static DEVICE_ATTR_RO(controller_fatal_error);
+
 /**
  * pm8001_ctl_fw_version_show - firmware version
  * @cdev: pointer to embedded class device
@@ -804,6 +823,7 @@ static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP,
        pm8001_show_update_fw, pm8001_store_update_fw);
 struct device_attribute *pm8001_host_attrs[] = {
        &dev_attr_interface_rev,
+       &dev_attr_controller_fatal_error,
        &dev_attr_fw_version,
        &dev_attr_update_fw,
        &dev_attr_aap_log,
index 68a8217..2328ff1 100644 (file)
@@ -1186,7 +1186,7 @@ static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
 void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
 {
        s8 bar, logical = 0;
-       for (bar = 0; bar < 6; bar++) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                /*
                ** logical BARs for SPC:
                ** bar 0 and 1 - logical BAR0
@@ -1336,10 +1336,13 @@ int pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ,
  * @circularQ: the inbound queue we want to transfer to HBA.
  * @opCode: the operation code represents commands which LLDD and fw recognized.
  * @payload: the command payload of each operation command.
+ * @nb: size in bytes of the command payload
+ * @responseQueue: queue to interrupt on w/ command response (if any)
  */
 int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
                         struct inbound_queue_table *circularQ,
-                        u32 opCode, void *payload, u32 responseQueue)
+                        u32 opCode, void *payload, size_t nb,
+                        u32 responseQueue)
 {
        u32 Header = 0, hpriority = 0, bc = 1, category = 0x02;
        void *pMessage;
@@ -1350,10 +1353,13 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
                        pm8001_printk("No free mpi buffer\n"));
                return -ENOMEM;
        }
-       BUG_ON(!payload);
-       /*Copy to the payload*/
-       memcpy(pMessage, payload, (pm8001_ha->iomb_size -
-                               sizeof(struct mpi_msg_hdr)));
+
+       if (nb > (pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr)))
+               nb = pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr);
+       memcpy(pMessage, payload, nb);
+       if (nb + sizeof(struct mpi_msg_hdr) < pm8001_ha->iomb_size)
+               memset(pMessage + nb, 0, pm8001_ha->iomb_size -
+                               (nb + sizeof(struct mpi_msg_hdr)));
 
        /*Build the header*/
        Header = ((1 << 31) | (hpriority << 30) | ((bc & 0x1f) << 24)
@@ -1364,7 +1370,7 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
        /*Update the PI to the firmware*/
        pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar,
                circularQ->pi_offset, circularQ->producer_idx);
-       PM8001_IO_DBG(pm8001_ha,
+       PM8001_DEVIO_DBG(pm8001_ha,
                pm8001_printk("INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n",
                        responseQueue, opCode, circularQ->producer_idx,
                        circularQ->consumer_index));
@@ -1436,6 +1442,10 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
                        /* read header */
                        header_tmp = pm8001_read_32(msgHeader);
                        msgHeader_tmp = cpu_to_le32(header_tmp);
+                       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
+                               "outbound opcode msgheader:%x ci=%d pi=%d\n",
+                               msgHeader_tmp, circularQ->consumer_idx,
+                               circularQ->producer_index));
                        if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) {
                                if (OPC_OUB_SKIP_ENTRY !=
                                        (le32_to_cpu(msgHeader_tmp) & 0xfff)) {
@@ -1604,7 +1614,8 @@ void pm8001_work_fn(struct work_struct *work)
                                break;
 
                        default:
-                               pm8001_printk("...query task failed!!!\n");
+                               PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
+                                       "...query task failed!!!\n"));
                                break;
                        });
 
@@ -1758,7 +1769,8 @@ static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha,
        task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
        task_abort.tag = cpu_to_le32(ccb_tag);
 
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort,
+                       sizeof(task_abort), 0);
        if (ret)
                pm8001_tag_free(pm8001_ha, ccb_tag);
 
@@ -1831,7 +1843,8 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha,
        sata_cmd.ncqtag_atap_dir_m |= ((0x1 << 7) | (0x5 << 9));
        memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis));
 
-       res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0);
+       res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd,
+                       sizeof(sata_cmd), 0);
        if (res) {
                sas_free_task(task);
                pm8001_tag_free(pm8001_ha, ccb_tag);
@@ -1890,6 +1903,11 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
                        pm8001_printk("SAS Address of IO Failure Drive:"
                        "%016llx", SAS_ADDR(t->dev->sas_addr)));
 
+       if (status)
+               PM8001_IOERR_DBG(pm8001_ha, pm8001_printk(
+                       "status:0x%x, tag:0x%x, task:0x%p\n",
+                       status, tag, t));
+
        switch (status) {
        case IO_SUCCESS:
                PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS"
@@ -2072,7 +2090,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
                ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", status));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -2125,7 +2143,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
        if (unlikely(!t || !t->lldd_task || !t->dev))
                return;
        ts = &t->task_status;
-       PM8001_IO_DBG(pm8001_ha,
+       PM8001_DEVIO_DBG(pm8001_ha,
                pm8001_printk("port_id = %x,device_id = %x\n",
                port_id, dev_id));
        switch (event) {
@@ -2263,7 +2281,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
                        pm8001_printk("  IO_XFER_CMD_FRAME_ISSUED\n"));
                return;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", event));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -2352,6 +2370,12 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        pm8001_printk("ts null\n"));
                return;
        }
+
+       if (status)
+               PM8001_IOERR_DBG(pm8001_ha, pm8001_printk(
+                       "status:0x%x, tag:0x%x, task::0x%p\n",
+                       status, tag, t));
+
        /* Print sas address of IO failed device */
        if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
                (status != IO_UNDERFLOW)) {
@@ -2652,7 +2676,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", status));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -2723,7 +2747,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
        if (unlikely(!t || !t->lldd_task || !t->dev))
                return;
        ts = &t->task_status;
-       PM8001_IO_DBG(pm8001_ha, pm8001_printk(
+       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
                "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n",
                port_id, dev_id, tag, event));
        switch (event) {
@@ -2872,7 +2896,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
                ts->stat = SAS_OPEN_TO;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", event));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -2917,9 +2941,13 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
        t = ccb->task;
        ts = &t->task_status;
        pm8001_dev = ccb->device;
-       if (status)
+       if (status) {
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("smp IO status 0x%x\n", status));
+               PM8001_IOERR_DBG(pm8001_ha,
+                       pm8001_printk("status:0x%x, tag:0x%x, task:0x%p\n",
+                       status, tag, t));
+       }
        if (unlikely(!t || !t->lldd_task || !t->dev))
                return;
 
@@ -3070,7 +3098,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", status));
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DEV_NO_RESPONSE;
@@ -3355,7 +3383,8 @@ static void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha,
                ((phyId & 0x0F) << 4) | (port_id & 0x0F));
        payload.param0 = cpu_to_le32(param0);
        payload.param1 = cpu_to_le32(param1);
-       pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
 }
 
 static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
@@ -3416,7 +3445,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
                pm8001_get_lrate_mode(phy, link_rate);
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("unknown device type(%x)\n", deviceType));
                break;
        }
@@ -3463,7 +3492,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
        struct sas_ha_struct *sas_ha = pm8001_ha->sas;
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        unsigned long flags;
-       PM8001_MSG_DBG(pm8001_ha,
+       PM8001_DEVIO_DBG(pm8001_ha,
                pm8001_printk("HW_EVENT_SATA_PHY_UP port id = %d,"
                " phy id = %d\n", port_id, phy_id));
        port->port_state =  portstate;
@@ -3541,7 +3570,7 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
                break;
        default:
                port->port_attached = 0;
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk(" phy Down and(default) = %x\n",
                        portstate));
                break;
@@ -3689,7 +3718,7 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
                        pm8001_printk(": FLASH_UPDATE_DISABLED\n"));
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("No matched status = %d\n", status));
                break;
        }
@@ -3805,8 +3834,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
        struct sas_ha_struct *sas_ha = pm8001_ha->sas;
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
-       PM8001_MSG_DBG(pm8001_ha,
-               pm8001_printk("outbound queue HW event & event type : "));
+       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
+               "SPC HW event for portid:%d, phyid:%d, event:%x, status:%x\n",
+               port_id, phy_id, eventType, status));
        switch (eventType) {
        case HW_EVENT_PHY_START_STATUS:
                PM8001_MSG_DBG(pm8001_ha,
@@ -3990,7 +4020,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
                        pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n"));
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown event type = %x\n", eventType));
                break;
        }
@@ -4161,7 +4191,7 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        pm8001_printk("OPC_OUB_SAS_RE_INITIALIZE\n"));
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown outbound Queue IOMB OPC = %x\n",
                        opc));
                break;
@@ -4284,7 +4314,7 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
                cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
        build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd);
        rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
-                                       (u32 *)&smp_cmd, 0);
+                       &smp_cmd, sizeof(smp_cmd), 0);
        if (rc)
                goto err_out_2;
 
@@ -4352,7 +4382,8 @@ static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
                ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
                ssp_cmd.esgl = 0;
        }
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd,
+                       sizeof(ssp_cmd), 0);
        return ret;
 }
 
@@ -4461,7 +4492,8 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
                }
        }
 
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd,
+                       sizeof(sata_cmd), 0);
        return ret;
 }
 
@@ -4496,7 +4528,8 @@ pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
        memcpy(payload.sas_identify.sas_addr,
                pm8001_ha->sas_addr, SAS_ADDR_SIZE);
        payload.sas_identify.phy_id = phy_id;
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4518,7 +4551,8 @@ static int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
        memset(&payload, 0, sizeof(payload));
        payload.tag = cpu_to_le32(tag);
        payload.phy_id = cpu_to_le32(phy_id);
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4577,7 +4611,8 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
                cpu_to_le32(ITNT | (firstBurstSize * 0x10000));
        memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
                SAS_ADDR_SIZE);
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        return rc;
 }
 
@@ -4598,7 +4633,8 @@ int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha,
        payload.device_id = cpu_to_le32(device_id);
        PM8001_MSG_DBG(pm8001_ha,
                pm8001_printk("unregister device device_id = %d\n", device_id));
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4621,7 +4657,8 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
        payload.tag = cpu_to_le32(1);
        payload.phyop_phyid =
                cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F));
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4649,6 +4686,9 @@ static irqreturn_t
 pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
 {
        pm8001_chip_interrupt_disable(pm8001_ha, vec);
+       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
+               "irq vec %d, ODMR:0x%x\n",
+               vec, pm8001_cr32(pm8001_ha, 0, 0x30)));
        process_oq(pm8001_ha, vec);
        pm8001_chip_interrupt_enable(pm8001_ha, vec);
        return IRQ_HANDLED;
@@ -4672,7 +4712,8 @@ static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc,
                task_abort.device_id = cpu_to_le32(dev_id);
                task_abort.tag = cpu_to_le32(cmd_tag);
        }
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort,
+                       sizeof(task_abort), 0);
        return ret;
 }
 
@@ -4729,7 +4770,8 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha,
        if (pm8001_ha->chip_id != chip_8001)
                sspTMCmd.ds_ads_m = 0x08;
        circularQ = &pm8001_ha->inbnd_q_tbl[0];
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd,
+                       sizeof(sspTMCmd), 0);
        return ret;
 }
 
@@ -4819,7 +4861,8 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
        default:
                break;
        }
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req,
+                       sizeof(nvmd_req), 0);
        if (rc) {
                kfree(fw_control_context);
                pm8001_tag_free(pm8001_ha, tag);
@@ -4903,7 +4946,8 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
        default:
                break;
        }
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req,
+                       sizeof(nvmd_req), 0);
        if (rc) {
                kfree(fw_control_context);
                pm8001_tag_free(pm8001_ha, tag);
@@ -4938,7 +4982,8 @@ pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha,
                cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr)));
        payload.sgl_addr_hi =
                cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr)));
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4960,6 +5005,8 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
        if (!fw_control_context)
                return -ENOMEM;
        fw_control = (struct fw_control_info *)&ioctl_payload->func_specific;
+       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
+               "dma fw_control context input length :%x\n", fw_control->len));
        memcpy(buffer, fw_control->buffer, fw_control->len);
        flash_update_info.sgl.addr = cpu_to_le64(phys_addr);
        flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len);
@@ -5083,7 +5130,8 @@ pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
        payload.tag = cpu_to_le32(tag);
        payload.device_id = cpu_to_le32(pm8001_dev->device_id);
        payload.nds = cpu_to_le32(state);
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        return rc;
 
 }
@@ -5108,7 +5156,8 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
        payload.SSAHOLT = cpu_to_le32(0xd << 25);
        payload.sata_hol_tmo = cpu_to_le32(80);
        payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff);
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
        return rc;
index 3374f55..ff618ad 100644 (file)
 #include <linux/slab.h>
 #include "pm8001_sas.h"
 #include "pm8001_chips.h"
+#include "pm80xx_hwi.h"
+
+static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING;
+module_param(logging_level, ulong, 0644);
+MODULE_PARM_DESC(logging_level, " bits for enabling logging info.");
+
+static ulong link_rate = LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | LINKRATE_120;
+module_param(link_rate, ulong, 0644);
+MODULE_PARM_DESC(link_rate, "Enable link rate.\n"
+               " 1: Link rate 1.5G\n"
+               " 2: Link rate 3.0G\n"
+               " 4: Link rate 6.0G\n"
+               " 8: Link rate 12.0G\n");
 
 static struct scsi_transport_template *pm8001_stt;
 
@@ -401,7 +414,7 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
 
        pdev = pm8001_ha->pdev;
        /* map pci mem (PMC pci base 0-3)*/
-       for (bar = 0; bar < 6; bar++) {
+       for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                /*
                ** logical BARs for SPC:
                ** bar 0 and 1 - logical BAR0
@@ -432,7 +445,7 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
                } else {
                        pm8001_ha->io_mem[logicalBar].membase   = 0;
                        pm8001_ha->io_mem[logicalBar].memsize   = 0;
-                       pm8001_ha->io_mem[logicalBar].memvirtaddr = 0;
+                       pm8001_ha->io_mem[logicalBar].memvirtaddr = NULL;
                }
                logicalBar++;
        }
@@ -466,7 +479,15 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
        pm8001_ha->sas = sha;
        pm8001_ha->shost = shost;
        pm8001_ha->id = pm8001_id++;
-       pm8001_ha->logging_level = 0x01;
+       pm8001_ha->logging_level = logging_level;
+       if (link_rate >= 1 && link_rate <= 15)
+               pm8001_ha->link_rate = (link_rate << 8);
+       else {
+               pm8001_ha->link_rate = LINKRATE_15 | LINKRATE_30 |
+                       LINKRATE_60 | LINKRATE_120;
+               PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+                       "Setting link rate to default value\n"));
+       }
        sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id);
        /* IOMB size is 128 for 8088/89 controllers */
        if (pm8001_ha->chip_id != chip_8001)
@@ -873,7 +894,6 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
        u32 number_of_intr;
        int flag = 0;
        int rc;
-       static char intr_drvname[PM8001_MAX_MSIX_VEC][sizeof(DRV_NAME)+3];
 
        /* SPCv controllers supports 64 msi-x */
        if (pm8001_ha->chip_id == chip_8001) {
@@ -894,14 +914,16 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
                                rc, pm8001_ha->number_of_intr));
 
        for (i = 0; i < number_of_intr; i++) {
-               snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
-                               DRV_NAME"%d", i);
+               snprintf(pm8001_ha->intr_drvname[i],
+                       sizeof(pm8001_ha->intr_drvname[0]),
+                       "%s-%d", pm8001_ha->name, i);
                pm8001_ha->irq_vector[i].irq_id = i;
                pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
 
                rc = request_irq(pci_irq_vector(pm8001_ha->pdev, i),
                        pm8001_interrupt_handler_msix, flag,
-                       intr_drvname[i], &(pm8001_ha->irq_vector[i]));
+                       pm8001_ha->intr_drvname[i],
+                       &(pm8001_ha->irq_vector[i]));
                if (rc) {
                        for (j = 0; j < i; j++) {
                                free_irq(pci_irq_vector(pm8001_ha->pdev, i),
@@ -942,7 +964,7 @@ intx:
        pm8001_ha->irq_vector[0].irq_id = 0;
        pm8001_ha->irq_vector[0].drv_inst = pm8001_ha;
        rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED,
-               DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost));
+               pm8001_ha->name, SHOST_TO_SAS_HA(pm8001_ha->shost));
        return rc;
 }
 
index 7e48154..b7cbc31 100644 (file)
@@ -119,7 +119,7 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
        mem_virt_alloc = dma_alloc_coherent(&pdev->dev, mem_size + align,
                                            &mem_dma_handle, GFP_KERNEL);
        if (!mem_virt_alloc) {
-               pm8001_printk("memory allocation error\n");
+               pr_err("pm80xx: memory allocation error\n");
                return -1;
        }
        *pphys_addr = mem_dma_handle;
@@ -249,6 +249,8 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
                spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                return 0;
        default:
+               PM8001_DEVIO_DBG(pm8001_ha,
+                       pm8001_printk("func 0x%x\n", func));
                rc = -EOPNOTSUPP;
        }
        msleep(300);
@@ -384,8 +386,9 @@ static int pm8001_task_exec(struct sas_task *task,
        struct pm8001_port *port = NULL;
        struct sas_task *t = task;
        struct pm8001_ccb_info *ccb;
-       u32 tag = 0xdeadbeef, rc, n_elem = 0;
+       u32 tag = 0xdeadbeef, rc = 0, n_elem = 0;
        unsigned long flags = 0;
+       enum sas_protocol task_proto = t->task_proto;
 
        if (!dev->port) {
                struct task_status_struct *tsm = &t->task_status;
@@ -410,7 +413,7 @@ static int pm8001_task_exec(struct sas_task *task,
                pm8001_dev = dev->lldd_dev;
                port = &pm8001_ha->port[sas_find_local_port_id(dev)];
                if (DEV_IS_GONE(pm8001_dev) || !port->port_attached) {
-                       if (sas_protocol_ata(t->task_proto)) {
+                       if (sas_protocol_ata(task_proto)) {
                                struct task_status_struct *ts = &t->task_status;
                                ts->resp = SAS_TASK_UNDELIVERED;
                                ts->stat = SAS_PHY_DOWN;
@@ -432,7 +435,7 @@ static int pm8001_task_exec(struct sas_task *task,
                        goto err_out;
                ccb = &pm8001_ha->ccb_info[tag];
 
-               if (!sas_protocol_ata(t->task_proto)) {
+               if (!sas_protocol_ata(task_proto)) {
                        if (t->num_scatter) {
                                n_elem = dma_map_sg(pm8001_ha->dev,
                                        t->scatter,
@@ -452,7 +455,7 @@ static int pm8001_task_exec(struct sas_task *task,
                ccb->ccb_tag = tag;
                ccb->task = t;
                ccb->device = pm8001_dev;
-               switch (t->task_proto) {
+               switch (task_proto) {
                case SAS_PROTOCOL_SMP:
                        rc = pm8001_task_prep_smp(pm8001_ha, ccb);
                        break;
@@ -469,8 +472,7 @@ static int pm8001_task_exec(struct sas_task *task,
                        break;
                default:
                        dev_printk(KERN_ERR, pm8001_ha->dev,
-                               "unknown sas_task proto: 0x%x\n",
-                               t->task_proto);
+                               "unknown sas_task proto: 0x%x\n", task_proto);
                        rc = -EINVAL;
                        break;
                }
@@ -493,7 +495,7 @@ err_out_tag:
        pm8001_tag_free(pm8001_ha, tag);
 err_out:
        dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc);
-       if (!sas_protocol_ata(t->task_proto))
+       if (!sas_protocol_ata(task_proto))
                if (n_elem)
                        dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter,
                                t->data_dir);
@@ -1179,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task)
                        break;
                }
        }
-       pm8001_printk(":rc= %d\n", rc);
+       pr_err("pm80xx: rc= %d\n", rc);
        return rc;
 }
 
@@ -1202,8 +1204,8 @@ int pm8001_abort_task(struct sas_task *task)
        pm8001_dev = dev->lldd_dev;
        pm8001_ha = pm8001_find_ha_by_dev(dev);
        phy_id = pm8001_dev->attached_phy;
-       rc = pm8001_find_tag(task, &tag);
-       if (rc == 0) {
+       ret = pm8001_find_tag(task, &tag);
+       if (ret == 0) {
                pm8001_printk("no tag for task:%p\n", task);
                return TMF_RESP_FUNC_FAILED;
        }
@@ -1241,26 +1243,50 @@ int pm8001_abort_task(struct sas_task *task)
 
                        /* 2. Send Phy Control Hard Reset */
                        reinit_completion(&completion);
+                       phy->port_reset_status = PORT_RESET_TMO;
                        phy->reset_success = false;
                        phy->enable_completion = &completion;
                        phy->reset_completion = &completion_reset;
                        ret = PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id,
                                PHY_HARD_RESET);
-                       if (ret)
-                               goto out;
-                       PM8001_MSG_DBG(pm8001_ha,
-                               pm8001_printk("Waiting for local phy ctl\n"));
-                       wait_for_completion(&completion);
-                       if (!phy->reset_success)
+                       if (ret) {
+                               phy->enable_completion = NULL;
+                               phy->reset_completion = NULL;
                                goto out;
+                       }
 
-                       /* 3. Wait for Port Reset complete / Port reset TMO */
+                       /* In the case of the reset timeout/fail we still
+                        * abort the command at the firmware. The assumption
+                        * here is that the drive is off doing something so
+                        * that it's not processing requests, and we want to
+                        * avoid getting a completion for this and either
+                        * leaking the task in libsas or losing the race and
+                        * getting a double free.
+                        */
                        PM8001_MSG_DBG(pm8001_ha,
+                               pm8001_printk("Waiting for local phy ctl\n"));
+                       ret = wait_for_completion_timeout(&completion,
+                                       PM8001_TASK_TIMEOUT * HZ);
+                       if (!ret || !phy->reset_success) {
+                               phy->enable_completion = NULL;
+                               phy->reset_completion = NULL;
+                       } else {
+                               /* 3. Wait for Port Reset complete or
+                                * Port reset TMO
+                                */
+                               PM8001_MSG_DBG(pm8001_ha,
                                pm8001_printk("Waiting for Port reset\n"));
-                       wait_for_completion(&completion_reset);
-                       if (phy->port_reset_status) {
-                               pm8001_dev_gone_notify(dev);
-                               goto out;
+                               ret = wait_for_completion_timeout(
+                                       &completion_reset,
+                                       PM8001_TASK_TIMEOUT * HZ);
+                               if (!ret)
+                                       phy->reset_completion = NULL;
+                               WARN_ON(phy->port_reset_status ==
+                                               PORT_RESET_TMO);
+                               if (phy->port_reset_status == PORT_RESET_TMO) {
+                                       pm8001_dev_gone_notify(dev);
+                                       goto out;
+                               }
                        }
 
                        /*
index ff17c6a..93438c8 100644 (file)
 #define PM8001_EH_LOGGING      0x10 /* libsas EH function logging*/
 #define PM8001_IOCTL_LOGGING   0x20 /* IOCTL message logging */
 #define PM8001_MSG_LOGGING     0x40 /* misc message logging */
-#define pm8001_printk(format, arg...)  printk(KERN_INFO "pm80xx %s %d:" \
-                       format, __func__, __LINE__, ## arg)
+#define PM8001_DEV_LOGGING     0x80 /* development message logging */
+#define PM8001_DEVIO_LOGGING   0x100 /* development io message logging */
+#define PM8001_IOERR_LOGGING   0x200 /* development io err message logging */
+#define pm8001_printk(format, arg...)  pr_info("%s:: %s  %d:" \
+                       format, pm8001_ha->name, __func__, __LINE__, ## arg)
 #define PM8001_CHECK_LOGGING(HBA, LEVEL, CMD)  \
 do {                                           \
        if (unlikely(HBA->logging_level & LEVEL))       \
@@ -97,6 +100,14 @@ do {                                                \
 #define PM8001_MSG_DBG(HBA, CMD)               \
        PM8001_CHECK_LOGGING(HBA, PM8001_MSG_LOGGING, CMD)
 
+#define PM8001_DEV_DBG(HBA, CMD)               \
+       PM8001_CHECK_LOGGING(HBA, PM8001_DEV_LOGGING, CMD)
+
+#define PM8001_DEVIO_DBG(HBA, CMD)             \
+       PM8001_CHECK_LOGGING(HBA, PM8001_DEVIO_LOGGING, CMD)
+
+#define PM8001_IOERR_DBG(HBA, CMD)             \
+       PM8001_CHECK_LOGGING(HBA, PM8001_IOERR_LOGGING, CMD)
 
 #define PM8001_USE_TASKLET
 #define PM8001_USE_MSIX
@@ -141,6 +152,8 @@ struct pm8001_ioctl_payload {
 #define MPI_FATAL_EDUMP_TABLE_HANDSHAKE            0x0C     /* FDDHSHK */
 #define MPI_FATAL_EDUMP_TABLE_STATUS               0x10     /* FDDTSTAT */
 #define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN            0x14     /* ACCDDLEN */
+#define MPI_FATAL_EDUMP_TABLE_TOTAL_LEN                   0x18     /* TOTALLEN */
+#define MPI_FATAL_EDUMP_TABLE_SIGNATURE                   0x1C     /* SIGNITURE */
 #define MPI_FATAL_EDUMP_HANDSHAKE_RDY              0x1
 #define MPI_FATAL_EDUMP_HANDSHAKE_BUSY             0x0
 #define MPI_FATAL_EDUMP_TABLE_STAT_RSVD                 0x0
@@ -496,6 +509,7 @@ struct pm8001_hba_info {
        u32                     forensic_last_offset;
        u32                     fatal_forensic_shift_offset;
        u32                     forensic_fatal_step;
+       u32                     forensic_preserved_accumulated_transfer;
        u32                     evtlog_ib_offset;
        u32                     evtlog_ob_offset;
        void __iomem    *msg_unit_tbl_addr;/*Message Unit Table Addr*/
@@ -530,11 +544,14 @@ struct pm8001_hba_info {
        struct pm8001_ccb_info  *ccb_info;
 #ifdef PM8001_USE_MSIX
        int                     number_of_intr;/*will be used in remove()*/
+       char                    intr_drvname[PM8001_MAX_MSIX_VEC]
+                               [PM8001_NAME_LENGTH+1+3+1];
 #endif
 #ifdef PM8001_USE_TASKLET
        struct tasklet_struct   tasklet[PM8001_MAX_MSIX_VEC];
 #endif
        u32                     logging_level;
+       u32                     link_rate;
        u32                     fw_status;
        u32                     smp_exp_mode;
        bool                    controller_fatal_error;
@@ -663,7 +680,8 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
 void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha);
 int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
                        struct inbound_queue_table *circularQ,
-                       u32 opCode, void *payload, u32 responseQueue);
+                       u32 opCode, void *payload, size_t nb,
+                       u32 responseQueue);
 int pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ,
                                u16 messageSize, void **messagePtr);
 u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
index 7326190..1960113 100644 (file)
@@ -37,6 +37,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  *
  */
+ #include <linux/version.h>
  #include <linux/slab.h>
  #include "pm8001_sas.h"
  #include "pm80xx_hwi.h"
@@ -75,7 +76,7 @@ void pm80xx_pci_mem_copy(struct pm8001_hba_info  *pm8001_ha, u32 soffset,
        destination1 = (u32 *)destination;
 
        for (index = 0; index < dw_count; index += 4, destination1++) {
-               offset = (soffset + index / 4);
+               offset = (soffset + index);
                if (offset < (64 * 1024)) {
                        value = pm8001_cr32(pm8001_ha, bus_base_number, offset);
                        *destination1 =  cpu_to_le32(value);
@@ -92,9 +93,12 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
        struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
        void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
        u32 accum_len , reg_val, index, *temp;
+       u32 status = 1;
        unsigned long start;
        u8 *direct_data;
        char *fatal_error_data = buf;
+       u32 length_to_read;
+       u32 offset;
 
        pm8001_ha->forensic_info.data_buf.direct_data = buf;
        if (pm8001_ha->chip_id == chip_8001) {
@@ -104,16 +108,35 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
                return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
                        (char *)buf;
        }
+       /* initialize variables for very first call from host application */
        if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
                PM8001_IO_DBG(pm8001_ha,
                pm8001_printk("forensic_info TYPE_NON_FATAL..............\n"));
                direct_data = (u8 *)fatal_error_data;
                pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL;
                pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET;
+               pm8001_ha->forensic_info.data_buf.direct_offset = 0;
                pm8001_ha->forensic_info.data_buf.read_len = 0;
+               pm8001_ha->forensic_preserved_accumulated_transfer = 0;
 
-               pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
+               /* Write signature to fatal dump table */
+               pm8001_mw32(fatal_table_address,
+                               MPI_FATAL_EDUMP_TABLE_SIGNATURE, 0x1234abcd);
 
+               pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
+               PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("ossaHwCB: status1 %d\n", status));
+               PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("ossaHwCB: read_len 0x%x\n",
+                       pm8001_ha->forensic_info.data_buf.read_len));
+               PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("ossaHwCB: direct_len 0x%x\n",
+                       pm8001_ha->forensic_info.data_buf.direct_len));
+               PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("ossaHwCB: direct_offset 0x%x\n",
+                       pm8001_ha->forensic_info.data_buf.direct_offset));
+       }
+       if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
                /* start to get data */
                /* Program the MEMBASE II Shifting Register with 0x00.*/
                pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
@@ -126,30 +149,66 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
        /* Read until accum_len is retrived */
        accum_len = pm8001_mr32(fatal_table_address,
                                MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
-       PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n",
-                                               accum_len));
+       /* Determine length of data between previously stored transfer length
+        * and current accumulated transfer length
+        */
+       length_to_read =
+               accum_len - pm8001_ha->forensic_preserved_accumulated_transfer;
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv: accum_len 0x%x\n", accum_len));
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv: length_to_read 0x%x\n",
+               length_to_read));
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv: last_offset 0x%x\n",
+               pm8001_ha->forensic_last_offset));
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv: read_len 0x%x\n",
+               pm8001_ha->forensic_info.data_buf.read_len));
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv:: direct_len 0x%x\n",
+               pm8001_ha->forensic_info.data_buf.direct_len));
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv:: direct_offset 0x%x\n",
+               pm8001_ha->forensic_info.data_buf.direct_offset));
+
+       /* If accumulated length failed to read correctly fail the attempt.*/
        if (accum_len == 0xFFFFFFFF) {
                PM8001_IO_DBG(pm8001_ha,
                        pm8001_printk("Possible PCI issue 0x%x not expected\n",
-                               accum_len));
-               return -EIO;
+                       accum_len));
+               return status;
        }
-       if (accum_len == 0 || accum_len >= 0x100000) {
+       /* If accumulated length is zero fail the attempt */
+       if (accum_len == 0) {
                pm8001_ha->forensic_info.data_buf.direct_data +=
                        sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
-                               "%08x ", 0xFFFFFFFF);
+                       "%08x ", 0xFFFFFFFF);
                return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
                        (char *)buf;
        }
+       /* Accumulated length is good so start capturing the first data */
        temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr;
        if (pm8001_ha->forensic_fatal_step == 0) {
 moreData:
+               /* If data to read is less than SYSFS_OFFSET then reduce the
+                * length of dataLen
+                */
+               if (pm8001_ha->forensic_last_offset + SYSFS_OFFSET
+                               > length_to_read) {
+                       pm8001_ha->forensic_info.data_buf.direct_len =
+                               length_to_read -
+                               pm8001_ha->forensic_last_offset;
+               } else {
+                       pm8001_ha->forensic_info.data_buf.direct_len =
+                               SYSFS_OFFSET;
+               }
                if (pm8001_ha->forensic_info.data_buf.direct_data) {
                        /* Data is in bar, copy to host memory */
-                       pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc,
-                        pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr,
-                               pm8001_ha->forensic_info.data_buf.direct_len ,
-                                       1);
+                       pm80xx_pci_mem_copy(pm8001_ha,
+                       pm8001_ha->fatal_bar_loc,
+                       pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr,
+                       pm8001_ha->forensic_info.data_buf.direct_len, 1);
                }
                pm8001_ha->fatal_bar_loc +=
                        pm8001_ha->forensic_info.data_buf.direct_len;
@@ -160,21 +219,29 @@ moreData:
                pm8001_ha->forensic_info.data_buf.read_len =
                        pm8001_ha->forensic_info.data_buf.direct_len;
 
-               if (pm8001_ha->forensic_last_offset  >= accum_len) {
+               if (pm8001_ha->forensic_last_offset  >= length_to_read) {
                        pm8001_ha->forensic_info.data_buf.direct_data +=
                        sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
                                "%08x ", 3);
-                       for (index = 0; index < (SYSFS_OFFSET / 4); index++) {
+                       for (index = 0; index <
+                               (pm8001_ha->forensic_info.data_buf.direct_len
+                                / 4); index++) {
                                pm8001_ha->forensic_info.data_buf.direct_data +=
-                                       sprintf(pm8001_ha->
-                                        forensic_info.data_buf.direct_data,
-                                               "%08x ", *(temp + index));
+                               sprintf(
+                               pm8001_ha->forensic_info.data_buf.direct_data,
+                               "%08x ", *(temp + index));
                        }
 
                        pm8001_ha->fatal_bar_loc = 0;
                        pm8001_ha->forensic_fatal_step = 1;
                        pm8001_ha->fatal_forensic_shift_offset = 0;
                        pm8001_ha->forensic_last_offset = 0;
+                       status = 0;
+                       offset = (int)
+                       ((char *)pm8001_ha->forensic_info.data_buf.direct_data
+                       - (char *)buf);
+                       PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("get_fatal_spcv:return1 0x%x\n", offset));
                        return (char *)pm8001_ha->
                                forensic_info.data_buf.direct_data -
                                (char *)buf;
@@ -184,12 +251,20 @@ moreData:
                                sprintf(pm8001_ha->
                                        forensic_info.data_buf.direct_data,
                                        "%08x ", 2);
-                       for (index = 0; index < (SYSFS_OFFSET / 4); index++) {
-                               pm8001_ha->forensic_info.data_buf.direct_data +=
-                                       sprintf(pm8001_ha->
+                       for (index = 0; index <
+                               (pm8001_ha->forensic_info.data_buf.direct_len
+                                / 4); index++) {
+                               pm8001_ha->forensic_info.data_buf.direct_data
+                                       += sprintf(pm8001_ha->
                                        forensic_info.data_buf.direct_data,
                                        "%08x ", *(temp + index));
                        }
+                       status = 0;
+                       offset = (int)
+                       ((char *)pm8001_ha->forensic_info.data_buf.direct_data
+                       - (char *)buf);
+                       PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("get_fatal_spcv:return2 0x%x\n", offset));
                        return (char *)pm8001_ha->
                                forensic_info.data_buf.direct_data -
                                (char *)buf;
@@ -199,63 +274,122 @@ moreData:
                pm8001_ha->forensic_info.data_buf.direct_data +=
                        sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
                                "%08x ", 2);
-               for (index = 0; index < 256; index++) {
+               for (index = 0; index <
+                       (pm8001_ha->forensic_info.data_buf.direct_len
+                        / 4) ; index++) {
                        pm8001_ha->forensic_info.data_buf.direct_data +=
                                sprintf(pm8001_ha->
-                                       forensic_info.data_buf.direct_data,
-                                               "%08x ", *(temp + index));
+                               forensic_info.data_buf.direct_data,
+                               "%08x ", *(temp + index));
                }
                pm8001_ha->fatal_forensic_shift_offset += 0x100;
                pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
                        pm8001_ha->fatal_forensic_shift_offset);
                pm8001_ha->fatal_bar_loc = 0;
+               status = 0;
+               offset = (int)
+                       ((char *)pm8001_ha->forensic_info.data_buf.direct_data
+                       - (char *)buf);
+               PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv: return3 0x%x\n", offset));
                return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
                        (char *)buf;
        }
        if (pm8001_ha->forensic_fatal_step == 1) {
-               pm8001_ha->fatal_forensic_shift_offset = 0;
-               /* Read 64K of the debug data. */
-               pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
-                       pm8001_ha->fatal_forensic_shift_offset);
-               pm8001_mw32(fatal_table_address,
-                       MPI_FATAL_EDUMP_TABLE_HANDSHAKE,
+               /* store previous accumulated length before triggering next
+                * accumulated length update
+                */
+               pm8001_ha->forensic_preserved_accumulated_transfer =
+                       pm8001_mr32(fatal_table_address,
+                       MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
+
+               /* continue capturing the fatal log until Dump status is 0x3 */
+               if (pm8001_mr32(fatal_table_address,
+                       MPI_FATAL_EDUMP_TABLE_STATUS) <
+                       MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) {
+
+                       /* reset fddstat bit by writing to zero*/
+                       pm8001_mw32(fatal_table_address,
+                                       MPI_FATAL_EDUMP_TABLE_STATUS, 0x0);
+
+                       /* set dump control value to '1' so that new data will
+                        * be transferred to shared memory
+                        */
+                       pm8001_mw32(fatal_table_address,
+                               MPI_FATAL_EDUMP_TABLE_HANDSHAKE,
                                MPI_FATAL_EDUMP_HANDSHAKE_RDY);
 
-               /* Poll FDDHSHK  until clear  */
-               start = jiffies + (2 * HZ); /* 2 sec */
+                       /*Poll FDDHSHK  until clear */
+                       start = jiffies + (2 * HZ); /* 2 sec */
 
-               do {
-                       reg_val = pm8001_mr32(fatal_table_address,
+                       do {
+                               reg_val = pm8001_mr32(fatal_table_address,
                                        MPI_FATAL_EDUMP_TABLE_HANDSHAKE);
-               } while ((reg_val) && time_before(jiffies, start));
+                       } while ((reg_val) && time_before(jiffies, start));
 
-               if (reg_val != 0) {
-                       PM8001_FAIL_DBG(pm8001_ha,
-                       pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
-                       " = 0x%x\n", reg_val));
-                       return -EIO;
-               }
-
-               /* Read the next 64K of the debug data. */
-               pm8001_ha->forensic_fatal_step = 0;
-               if (pm8001_mr32(fatal_table_address,
-                       MPI_FATAL_EDUMP_TABLE_STATUS) !=
-                               MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) {
-                       pm8001_mw32(fatal_table_address,
-                               MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0);
-                       goto moreData;
-               } else {
-                       pm8001_ha->forensic_info.data_buf.direct_data +=
-                               sprintf(pm8001_ha->
-                                       forensic_info.data_buf.direct_data,
-                                               "%08x ", 4);
-                       pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF;
-                       pm8001_ha->forensic_info.data_buf.direct_len =  0;
-                       pm8001_ha->forensic_info.data_buf.direct_offset = 0;
-                       pm8001_ha->forensic_info.data_buf.read_len = 0;
+                       if (reg_val != 0) {
+                               PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+                               "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n",
+                               reg_val));
+                              /* Fail the dump if a timeout occurs */
+                               pm8001_ha->forensic_info.data_buf.direct_data +=
+                               sprintf(
+                               pm8001_ha->forensic_info.data_buf.direct_data,
+                               "%08x ", 0xFFFFFFFF);
+                               return((char *)
+                               pm8001_ha->forensic_info.data_buf.direct_data
+                               - (char *)buf);
+                       }
+                       /* Poll status register until set to 2 or
+                        * 3 for up to 2 seconds
+                        */
+                       start = jiffies + (2 * HZ); /* 2 sec */
+
+                       do {
+                               reg_val = pm8001_mr32(fatal_table_address,
+                                       MPI_FATAL_EDUMP_TABLE_STATUS);
+                       } while (((reg_val != 2) || (reg_val != 3)) &&
+                                       time_before(jiffies, start));
+
+                       if (reg_val < 2) {
+                               PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+                               "TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n",
+                               reg_val));
+                               /* Fail the dump if a timeout occurs */
+                               pm8001_ha->forensic_info.data_buf.direct_data +=
+                               sprintf(
+                               pm8001_ha->forensic_info.data_buf.direct_data,
+                               "%08x ", 0xFFFFFFFF);
+                               pm8001_cw32(pm8001_ha, 0,
+                                       MEMBASE_II_SHIFT_REGISTER,
+                                       pm8001_ha->fatal_forensic_shift_offset);
+                       }
+                       /* Read the next block of the debug data.*/
+                       length_to_read = pm8001_mr32(fatal_table_address,
+                       MPI_FATAL_EDUMP_TABLE_ACCUM_LEN) -
+                       pm8001_ha->forensic_preserved_accumulated_transfer;
+                       if (length_to_read != 0x0) {
+                               pm8001_ha->forensic_fatal_step = 0;
+                               goto moreData;
+                       } else {
+                               pm8001_ha->forensic_info.data_buf.direct_data +=
+                               sprintf(
+                               pm8001_ha->forensic_info.data_buf.direct_data,
+                               "%08x ", 4);
+                               pm8001_ha->forensic_info.data_buf.read_len
+                                                               = 0xFFFFFFFF;
+                               pm8001_ha->forensic_info.data_buf.direct_len
+                                                               =  0;
+                               pm8001_ha->forensic_info.data_buf.direct_offset
+                                                               = 0;
+                               pm8001_ha->forensic_info.data_buf.read_len = 0;
+                       }
                }
        }
-
+       offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data
+                       - (char *)buf);
+       PM8001_IO_DBG(pm8001_ha,
+               pm8001_printk("get_fatal_spcv: return4 0x%x\n", offset));
        return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
                (char *)buf;
 }
@@ -317,6 +451,25 @@ static void read_main_config_table(struct pm8001_hba_info *pm8001_ha)
                pm8001_mr32(address, MAIN_MPI_ILA_RELEASE_TYPE);
        pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version =
                pm8001_mr32(address, MAIN_MPI_INACTIVE_FW_VERSION);
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "Main cfg table: sign:%x interface rev:%x fw_rev:%x\n",
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev));
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n",
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset));
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "Main cfg table; ila rev:%x Inactive fw rev:%x\n",
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version,
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version));
 }
 
 /**
@@ -521,6 +674,11 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
                        pm8001_mr32(addressib, (offsetib + 0x18));
                pm8001_ha->inbnd_q_tbl[i].producer_idx          = 0;
                pm8001_ha->inbnd_q_tbl[i].consumer_index        = 0;
+
+               PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+                       "IQ %d pi_bar 0x%x pi_offset 0x%x\n", i,
+                       pm8001_ha->inbnd_q_tbl[i].pi_pci_bar,
+                       pm8001_ha->inbnd_q_tbl[i].pi_offset));
        }
        for (i = 0; i < PM8001_MAX_SPCV_OUTB_NUM; i++) {
                pm8001_ha->outbnd_q_tbl[i].element_size_cnt     =
@@ -549,6 +707,11 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
                        pm8001_mr32(addressob, (offsetob + 0x18));
                pm8001_ha->outbnd_q_tbl[i].consumer_idx         = 0;
                pm8001_ha->outbnd_q_tbl[i].producer_index       = 0;
+
+               PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+                       "OQ %d ci_bar 0x%x ci_offset 0x%x\n", i,
+                       pm8001_ha->outbnd_q_tbl[i].ci_pci_bar,
+                       pm8001_ha->outbnd_q_tbl[i].ci_offset));
        }
 }
 
@@ -582,6 +745,10 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
                                        ((pm8001_ha->number_of_intr - 1) << 8);
        pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT,
                pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt);
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "Updated Fatal error interrupt vector 0x%x\n",
+               pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT)));
+
        pm8001_mw32(address, MAIN_EVENT_CRC_CHECK,
                pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump);
 
@@ -591,6 +758,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
        pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping |= 0x20000000;
        pm8001_mw32(address, MAIN_GPIO_LED_FLAGS_OFFSET,
                pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping);
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "Programming DW 0x21 in main cfg table with 0x%x\n",
+               pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET)));
 
        pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER,
                pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer);
@@ -629,6 +799,21 @@ static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
                pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr);
        pm8001_mw32(address, offset + IB_CI_BASE_ADDR_LO_OFFSET,
                pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr);
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "IQ %d: Element pri size 0x%x\n",
+               number,
+               pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt));
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "IQ upr base addr 0x%x IQ lwr base addr 0x%x\n",
+               pm8001_ha->inbnd_q_tbl[number].upper_base_addr,
+               pm8001_ha->inbnd_q_tbl[number].lower_base_addr));
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "CI upper base addr 0x%x CI lower base addr 0x%x\n",
+               pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr,
+               pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr));
 }
 
 /**
@@ -652,6 +837,21 @@ static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
                pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr);
        pm8001_mw32(address, offset + OB_INTERRUPT_COALES_OFFSET,
                pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay);
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "OQ %d: Element pri size 0x%x\n",
+               number,
+               pm8001_ha->outbnd_q_tbl[number].element_size_cnt));
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "OQ upr base addr 0x%x OQ lwr base addr 0x%x\n",
+               pm8001_ha->outbnd_q_tbl[number].upper_base_addr,
+               pm8001_ha->outbnd_q_tbl[number].lower_base_addr));
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "PI upper base addr 0x%x PI lower base addr 0x%x\n",
+               pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr,
+               pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr));
 }
 
 /**
@@ -669,9 +869,9 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha)
        pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_UPDATE);
        /* wait until Inbound DoorBell Clear Register toggled */
        if (IS_SPCV_12G(pm8001_ha->pdev)) {
-               max_wait_count = 4 * 1000 * 1000;/* 4 sec */
+               max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT;
        } else {
-               max_wait_count = 2 * 1000 * 1000;/* 2 sec */
+               max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT;
        }
        do {
                udelay(1);
@@ -797,7 +997,7 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
        value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
        offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */
 
-       PM8001_INIT_DBG(pm8001_ha,
+       PM8001_DEV_DBG(pm8001_ha,
                pm8001_printk("Scratchpad 0 Offset: 0x%x value 0x%x\n",
                                offset, value));
        pcilogic = (value & 0xFC000000) >> 26;
@@ -885,7 +1085,12 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha)
                                (THERMAL_ENABLE << 8) | page_code;
        payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8);
 
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n",
+               payload.cfg_pg[0], payload.cfg_pg[1]));
+
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
        return rc;
@@ -967,7 +1172,8 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha)
        memcpy(&payload.cfg_pg, &SASConfigPage,
                         sizeof(SASProtocolTimerConfig_t));
 
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
 
@@ -1090,7 +1296,12 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha)
        payload.new_curidx_ksop = ((1 << 24) | (1 << 16) | (1 << 8) |
                                        KEK_MGMT_SUBOP_KEYCARDUPDATE);
 
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "Saving Encryption info to flash. payload 0x%x\n",
+               payload.new_curidx_ksop));
+
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
 
@@ -1241,7 +1452,7 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
                pm8001_printk("reset register before write : 0x%x\n", regval));
 
        pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, SPCv_NORMAL_RESET_VALUE);
-       mdelay(500);
+       msleep(500);
 
        regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET);
        PM8001_INIT_DBG(pm8001_ha,
@@ -1443,7 +1654,10 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha,
        task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
        task_abort.tag = cpu_to_le32(ccb_tag);
 
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort,
+                       sizeof(task_abort), 0);
+       PM8001_FAIL_DBG(pm8001_ha,
+               pm8001_printk("Executing abort task end\n"));
        if (ret) {
                sas_free_task(task);
                pm8001_tag_free(pm8001_ha, ccb_tag);
@@ -1519,7 +1733,9 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha,
        sata_cmd.ncqtag_atap_dir_m_dad |= ((0x1 << 7) | (0x5 << 9));
        memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis));
 
-       res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0);
+       res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd,
+                       sizeof(sata_cmd), 0);
+       PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Executing read log end\n"));
        if (res) {
                sas_free_task(task);
                pm8001_tag_free(pm8001_ha, ccb_tag);
@@ -1570,6 +1786,10 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
        if (unlikely(!t || !t->lldd_task || !t->dev))
                return;
        ts = &t->task_status;
+
+       PM8001_DEV_DBG(pm8001_ha, pm8001_printk(
+               "tag::0x%x, status::0x%x task::0x%p\n", tag, status, t));
+
        /* Print sas address of IO failed device */
        if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
                (status != IO_UNDERFLOW))
@@ -1772,7 +1992,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
                ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", status));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -1826,7 +2046,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
        if (unlikely(!t || !t->lldd_task || !t->dev))
                return;
        ts = &t->task_status;
-       PM8001_IO_DBG(pm8001_ha,
+       PM8001_IOERR_DBG(pm8001_ha,
                pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n",
                                port_id, tag, event));
        switch (event) {
@@ -1963,7 +2183,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
                ts->stat = SAS_DATA_OVERRUN;
                break;
        case IO_XFER_ERROR_INTERNAL_CRC_ERROR:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_IOERR_DBG(pm8001_ha,
                        pm8001_printk("IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"));
                /* TBC: used default set values */
                ts->resp = SAS_TASK_COMPLETE;
@@ -1974,7 +2194,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
                        pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n"));
                return;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", event));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -2062,6 +2282,12 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        pm8001_printk("ts null\n"));
                return;
        }
+
+       if (unlikely(status))
+               PM8001_IOERR_DBG(pm8001_ha, pm8001_printk(
+                       "status:0x%x, tag:0x%x, task::0x%p\n",
+                       status, tag, t));
+
        /* Print sas address of IO failed device */
        if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
                (status != IO_UNDERFLOW)) {
@@ -2365,7 +2591,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", status));
                /* not allowed case. Therefore, return failed status */
                ts->resp = SAS_TASK_COMPLETE;
@@ -2382,6 +2608,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        pm8001_printk("task 0x%p done with io_status 0x%x"
                        " resp 0x%x stat 0x%x but aborted by upper layer!\n",
                        t, status, ts->resp, ts->stat));
+               if (t->slow_task)
+                       complete(&t->slow_task->completion);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
@@ -2435,7 +2663,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
        }
 
        ts = &t->task_status;
-       PM8001_IO_DBG(pm8001_ha,
+       PM8001_IOERR_DBG(pm8001_ha,
                pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n",
                                port_id, tag, event));
        switch (event) {
@@ -2655,6 +2883,9 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
        if (unlikely(!t || !t->lldd_task || !t->dev))
                return;
 
+       PM8001_DEV_DBG(pm8001_ha,
+               pm8001_printk("tag::0x%x status::0x%x\n", tag, status));
+
        switch (status) {
 
        case IO_SUCCESS:
@@ -2822,7 +3053,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        default:
-               PM8001_IO_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown status 0x%x\n", status));
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DEV_NO_RESPONSE;
@@ -2873,7 +3104,8 @@ static void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha,
                ((phyId & 0xFF) << 24) | (port_id & 0xFF));
        payload.param0 = cpu_to_le32(param0);
        payload.param1 = cpu_to_le32(param1);
-       pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
 }
 
 static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
@@ -2964,7 +3196,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
                pm8001_get_lrate_mode(phy, link_rate);
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("unknown device type(%x)\n", deviceType));
                break;
        }
@@ -2984,7 +3216,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
        pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
        spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
        if (pm8001_ha->flags == PM8001F_RUN_TIME)
-               mdelay(200);/*delay a moment to wait disk to spinup*/
+               msleep(200);/*delay a moment to wait disk to spinup*/
        pm8001_bytes_dmaed(pm8001_ha, phy_id);
 }
 
@@ -3013,7 +3245,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
        struct sas_ha_struct *sas_ha = pm8001_ha->sas;
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        unsigned long flags;
-       PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
                "port id %d, phy id %d link_rate %d portstate 0x%x\n",
                                port_id, phy_id, link_rate, portstate));
 
@@ -3101,7 +3333,7 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
                break;
        default:
                port->port_attached = 0;
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk(" Phy Down and(default) = 0x%x\n",
                        portstate));
                break;
@@ -3130,8 +3362,10 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
        if (status == 0) {
                phy->phy_state = PHY_LINK_DOWN;
                if (pm8001_ha->flags == PM8001F_RUN_TIME &&
-                               phy->enable_completion != NULL)
+                               phy->enable_completion != NULL) {
                        complete(phy->enable_completion);
+                       phy->enable_completion = NULL;
+               }
        }
        return 0;
 
@@ -3191,7 +3425,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        struct pm8001_port *port = &pm8001_ha->port[port_id];
        struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
-       PM8001_MSG_DBG(pm8001_ha,
+       PM8001_DEV_DBG(pm8001_ha,
                pm8001_printk("portid:%d phyid:%d event:0x%x status:0x%x\n",
                                port_id, phy_id, eventType, status));
 
@@ -3376,7 +3610,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n"));
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha,
+               PM8001_DEVIO_DBG(pm8001_ha,
                        pm8001_printk("Unknown event type 0x%x\n", eventType));
                break;
        }
@@ -3758,7 +3992,7 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ssp_coalesced_comp_resp(pm8001_ha, piomb);
                break;
        default:
-               PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+               PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
                        "Unknown outbound Queue IOMB OPC = 0x%x\n", opc));
                break;
        }
@@ -3991,8 +4225,8 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
 
        build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag,
                                &smp_cmd, pm8001_ha->smp_exp_mode, length);
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
-                                       (u32 *)&smp_cmd, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &smp_cmd,
+                       sizeof(smp_cmd), 0);
        if (rc)
                goto err_out_2;
        return 0;
@@ -4200,7 +4434,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
        }
        q_index = (u32) (pm8001_dev->id & 0x00ffffff) % PM8001_MAX_OUTB_NUM;
        ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
-                                               &ssp_cmd, q_index);
+                       &ssp_cmd, sizeof(ssp_cmd), q_index);
        return ret;
 }
 
@@ -4441,7 +4675,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
        }
        q_index = (u32) (pm8001_ha_dev->id & 0x00ffffff) % PM8001_MAX_OUTB_NUM;
        ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
-                                               &sata_cmd, q_index);
+                       &sata_cmd, sizeof(sata_cmd), q_index);
        return ret;
 }
 
@@ -4465,23 +4699,9 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
 
        PM8001_INIT_DBG(pm8001_ha,
                pm8001_printk("PHY START REQ for phy_id %d\n", phy_id));
-       /*
-        ** [0:7]       PHY Identifier
-        ** [8:11]      link rate 1.5G, 3G, 6G
-        ** [12:13] link mode 01b SAS mode; 10b SATA mode; 11b Auto mode
-        ** [14]        0b disable spin up hold; 1b enable spin up hold
-        ** [15] ob no change in current PHY analig setup 1b enable using SPAST
-        */
-       if (!IS_SPCV_12G(pm8001_ha->pdev))
-               payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
-                               LINKMODE_AUTO | LINKRATE_15 |
-                               LINKRATE_30 | LINKRATE_60 | phy_id);
-       else
-               payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
-                               LINKMODE_AUTO | LINKRATE_15 |
-                               LINKRATE_30 | LINKRATE_60 | LINKRATE_120 |
-                               phy_id);
 
+       payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
+                       LINKMODE_AUTO | pm8001_ha->link_rate | phy_id);
        /* SSC Disable and SAS Analog ST configuration */
        /**
        payload.ase_sh_lm_slr_phyid =
@@ -4494,9 +4714,10 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
        payload.sas_identify.dev_type = SAS_END_DEVICE;
        payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL;
        memcpy(payload.sas_identify.sas_addr,
-         &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE);
+         &pm8001_ha->sas_addr, SAS_ADDR_SIZE);
        payload.sas_identify.phy_id = phy_id;
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4518,7 +4739,8 @@ static int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
        memset(&payload, 0, sizeof(payload));
        payload.tag = cpu_to_le32(tag);
        payload.phy_id = cpu_to_le32(phy_id);
-       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0);
+       ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload,
+                       sizeof(payload), 0);
        return ret;
 }
 
@@ -4584,7 +4806,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
        memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
                SAS_ADDR_SIZE);
 
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
 
@@ -4614,7 +4837,8 @@ static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
        payload.tag = cpu_to_le32(tag);
        payload.phyop_phyid =
                cpu_to_le32(((phy_op & 0xFF) << 8) | (phyId & 0xFF));
-       return pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       return pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
 }
 
 static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha)
@@ -4641,6 +4865,9 @@ static irqreturn_t
 pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
 {
        pm80xx_chip_interrupt_disable(pm8001_ha, vec);
+       PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
+               "irq vec %d, ODMR:0x%x\n",
+               vec, pm8001_cr32(pm8001_ha, 0, 0x30)));
        process_oq(pm8001_ha, vec);
        pm80xx_chip_interrupt_enable(pm8001_ha, vec);
        return IRQ_HANDLED;
@@ -4669,7 +4896,8 @@ void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
                payload.reserved[j] =  cpu_to_le32(*((u32 *)buf + i));
                j++;
        }
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
 }
@@ -4711,7 +4939,8 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
        for (i = 0; i < length; i++)
                payload.reserved[i] = cpu_to_le32(*(buf + i));
 
-       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+       rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
        if (rc)
                pm8001_tag_free(pm8001_ha, tag);
 
index dc9ab76..701951a 100644 (file)
 #define SAS_DOPNRJT_RTRY_TMO            128
 #define SAS_COPNRJT_RTRY_TMO            128
 
+#define SPCV_DOORBELL_CLEAR_TIMEOUT    (30 * 1000 * 1000) /* 30 sec */
+#define SPC_DOORBELL_CLEAR_TIMEOUT     (15 * 1000 * 1000) /* 15 sec */
+
 /*
   Making ORR bigger than IT NEXUS LOSS which is 2000000us = 2 second.
   Assuming a bigger value 3 second, 3000000/128 = 23437.5 where 128
index d979f09..2386bfb 100644 (file)
@@ -42,7 +42,7 @@ extern uint qedf_debug;
 #define QEDF_LOG_LPORT         0x4000          /* lport logs */
 #define QEDF_LOG_ELS           0x8000          /* ELS logs */
 #define QEDF_LOG_NPIV          0x10000         /* NPIV logs */
-#define QEDF_LOG_SESS          0x20000         /* Conection setup, cleanup */
+#define QEDF_LOG_SESS          0x20000         /* Connection setup, cleanup */
 #define QEDF_LOG_TID           0x80000         /*
                                                 * FW TID context acquire
                                                 * free
index 59ca98f..604856e 100644 (file)
@@ -1926,6 +1926,13 @@ static int qedf_fcoe_reset(struct Scsi_Host *shost)
        return 0;
 }
 
+static void qedf_get_host_port_id(struct Scsi_Host *shost)
+{
+       struct fc_lport *lport = shost_priv(shost);
+
+       fc_host_port_id(shost) = lport->port_id;
+}
+
 static struct fc_host_statistics *qedf_fc_get_host_stats(struct Scsi_Host
        *shost)
 {
@@ -1996,6 +2003,7 @@ static struct fc_function_template qedf_fc_transport_fn = {
        .show_host_active_fc4s = 1,
        .show_host_maxframe_size = 1,
 
+       .get_host_port_id = qedf_get_host_port_id,
        .show_host_port_id = 1,
        .show_host_supported_speeds = 1,
        .get_host_speed = fc_get_host_speed,
index 243acc8..37d0840 100644 (file)
@@ -44,7 +44,7 @@ extern uint qedi_dbg_log;
 #define QEDI_LOG_LPORT         0x4000          /* lport logs */
 #define QEDI_LOG_ELS           0x8000          /* ELS logs */
 #define QEDI_LOG_NPIV          0x10000         /* NPIV logs */
-#define QEDI_LOG_SESS          0x20000         /* Conection setup, cleanup */
+#define QEDI_LOG_SESS          0x20000         /* Connection setup, cleanup */
 #define QEDI_LOG_UIO           0x40000         /* iSCSI UIO logs */
 #define QEDI_LOG_TID           0x80000         /* FW TID context acquire,
                                                 * free
index 7259bce..ae97e2f 100644 (file)
@@ -102,8 +102,10 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
                        qla8044_idc_lock(ha);
                        qla82xx_set_reset_owner(vha);
                        qla8044_idc_unlock(ha);
-               } else
+               } else {
+                       ha->fw_dump_mpi = 1;
                        qla2x00_system_error(vha);
+               }
                break;
        case 4:
                if (IS_P3P_TYPE(ha)) {
index 6ffa987..460f443 100644 (file)
@@ -591,19 +591,23 @@ typedef struct srb {
         */
        uint8_t cmd_type;
        uint8_t pad[3];
-       atomic_t ref_count;
        struct kref cmd_kref;   /* need to migrate ref_count over to this */
        void *priv;
        wait_queue_head_t nvme_ls_waitq;
        struct fc_port *fcport;
        struct scsi_qla_host *vha;
        unsigned int start_timer:1;
+       unsigned int abort:1;
+       unsigned int aborted:1;
+       unsigned int completed:1;
+
        uint32_t handle;
        uint16_t flags;
        uint16_t type;
        const char *name;
        int iocbs;
        struct qla_qpair *qpair;
+       struct srb *cmd_sp;
        struct list_head elem;
        u32 gen1;       /* scratch */
        u32 gen2;       /* scratch */
@@ -2277,7 +2281,7 @@ typedef struct {
        uint8_t fabric_port_name[WWN_SIZE];
        uint16_t fp_speed;
        uint8_t fc4_type;
-       uint8_t fc4f_nvme;      /* nvme fc4 feature bits */
+       uint8_t fc4_features;
 } sw_info_t;
 
 /* FCP-4 types */
@@ -2445,7 +2449,7 @@ typedef struct fc_port {
        u32 supported_classes;
 
        uint8_t fc4_type;
-       uint8_t fc4f_nvme;
+       uint8_t fc4_features;
        uint8_t scan_state;
 
        unsigned long last_queue_full;
@@ -2476,6 +2480,11 @@ typedef struct fc_port {
        u16 n2n_chip_reset;
 } fc_port_t;
 
+enum {
+       FC4_PRIORITY_NVME = 1,
+       FC4_PRIORITY_FCP  = 2,
+};
+
 #define QLA_FCPORT_SCAN                1
 #define QLA_FCPORT_FOUND       2
 
@@ -4291,6 +4300,8 @@ struct qla_hw_data {
        atomic_t        nvme_active_aen_cnt;
        uint16_t        nvme_last_rptd_aen;             /* Last recorded aen count */
 
+       uint8_t fc4_type_priority;
+
        atomic_t zio_threshold;
        uint16_t last_zio_threshold;
 
@@ -4816,6 +4827,23 @@ struct sff_8247_a0 {
         ha->current_topology == ISP_CFG_N || \
         !ha->current_topology)
 
+#define NVME_TYPE(fcport) \
+       (fcport->fc4_type & FS_FC4TYPE_NVME) \
+
+#define FCP_TYPE(fcport) \
+       (fcport->fc4_type & FS_FC4TYPE_FCP) \
+
+#define NVME_ONLY_TARGET(fcport) \
+       (NVME_TYPE(fcport) && !FCP_TYPE(fcport))  \
+
+#define NVME_FCP_TARGET(fcport) \
+       (FCP_TYPE(fcport) && NVME_TYPE(fcport)) \
+
+#define NVME_TARGET(ha, fcport) \
+       ((NVME_FCP_TARGET(fcport) && \
+       (ha->fc4_type_priority == FC4_PRIORITY_NVME)) || \
+       NVME_ONLY_TARGET(fcport)) \
+
 #include "qla_target.h"
 #include "qla_gbl.h"
 #include "qla_dbg.h"
index 732bb87..59f6903 100644 (file)
@@ -2101,4 +2101,6 @@ struct qla_fcp_prio_cfg {
 #define FA_FLASH_LAYOUT_ADDR_83        (0x3F1000/4)
 #define FA_FLASH_LAYOUT_ADDR_28        (0x11000/4)
 
+#define NVRAM_DUAL_FCP_NVME_FLAG_OFFSET        0x196
+
 #endif
index d11416d..5b163ad 100644 (file)
@@ -917,4 +917,5 @@ int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
 
 /* nvme.c */
 void qla_nvme_unregister_remote_port(struct fc_port *fcport);
+void qla_handle_els_plogi_done(scsi_qla_host_t *vha, struct event_arg *ea);
 #endif /* _QLA_GBL_H */
index 5298ed1..6723068 100644 (file)
@@ -248,7 +248,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    WWN_SIZE);
 
                fcport->fc4_type = (ct_rsp->rsp.ga_nxt.fc4_types[2] & BIT_0) ?
-                   FC4_TYPE_FCP_SCSI : FC4_TYPE_OTHER;
+                   FS_FC4TYPE_FCP : FC4_TYPE_OTHER;
 
                if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE &&
                    ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE)
@@ -2887,7 +2887,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
        struct ct_sns_req       *ct_req;
        struct ct_sns_rsp       *ct_rsp;
        struct qla_hw_data *ha = vha->hw;
-       uint8_t fcp_scsi_features = 0;
+       uint8_t fcp_scsi_features = 0, nvme_features = 0;
        struct ct_arg arg;
 
        for (i = 0; i < ha->max_fibre_devices; i++) {
@@ -2933,14 +2933,19 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
                           ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
                        fcp_scsi_features &= 0x0f;
 
-                       if (fcp_scsi_features)
-                               list[i].fc4_type = FC4_TYPE_FCP_SCSI;
-                       else
-                               list[i].fc4_type = FC4_TYPE_OTHER;
+                       if (fcp_scsi_features) {
+                               list[i].fc4_type = FS_FC4TYPE_FCP;
+                               list[i].fc4_features = fcp_scsi_features;
+                       }
 
-                       list[i].fc4f_nvme =
+                       nvme_features =
                            ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET];
-                       list[i].fc4f_nvme &= 0xf;
+                       nvme_features &= 0xf;
+
+                       if (nvme_features) {
+                               list[i].fc4_type |= FS_FC4TYPE_NVME;
+                               list[i].fc4_features = nvme_features;
+                       }
                }
 
                /* Last device exit. */
@@ -3005,7 +3010,7 @@ static void qla24xx_async_gpsc_sp_done(srb_t *sp, int res)
        fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
 
        if (res == QLA_FUNCTION_TIMEOUT)
-               return;
+               goto done;
 
        if (res == (DID_ERROR << 16)) {
                /* entry status error */
@@ -3435,6 +3440,8 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res)
        fc_port_t *fcport = sp->fcport;
        struct ct_sns_rsp *ct_rsp;
        struct event_arg ea;
+       uint8_t fc4_scsi_feat;
+       uint8_t fc4_nvme_feat;
 
        ql_dbg(ql_dbg_disc, vha, 0x2133,
               "Async done-%s res %x ID %x. %8phC\n",
@@ -3442,24 +3449,25 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res)
 
        fcport->flags &= ~FCF_ASYNC_SENT;
        ct_rsp = &fcport->ct_desc.ct_sns->p.rsp;
+       fc4_scsi_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
+       fc4_nvme_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET];
+
        /*
         * FC-GS-7, 5.2.3.12 FC-4 Features - format
         * The format of the FC-4 Features object, as defined by the FC-4,
         * Shall be an array of 4-bit values, one for each type code value
         */
        if (!res) {
-               if (ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET] & 0xf) {
+               if (fc4_scsi_feat & 0xf) {
                        /* w1 b00:03 */
-                       fcport->fc4_type =
-                           ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
-                       fcport->fc4_type &= 0xf;
-              }
+                       fcport->fc4_type = FS_FC4TYPE_FCP;
+                       fcport->fc4_features = fc4_scsi_feat & 0xf;
+               }
 
-               if (ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET] & 0xf) {
+               if (fc4_nvme_feat & 0xf) {
                        /* w5 [00:03]/28h */
-                       fcport->fc4f_nvme =
-                           ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET];
-                       fcport->fc4f_nvme &= 0xf;
+                       fcport->fc4_type |= FS_FC4TYPE_NVME;
+                       fcport->fc4_features = fc4_nvme_feat & 0xf;
                }
        }
 
@@ -3563,7 +3571,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
        u8 recheck = 0;
        u16 dup = 0, dup_cnt = 0;
 
-       ql_dbg(ql_dbg_disc, vha, 0xffff,
+       ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
            "%s enter\n", __func__);
 
        if (sp->gen1 != vha->hw->base_qpair->chip_reset) {
@@ -3580,8 +3588,9 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
                        set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
                        set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
                } else {
-                       ql_dbg(ql_dbg_disc, vha, 0xffff,
-                           "Fabric scan failed on all retries.\n");
+                       ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
+                           "%s: Fabric scan failed for %d retries.\n",
+                           __func__, vha->scan.scan_retry);
                }
                goto out;
        }
@@ -4047,7 +4056,7 @@ done_free_sp:
 
 void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp)
 {
-       ql_dbg(ql_dbg_disc, vha, 0xffff,
+       ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
            "%s enter\n", __func__);
        qla24xx_async_gnnft(vha, sp, sp->gen2);
 }
@@ -4061,7 +4070,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
        u32 rspsz;
        unsigned long flags;
 
-       ql_dbg(ql_dbg_disc, vha, 0xffff,
+       ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
            "%s enter\n", __func__);
 
        if (!vha->flags.online)
@@ -4070,14 +4079,15 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
        spin_lock_irqsave(&vha->work_lock, flags);
        if (vha->scan.scan_flags & SF_SCANNING) {
                spin_unlock_irqrestore(&vha->work_lock, flags);
-               ql_dbg(ql_dbg_disc, vha, 0xffff, "scan active\n");
+               ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
+                   "%s: scan active\n", __func__);
                return rval;
        }
        vha->scan.scan_flags |= SF_SCANNING;
        spin_unlock_irqrestore(&vha->work_lock, flags);
 
        if (fc4_type == FC4_TYPE_FCP_SCSI) {
-               ql_dbg(ql_dbg_disc, vha, 0xffff,
+               ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
                    "%s: Performing FCP Scan\n", __func__);
 
                if (sp)
@@ -4132,7 +4142,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
                }
                sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz;
 
-               ql_dbg(ql_dbg_disc, vha, 0xffff,
+               ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
                    "%s scan list size %d\n", __func__, vha->scan.size);
 
                memset(vha->scan.l, 0, vha->scan.size);
@@ -4197,8 +4207,8 @@ done_free_sp:
        spin_lock_irqsave(&vha->work_lock, flags);
        vha->scan.scan_flags &= ~SF_SCANNING;
        if (vha->scan.scan_flags == 0) {
-               ql_dbg(ql_dbg_disc, vha, 0xffff,
-                   "%s: schedule\n", __func__);
+               ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
+                   "%s: Scan scheduled.\n", __func__);
                vha->scan.scan_flags |= SF_QUEUED;
                schedule_delayed_work(&vha->scan.scan_work, 5);
        }
index 1d04131..1dbee88 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/prom.h>
 #endif
 
-#include <target/target_core_base.h>
 #include "qla_target.h"
 
 /*
@@ -101,8 +100,22 @@ static void qla24xx_abort_iocb_timeout(void *data)
        u32 handle;
        unsigned long flags;
 
+       if (sp->cmd_sp)
+               ql_dbg(ql_dbg_async, sp->vha, 0x507c,
+                   "Abort timeout - cmd hdl=%x, cmd type=%x hdl=%x, type=%x\n",
+                   sp->cmd_sp->handle, sp->cmd_sp->type,
+                   sp->handle, sp->type);
+       else
+               ql_dbg(ql_dbg_async, sp->vha, 0x507c,
+                   "Abort timeout 2 - hdl=%x, type=%x\n",
+                   sp->handle, sp->type);
+
        spin_lock_irqsave(qpair->qp_lock_ptr, flags);
        for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) {
+               if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] ==
+                   sp->cmd_sp))
+                       qpair->req->outstanding_cmds[handle] = NULL;
+
                /* removing the abort */
                if (qpair->req->outstanding_cmds[handle] == sp) {
                        qpair->req->outstanding_cmds[handle] = NULL;
@@ -111,6 +124,9 @@ static void qla24xx_abort_iocb_timeout(void *data)
        }
        spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
 
+       if (sp->cmd_sp)
+               sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED);
+
        abt->u.abt.comp_status = CS_TIMEOUT;
        sp->done(sp, QLA_OS_TIMER_EXPIRED);
 }
@@ -142,6 +158,7 @@ static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
        sp->type = SRB_ABT_CMD;
        sp->name = "abort";
        sp->qpair = cmd_sp->qpair;
+       sp->cmd_sp = cmd_sp;
        if (wait)
                sp->flags = SRB_WAKEUP_ON_COMP;
 
@@ -328,7 +345,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        else
                lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
 
-       if (fcport->fc4f_nvme)
+       if (NVME_TARGET(vha->hw, fcport))
                lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
 
        ql_dbg(ql_dbg_disc, vha, 0x2072,
@@ -726,19 +743,17 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
 
                loop_id = le16_to_cpu(e->nport_handle);
                loop_id = (loop_id & 0x7fff);
-               if  (fcport->fc4f_nvme)
+               if (NVME_TARGET(vha->hw, fcport))
                        current_login_state = e->current_login_state >> 4;
                else
                        current_login_state = e->current_login_state & 0xf;
 
-
                ql_dbg(ql_dbg_disc, vha, 0x20e2,
-                   "%s found %8phC CLS [%x|%x] nvme %d ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n",
+                   "%s found %8phC CLS [%x|%x] fc4_type %d ID[%06x|%06x] lid[%d|%d]\n",
                    __func__, fcport->port_name,
                    e->current_login_state, fcport->fw_login_state,
-                   fcport->fc4f_nvme, id.b.domain, id.b.area, id.b.al_pa,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, loop_id, fcport->loop_id);
+                   fcport->fc4_type, id.b24, fcport->d_id.b24,
+                   loop_id, fcport->loop_id);
 
                switch (fcport->disc_state) {
                case DSC_DELETE_PEND:
@@ -1135,19 +1150,18 @@ static void qla24xx_async_gpdb_sp_done(srb_t *sp, int res)
            "Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n",
            sp->name, res, fcport->port_name, mb[1], mb[2]);
 
-       if (res == QLA_FUNCTION_TIMEOUT) {
-               dma_pool_free(sp->vha->hw->s_dma_pool, sp->u.iocb_cmd.u.mbx.in,
-                       sp->u.iocb_cmd.u.mbx.in_dma);
-               return;
-       }
-
        fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+
+       if (res == QLA_FUNCTION_TIMEOUT)
+               goto done;
+
        memset(&ea, 0, sizeof(ea));
        ea.fcport = fcport;
        ea.sp = sp;
 
        qla24xx_handle_gpdb_event(vha, &ea);
 
+done:
        dma_pool_free(ha->s_dma_pool, sp->u.iocb_cmd.u.mbx.in,
                sp->u.iocb_cmd.u.mbx.in_dma);
 
@@ -1225,13 +1239,13 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport)
        sp->done = qla2x00_async_prli_sp_done;
        lio->u.logio.flags = 0;
 
-       if  (fcport->fc4f_nvme)
+       if (NVME_TARGET(vha->hw, fcport))
                lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI;
 
        ql_dbg(ql_dbg_disc, vha, 0x211b,
            "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n",
            fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24,
-           fcport->login_retry, fcport->fc4f_nvme ? "nvme" : "fc");
+           fcport->login_retry, NVME_TARGET(vha->hw, fcport) ? "nvme" : "fc");
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
@@ -1382,14 +1396,14 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
        fcport->flags &= ~FCF_ASYNC_SENT;
 
        ql_dbg(ql_dbg_disc, vha, 0x20d2,
-           "%s %8phC DS %d LS %d nvme %x rc %d\n", __func__, fcport->port_name,
-           fcport->disc_state, pd->current_login_state, fcport->fc4f_nvme,
-           ea->rc);
+           "%s %8phC DS %d LS %d fc4_type %x rc %d\n", __func__,
+           fcport->port_name, fcport->disc_state, pd->current_login_state,
+           fcport->fc4_type, ea->rc);
 
        if (fcport->disc_state == DSC_DELETE_PEND)
                return;
 
-       if (fcport->fc4f_nvme)
+       if (NVME_TARGET(vha->hw, fcport))
                ls = pd->current_login_state >> 4;
        else
                ls = pd->current_login_state & 0xf;
@@ -1578,7 +1592,8 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
                                ql_dbg(ql_dbg_disc, vha, 0x2118,
                                    "%s %d %8phC post %s PRLI\n",
                                    __func__, __LINE__, fcport->port_name,
-                                   fcport->fc4f_nvme ? "NVME" : "FC");
+                                   NVME_TARGET(vha->hw, fcport) ? "NVME" :
+                                   "FC");
                                qla24xx_post_prli_work(vha, fcport);
                        }
                        break;
@@ -1701,6 +1716,15 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
        qla24xx_fcport_handle_login(vha, fcport);
 }
 
+void qla_handle_els_plogi_done(scsi_qla_host_t *vha,
+                                     struct event_arg *ea)
+{
+       ql_dbg(ql_dbg_disc, vha, 0x2118,
+           "%s %d %8phC post PRLI\n",
+           __func__, __LINE__, ea->fcport->port_name);
+       qla24xx_post_prli_work(vha, ea->fcport);
+}
+
 /*
  * RSCN(s) came in for this fcport, but the RSCN(s) was not able
  * to be consumed by the fcport
@@ -1860,38 +1884,26 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                        break;
                }
 
-               if (ea->fcport->fc4f_nvme) {
+               /*
+                * Retry PRLI with other FC-4 type if failure occurred on dual
+                * FCP/NVMe port
+                */
+               if (NVME_FCP_TARGET(ea->fcport)) {
                        ql_dbg(ql_dbg_disc, vha, 0x2118,
-                               "%s %d %8phC post fc4 prli\n",
-                               __func__, __LINE__, ea->fcport->port_name);
-                       ea->fcport->fc4f_nvme = 0;
-                       qla24xx_post_prli_work(vha, ea->fcport);
-                       return;
+                               "%s %d %8phC post %s prli\n",
+                               __func__, __LINE__, ea->fcport->port_name,
+                               (ea->fcport->fc4_type & FS_FC4TYPE_NVME) ?
+                               "NVMe" : "FCP");
+                       if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME)
+                               ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME;
+                       else
+                               ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP;
                }
 
-               /* at this point both PRLI NVME & PRLI FCP failed */
-               if (N2N_TOPO(vha->hw)) {
-                       if (ea->fcport->n2n_link_reset_cnt < 3) {
-                               ea->fcport->n2n_link_reset_cnt++;
-                               /*
-                                * remote port is not sending Plogi. Reset
-                                * link to kick start his state machine
-                                */
-                               set_bit(N2N_LINK_RESET, &vha->dpc_flags);
-                       } else {
-                               ql_log(ql_log_warn, vha, 0x2119,
-                                   "%s %d %8phC Unable to reconnect\n",
-                                   __func__, __LINE__, ea->fcport->port_name);
-                       }
-               } else {
-                       /*
-                        * switch connect. login failed. Take connection
-                        * down and allow relogin to retrigger
-                        */
-                       ea->fcport->flags &= ~FCF_ASYNC_SENT;
-                       ea->fcport->keep_nport_handle = 0;
-                       qlt_schedule_sess_for_deletion(ea->fcport);
-               }
+               ea->fcport->flags &= ~FCF_ASYNC_SENT;
+               ea->fcport->keep_nport_handle = 0;
+               ea->fcport->logout_on_delete = 1;
+               qlt_schedule_sess_for_deletion(ea->fcport);
                break;
        }
 }
@@ -1952,7 +1964,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                 * force a relogin attempt via implicit LOGO, PLOGI, and PRLI
                 * requests.
                 */
-               if (ea->fcport->fc4f_nvme) {
+               if (NVME_TARGET(vha->hw, ea->fcport)) {
                        ql_dbg(ql_dbg_disc, vha, 0x2117,
                                "%s %d %8phC post prli\n",
                                __func__, __LINE__, ea->fcport->port_name);
@@ -2206,8 +2218,18 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        ql_dbg(ql_dbg_init, vha, 0x0061,
            "Configure NVRAM parameters...\n");
 
+       /* Let priority default to FCP, can be overridden by nvram_config */
+       ha->fc4_type_priority = FC4_PRIORITY_FCP;
+
        ha->isp_ops->nvram_config(vha);
 
+       if (ha->fc4_type_priority != FC4_PRIORITY_FCP &&
+           ha->fc4_type_priority != FC4_PRIORITY_NVME)
+               ha->fc4_type_priority = FC4_PRIORITY_FCP;
+
+       ql_log(ql_log_info, vha, 0xffff, "FC4 priority set to %s\n",
+              ha->fc4_type_priority == FC4_PRIORITY_FCP ? "FCP" : "NVMe");
+
        if (ha->flags.disable_serdes) {
                /* Mask HBA via NVRAM settings? */
                ql_log(ql_log_info, vha, 0x0077,
@@ -5382,7 +5404,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 
        qla2x00_iidma_fcport(vha, fcport);
 
-       if (fcport->fc4f_nvme) {
+       if (NVME_TARGET(vha->hw, fcport)) {
                qla_nvme_register_remote(vha, fcport);
                fcport->disc_state = DSC_LOGIN_COMPLETE;
                qla2x00_set_fcport_state(fcport, FCS_ONLINE);
@@ -5710,11 +5732,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
                                new_fcport->fc4_type = swl[swl_idx].fc4_type;
 
                                new_fcport->nvme_flag = 0;
-                               new_fcport->fc4f_nvme = 0;
                                if (vha->flags.nvme_enabled &&
-                                   swl[swl_idx].fc4f_nvme) {
-                                       new_fcport->fc4f_nvme =
-                                           swl[swl_idx].fc4f_nvme;
+                                   swl[swl_idx].fc4_type & FS_FC4TYPE_NVME) {
                                        ql_log(ql_log_info, vha, 0x2131,
                                            "FOUND: NVME port %8phC as FC Type 28h\n",
                                            new_fcport->port_name);
@@ -5770,7 +5789,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
 
                /* Bypass ports whose FCP-4 type is not FCP_SCSI */
                if (ql2xgffidenable &&
-                   (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
+                   (!(new_fcport->fc4_type & FS_FC4TYPE_FCP) &&
                    new_fcport->fc4_type != FC4_TYPE_UNKNOWN))
                        continue;
 
@@ -5839,7 +5858,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
                        break;
                }
 
-               if (fcport->fc4f_nvme) {
+               if (NVME_TARGET(vha->hw, fcport)) {
                        if (fcport->disc_state == DSC_DELETE_PEND) {
                                fcport->disc_state = DSC_GNL;
                                vha->fcport_count--;
@@ -8514,6 +8533,9 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        /* N2N: driver will initiate Login instead of FW */
        icb->firmware_options_3 |= BIT_8;
 
+       /* Determine NVMe/FCP priority for target ports */
+       ha->fc4_type_priority = qla2xxx_get_fc4_priority(vha);
+
        if (rval) {
                ql_log(ql_log_warn, vha, 0x0076,
                    "NVRAM configuration failed.\n");
@@ -9003,8 +9025,6 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair)
        struct qla_hw_data *ha = qpair->hw;
 
        qpair->delete_in_progress = 1;
-       while (atomic_read(&qpair->ref_count))
-               msleep(500);
 
        ret = qla25xx_delete_req_que(vha, qpair->req);
        if (ret != QLA_SUCCESS)
index 0c3d907..352aba4 100644 (file)
@@ -307,3 +307,15 @@ qla_83xx_start_iocbs(struct qla_qpair *qpair)
 
        WRT_REG_DWORD(req->req_q_in, req->ring_index);
 }
+
+static inline int
+qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
+{
+       uint32_t data;
+
+       data =
+           ((uint8_t *)vha->hw->nvram)[NVRAM_DUAL_FCP_NVME_FLAG_OFFSET];
+
+
+       return (data >> 6) & BIT_0 ? FC4_PRIORITY_FCP : FC4_PRIORITY_NVME;
+}
index 518eb95..b25f87f 100644 (file)
@@ -2740,6 +2740,10 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
        struct scsi_qla_host *vha = sp->vha;
        struct event_arg ea;
        struct qla_work_evt *e;
+       struct fc_port *conflict_fcport;
+       port_id_t cid;  /* conflict Nport id */
+       u32 *fw_status = sp->u.iocb_cmd.u.els_plogi.fw_status;
+       u16 lid;
 
        ql_dbg(ql_dbg_disc, vha, 0x3072,
            "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n",
@@ -2751,14 +2755,101 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
        if (sp->flags & SRB_WAKEUP_ON_COMP)
                complete(&lio->u.els_plogi.comp);
        else {
-               if (res) {
-                       set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
-               } else {
+               switch (fw_status[0]) {
+               case CS_DATA_UNDERRUN:
+               case CS_COMPLETE:
                        memset(&ea, 0, sizeof(ea));
                        ea.fcport = fcport;
-                       ea.data[0] = MBS_COMMAND_COMPLETE;
-                       ea.sp = sp;
-                       qla24xx_handle_plogi_done_event(vha, &ea);
+                       ea.rc = res;
+                       qla_handle_els_plogi_done(vha, &ea);
+                       break;
+
+               case CS_IOCB_ERROR:
+                       switch (fw_status[1]) {
+                       case LSC_SCODE_PORTID_USED:
+                               lid = fw_status[2] & 0xffff;
+                               qlt_find_sess_invalidate_other(vha,
+                                   wwn_to_u64(fcport->port_name),
+                                   fcport->d_id, lid, &conflict_fcport);
+                               if (conflict_fcport) {
+                                       /*
+                                        * Another fcport shares the same
+                                        * loop_id & nport id; conflict
+                                        * fcport needs to finish cleanup
+                                        * before this fcport can proceed
+                                        * to login.
+                                        */
+                                       conflict_fcport->conflict = fcport;
+                                       fcport->login_pause = 1;
+                                       ql_dbg(ql_dbg_disc, vha, 0x20ed,
+                                           "%s %d %8phC pid %06x inuse with lid %#x post gidpn\n",
+                                           __func__, __LINE__,
+                                           fcport->port_name,
+                                           fcport->d_id.b24, lid);
+                               } else {
+                                       ql_dbg(ql_dbg_disc, vha, 0x20ed,
+                                           "%s %d %8phC pid %06x inuse with lid %#x sched del\n",
+                                           __func__, __LINE__,
+                                           fcport->port_name,
+                                           fcport->d_id.b24, lid);
+                                       qla2x00_clear_loop_id(fcport);
+                                       set_bit(lid, vha->hw->loop_id_map);
+                                       fcport->loop_id = lid;
+                                       fcport->keep_nport_handle = 0;
+                                       qlt_schedule_sess_for_deletion(fcport);
+                               }
+                               break;
+
+                       case LSC_SCODE_NPORT_USED:
+                               cid.b.domain = (fw_status[2] >> 16) & 0xff;
+                               cid.b.area   = (fw_status[2] >>  8) & 0xff;
+                               cid.b.al_pa  = fw_status[2] & 0xff;
+                               cid.b.rsvd_1 = 0;
+
+                               ql_dbg(ql_dbg_disc, vha, 0x20ec,
+                                   "%s %d %8phC lid %#x in use with pid %06x post gnl\n",
+                                   __func__, __LINE__, fcport->port_name,
+                                   fcport->loop_id, cid.b24);
+                               set_bit(fcport->loop_id,
+                                   vha->hw->loop_id_map);
+                               fcport->loop_id = FC_NO_LOOP_ID;
+                               qla24xx_post_gnl_work(vha, fcport);
+                               break;
+
+                       case LSC_SCODE_NOXCB:
+                               vha->hw->exch_starvation++;
+                               if (vha->hw->exch_starvation > 5) {
+                                       ql_log(ql_log_warn, vha, 0xd046,
+                                           "Exchange starvation. Resetting RISC\n");
+                                       vha->hw->exch_starvation = 0;
+                                       set_bit(ISP_ABORT_NEEDED,
+                                           &vha->dpc_flags);
+                                       qla2xxx_wake_dpc(vha);
+                               }
+                               /* fall through */
+                       default:
+                               ql_dbg(ql_dbg_disc, vha, 0x20eb,
+                                   "%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n",
+                                   __func__, sp->fcport->port_name,
+                                   fw_status[0], fw_status[1], fw_status[2]);
+
+                               fcport->flags &= ~FCF_ASYNC_SENT;
+                               fcport->disc_state = DSC_LOGIN_FAILED;
+                               set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+                               break;
+                       }
+                       break;
+
+               default:
+                       ql_dbg(ql_dbg_disc, vha, 0x20eb,
+                           "%s %8phC cmd error 2 fw_status 0x%x 0x%x 0x%x\n",
+                           __func__, sp->fcport->port_name,
+                           fw_status[0], fw_status[1], fw_status[2]);
+
+                       sp->fcport->flags &= ~FCF_ASYNC_SENT;
+                       sp->fcport->disc_state = DSC_LOGIN_FAILED;
+                       set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+                       break;
                }
 
                e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP);
@@ -2792,11 +2883,12 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
                return -ENOMEM;
        }
 
+       fcport->flags |= FCF_ASYNC_SENT;
+       fcport->disc_state = DSC_LOGIN_PEND;
        elsio = &sp->u.iocb_cmd;
        ql_dbg(ql_dbg_io, vha, 0x3073,
            "Enter: PLOGI portid=%06x\n", fcport->d_id.b24);
 
-       fcport->flags |= FCF_ASYNC_SENT;
        sp->type = SRB_ELS_DCMD;
        sp->name = "ELS_DCMD";
        sp->fcport = fcport;
index 009fd5a..1b8f297 100644 (file)
@@ -1227,11 +1227,32 @@ global_port_update:
                break;
 
        case MBA_IDC_AEN:
-               mb[4] = RD_REG_WORD(&reg24->mailbox4);
-               mb[5] = RD_REG_WORD(&reg24->mailbox5);
-               mb[6] = RD_REG_WORD(&reg24->mailbox6);
-               mb[7] = RD_REG_WORD(&reg24->mailbox7);
-               qla83xx_handle_8200_aen(vha, mb);
+               if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+                       ha->flags.fw_init_done = 0;
+                       ql_log(ql_log_warn, vha, 0xffff,
+                           "MPI Heartbeat stop. Chip reset needed. MB0[%xh] MB1[%xh] MB2[%xh] MB3[%xh]\n",
+                           mb[0], mb[1], mb[2], mb[3]);
+
+                       if ((mb[1] & BIT_8) ||
+                           (mb[2] & BIT_8)) {
+                               ql_log(ql_log_warn, vha, 0xd013,
+                                   "MPI Heartbeat stop. FW dump needed\n");
+                               ha->fw_dump_mpi = 1;
+                               ha->isp_ops->fw_dump(vha, 1);
+                       }
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+                       qla2xxx_wake_dpc(vha);
+               } else if (IS_QLA83XX(ha)) {
+                       mb[4] = RD_REG_WORD(&reg24->mailbox4);
+                       mb[5] = RD_REG_WORD(&reg24->mailbox5);
+                       mb[6] = RD_REG_WORD(&reg24->mailbox6);
+                       mb[7] = RD_REG_WORD(&reg24->mailbox7);
+                       qla83xx_handle_8200_aen(vha, mb);
+               } else {
+                       ql_dbg(ql_dbg_async, vha, 0x5052,
+                           "skip Heartbeat processing mb0-3=[0x%04x] [0x%04x] [0x%04x] [0x%04x]\n",
+                           mb[0], mb[1], mb[2], mb[3]);
+               }
                break;
 
        case MBA_DPORT_DIAGNOSTICS:
@@ -2466,6 +2487,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                return;
        }
 
+       if (sp->abort)
+               sp->aborted = 1;
+       else
+               sp->completed = 1;
+
        if (sp->cmd_type != TYPE_SRB) {
                req->outstanding_cmds[handle] = NULL;
                ql_dbg(ql_dbg_io, vha, 0x3015,
index 4a1f21c..0cf94f0 100644 (file)
@@ -1932,7 +1932,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
                pd24 = (struct port_database_24xx *) pd;
 
                /* Check for logged in state. */
-               if (fcport->fc4f_nvme) {
+               if (NVME_TARGET(ha, fcport)) {
                        current_login_state = pd24->current_login_state >> 4;
                        last_login_state = pd24->last_login_state >> 4;
                } else {
@@ -3899,8 +3899,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                                fcport->scan_state = QLA_FCPORT_FOUND;
                                fcport->n2n_flag = 1;
                                fcport->keep_nport_handle = 1;
+                               fcport->fc4_type = FS_FC4TYPE_FCP;
                                if (vha->flags.nvme_enabled)
-                                       fcport->fc4f_nvme = 1;
+                                       fcport->fc4_type |= FS_FC4TYPE_NVME;
 
                                switch (fcport->disc_state) {
                                case DSC_DELETED:
@@ -6287,17 +6288,13 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mbx_cmd_t *mcp)
        case  QLA_SUCCESS:
                ql_dbg(ql_dbg_mbx, vha, 0x119d, "%s: %s done.\n",
                    __func__, sp->name);
-               sp->free(sp);
                break;
        default:
                ql_dbg(ql_dbg_mbx, vha, 0x119e, "%s: %s Failed. %x.\n",
                    __func__, sp->name, rval);
-               sp->free(sp);
                break;
        }
 
-       return rval;
-
 done_free_sp:
        sp->free(sp);
 done:
@@ -6362,7 +6359,7 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport,
        uint64_t zero = 0;
        u8 current_login_state, last_login_state;
 
-       if (fcport->fc4f_nvme) {
+       if (NVME_TARGET(vha->hw, fcport)) {
                current_login_state = pd->current_login_state >> 4;
                last_login_state = pd->last_login_state >> 4;
        } else {
@@ -6397,8 +6394,8 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport,
        fcport->d_id.b.al_pa = pd->port_id[2];
        fcport->d_id.b.rsvd_1 = 0;
 
-       if (fcport->fc4f_nvme) {
-               fcport->port_type = 0;
+       if (NVME_TARGET(vha->hw, fcport)) {
+               fcport->port_type = FCT_NVME;
                if ((pd->prli_svc_param_word_3[0] & BIT_5) == 0)
                        fcport->port_type |= FCT_NVME_INITIATOR;
                if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0)
index 2382409..eabc512 100644 (file)
@@ -946,7 +946,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
 
        sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
        if (!sp)
-               goto done;
+               return rval;
 
        sp->type = SRB_CTRL_VP;
        sp->name = "ctrl_vp";
@@ -962,7 +962,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
                ql_dbg(ql_dbg_async, vha, 0xffff,
                    "%s: %s Failed submission. %x.\n",
                    __func__, sp->name, rval);
-               goto done_free_sp;
+               goto done;
        }
 
        ql_dbg(ql_dbg_vport, vha, 0x113f, "%s hndl %x submitted\n",
@@ -980,16 +980,13 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
        case QLA_SUCCESS:
                ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s done.\n",
                    __func__, sp->name);
-               goto done_free_sp;
+               break;
        default:
                ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s Failed. %x.\n",
                    __func__, sp->name, rval);
-               goto done_free_sp;
+               break;
        }
 done:
-       return rval;
-
-done_free_sp:
        sp->free(sp);
        return rval;
 }
index 6cc19e0..941aa53 100644 (file)
@@ -224,8 +224,8 @@ static void qla_nvme_abort_work(struct work_struct *work)
 
        if (ha->flags.host_shutting_down) {
                ql_log(ql_log_info, sp->fcport->vha, 0xffff,
-                   "%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n",
-                   __func__, sp, sp->type, atomic_read(&sp->ref_count));
+                   "%s Calling done on sp: %p, type: 0x%x\n",
+                   __func__, sp, sp->type);
                sp->done(sp, 0);
                goto out;
        }
index 726ad4c..8b84bc4 100644 (file)
@@ -698,11 +698,6 @@ void qla2x00_sp_compl(srb_t *sp, int res)
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct completion *comp = sp->comp;
 
-       if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
-               return;
-
-       atomic_dec(&sp->ref_count);
-
        sp->free(sp);
        cmd->result = res;
        CMD_SP(cmd) = NULL;
@@ -794,11 +789,6 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res)
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct completion *comp = sp->comp;
 
-       if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
-               return;
-
-       atomic_dec(&sp->ref_count);
-
        sp->free(sp);
        cmd->result = res;
        CMD_SP(cmd) = NULL;
@@ -903,7 +893,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 
        sp->u.scmd.cmd = cmd;
        sp->type = SRB_SCSI_CMD;
-       atomic_set(&sp->ref_count, 1);
+
        CMD_SP(cmd) = (void *)sp;
        sp->free = qla2x00_sp_free_dma;
        sp->done = qla2x00_sp_compl;
@@ -985,18 +975,16 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
 
        sp->u.scmd.cmd = cmd;
        sp->type = SRB_SCSI_CMD;
-       atomic_set(&sp->ref_count, 1);
        CMD_SP(cmd) = (void *)sp;
        sp->free = qla2xxx_qpair_sp_free_dma;
        sp->done = qla2xxx_qpair_sp_compl;
-       sp->qpair = qpair;
 
        rval = ha->isp_ops->start_scsi_mq(sp);
        if (rval != QLA_SUCCESS) {
                ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3078,
                    "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
                if (rval == QLA_INTERFACE_ERROR)
-                       goto qc24_fail_command;
+                       goto qc24_free_sp_fail_command;
                goto qc24_host_busy_free_sp;
        }
 
@@ -1008,6 +996,11 @@ qc24_host_busy_free_sp:
 qc24_target_busy:
        return SCSI_MLQUEUE_TARGET_BUSY;
 
+qc24_free_sp_fail_command:
+       sp->free(sp);
+       CMD_SP(cmd) = NULL;
+       qla2xxx_rel_qpair_sp(sp->qpair, sp);
+
 qc24_fail_command:
        cmd->scsi_done(cmd);
 
@@ -1184,16 +1177,6 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
        return return_status;
 }
 
-static int
-sp_get(struct srb *sp)
-{
-       if (!refcount_inc_not_zero((refcount_t *)&sp->ref_count))
-               /* kref get fail */
-               return ENXIO;
-       else
-               return 0;
-}
-
 #define ISP_REG_DISCONNECT 0xffffffffU
 /**************************************************************************
 * qla2x00_isp_reg_stat
@@ -1249,6 +1232,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        uint64_t lun;
        int rval;
        struct qla_hw_data *ha = vha->hw;
+       uint32_t ratov_j;
+       struct qla_qpair *qpair;
+       unsigned long flags;
 
        if (qla2x00_isp_reg_stat(ha)) {
                ql_log(ql_log_info, vha, 0x8042,
@@ -1261,13 +1247,26 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                return ret;
 
        sp = scsi_cmd_priv(cmd);
+       qpair = sp->qpair;
 
-       if (sp->fcport && sp->fcport->deleted)
+       if ((sp->fcport && sp->fcport->deleted) || !qpair)
                return SUCCESS;
 
-       /* Return if the command has already finished. */
-       if (sp_get(sp))
+       spin_lock_irqsave(qpair->qp_lock_ptr, flags);
+       if (sp->completed) {
+               spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
                return SUCCESS;
+       }
+
+       if (sp->abort || sp->aborted) {
+               spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+               return FAILED;
+       }
+
+       sp->abort = 1;
+       sp->comp = &comp;
+       spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+
 
        id = cmd->device->id;
        lun = cmd->device->lun;
@@ -1276,47 +1275,37 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
            "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n",
            vha->host_no, id, lun, sp, cmd, sp->handle);
 
+       /*
+        * Abort will release the original Command/sp from FW. Let the
+        * original command call scsi_done. In return, he will wakeup
+        * this sleeping thread.
+        */
        rval = ha->isp_ops->abort_command(sp);
+
        ql_dbg(ql_dbg_taskm, vha, 0x8003,
               "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval);
 
+       /* Wait for the command completion. */
+       ratov_j = ha->r_a_tov/10 * 4 * 1000;
+       ratov_j = msecs_to_jiffies(ratov_j);
        switch (rval) {
        case QLA_SUCCESS:
-               /*
-                * The command has been aborted. That means that the firmware
-                * won't report a completion.
-                */
-               sp->done(sp, DID_ABORT << 16);
-               ret = SUCCESS;
-               break;
-       case QLA_FUNCTION_PARAMETER_ERROR: {
-               /* Wait for the command completion. */
-               uint32_t ratov = ha->r_a_tov/10;
-               uint32_t ratov_j = msecs_to_jiffies(4 * ratov * 1000);
-
-               WARN_ON_ONCE(sp->comp);
-               sp->comp = &comp;
                if (!wait_for_completion_timeout(&comp, ratov_j)) {
                        ql_dbg(ql_dbg_taskm, vha, 0xffff,
                            "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n",
-                           __func__, ha->r_a_tov);
+                           __func__, ha->r_a_tov/10);
                        ret = FAILED;
                } else {
                        ret = SUCCESS;
                }
                break;
-       }
        default:
-               /*
-                * Either abort failed or abort and completion raced. Let
-                * the SCSI core retry the abort in the former case.
-                */
                ret = FAILED;
                break;
        }
 
        sp->comp = NULL;
-       atomic_dec(&sp->ref_count);
+
        ql_log(ql_log_info, vha, 0x801c,
            "Abort command issued nexus=%ld:%d:%llu -- %x.\n",
            vha->host_no, id, lun, ret);
@@ -1708,32 +1697,53 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res,
        scsi_qla_host_t *vha = qp->vha;
        struct qla_hw_data *ha = vha->hw;
        int rval;
+       bool ret_cmd;
+       uint32_t ratov_j;
 
-       if (sp_get(sp))
+       if (qla2x00_chip_is_down(vha)) {
+               sp->done(sp, res);
                return;
+       }
 
        if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS ||
            (sp->type == SRB_SCSI_CMD && !ha->flags.eeh_busy &&
             !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
             !qla2x00_isp_reg_stat(ha))) {
+               if (sp->comp) {
+                       sp->done(sp, res);
+                       return;
+               }
+
                sp->comp = &comp;
+               sp->abort =  1;
                spin_unlock_irqrestore(qp->qp_lock_ptr, *flags);
-               rval = ha->isp_ops->abort_command(sp);
 
+               rval = ha->isp_ops->abort_command(sp);
+               /* Wait for command completion. */
+               ret_cmd = false;
+               ratov_j = ha->r_a_tov/10 * 4 * 1000;
+               ratov_j = msecs_to_jiffies(ratov_j);
                switch (rval) {
                case QLA_SUCCESS:
-                       sp->done(sp, res);
+                       if (wait_for_completion_timeout(&comp, ratov_j)) {
+                               ql_dbg(ql_dbg_taskm, vha, 0xffff,
+                                   "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n",
+                                   __func__, ha->r_a_tov/10);
+                               ret_cmd = true;
+                       }
+                       /* else FW return SP to driver */
                        break;
-               case QLA_FUNCTION_PARAMETER_ERROR:
-                       wait_for_completion(&comp);
+               default:
+                       ret_cmd = true;
                        break;
                }
 
                spin_lock_irqsave(qp->qp_lock_ptr, *flags);
-               sp->comp = NULL;
+               if (ret_cmd && (!sp->completed || !sp->aborted))
+                       sp->done(sp, res);
+       } else {
+               sp->done(sp, res);
        }
-
-       atomic_dec(&sp->ref_count);
 }
 
 static void
@@ -1755,7 +1765,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
        for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
                sp = req->outstanding_cmds[cnt];
                if (sp) {
-                       req->outstanding_cmds[cnt] = NULL;
                        switch (sp->cmd_type) {
                        case TYPE_SRB:
                                qla2x00_abort_srb(qp, sp, res, &flags);
@@ -1777,6 +1786,7 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
                        default:
                                break;
                        }
+                       req->outstanding_cmds[cnt] = NULL;
                }
        }
        spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
@@ -3492,6 +3502,29 @@ disable_device:
        return ret;
 }
 
+static void __qla_set_remove_flag(scsi_qla_host_t *base_vha)
+{
+       scsi_qla_host_t *vp;
+       unsigned long flags;
+       struct qla_hw_data *ha;
+
+       if (!base_vha)
+               return;
+
+       ha = base_vha->hw;
+
+       spin_lock_irqsave(&ha->vport_slock, flags);
+       list_for_each_entry(vp, &ha->vp_list, list)
+               set_bit(PFLG_DRIVER_REMOVING, &vp->pci_flags);
+
+       /*
+        * Indicate device removal to prevent future board_disable
+        * and wait until any pending board_disable has completed.
+        */
+       set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags);
+       spin_unlock_irqrestore(&ha->vport_slock, flags);
+}
+
 static void
 qla2x00_shutdown(struct pci_dev *pdev)
 {
@@ -3508,7 +3541,7 @@ qla2x00_shutdown(struct pci_dev *pdev)
         * Prevent future board_disable and wait
         * until any pending board_disable has completed.
         */
-       set_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags);
+       __qla_set_remove_flag(vha);
        cancel_work_sync(&ha->board_disable);
 
        if (!atomic_read(&pdev->enable_cnt))
@@ -3668,10 +3701,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
        ha = base_vha->hw;
        ql_log(ql_log_info, base_vha, 0xb079,
            "Removing driver\n");
-
-       /* Indicate device removal to prevent future board_disable and wait
-        * until any pending board_disable has completed. */
-       set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags);
+       __qla_set_remove_flag(base_vha);
        cancel_work_sync(&ha->board_disable);
 
        /*
@@ -4666,7 +4696,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        ha->sfp_data = NULL;
 
        if (ha->flt)
-               dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
+               dma_free_coherent(&ha->pdev->dev,
+                   sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE,
                    ha->flt, ha->flt_dma);
        ha->flt = NULL;
        ha->flt_dma = 0;
@@ -5042,19 +5073,17 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                        fcport->d_id = e->u.new_sess.id;
                        fcport->flags |= FCF_FABRIC_DEVICE;
                        fcport->fw_login_state = DSC_LS_PLOGI_PEND;
-                       if (e->u.new_sess.fc4_type == FS_FC4TYPE_FCP)
-                               fcport->fc4_type = FC4_TYPE_FCP_SCSI;
-
-                       if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) {
-                               fcport->fc4_type = FC4_TYPE_OTHER;
-                               fcport->fc4f_nvme = FC4_TYPE_NVME;
-                       }
 
                        memcpy(fcport->port_name, e->u.new_sess.port_name,
                            WWN_SIZE);
 
-                       if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N)
+                       fcport->fc4_type = e->u.new_sess.fc4_type;
+                       if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N) {
+                               fcport->fc4_type = FS_FC4TYPE_FCP;
                                fcport->n2n_flag = 1;
+                               if (vha->flags.nvme_enabled)
+                                       fcport->fc4_type |= FS_FC4TYPE_NVME;
+                       }
 
                } else {
                        ql_dbg(ql_dbg_disc, vha, 0xffff,
@@ -5158,7 +5187,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                                fcport->flags &= ~FCF_FABRIC_DEVICE;
                                fcport->keep_nport_handle = 1;
                                if (vha->flags.nvme_enabled) {
-                                       fcport->fc4f_nvme = 1;
+                                       fcport->fc4_type =
+                                           (FS_FC4TYPE_NVME | FS_FC4TYPE_FCP);
                                        fcport->n2n_flag = 1;
                                }
                                fcport->fw_login_state = 0;
index a06e562..51b275a 100644 (file)
@@ -463,7 +463,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
 
        case IMMED_NOTIFY_TYPE:
        {
-               struct scsi_qla_host *host = vha;
+               struct scsi_qla_host *host;
                struct imm_ntfy_from_isp *entry =
                    (struct imm_ntfy_from_isp *)pkt;
 
index 294d77c..5b0c057 100644 (file)
@@ -10,6 +10,7 @@
 #define ISPREG(vha)    (&(vha)->hw->iobase->isp24)
 #define IOBAR(reg)     offsetof(typeof(*(reg)), iobase_addr)
 #define IOBASE(vha)    IOBAR(ISPREG(vha))
+#define INVALID_ENTRY ((struct qla27xx_fwdt_entry *)0xffffffffffffffffUL)
 
 static inline void
 qla27xx_insert16(uint16_t value, void *buf, ulong *len)
@@ -261,6 +262,7 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
        ulong start = le32_to_cpu(ent->t262.start_addr);
        ulong end = le32_to_cpu(ent->t262.end_addr);
        ulong dwords;
+       int rc;
 
        ql_dbg(ql_dbg_misc, vha, 0xd206,
            "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
@@ -308,7 +310,13 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
        dwords = end - start + 1;
        if (buf) {
                buf += *len;
-               qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
+               rc = qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
+               if (rc != QLA_SUCCESS) {
+                       ql_dbg(ql_dbg_async, vha, 0xffff,
+                           "%s: dump ram MB failed. Area %xh start %lxh end %lxh\n",
+                           __func__, area, start, end);
+                       return INVALID_ENTRY;
+               }
        }
        *len += dwords * sizeof(uint32_t);
 done:
@@ -838,6 +846,13 @@ qla27xx_walk_template(struct scsi_qla_host *vha,
                ent = qla27xx_find_entry(type)(vha, ent, buf, len);
                if (!ent)
                        break;
+
+               if (ent == INVALID_ENTRY) {
+                       *len = 0;
+                       ql_dbg(ql_dbg_async, vha, 0xffff,
+                           "Unable to capture FW dump");
+                       goto bailout;
+               }
        }
 
        if (tmp->count)
@@ -847,6 +862,9 @@ qla27xx_walk_template(struct scsi_qla_host *vha,
        if (ent)
                ql_dbg(ql_dbg_misc, vha, 0xd019,
                    "%s: missing end entry\n", __func__);
+
+bailout:
+       cpu_to_le32s(&tmp->count);      /* endianize residual count */
 }
 
 static void
@@ -999,8 +1017,9 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
                uint j;
                ulong len;
                void *buf = vha->hw->fw_dump;
+               uint count = vha->hw->fw_dump_mpi ? 2 : 1;
 
-               for (j = 0; j < 2; j++, fwdt++, buf += len) {
+               for (j = 0; j < count; j++, fwdt++, buf += len) {
                        ql_log(ql_log_warn, vha, 0xd011,
                            "-> fwdt%u running...\n", j);
                        if (!fwdt->template) {
@@ -1010,7 +1029,9 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
                        }
                        len = qla27xx_execute_fwdt_template(vha,
                            fwdt->template, buf);
-                       if (len != fwdt->dump_size) {
+                       if (len == 0) {
+                               goto bailout;
+                       } else if (len != fwdt->dump_size) {
                                ql_log(ql_log_warn, vha, 0xd013,
                                    "-> fwdt%u fwdump residual=%+ld\n",
                                    j, fwdt->dump_size - len);
@@ -1025,6 +1046,8 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
                qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
        }
 
+bailout:
+       vha->hw->fw_dump_mpi = 0;
 #ifndef __CHECKER__
        if (!hardware_locked)
                spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
index a8f2a95..03bd3b7 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "10.01.00.19-k"
+#define QLA2XXX_VERSION      "10.01.00.21-k"
 
 #define QLA_DRIVER_MAJOR_VER   10
 #define QLA_DRIVER_MINOR_VER   1
index dac9a70..02636b4 100644 (file)
@@ -640,9 +640,6 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
 
        if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=
            QLA_SUCCESS) {
-               dma_free_coherent(&ha->pdev->dev,
-                                 sizeof(struct addr_ctrl_blk),
-                                 init_fw_cb, init_fw_cb_dma);
                goto exit_init_fw_cb;
        }
 
index 7a1b6c7..930e480 100644 (file)
@@ -186,7 +186,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
        struct scsi_driver *drv;
        unsigned int good_bytes;
 
-       scsi_device_unbusy(sdev);
+       scsi_device_unbusy(sdev, cmd);
 
        /*
         * Clear the flags that say that the device/target/host is no longer
@@ -465,10 +465,14 @@ void scsi_attach_vpd(struct scsi_device *sdev)
                return;
 
        for (i = 4; i < vpd_buf->len; i++) {
+               if (vpd_buf->data[i] == 0x0)
+                       scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0);
                if (vpd_buf->data[i] == 0x80)
                        scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80);
                if (vpd_buf->data[i] == 0x83)
                        scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83);
+               if (vpd_buf->data[i] == 0x89)
+                       scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89);
        }
        kfree(vpd_buf);
 }
index d323523..44cb054 100644 (file)
@@ -1025,7 +1025,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
 static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
                                  int arr_len, unsigned int off_dst)
 {
-       int act_len, n;
+       unsigned int act_len, n;
        struct scsi_data_buffer *sdb = &scp->sdb;
        off_t skip = off_dst;
 
@@ -1039,7 +1039,7 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
        pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
                 __func__, off_dst, scsi_bufflen(scp), act_len,
                 scsi_get_resid(scp));
-       n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
+       n = scsi_bufflen(scp) - (off_dst + act_len);
        scsi_set_resid(scp, min(scsi_get_resid(scp), n));
        return 0;
 }
@@ -5263,6 +5263,11 @@ static int __init scsi_debug_init(void)
                return -EINVAL;
        }
 
+       if (sdebug_num_tgts < 0) {
+               pr_err("num_tgts must be >= 0\n");
+               return -EINVAL;
+       }
+
        if (sdebug_guard > 1) {
                pr_err("guard must be 0 or 1\n");
                return -EINVAL;
index 91c007d..3e7a45d 100644 (file)
@@ -189,7 +189,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy)
         * active on the host/device.
         */
        if (unbusy)
-               scsi_device_unbusy(device);
+               scsi_device_unbusy(device, cmd);
 
        /*
         * Requeue this command.  It will go before all other commands
@@ -321,20 +321,20 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 }
 
 /*
- * Decrement the host_busy counter and wake up the error handler if necessary.
- * Avoid as follows that the error handler is not woken up if shost->host_busy
- * == shost->host_failed: use call_rcu() in scsi_eh_scmd_add() in combination
- * with an RCU read lock in this function to ensure that this function in its
- * entirety either finishes before scsi_eh_scmd_add() increases the
+ * Wake up the error handler if necessary. Avoid as follows that the error
+ * handler is not woken up if host in-flight requests number ==
+ * shost->host_failed: use call_rcu() in scsi_eh_scmd_add() in combination
+ * with an RCU read lock in this function to ensure that this function in
+ * its entirety either finishes before scsi_eh_scmd_add() increases the
  * host_failed counter or that it notices the shost state change made by
  * scsi_eh_scmd_add().
  */
-static void scsi_dec_host_busy(struct Scsi_Host *shost)
+static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 {
        unsigned long flags;
 
        rcu_read_lock();
-       atomic_dec(&shost->host_busy);
+       __clear_bit(SCMD_STATE_INFLIGHT, &cmd->state);
        if (unlikely(scsi_host_in_recovery(shost))) {
                spin_lock_irqsave(shost->host_lock, flags);
                if (shost->host_failed || shost->host_eh_scheduled)
@@ -344,12 +344,12 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost)
        rcu_read_unlock();
 }
 
-void scsi_device_unbusy(struct scsi_device *sdev)
+void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd)
 {
        struct Scsi_Host *shost = sdev->host;
        struct scsi_target *starget = scsi_target(sdev);
 
-       scsi_dec_host_busy(shost);
+       scsi_dec_host_busy(shost, cmd);
 
        if (starget->can_queue > 0)
                atomic_dec(&starget->target_busy);
@@ -430,9 +430,6 @@ static inline bool scsi_target_is_busy(struct scsi_target *starget)
 
 static inline bool scsi_host_is_busy(struct Scsi_Host *shost)
 {
-       if (shost->can_queue > 0 &&
-           atomic_read(&shost->host_busy) >= shost->can_queue)
-               return true;
        if (atomic_read(&shost->host_blocked) > 0)
                return true;
        if (shost->host_self_blocked)
@@ -1139,6 +1136,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
        unsigned int flags = cmd->flags & SCMD_PRESERVED_FLAGS;
        unsigned long jiffies_at_alloc;
        int retries;
+       bool in_flight;
 
        if (!blk_rq_is_scsi(rq) && !(flags & SCMD_INITIALIZED)) {
                flags |= SCMD_INITIALIZED;
@@ -1147,6 +1145,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
 
        jiffies_at_alloc = cmd->jiffies_at_alloc;
        retries = cmd->retries;
+       in_flight = test_bit(SCMD_STATE_INFLIGHT, &cmd->state);
        /* zero out the cmd, except for the embedded scsi_request */
        memset((char *)cmd + sizeof(cmd->req), 0,
                sizeof(*cmd) - sizeof(cmd->req) + dev->host->hostt->cmd_size);
@@ -1158,6 +1157,8 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
        INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
        cmd->jiffies_at_alloc = jiffies_at_alloc;
        cmd->retries = retries;
+       if (in_flight)
+               __set_bit(SCMD_STATE_INFLIGHT, &cmd->state);
 
        scsi_add_cmd_to_list(cmd);
 }
@@ -1367,16 +1368,14 @@ out_dec:
  */
 static inline int scsi_host_queue_ready(struct request_queue *q,
                                   struct Scsi_Host *shost,
-                                  struct scsi_device *sdev)
+                                  struct scsi_device *sdev,
+                                  struct scsi_cmnd *cmd)
 {
-       unsigned int busy;
-
        if (scsi_host_in_recovery(shost))
                return 0;
 
-       busy = atomic_inc_return(&shost->host_busy) - 1;
        if (atomic_read(&shost->host_blocked) > 0) {
-               if (busy)
+               if (scsi_host_busy(shost) > 0)
                        goto starved;
 
                /*
@@ -1390,8 +1389,6 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
                                     "unblocking host at zero depth\n"));
        }
 
-       if (shost->can_queue > 0 && busy >= shost->can_queue)
-               goto starved;
        if (shost->host_self_blocked)
                goto starved;
 
@@ -1403,6 +1400,8 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
                spin_unlock_irq(shost->host_lock);
        }
 
+       __set_bit(SCMD_STATE_INFLIGHT, &cmd->state);
+
        return 1;
 
 starved:
@@ -1411,7 +1410,7 @@ starved:
                list_add_tail(&sdev->starved_entry, &shost->starved_list);
        spin_unlock_irq(shost->host_lock);
 out_dec:
-       scsi_dec_host_busy(shost);
+       scsi_dec_host_busy(shost, cmd);
        return 0;
 }
 
@@ -1665,7 +1664,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
        ret = BLK_STS_RESOURCE;
        if (!scsi_target_queue_ready(shost, sdev))
                goto out_put_budget;
-       if (!scsi_host_queue_ready(q, shost, sdev))
+       if (!scsi_host_queue_ready(q, shost, sdev, cmd))
                goto out_dec_target_busy;
 
        if (!(req->rq_flags & RQF_DONTPREP)) {
@@ -1697,7 +1696,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
        return BLK_STS_OK;
 
 out_dec_host_busy:
-       scsi_dec_host_busy(shost);
+       scsi_dec_host_busy(shost, cmd);
 out_dec_target_busy:
        if (scsi_target(sdev)->can_queue > 0)
                atomic_dec(&scsi_target(sdev)->target_busy);
index c6ed0b1..c91fa3f 100644 (file)
@@ -390,6 +390,7 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
        const char *mlret_string = scsi_mlreturn_string(disposition);
        const char *hb_string = scsi_hostbyte_string(cmd->result);
        const char *db_string = scsi_driverbyte_string(cmd->result);
+       unsigned long cmd_age = (jiffies - cmd->jiffies_at_alloc) / HZ;
 
        logbuf = scsi_log_reserve_buffer(&logbuf_len);
        if (!logbuf)
@@ -431,10 +432,15 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
 
        if (db_string)
                off += scnprintf(logbuf + off, logbuf_len - off,
-                                "driverbyte=%s", db_string);
+                                "driverbyte=%s ", db_string);
        else
                off += scnprintf(logbuf + off, logbuf_len - off,
-                                "driverbyte=0x%02x", driver_byte(cmd->result));
+                                "driverbyte=0x%02x ",
+                                driver_byte(cmd->result));
+
+       off += scnprintf(logbuf + off, logbuf_len - off,
+                        "cmd_age=%lus", cmd_age);
+
 out_printk:
        dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
        scsi_log_release_buffer(logbuf);
index cc2859d..3bff9f7 100644 (file)
@@ -87,7 +87,7 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd);
 extern void scsi_add_cmd_to_list(struct scsi_cmnd *cmd);
 extern void scsi_del_cmd_from_list(struct scsi_cmnd *cmd);
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
-extern void scsi_device_unbusy(struct scsi_device *sdev);
+extern void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd);
 extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
index cc51f47..677b5c5 100644 (file)
@@ -437,6 +437,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
        struct device *parent;
        struct list_head *this, *tmp;
        struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
+       struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
        unsigned long flags;
 
        sdev = container_of(work, struct scsi_device, ew.work);
@@ -466,16 +467,24 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
        sdev->request_queue = NULL;
 
        mutex_lock(&sdev->inquiry_mutex);
+       vpd_pg0 = rcu_replace_pointer(sdev->vpd_pg0, vpd_pg0,
+                                      lockdep_is_held(&sdev->inquiry_mutex));
        vpd_pg80 = rcu_replace_pointer(sdev->vpd_pg80, vpd_pg80,
                                       lockdep_is_held(&sdev->inquiry_mutex));
        vpd_pg83 = rcu_replace_pointer(sdev->vpd_pg83, vpd_pg83,
                                       lockdep_is_held(&sdev->inquiry_mutex));
+       vpd_pg89 = rcu_replace_pointer(sdev->vpd_pg89, vpd_pg89,
+                                      lockdep_is_held(&sdev->inquiry_mutex));
        mutex_unlock(&sdev->inquiry_mutex);
 
+       if (vpd_pg0)
+               kfree_rcu(vpd_pg0, rcu);
        if (vpd_pg83)
                kfree_rcu(vpd_pg83, rcu);
        if (vpd_pg80)
                kfree_rcu(vpd_pg80, rcu);
+       if (vpd_pg89)
+               kfree_rcu(vpd_pg89, rcu);
        kfree(sdev->inquiry);
        kfree(sdev);
 
@@ -868,6 +877,8 @@ static struct bin_attribute dev_attr_vpd_##_page = {                \
 
 sdev_vpd_pg_attr(pg83);
 sdev_vpd_pg_attr(pg80);
+sdev_vpd_pg_attr(pg89);
+sdev_vpd_pg_attr(pg0);
 
 static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
                            struct bin_attribute *bin_attr,
@@ -1200,12 +1211,18 @@ static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
        struct scsi_device *sdev = to_scsi_device(dev);
 
 
+       if (attr == &dev_attr_vpd_pg0 && !sdev->vpd_pg0)
+               return 0;
+
        if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80)
                return 0;
 
        if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83)
                return 0;
 
+       if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89)
+               return 0;
+
        return S_IRUGO;
 }
 
@@ -1248,8 +1265,10 @@ static struct attribute *scsi_sdev_attrs[] = {
 };
 
 static struct bin_attribute *scsi_sdev_bin_attrs[] = {
+       &dev_attr_vpd_pg0,
        &dev_attr_vpd_pg83,
        &dev_attr_vpd_pg80,
+       &dev_attr_vpd_pg89,
        &dev_attr_inquiry,
        NULL
 };
@@ -1309,7 +1328,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
        device_enable_async_suspend(&sdev->sdev_gendev);
        scsi_autopm_get_target(starget);
        pm_runtime_set_active(&sdev->sdev_gendev);
-       pm_runtime_forbid(&sdev->sdev_gendev);
+       if (!sdev->rpm_autosuspend)
+               pm_runtime_forbid(&sdev->sdev_gendev);
        pm_runtime_enable(&sdev->sdev_gendev);
        scsi_autopm_put_target(starget);
 
index 0f17e7d..ac35c30 100644 (file)
@@ -9,7 +9,7 @@
 #include <trace/events/scsi.h>
 
 #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
-#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
+#define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8]))
 
 static const char *
 scsi_trace_misc(struct trace_seq *, unsigned char *, int);
@@ -18,15 +18,18 @@ static const char *
 scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p);
-       sector_t lba = 0, txlen = 0;
+       u32 lba = 0, txlen;
 
        lba |= ((cdb[1] & 0x1F) << 16);
        lba |=  (cdb[2] << 8);
        lba |=   cdb[3];
-       txlen = cdb[4];
+       /*
+        * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 256
+        * logical blocks shall be read (READ(6)) or written (WRITE(6)).
+        */
+       txlen = cdb[4] ? cdb[4] : 256;
 
-       trace_seq_printf(p, "lba=%llu txlen=%llu",
-                        (unsigned long long)lba, (unsigned long long)txlen);
+       trace_seq_printf(p, "lba=%u txlen=%u", lba, txlen);
        trace_seq_putc(p, 0);
 
        return ret;
@@ -36,17 +39,12 @@ static const char *
 scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p);
-       sector_t lba = 0, txlen = 0;
+       u32 lba, txlen;
 
-       lba |= (cdb[2] << 24);
-       lba |= (cdb[3] << 16);
-       lba |= (cdb[4] << 8);
-       lba |=  cdb[5];
-       txlen |= (cdb[7] << 8);
-       txlen |=  cdb[8];
+       lba = get_unaligned_be32(&cdb[2]);
+       txlen = get_unaligned_be16(&cdb[7]);
 
-       trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
-                        (unsigned long long)lba, (unsigned long long)txlen,
+       trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,
                         cdb[1] >> 5);
 
        if (cdb[0] == WRITE_SAME)
@@ -61,19 +59,12 @@ static const char *
 scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p);
-       sector_t lba = 0, txlen = 0;
-
-       lba |= (cdb[2] << 24);
-       lba |= (cdb[3] << 16);
-       lba |= (cdb[4] << 8);
-       lba |=  cdb[5];
-       txlen |= (cdb[6] << 24);
-       txlen |= (cdb[7] << 16);
-       txlen |= (cdb[8] << 8);
-       txlen |=  cdb[9];
-
-       trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
-                        (unsigned long long)lba, (unsigned long long)txlen,
+       u32 lba, txlen;
+
+       lba = get_unaligned_be32(&cdb[2]);
+       txlen = get_unaligned_be32(&cdb[6]);
+
+       trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,
                         cdb[1] >> 5);
        trace_seq_putc(p, 0);
 
@@ -84,23 +75,13 @@ static const char *
 scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p);
-       sector_t lba = 0, txlen = 0;
-
-       lba |= ((u64)cdb[2] << 56);
-       lba |= ((u64)cdb[3] << 48);
-       lba |= ((u64)cdb[4] << 40);
-       lba |= ((u64)cdb[5] << 32);
-       lba |= (cdb[6] << 24);
-       lba |= (cdb[7] << 16);
-       lba |= (cdb[8] << 8);
-       lba |=  cdb[9];
-       txlen |= (cdb[10] << 24);
-       txlen |= (cdb[11] << 16);
-       txlen |= (cdb[12] << 8);
-       txlen |=  cdb[13];
-
-       trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
-                        (unsigned long long)lba, (unsigned long long)txlen,
+       u64 lba;
+       u32 txlen;
+
+       lba = get_unaligned_be64(&cdb[2]);
+       txlen = get_unaligned_be32(&cdb[10]);
+
+       trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen,
                         cdb[1] >> 5);
 
        if (cdb[0] == WRITE_SAME_16)
@@ -115,8 +96,8 @@ static const char *
 scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p), *cmd;
-       sector_t lba = 0, txlen = 0;
-       u32 ei_lbrt = 0;
+       u64 lba;
+       u32 ei_lbrt, txlen;
 
        switch (SERVICE_ACTION32(cdb)) {
        case READ_32:
@@ -136,26 +117,12 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
                goto out;
        }
 
-       lba |= ((u64)cdb[12] << 56);
-       lba |= ((u64)cdb[13] << 48);
-       lba |= ((u64)cdb[14] << 40);
-       lba |= ((u64)cdb[15] << 32);
-       lba |= (cdb[16] << 24);
-       lba |= (cdb[17] << 16);
-       lba |= (cdb[18] << 8);
-       lba |=  cdb[19];
-       ei_lbrt |= (cdb[20] << 24);
-       ei_lbrt |= (cdb[21] << 16);
-       ei_lbrt |= (cdb[22] << 8);
-       ei_lbrt |=  cdb[23];
-       txlen |= (cdb[28] << 24);
-       txlen |= (cdb[29] << 16);
-       txlen |= (cdb[30] << 8);
-       txlen |=  cdb[31];
-
-       trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
-                        cmd, (unsigned long long)lba,
-                        (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
+       lba = get_unaligned_be64(&cdb[12]);
+       ei_lbrt = get_unaligned_be32(&cdb[20]);
+       txlen = get_unaligned_be32(&cdb[28]);
+
+       trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u",
+                        cmd, lba, txlen, cdb[10] >> 5, ei_lbrt);
 
        if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
                trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
@@ -170,7 +137,7 @@ static const char *
 scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p);
-       unsigned int regions = cdb[7] << 8 | cdb[8];
+       unsigned int regions = get_unaligned_be16(&cdb[7]);
 
        trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
        trace_seq_putc(p, 0);
@@ -182,8 +149,8 @@ static const char *
 scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
 {
        const char *ret = trace_seq_buffer_ptr(p), *cmd;
-       sector_t lba = 0;
-       u32 alloc_len = 0;
+       u64 lba;
+       u32 alloc_len;
 
        switch (SERVICE_ACTION16(cdb)) {
        case SAI_READ_CAPACITY_16:
@@ -197,21 +164,10 @@ scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
                goto out;
        }
 
-       lba |= ((u64)cdb[2] << 56);
-       lba |= ((u64)cdb[3] << 48);
-       lba |= ((u64)cdb[4] << 40);
-       lba |= ((u64)cdb[5] << 32);
-       lba |= (cdb[6] << 24);
-       lba |= (cdb[7] << 16);
-       lba |= (cdb[8] << 8);
-       lba |=  cdb[9];
-       alloc_len |= (cdb[10] << 24);
-       alloc_len |= (cdb[11] << 16);
-       alloc_len |= (cdb[12] << 8);
-       alloc_len |=  cdb[13];
-
-       trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
-                        (unsigned long long)lba, alloc_len);
+       lba = get_unaligned_be64(&cdb[2]);
+       alloc_len = get_unaligned_be32(&cdb[10]);
+
+       trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len);
 
 out:
        trace_seq_putc(p, 0);
index 1392502..7dc1782 100644 (file)
@@ -3390,6 +3390,10 @@ static int sd_probe(struct device *dev)
        }
 
        blk_pm_runtime_init(sdp->request_queue, dev);
+       if (sdp->rpm_autosuspend) {
+               pm_runtime_set_autosuspend_delay(dev,
+                       sdp->host->hostt->rpm_autosuspend_delay);
+       }
        device_add_disk(dev, gd, NULL);
        if (sdkp->capacity)
                sd_dif_config_host(sdkp);
index 9e4ef22..160748a 100644 (file)
@@ -429,18 +429,26 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
        SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
                                      "sg_read: count=%d\n", (int) count));
 
-       if (!access_ok(buf, count))
-               return -EFAULT;
        if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
-               old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL);
-               if (!old_hdr)
-                       return -ENOMEM;
-               if (__copy_from_user(old_hdr, buf, SZ_SG_HEADER)) {
-                       retval = -EFAULT;
-                       goto free_old_hdr;
-               }
+               old_hdr = memdup_user(buf, SZ_SG_HEADER);
+               if (IS_ERR(old_hdr))
+                       return PTR_ERR(old_hdr);
                if (old_hdr->reply_len < 0) {
                        if (count >= SZ_SG_IO_HDR) {
+                               /*
+                                * This is stupid.
+                                *
+                                * We're copying the whole sg_io_hdr_t from user
+                                * space just to get the 'pack_id' field. But the
+                                * field is at different offsets for the compat
+                                * case, so we'll use "get_sg_io_hdr()" to copy
+                                * the whole thing and convert it.
+                                *
+                                * We could do something like just calculating the
+                                * offset based of 'in_compat_syscall()', but the
+                                * 'compat_sg_io_hdr' definition is in the wrong
+                                * place for that.
+                                */
                                sg_io_hdr_t *new_hdr;
                                new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL);
                                if (!new_hdr) {
@@ -537,7 +545,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
 
        /* Now copy the result back to the user buffer.  */
        if (count >= SZ_SG_HEADER) {
-               if (__copy_to_user(buf, old_hdr, SZ_SG_HEADER)) {
+               if (copy_to_user(buf, old_hdr, SZ_SG_HEADER)) {
                        retval = -EFAULT;
                        goto free_old_hdr;
                }
@@ -623,11 +631,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
              scsi_block_when_processing_errors(sdp->device)))
                return -ENXIO;
 
-       if (!access_ok(buf, count))
-               return -EFAULT; /* protects following copy_from_user()s + get_user()s */
        if (count < SZ_SG_HEADER)
                return -EIO;
-       if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+       if (copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
                return -EFAULT;
        blocking = !(filp->f_flags & O_NONBLOCK);
        if (old_hdr.reply_len < 0)
@@ -636,13 +642,15 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        if (count < (SZ_SG_HEADER + 6))
                return -EIO;    /* The minimum scsi command length is 6 bytes. */
 
+       buf += SZ_SG_HEADER;
+       if (get_user(opcode, buf))
+               return -EFAULT;
+
        if (!(srp = sg_add_request(sfp))) {
                SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sdp,
                                              "sg_write: queue full\n"));
                return -EDOM;
        }
-       buf += SZ_SG_HEADER;
-       __get_user(opcode, buf);
        mutex_lock(&sfp->f_mutex);
        if (sfp->next_cmd_len > 0) {
                cmd_size = sfp->next_cmd_len;
@@ -685,7 +693,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        hp->flags = input_size; /* structure abuse ... */
        hp->pack_id = old_hdr.pack_id;
        hp->usr_ptr = NULL;
-       if (__copy_from_user(cmnd, buf, cmd_size))
+       if (copy_from_user(cmnd, buf, cmd_size))
                return -EFAULT;
        /*
         * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV,
@@ -720,8 +728,6 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
 
        if (count < SZ_SG_IO_HDR)
                return -EINVAL;
-       if (!access_ok(buf, count))
-               return -EFAULT; /* protects following copy_from_user()s + get_user()s */
 
        sfp->cmd_q = 1; /* when sg_io_hdr seen, set command queuing on */
        if (!(srp = sg_add_request(sfp))) {
@@ -759,11 +765,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
                sg_remove_request(sfp, srp);
                return -EMSGSIZE;
        }
-       if (!access_ok(hp->cmdp, hp->cmd_len)) {
-               sg_remove_request(sfp, srp);
-               return -EFAULT; /* protects following copy_from_user()s + get_user()s */
-       }
-       if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
+       if (copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
                sg_remove_request(sfp, srp);
                return -EFAULT;
        }
@@ -940,8 +942,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
                        return -ENODEV;
                if (!scsi_block_when_processing_errors(sdp->device))
                        return -ENXIO;
-               if (!access_ok(p, SZ_SG_IO_HDR))
-                       return -EFAULT;
                result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
                                 1, read_only, 1, &srp);
                if (result < 0)
@@ -986,26 +986,21 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
        case SG_GET_LOW_DMA:
                return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
        case SG_GET_SCSI_ID:
-               if (!access_ok(p, sizeof (sg_scsi_id_t)))
-                       return -EFAULT;
-               else {
-                       sg_scsi_id_t __user *sg_idp = p;
+               {
+                       sg_scsi_id_t v;
 
                        if (atomic_read(&sdp->detaching))
                                return -ENODEV;
-                       __put_user((int) sdp->device->host->host_no,
-                                  &sg_idp->host_no);
-                       __put_user((int) sdp->device->channel,
-                                  &sg_idp->channel);
-                       __put_user((int) sdp->device->id, &sg_idp->scsi_id);
-                       __put_user((int) sdp->device->lun, &sg_idp->lun);
-                       __put_user((int) sdp->device->type, &sg_idp->scsi_type);
-                       __put_user((short) sdp->device->host->cmd_per_lun,
-                                  &sg_idp->h_cmd_per_lun);
-                       __put_user((short) sdp->device->queue_depth,
-                                  &sg_idp->d_queue_depth);
-                       __put_user(0, &sg_idp->unused[0]);
-                       __put_user(0, &sg_idp->unused[1]);
+                       memset(&v, 0, sizeof(v));
+                       v.host_no = sdp->device->host->host_no;
+                       v.channel = sdp->device->channel;
+                       v.scsi_id = sdp->device->id;
+                       v.lun = sdp->device->lun;
+                       v.scsi_type = sdp->device->type;
+                       v.h_cmd_per_lun = sdp->device->host->cmd_per_lun;
+                       v.d_queue_depth = sdp->device->queue_depth;
+                       if (copy_to_user(p, &v, sizeof(sg_scsi_id_t)))
+                               return -EFAULT;
                        return 0;
                }
        case SG_SET_FORCE_PACK_ID:
@@ -1015,20 +1010,16 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
                sfp->force_packid = val ? 1 : 0;
                return 0;
        case SG_GET_PACK_ID:
-               if (!access_ok(ip, sizeof (int)))
-                       return -EFAULT;
                read_lock_irqsave(&sfp->rq_list_lock, iflags);
                list_for_each_entry(srp, &sfp->rq_list, entry) {
                        if ((1 == srp->done) && (!srp->sg_io_owned)) {
                                read_unlock_irqrestore(&sfp->rq_list_lock,
                                                       iflags);
-                               __put_user(srp->header.pack_id, ip);
-                               return 0;
+                               return put_user(srp->header.pack_id, ip);
                        }
                }
                read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-               __put_user(-1, ip);
-               return 0;
+               return put_user(-1, ip);
        case SG_GET_NUM_WAITING:
                read_lock_irqsave(&sfp->rq_list_lock, iflags);
                val = 0;
@@ -2017,12 +2008,12 @@ sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
        num = 1 << (PAGE_SHIFT + schp->page_order);
        for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
                if (num > num_read_xfer) {
-                       if (__copy_to_user(outp, page_address(schp->pages[k]),
+                       if (copy_to_user(outp, page_address(schp->pages[k]),
                                           num_read_xfer))
                                return -EFAULT;
                        break;
                } else {
-                       if (__copy_to_user(outp, page_address(schp->pages[k]),
+                       if (copy_to_user(outp, page_address(schp->pages[k]),
                                           num))
                                return -EFAULT;
                        num_read_xfer -= num;
index 79d2af3..1129fe7 100644 (file)
@@ -276,7 +276,9 @@ struct pqi_raid_path_request {
        u8      reserved4 : 2;
        u8      additional_cdb_bytes_usage : 3;
        u8      reserved5 : 3;
-       u8      cdb[32];
+       u8      cdb[16];
+       u8      reserved6[12];
+       __le32  timeout;
        struct pqi_sg_descriptor
                sg_descriptors[PQI_MAX_EMBEDDED_SG_DESCRIPTORS];
 };
@@ -385,7 +387,8 @@ struct pqi_task_management_request {
        struct pqi_iu_header header;
        __le16  request_id;
        __le16  nexus_id;
-       u8      reserved[4];
+       u8      reserved[2];
+       __le16  timeout;
        u8      lun_number[8];
        __le16  protocol_specific;
        __le16  outbound_queue_id_to_manage;
@@ -445,7 +448,7 @@ struct pqi_vendor_general_response {
 
 struct pqi_ofa_memory {
        __le64  signature;      /* "OFA_QRM" */
-       __le16  version;        /* version of this struct(1 = 1st version) */
+       __le16  version;        /* version of this struct (1 = 1st version) */
        u8      reserved[62];
        __le32  bytes_allocated;        /* total allocated memory in bytes */
        __le16  num_memory_descriptors;
@@ -761,6 +764,8 @@ struct pqi_config_table_firmware_features {
 #define PQI_FIRMWARE_FEATURE_OFA                       0
 #define PQI_FIRMWARE_FEATURE_SMP                       1
 #define PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE      11
+#define PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT           13
+#define PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT            14
 
 struct pqi_config_table_debug {
        struct pqi_config_table_section_header header;
@@ -826,10 +831,17 @@ union pqi_reset_register {
 
 struct report_lun_header {
        __be32  list_length;
-       u8      extended_response;
+       u8      flags;
        u8      reserved[3];
 };
 
+/* for flags field of struct report_lun_header */
+#define CISS_REPORT_LOG_FLAG_UNIQUE_LUN_ID     (1 << 0)
+#define CISS_REPORT_LOG_FLAG_QUEUE_DEPTH       (1 << 5)
+#define CISS_REPORT_LOG_FLAG_DRIVE_TYPE_MIX    (1 << 6)
+
+#define CISS_REPORT_PHYS_FLAG_OTHER            (1 << 1)
+
 struct report_log_lun_extended_entry {
        u8      lunid[8];
        u8      volume_id[16];
@@ -851,7 +863,7 @@ struct report_phys_lun_extended_entry {
 };
 
 /* for device_flags field of struct report_phys_lun_extended_entry */
-#define REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED   0x8
+#define CISS_REPORT_PHYS_DEV_FLAG_AIO_ENABLED  0x8
 
 struct report_phys_lun_extended {
        struct report_lun_header header;
@@ -864,7 +876,7 @@ struct raid_map_disk_data {
        u8      reserved[2];
 };
 
-/* constants for flags field of RAID map */
+/* for flags field of RAID map */
 #define RAID_MAP_ENCRYPTION_ENABLED    0x1
 
 struct raid_map {
@@ -907,7 +919,6 @@ struct pqi_scsi_dev {
        u8      scsi3addr[8];
        __be64  wwid;
        u8      volume_id[16];
-       u8      unique_id[16];
        u8      is_physical_device : 1;
        u8      is_external_raid_device : 1;
        u8      is_expander_smp_device : 1;
@@ -954,13 +965,9 @@ struct pqi_scsi_dev {
 };
 
 /* VPD inquiry pages */
-#define SCSI_VPD_SUPPORTED_PAGES       0x0     /* standard page */
-#define SCSI_VPD_DEVICE_ID             0x83    /* standard page */
 #define CISS_VPD_LV_DEVICE_GEOMETRY    0xc1    /* vendor-specific page */
 #define CISS_VPD_LV_BYPASS_STATUS      0xc2    /* vendor-specific page */
 #define CISS_VPD_LV_STATUS             0xc3    /* vendor-specific page */
-#define SCSI_VPD_HEADER_SZ             4
-#define SCSI_VPD_DEVICE_ID_IDX         8       /* Index of page id in page */
 
 #define VPD_PAGE       (1 << 8)
 
@@ -1130,13 +1137,16 @@ struct pqi_ctrl_info {
        struct mutex    ofa_mutex; /* serialize ofa */
        bool            controller_online;
        bool            block_requests;
-       bool            in_shutdown;
+       bool            block_device_reset;
        bool            in_ofa;
+       bool            in_shutdown;
        u8              inbound_spanning_supported : 1;
        u8              outbound_spanning_supported : 1;
        u8              pqi_mode_enabled : 1;
        u8              pqi_reset_quiesce_supported : 1;
        u8              soft_reset_handshake_supported : 1;
+       u8              raid_iu_timeout_supported: 1;
+       u8              tmf_iu_timeout_supported: 1;
 
        struct list_head scsi_device_list;
        spinlock_t      scsi_device_list_lock;
@@ -1170,9 +1180,10 @@ struct pqi_ctrl_info {
        spinlock_t      raid_bypass_retry_list_lock;
        struct work_struct raid_bypass_retry_work;
 
-       struct          pqi_ofa_memory *pqi_ofa_mem_virt_addr;
-       dma_addr_t      pqi_ofa_mem_dma_handle;
-       void            **pqi_ofa_chunk_virt_addr;
+       struct pqi_ofa_memory *pqi_ofa_mem_virt_addr;
+       dma_addr_t      pqi_ofa_mem_dma_handle;
+       void            **pqi_ofa_chunk_virt_addr;
+       atomic_t        sync_cmds_outstanding;
 };
 
 enum pqi_ctrl_mode {
@@ -1191,10 +1202,6 @@ enum pqi_ctrl_mode {
 #define CISS_REPORT_PHYS       0xc3    /* Report Physical LUNs */
 #define CISS_GET_RAID_MAP      0xc8
 
-/* constants for CISS_REPORT_LOG/CISS_REPORT_PHYS commands */
-#define CISS_REPORT_LOG_EXTENDED               0x1
-#define CISS_REPORT_PHYS_EXTENDED              0x2
-
 /* BMIC commands */
 #define BMIC_IDENTIFY_CONTROLLER               0x11
 #define BMIC_IDENTIFY_PHYSICAL_DEVICE          0x15
@@ -1208,7 +1215,7 @@ enum pqi_ctrl_mode {
 #define BMIC_SET_DIAG_OPTIONS                  0xf4
 #define BMIC_SENSE_DIAG_OPTIONS                        0xf5
 
-#define CSMI_CC_SAS_SMP_PASSTHRU               0X17
+#define CSMI_CC_SAS_SMP_PASSTHRU               0x17
 
 #define SA_FLUSH_CACHE                         0x1
 
@@ -1244,10 +1251,12 @@ struct bmic_sense_subsystem_info {
        u8      ctrl_serial_number[16];
 };
 
-#define SA_EXPANDER_SMP_DEVICE         0x05
-#define SA_CONTROLLER_DEVICE           0x07
-/*SCSI Invalid Device Type for SAS devices*/
-#define PQI_SAS_SCSI_INVALID_DEVTYPE   0xff
+/* constants for device_type field */
+#define SA_DEVICE_TYPE_SATA            0x1
+#define SA_DEVICE_TYPE_SAS             0x2
+#define SA_DEVICE_TYPE_EXPANDER_SMP    0x5
+#define SA_DEVICE_TYPE_CONTROLLER      0x7
+#define SA_DEVICE_TYPE_NVME            0x9
 
 struct bmic_identify_physical_device {
        u8      scsi_bus;               /* SCSI Bus number on controller */
@@ -1273,7 +1282,7 @@ struct bmic_identify_physical_device {
        __le32  rpm;                    /* drive rotational speed in RPM */
        u8      device_type;            /* type of drive */
        u8      sata_version;           /* only valid when device_type = */
-                                       /* BMIC_DEVICE_TYPE_SATA */
+                                       /* SA_DEVICE_TYPE_SATA */
        __le64  big_total_block_count;
        __le64  ris_starting_lba;
        __le32  ris_size;
@@ -1396,18 +1405,6 @@ struct bmic_diag_options {
 
 #pragma pack()
 
-static inline struct pqi_ctrl_info *shost_to_hba(struct Scsi_Host *shost)
-{
-       void *hostdata = shost_priv(shost);
-
-       return *((struct pqi_ctrl_info **)hostdata);
-}
-
-static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
-{
-       return !ctrl_info->controller_online;
-}
-
 static inline void pqi_ctrl_busy(struct pqi_ctrl_info *ctrl_info)
 {
        atomic_inc(&ctrl_info->num_busy_threads);
@@ -1418,9 +1415,11 @@ static inline void pqi_ctrl_unbusy(struct pqi_ctrl_info *ctrl_info)
        atomic_dec(&ctrl_info->num_busy_threads);
 }
 
-static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info)
+static inline struct pqi_ctrl_info *shost_to_hba(struct Scsi_Host *shost)
 {
-       return ctrl_info->block_requests;
+       void *hostdata = shost_priv(shost);
+
+       return *((struct pqi_ctrl_info **)hostdata);
 }
 
 void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
index ea5409b..7b7ef3a 100644 (file)
 #define BUILD_TIMESTAMP
 #endif
 
-#define DRIVER_VERSION         "1.2.8-026"
+#define DRIVER_VERSION         "1.2.10-025"
 #define DRIVER_MAJOR           1
 #define DRIVER_MINOR           2
-#define DRIVER_RELEASE         8
-#define DRIVER_REVISION                26
+#define DRIVER_RELEASE         10
+#define DRIVER_REVISION                25
 
 #define DRIVER_NAME            "Microsemi PQI Driver (v" \
                                DRIVER_VERSION BUILD_TIMESTAMP ")"
@@ -211,6 +211,11 @@ static inline bool pqi_is_external_raid_addr(u8 *scsi3addr)
        return scsi3addr[2] != 0;
 }
 
+static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
+{
+       return !ctrl_info->controller_online;
+}
+
 static inline void pqi_check_ctrl_health(struct pqi_ctrl_info *ctrl_info)
 {
        if (ctrl_info->controller_online)
@@ -235,6 +240,21 @@ static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info *ctrl_info,
        sis_write_driver_scratch(ctrl_info, mode);
 }
 
+static inline void pqi_ctrl_block_device_reset(struct pqi_ctrl_info *ctrl_info)
+{
+       ctrl_info->block_device_reset = true;
+}
+
+static inline bool pqi_device_reset_blocked(struct pqi_ctrl_info *ctrl_info)
+{
+       return ctrl_info->block_device_reset;
+}
+
+static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info)
+{
+       return ctrl_info->block_requests;
+}
+
 static inline void pqi_ctrl_block_requests(struct pqi_ctrl_info *ctrl_info)
 {
        ctrl_info->block_requests = true;
@@ -331,6 +351,16 @@ static inline bool pqi_device_in_remove(struct pqi_ctrl_info *ctrl_info,
        return device->in_remove && !ctrl_info->in_shutdown;
 }
 
+static inline void pqi_ctrl_shutdown_start(struct pqi_ctrl_info *ctrl_info)
+{
+       ctrl_info->in_shutdown = true;
+}
+
+static inline bool pqi_ctrl_in_shutdown(struct pqi_ctrl_info *ctrl_info)
+{
+       return ctrl_info->in_shutdown;
+}
+
 static inline void pqi_schedule_rescan_worker_with_delay(
        struct pqi_ctrl_info *ctrl_info, unsigned long delay)
 {
@@ -360,6 +390,11 @@ static inline void pqi_cancel_rescan_worker(struct pqi_ctrl_info *ctrl_info)
        cancel_delayed_work_sync(&ctrl_info->rescan_work);
 }
 
+static inline void pqi_cancel_event_worker(struct pqi_ctrl_info *ctrl_info)
+{
+       cancel_work_sync(&ctrl_info->event_work);
+}
+
 static inline u32 pqi_read_heartbeat_counter(struct pqi_ctrl_info *ctrl_info)
 {
        if (!ctrl_info->heartbeat_counter)
@@ -377,7 +412,7 @@ static inline u8 pqi_read_soft_reset_status(struct pqi_ctrl_info *ctrl_info)
 }
 
 static inline void pqi_clear_soft_reset_status(struct pqi_ctrl_info *ctrl_info,
-                                               u8 clear)
+       u8 clear)
 {
        u8 status;
 
@@ -462,9 +497,9 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
                request->data_direction = SOP_READ_FLAG;
                cdb[0] = cmd;
                if (cmd == CISS_REPORT_PHYS)
-                       cdb[1] = CISS_REPORT_PHYS_EXTENDED;
+                       cdb[1] = CISS_REPORT_PHYS_FLAG_OTHER;
                else
-                       cdb[1] = CISS_REPORT_LOG_EXTENDED;
+                       cdb[1] = CISS_REPORT_LOG_FLAG_UNIQUE_LUN_ID;
                put_unaligned_be32(cdb_length, &cdb[6]);
                break;
        case CISS_GET_RAID_MAP:
@@ -567,13 +602,12 @@ static void pqi_free_io_request(struct pqi_io_request *io_request)
 }
 
 static int pqi_send_scsi_raid_request(struct pqi_ctrl_info *ctrl_info, u8 cmd,
-               u8 *scsi3addr, void *buffer, size_t buffer_length, u16 vpd_page,
-               struct pqi_raid_error_info *error_info,
-               unsigned long timeout_msecs)
+       u8 *scsi3addr, void *buffer, size_t buffer_length, u16 vpd_page,
+       struct pqi_raid_error_info *error_info, unsigned long timeout_msecs)
 {
        int rc;
-       enum dma_data_direction dir;
        struct pqi_raid_path_request request;
+       enum dma_data_direction dir;
 
        rc = pqi_build_raid_path_request(ctrl_info, &request,
                cmd, scsi3addr, buffer,
@@ -581,44 +615,44 @@ static int pqi_send_scsi_raid_request(struct pqi_ctrl_info *ctrl_info, u8 cmd,
        if (rc)
                return rc;
 
-       rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
-                0, error_info, timeout_msecs);
+       rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
+               error_info, timeout_msecs);
 
        pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
+
        return rc;
 }
 
-/* Helper functions for pqi_send_scsi_raid_request */
+/* helper functions for pqi_send_scsi_raid_request */
 
 static inline int pqi_send_ctrl_raid_request(struct pqi_ctrl_info *ctrl_info,
-               u8 cmd, void *buffer, size_t buffer_length)
+       u8 cmd, void *buffer, size_t buffer_length)
 {
        return pqi_send_scsi_raid_request(ctrl_info, cmd, RAID_CTLR_LUNID,
-                       buffer, buffer_length, 0, NULL, NO_TIMEOUT);
+               buffer, buffer_length, 0, NULL, NO_TIMEOUT);
 }
 
 static inline int pqi_send_ctrl_raid_with_error(struct pqi_ctrl_info *ctrl_info,
-               u8 cmd, void *buffer, size_t buffer_length,
-               struct pqi_raid_error_info *error_info)
+       u8 cmd, void *buffer, size_t buffer_length,
+       struct pqi_raid_error_info *error_info)
 {
        return pqi_send_scsi_raid_request(ctrl_info, cmd, RAID_CTLR_LUNID,
-                       buffer, buffer_length, 0, error_info, NO_TIMEOUT);
+               buffer, buffer_length, 0, error_info, NO_TIMEOUT);
 }
 
-
 static inline int pqi_identify_controller(struct pqi_ctrl_info *ctrl_info,
-               struct bmic_identify_controller *buffer)
+       struct bmic_identify_controller *buffer)
 {
        return pqi_send_ctrl_raid_request(ctrl_info, BMIC_IDENTIFY_CONTROLLER,
-                       buffer, sizeof(*buffer));
+               buffer, sizeof(*buffer));
 }
 
 static inline int pqi_sense_subsystem_info(struct  pqi_ctrl_info *ctrl_info,
-               struct bmic_sense_subsystem_info *sense_info)
+       struct bmic_sense_subsystem_info *sense_info)
 {
        return pqi_send_ctrl_raid_request(ctrl_info,
-                       BMIC_SENSE_SUBSYSTEM_INFORMATION,
-                       sense_info, sizeof(*sense_info));
+               BMIC_SENSE_SUBSYSTEM_INFORMATION, sense_info,
+               sizeof(*sense_info));
 }
 
 static inline int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info,
@@ -628,83 +662,9 @@ static inline int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info,
                buffer, buffer_length, vpd_page, NULL, NO_TIMEOUT);
 }
 
-static bool pqi_vpd_page_supported(struct pqi_ctrl_info *ctrl_info,
-       u8 *scsi3addr, u16 vpd_page)
-{
-       int rc;
-       int i;
-       int pages;
-       unsigned char *buf, bufsize;
-
-       buf = kzalloc(256, GFP_KERNEL);
-       if (!buf)
-               return false;
-
-       /* Get the size of the page list first */
-       rc = pqi_scsi_inquiry(ctrl_info, scsi3addr,
-                               VPD_PAGE | SCSI_VPD_SUPPORTED_PAGES,
-                               buf, SCSI_VPD_HEADER_SZ);
-       if (rc != 0)
-               goto exit_unsupported;
-
-       pages = buf[3];
-       if ((pages + SCSI_VPD_HEADER_SZ) <= 255)
-               bufsize = pages + SCSI_VPD_HEADER_SZ;
-       else
-               bufsize = 255;
-
-       /* Get the whole VPD page list */
-       rc = pqi_scsi_inquiry(ctrl_info, scsi3addr,
-                               VPD_PAGE | SCSI_VPD_SUPPORTED_PAGES,
-                               buf, bufsize);
-       if (rc != 0)
-               goto exit_unsupported;
-
-       pages = buf[3];
-       for (i = 1; i <= pages; i++)
-               if (buf[3 + i] == vpd_page)
-                       goto exit_supported;
-
-exit_unsupported:
-       kfree(buf);
-       return false;
-
-exit_supported:
-       kfree(buf);
-       return true;
-}
-
-static int pqi_get_device_id(struct pqi_ctrl_info *ctrl_info,
-       u8 *scsi3addr, u8 *device_id, int buflen)
-{
-       int rc;
-       unsigned char *buf;
-
-       if (!pqi_vpd_page_supported(ctrl_info, scsi3addr, SCSI_VPD_DEVICE_ID))
-               return 1; /* function not supported */
-
-       buf = kzalloc(64, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       rc = pqi_scsi_inquiry(ctrl_info, scsi3addr,
-                               VPD_PAGE | SCSI_VPD_DEVICE_ID,
-                               buf, 64);
-       if (rc == 0) {
-               if (buflen > 16)
-                       buflen = 16;
-               memcpy(device_id, &buf[SCSI_VPD_DEVICE_ID_IDX], buflen);
-       }
-
-       kfree(buf);
-
-       return rc;
-}
-
 static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info,
        struct pqi_scsi_dev *device,
-       struct bmic_identify_physical_device *buffer,
-       size_t buffer_length)
+       struct bmic_identify_physical_device *buffer, size_t buffer_length)
 {
        int rc;
        enum dma_data_direction dir;
@@ -725,6 +685,7 @@ static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info,
                0, NULL, NO_TIMEOUT);
 
        pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
+
        return rc;
 }
 
@@ -763,7 +724,7 @@ int pqi_csmi_smp_passthru(struct pqi_ctrl_info *ctrl_info,
                buffer, buffer_length, error_info);
 }
 
-#define PQI_FETCH_PTRAID_DATA (1UL<<31)
+#define PQI_FETCH_PTRAID_DATA          (1 << 31)
 
 static int pqi_set_diag_rescan(struct pqi_ctrl_info *ctrl_info)
 {
@@ -775,14 +736,15 @@ static int pqi_set_diag_rescan(struct pqi_ctrl_info *ctrl_info)
                return -ENOMEM;
 
        rc = pqi_send_ctrl_raid_request(ctrl_info, BMIC_SENSE_DIAG_OPTIONS,
-                                       diag, sizeof(*diag));
+               diag, sizeof(*diag));
        if (rc)
                goto out;
 
        diag->options |= cpu_to_le32(PQI_FETCH_PTRAID_DATA);
 
-       rc = pqi_send_ctrl_raid_request(ctrl_info, BMIC_SET_DIAG_OPTIONS,
-                                       diag, sizeof(*diag));
+       rc = pqi_send_ctrl_raid_request(ctrl_info, BMIC_SET_DIAG_OPTIONS, diag,
+               sizeof(*diag));
+
 out:
        kfree(diag);
 
@@ -793,7 +755,7 @@ static inline int pqi_write_host_wellness(struct pqi_ctrl_info *ctrl_info,
        void *buffer, size_t buffer_length)
 {
        return pqi_send_ctrl_raid_request(ctrl_info, BMIC_WRITE_HOST_WELLNESS,
-                                       buffer, buffer_length);
+               buffer, buffer_length);
 }
 
 #pragma pack(1)
@@ -946,7 +908,7 @@ static inline int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
        void *buffer, size_t buffer_length)
 {
        return pqi_send_ctrl_raid_request(ctrl_info, cmd, buffer,
-                                       buffer_length);
+               buffer_length);
 }
 
 static int pqi_report_phys_logical_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
@@ -1280,9 +1242,9 @@ static void pqi_get_raid_bypass_status(struct pqi_ctrl_info *ctrl_info,
        if (rc)
                goto out;
 
-#define RAID_BYPASS_STATUS     4
-#define RAID_BYPASS_CONFIGURED 0x1
-#define RAID_BYPASS_ENABLED    0x2
+#define RAID_BYPASS_STATUS             4
+#define RAID_BYPASS_CONFIGURED         0x1
+#define RAID_BYPASS_ENABLED            0x2
 
        bypass_status = buffer[RAID_BYPASS_STATUS];
        device->raid_bypass_configured =
@@ -1385,14 +1347,6 @@ static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info,
                }
        }
 
-       if (pqi_get_device_id(ctrl_info, device->scsi3addr,
-               device->unique_id, sizeof(device->unique_id)) < 0)
-               dev_warn(&ctrl_info->pci_dev->dev,
-                       "Can't get device id for scsi %d:%d:%d:%d\n",
-                       ctrl_info->scsi_host->host_no,
-                       device->bus, device->target,
-                       device->lun);
-
 out:
        kfree(buffer);
 
@@ -1413,6 +1367,7 @@ static void pqi_get_physical_disk_info(struct pqi_ctrl_info *ctrl_info,
                device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH;
                return;
        }
+
        device->box_index = id_phys->box_index;
        device->phys_box_on_bus = id_phys->phys_box_on_bus;
        device->phy_connected_dev_type = id_phys->phy_connected_dev_type[0];
@@ -1828,7 +1783,7 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
                device = new_device_list[i];
 
                find_result = pqi_scsi_find_entry(ctrl_info, device,
-                                               &matching_device);
+                       &matching_device);
 
                switch (find_result) {
                case DEVICE_SAME:
@@ -2057,9 +2012,8 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
                        rc = -ENOMEM;
                        goto out;
                }
-               if (pqi_hide_vsep) {
-                       int i;
 
+               if (pqi_hide_vsep) {
                        for (i = num_physicals - 1; i >= 0; i--) {
                                phys_lun_ext_entry =
                                                &physdev_list->lun_entries[i];
@@ -2132,7 +2086,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
                device->is_physical_device = is_physical_device;
                if (is_physical_device) {
                        if (phys_lun_ext_entry->device_type ==
-                               SA_EXPANDER_SMP_DEVICE)
+                               SA_DEVICE_TYPE_EXPANDER_SMP)
                                device->is_expander_smp_device = true;
                } else {
                        device->is_external_raid_device =
@@ -2169,16 +2123,13 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
                if (device->is_physical_device) {
                        device->wwid = phys_lun_ext_entry->wwid;
                        if ((phys_lun_ext_entry->device_flags &
-                               REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED) &&
+                               CISS_REPORT_PHYS_DEV_FLAG_AIO_ENABLED) &&
                                phys_lun_ext_entry->aio_handle) {
                                device->aio_enabled = true;
-                                       device->aio_handle =
-                                               phys_lun_ext_entry->aio_handle;
+                               device->aio_handle =
+                                       phys_lun_ext_entry->aio_handle;
                        }
-
-                               pqi_get_physical_disk_info(ctrl_info,
-                                       device, id_phys);
-
+                       pqi_get_physical_disk_info(ctrl_info, device, id_phys);
                } else {
                        memcpy(device->volume_id, log_lun_ext_entry->volume_id,
                                sizeof(device->volume_id));
@@ -3158,7 +3109,7 @@ static enum pqi_soft_reset_status pqi_poll_for_soft_reset_status(
 }
 
 static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info,
-               enum pqi_soft_reset_status reset_status)
+       enum pqi_soft_reset_status reset_status)
 {
        int rc;
 
@@ -3202,8 +3153,8 @@ static void pqi_ofa_process_event(struct pqi_ctrl_info *ctrl_info,
 
        if (event_id == PQI_EVENT_OFA_QUIESCE) {
                dev_info(&ctrl_info->pci_dev->dev,
-                        "Received Online Firmware Activation quiesce event for controller %u\n",
-                        ctrl_info->ctrl_id);
+                       "Received Online Firmware Activation quiesce event for controller %u\n",
+                       ctrl_info->ctrl_id);
                pqi_ofa_ctrl_quiesce(ctrl_info);
                pqi_acknowledge_event(ctrl_info, event);
                if (ctrl_info->soft_reset_handshake_supported) {
@@ -3223,8 +3174,8 @@ static void pqi_ofa_process_event(struct pqi_ctrl_info *ctrl_info,
                pqi_ofa_free_host_buffer(ctrl_info);
                pqi_acknowledge_event(ctrl_info, event);
                dev_info(&ctrl_info->pci_dev->dev,
-                        "Online Firmware Activation(%u) cancel reason : %u\n",
-                        ctrl_info->ctrl_id, event->ofa_cancel_reason);
+                       "Online Firmware Activation(%u) cancel reason : %u\n",
+                       ctrl_info->ctrl_id, event->ofa_cancel_reason);
        }
 
        mutex_unlock(&ctrl_info->ofa_mutex);
@@ -3403,7 +3354,7 @@ static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info)
 #define PQI_LEGACY_INTX_MASK   0x1
 
 static inline void pqi_configure_legacy_intx(struct pqi_ctrl_info *ctrl_info,
-                                               bool enable_intx)
+       bool enable_intx)
 {
        u32 intx_mask;
        struct pqi_device_registers __iomem *pqi_registers;
@@ -3841,7 +3792,7 @@ static int pqi_create_admin_queues(struct pqi_ctrl_info *ctrl_info)
                &pqi_registers->admin_oq_pi_addr);
 
        reg = PQI_ADMIN_IQ_NUM_ELEMENTS |
-               (PQI_ADMIN_OQ_NUM_ELEMENTS) << 8 |
+               (PQI_ADMIN_OQ_NUM_ELEMENTS << 8) |
                (admin_queues->int_msg_num << 16);
        writel(reg, &pqi_registers->admin_iq_num_elements);
        writel(PQI_CREATE_ADMIN_QUEUE_PAIR,
@@ -4048,8 +3999,8 @@ static void pqi_raid_synchronous_complete(struct pqi_io_request *io_request,
        complete(waiting);
 }
 
-static int pqi_process_raid_io_error_synchronous(struct pqi_raid_error_info
-                                               *error_info)
+static int pqi_process_raid_io_error_synchronous(
+       struct pqi_raid_error_info *error_info)
 {
        int rc = -EIO;
 
@@ -4122,6 +4073,8 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
                goto out;
        }
 
+       atomic_inc(&ctrl_info->sync_cmds_outstanding);
+
        io_request = pqi_alloc_io_request(ctrl_info);
 
        put_unaligned_le16(io_request->index,
@@ -4168,6 +4121,7 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
 
        pqi_free_io_request(io_request);
 
+       atomic_dec(&ctrl_info->sync_cmds_outstanding);
 out:
        up(&ctrl_info->sync_request_sem);
 
@@ -4665,11 +4619,11 @@ static void pqi_free_all_io_requests(struct pqi_ctrl_info *ctrl_info)
 
 static inline int pqi_alloc_error_buffer(struct pqi_ctrl_info *ctrl_info)
 {
-       ctrl_info->error_buffer = dma_alloc_coherent(&ctrl_info->pci_dev->dev,
-                                                    ctrl_info->error_buffer_length,
-                                                    &ctrl_info->error_buffer_dma_handle,
-                                                    GFP_KERNEL);
 
+       ctrl_info->error_buffer = dma_alloc_coherent(&ctrl_info->pci_dev->dev,
+                                    ctrl_info->error_buffer_length,
+                                    &ctrl_info->error_buffer_dma_handle,
+                                    GFP_KERNEL);
        if (!ctrl_info->error_buffer)
                return -ENOMEM;
 
@@ -5402,7 +5356,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost,
 
        pqi_ctrl_busy(ctrl_info);
        if (pqi_ctrl_blocked(ctrl_info) || pqi_device_in_reset(device) ||
-           pqi_ctrl_in_ofa(ctrl_info)) {
+           pqi_ctrl_in_ofa(ctrl_info) || pqi_ctrl_in_shutdown(ctrl_info)) {
                rc = SCSI_MLQUEUE_HOST_BUSY;
                goto out;
        }
@@ -5419,7 +5373,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost,
        if (pqi_is_logical_device(device)) {
                raid_bypassed = false;
                if (device->raid_bypass_enabled &&
-                               !blk_rq_is_passthrough(scmd->request)) {
+                       !blk_rq_is_passthrough(scmd->request)) {
                        rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
                                scmd, queue_group);
                        if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY)
@@ -5650,6 +5604,18 @@ static int pqi_ctrl_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
        return 0;
 }
 
+static int pqi_ctrl_wait_for_pending_sync_cmds(struct pqi_ctrl_info *ctrl_info)
+{
+       while (atomic_read(&ctrl_info->sync_cmds_outstanding)) {
+               pqi_check_ctrl_health(ctrl_info);
+               if (pqi_ctrl_offline(ctrl_info))
+                       return -ENXIO;
+               usleep_range(1000, 2000);
+       }
+
+       return 0;
+}
+
 static void pqi_lun_reset_complete(struct pqi_io_request *io_request,
        void *context)
 {
@@ -5658,7 +5624,8 @@ static void pqi_lun_reset_complete(struct pqi_io_request *io_request,
        complete(waiting);
 }
 
-#define PQI_LUN_RESET_TIMEOUT_SECS     10
+#define PQI_LUN_RESET_TIMEOUT_SECS             30
+#define PQI_LUN_RESET_POLL_COMPLETION_SECS     10
 
 static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info,
        struct pqi_scsi_dev *device, struct completion *wait)
@@ -5667,7 +5634,7 @@ static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info,
 
        while (1) {
                if (wait_for_completion_io_timeout(wait,
-                       PQI_LUN_RESET_TIMEOUT_SECS * PQI_HZ)) {
+                       PQI_LUN_RESET_POLL_COMPLETION_SECS * PQI_HZ)) {
                        rc = 0;
                        break;
                }
@@ -5704,6 +5671,9 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info,
        memcpy(request->lun_number, device->scsi3addr,
                sizeof(request->lun_number));
        request->task_management_function = SOP_TASK_MANAGEMENT_LUN_RESET;
+       if (ctrl_info->tmf_iu_timeout_supported)
+               put_unaligned_le16(PQI_LUN_RESET_TIMEOUT_SECS,
+                                       &request->timeout);
 
        pqi_start_io(ctrl_info,
                &ctrl_info->queue_groups[PQI_DEFAULT_QUEUE_GROUP], RAID_PATH,
@@ -5733,7 +5703,7 @@ static int _pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
 
        for (retries = 0;;) {
                rc = pqi_lun_reset(ctrl_info, device);
-               if (rc != -EAGAIN || ++retries > PQI_LUN_RESET_RETRIES)
+               if (rc == 0 || ++retries > PQI_LUN_RESET_RETRIES)
                        break;
                msleep(PQI_LUN_RESET_RETRY_INTERVAL_MSECS);
        }
@@ -5787,17 +5757,17 @@ static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd)
                shost->host_no, device->bus, device->target, device->lun);
 
        pqi_check_ctrl_health(ctrl_info);
-       if (pqi_ctrl_offline(ctrl_info)) {
-               dev_err(&ctrl_info->pci_dev->dev,
-                       "controller %u offlined - cannot send device reset\n",
-                       ctrl_info->ctrl_id);
+       if (pqi_ctrl_offline(ctrl_info) ||
+               pqi_device_reset_blocked(ctrl_info)) {
                rc = FAILED;
                goto out;
        }
 
        pqi_wait_until_ofa_finished(ctrl_info);
 
+       atomic_inc(&ctrl_info->sync_cmds_outstanding);
        rc = pqi_device_reset(ctrl_info, device);
+       atomic_dec(&ctrl_info->sync_cmds_outstanding);
 
 out:
        dev_err(&ctrl_info->pci_dev->dev,
@@ -6066,6 +6036,9 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg)
 
        put_unaligned_le16(iu_length, &request.header.iu_length);
 
+       if (ctrl_info->raid_iu_timeout_supported)
+               put_unaligned_le32(iocommand.Request.Timeout, &request.timeout);
+
        rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
                PQI_SYNC_FLAGS_INTERRUPTABLE, &pqi_error_info, NO_TIMEOUT);
 
@@ -6119,7 +6092,7 @@ static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd,
 
        ctrl_info = shost_to_hba(sdev->host);
 
-       if (pqi_ctrl_in_ofa(ctrl_info))
+       if (pqi_ctrl_in_ofa(ctrl_info) || pqi_ctrl_in_shutdown(ctrl_info))
                return -EBUSY;
 
        switch (cmd) {
@@ -6160,14 +6133,8 @@ static ssize_t pqi_firmware_version_show(struct device *dev,
 static ssize_t pqi_driver_version_show(struct device *dev,
        struct device_attribute *attr, char *buffer)
 {
-       struct Scsi_Host *shost;
-       struct pqi_ctrl_info *ctrl_info;
-
-       shost = class_to_shost(dev);
-       ctrl_info = shost_to_hba(shost);
-
-       return snprintf(buffer, PAGE_SIZE,
-               "%s\n", DRIVER_VERSION BUILD_TIMESTAMP);
+       return snprintf(buffer, PAGE_SIZE, "%s\n",
+                       DRIVER_VERSION BUILD_TIMESTAMP);
 }
 
 static ssize_t pqi_serial_number_show(struct device *dev,
@@ -6283,7 +6250,7 @@ static ssize_t pqi_unique_id_show(struct device *dev,
        struct scsi_device *sdev;
        struct pqi_scsi_dev *device;
        unsigned long flags;
-       unsigned char uid[16];
+       u8 unique_id[16];
 
        sdev = to_scsi_device(dev);
        ctrl_info = shost_to_hba(sdev->host);
@@ -6296,16 +6263,22 @@ static ssize_t pqi_unique_id_show(struct device *dev,
                        flags);
                return -ENODEV;
        }
-       memcpy(uid, device->unique_id, sizeof(uid));
+
+       if (device->is_physical_device) {
+               memset(unique_id, 0, 8);
+               memcpy(unique_id + 8, &device->wwid, sizeof(device->wwid));
+       } else {
+               memcpy(unique_id, device->volume_id, sizeof(device->volume_id));
+       }
 
        spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
 
        return snprintf(buffer, PAGE_SIZE,
                "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
-               uid[0], uid[1], uid[2], uid[3],
-               uid[4], uid[5], uid[6], uid[7],
-               uid[8], uid[9], uid[10], uid[11],
-               uid[12], uid[13], uid[14], uid[15]);
+               unique_id[0], unique_id[1], unique_id[2], unique_id[3],
+               unique_id[4], unique_id[5], unique_id[6], unique_id[7],
+               unique_id[8], unique_id[9], unique_id[10], unique_id[11],
+               unique_id[12], unique_id[13], unique_id[14], unique_id[15]);
 }
 
 static ssize_t pqi_lunid_show(struct device *dev,
@@ -6328,6 +6301,7 @@ static ssize_t pqi_lunid_show(struct device *dev,
                        flags);
                return -ENODEV;
        }
+
        memcpy(lunid, device->scsi3addr, sizeof(lunid));
 
        spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
@@ -6335,7 +6309,8 @@ static ssize_t pqi_lunid_show(struct device *dev,
        return snprintf(buffer, PAGE_SIZE, "0x%8phN\n", lunid);
 }
 
-#define MAX_PATHS 8
+#define MAX_PATHS      8
+
 static ssize_t pqi_path_info_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -6347,9 +6322,9 @@ static ssize_t pqi_path_info_show(struct device *dev,
        int output_len = 0;
        u8 box;
        u8 bay;
-       u8 path_map_index = 0;
+       u8 path_map_index;
        char *active;
-       unsigned char phys_connector[2];
+       u8 phys_connector[2];
 
        sdev = to_scsi_device(dev);
        ctrl_info = shost_to_hba(sdev->host);
@@ -6365,7 +6340,7 @@ static ssize_t pqi_path_info_show(struct device *dev,
 
        bay = device->bay;
        for (i = 0; i < MAX_PATHS; i++) {
-               path_map_index = 1<<i;
+               path_map_index = 1 << i;
                if (i == device->active_path_index)
                        active = "Active";
                else if (device->path_map & path_map_index)
@@ -6416,10 +6391,10 @@ end_buffer:
        }
 
        spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
        return output_len;
 }
 
-
 static ssize_t pqi_sas_address_show(struct device *dev,
        struct device_attribute *attr, char *buffer)
 {
@@ -6440,6 +6415,7 @@ static ssize_t pqi_sas_address_show(struct device *dev,
                        flags);
                return -ENODEV;
        }
+
        sas_address = device->sas_address;
 
        spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
@@ -6844,6 +6820,27 @@ static void pqi_firmware_feature_status(struct pqi_ctrl_info *ctrl_info,
                firmware_feature->feature_name);
 }
 
+static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info,
+       struct pqi_firmware_feature *firmware_feature)
+{
+       switch (firmware_feature->feature_bit) {
+       case PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE:
+               ctrl_info->soft_reset_handshake_supported =
+                       firmware_feature->enabled;
+               break;
+       case PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT:
+               ctrl_info->raid_iu_timeout_supported =
+                       firmware_feature->enabled;
+               break;
+       case PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT:
+               ctrl_info->tmf_iu_timeout_supported =
+                       firmware_feature->enabled;
+               break;
+       }
+
+       pqi_firmware_feature_status(ctrl_info, firmware_feature);
+}
+
 static inline void pqi_firmware_feature_update(struct pqi_ctrl_info *ctrl_info,
        struct pqi_firmware_feature *firmware_feature)
 {
@@ -6867,7 +6864,17 @@ static struct pqi_firmware_feature pqi_firmware_features[] = {
        {
                .feature_name = "New Soft Reset Handshake",
                .feature_bit = PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE,
-               .feature_status = pqi_firmware_feature_status,
+               .feature_status = pqi_ctrl_update_feature_flags,
+       },
+       {
+               .feature_name = "RAID IU Timeout",
+               .feature_bit = PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT,
+               .feature_status = pqi_ctrl_update_feature_flags,
+       },
+       {
+               .feature_name = "TMF IU Timeout",
+               .feature_bit = PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT,
+               .feature_status = pqi_ctrl_update_feature_flags,
        },
 };
 
@@ -6921,7 +6928,6 @@ static void pqi_process_firmware_features(
                return;
        }
 
-       ctrl_info->soft_reset_handshake_supported = false;
        for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) {
                if (!pqi_firmware_features[i].supported)
                        continue;
@@ -6929,10 +6935,6 @@ static void pqi_process_firmware_features(
                        firmware_features_iomem_addr,
                        pqi_firmware_features[i].feature_bit)) {
                        pqi_firmware_features[i].enabled = true;
-                       if (pqi_firmware_features[i].feature_bit ==
-                           PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE)
-                               ctrl_info->soft_reset_handshake_supported =
-                                                                       true;
                }
                pqi_firmware_feature_update(ctrl_info,
                        &pqi_firmware_features[i]);
@@ -7074,13 +7076,20 @@ static int pqi_force_sis_mode(struct pqi_ctrl_info *ctrl_info)
        return pqi_revert_to_sis_mode(ctrl_info);
 }
 
+#define PQI_POST_RESET_DELAY_B4_MSGU_READY     5000
+
 static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
 {
        int rc;
 
-       rc = pqi_force_sis_mode(ctrl_info);
-       if (rc)
-               return rc;
+       if (reset_devices) {
+               sis_soft_reset(ctrl_info);
+               msleep(PQI_POST_RESET_DELAY_B4_MSGU_READY);
+       } else {
+               rc = pqi_force_sis_mode(ctrl_info);
+               if (rc)
+                       return rc;
+       }
 
        /*
         * Wait until the controller is ready to start accepting SIS
@@ -7386,7 +7395,7 @@ static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info)
        rc = pqi_get_ctrl_product_details(ctrl_info);
        if (rc) {
                dev_err(&ctrl_info->pci_dev->dev,
-                       "error obtaining product detail\n");
+                       "error obtaining product details\n");
                return rc;
        }
 
@@ -7514,6 +7523,7 @@ static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node)
 
        INIT_WORK(&ctrl_info->event_work, pqi_event_worker);
        atomic_set(&ctrl_info->num_interrupts, 0);
+       atomic_set(&ctrl_info->sync_cmds_outstanding, 0);
 
        INIT_DELAYED_WORK(&ctrl_info->rescan_work, pqi_rescan_worker);
        INIT_DELAYED_WORK(&ctrl_info->update_time_work, pqi_update_time_worker);
@@ -7721,6 +7731,8 @@ static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info,
                dev_err(dev, "Failed to allocate host buffer of size = %u",
                        bytes_requested);
        }
+
+       return;
 }
 
 static void pqi_ofa_free_host_buffer(struct pqi_ctrl_info *ctrl_info)
@@ -7787,8 +7799,6 @@ static int pqi_ofa_host_memory_update(struct pqi_ctrl_info *ctrl_info)
                0, NULL, NO_TIMEOUT);
 }
 
-#define PQI_POST_RESET_DELAY_B4_MSGU_READY     5000
-
 static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info)
 {
        msleep(PQI_POST_RESET_DELAY_B4_MSGU_READY);
@@ -7956,28 +7966,73 @@ static void pqi_pci_remove(struct pci_dev *pci_dev)
        pqi_remove_ctrl(ctrl_info);
 }
 
+static void pqi_crash_if_pending_command(struct pqi_ctrl_info *ctrl_info)
+{
+       unsigned int i;
+       struct pqi_io_request *io_request;
+       struct scsi_cmnd *scmd;
+
+       for (i = 0; i < ctrl_info->max_io_slots; i++) {
+               io_request = &ctrl_info->io_request_pool[i];
+               if (atomic_read(&io_request->refcount) == 0)
+                       continue;
+               scmd = io_request->scmd;
+               WARN_ON(scmd != NULL); /* IO command from SML */
+               WARN_ON(scmd == NULL); /* Non-IO cmd or driver initiated*/
+       }
+}
+
 static void pqi_shutdown(struct pci_dev *pci_dev)
 {
        int rc;
        struct pqi_ctrl_info *ctrl_info;
 
        ctrl_info = pci_get_drvdata(pci_dev);
-       if (!ctrl_info)
-               goto error;
+       if (!ctrl_info) {
+               dev_err(&pci_dev->dev,
+                       "cache could not be flushed\n");
+               return;
+       }
+
+       pqi_disable_events(ctrl_info);
+       pqi_wait_until_ofa_finished(ctrl_info);
+       pqi_cancel_update_time_worker(ctrl_info);
+       pqi_cancel_rescan_worker(ctrl_info);
+       pqi_cancel_event_worker(ctrl_info);
+
+       pqi_ctrl_shutdown_start(ctrl_info);
+       pqi_ctrl_wait_until_quiesced(ctrl_info);
+
+       rc = pqi_ctrl_wait_for_pending_io(ctrl_info, NO_TIMEOUT);
+       if (rc) {
+               dev_err(&pci_dev->dev,
+                       "wait for pending I/O failed\n");
+               return;
+       }
+
+       pqi_ctrl_block_device_reset(ctrl_info);
+       pqi_wait_until_lun_reset_finished(ctrl_info);
 
        /*
         * Write all data in the controller's battery-backed cache to
         * storage.
         */
        rc = pqi_flush_cache(ctrl_info, SHUTDOWN);
-       pqi_free_interrupts(ctrl_info);
-       pqi_reset(ctrl_info);
-       if (rc == 0)
+       if (rc)
+               dev_err(&pci_dev->dev,
+                       "unable to flush controller cache\n");
+
+       pqi_ctrl_block_requests(ctrl_info);
+
+       rc = pqi_ctrl_wait_for_pending_sync_cmds(ctrl_info);
+       if (rc) {
+               dev_err(&pci_dev->dev,
+                       "wait for pending sync cmds failed\n");
                return;
+       }
 
-error:
-       dev_warn(&pci_dev->dev,
-               "unable to flush controller cache\n");
+       pqi_crash_if_pending_command(ctrl_info);
+       pqi_reset(ctrl_info);
 }
 
 static void pqi_process_lockup_action_param(void)
@@ -8685,6 +8740,8 @@ static void __attribute__((unused)) verify_structures(void)
                error_index) != 27);
        BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
                cdb) != 32);
+       BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+               timeout) != 60);
        BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
                sg_descriptors) != 64);
        BUILD_BUG_ON(sizeof(struct pqi_raid_path_request) !=
@@ -8839,6 +8896,8 @@ static void __attribute__((unused)) verify_structures(void)
                request_id) != 8);
        BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
                nexus_id) != 10);
+       BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+               timeout) != 14);
        BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
                lun_number) != 16);
        BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
index 6776dfc..b728911 100644 (file)
@@ -45,9 +45,9 @@ static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy)
        struct sas_phy *phy = pqi_sas_phy->phy;
 
        sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy);
-       sas_phy_free(phy);
        if (pqi_sas_phy->added_to_port)
                list_del(&pqi_sas_phy->phy_list_entry);
+       sas_phy_delete(phy);
        kfree(pqi_sas_phy);
 }
 
@@ -312,7 +312,6 @@ static int pqi_sas_get_linkerrors(struct sas_phy *phy)
 static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
        u64 *identifier)
 {
-
        int rc;
        unsigned long flags;
        struct Scsi_Host *shost;
@@ -361,7 +360,7 @@ static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
                }
        }
 
-       if (found_device->phy_connected_dev_type != SA_CONTROLLER_DEVICE) {
+       if (found_device->phy_connected_dev_type != SA_DEVICE_TYPE_CONTROLLER) {
                rc = -EINVAL;
                goto out;
        }
@@ -382,12 +381,10 @@ out:
        spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
 
        return rc;
-
 }
 
 static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy)
 {
-
        int rc;
        unsigned long flags;
        struct pqi_ctrl_info *ctrl_info;
@@ -482,7 +479,6 @@ pqi_build_csmi_smp_passthru_buffer(struct sas_rphy *rphy,
                req_size -= SMP_CRC_FIELD_LENGTH;
 
        put_unaligned_le32(req_size, &parameters->request_length);
-
        put_unaligned_le32(resp_size, &parameters->response_length);
 
        sg_copy_to_buffer(job->request_payload.sg_list,
@@ -512,12 +508,12 @@ void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
        struct sas_rphy *rphy)
 {
        int rc;
-       struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost);
+       struct pqi_ctrl_info *ctrl_info;
        struct bmic_csmi_smp_passthru_buffer *smp_buf;
        struct pqi_raid_error_info error_info;
        unsigned int reslen = 0;
 
-       pqi_ctrl_busy(ctrl_info);
+       ctrl_info = shost_to_hba(shost);
 
        if (job->reply_payload.payload_len == 0) {
                rc = -ENOMEM;
@@ -539,16 +535,6 @@ void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
                goto out;
        }
 
-       if (pqi_ctrl_offline(ctrl_info)) {
-               rc = -ENXIO;
-               goto out;
-       }
-
-       if (pqi_ctrl_blocked(ctrl_info)) {
-               rc = -EBUSY;
-               goto out;
-       }
-
        smp_buf = pqi_build_csmi_smp_passthru_buffer(rphy, job);
        if (!smp_buf) {
                rc = -ENOMEM;
index 955e4c9..701b842 100644 (file)
@@ -501,7 +501,7 @@ static struct scsi_host_template sun3_scsi_template = {
        .eh_host_reset_handler  = sun3scsi_host_reset,
        .can_queue              = 16,
        .this_id                = 7,
-       .sg_tablesize           = SG_NONE,
+       .sg_tablesize           = 1,
        .cmd_per_lun            = 2,
        .dma_boundary           = PAGE_SIZE - 1,
        .cmd_size               = NCR5380_CMD_SIZE,
@@ -523,7 +523,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
                sun3_scsi_template.can_queue = setup_can_queue;
        if (setup_cmd_per_lun > 0)
                sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
-       if (setup_sg_tablesize >= 0)
+       if (setup_sg_tablesize > 0)
                sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
        if (setup_hostid >= 0)
                sun3_scsi_template.this_id = setup_hostid & 7;
index 0b845ab..d14c224 100644 (file)
@@ -132,6 +132,16 @@ config SCSI_UFS_HISI
          Select this if you have UFS controller on Hisilicon chipset.
          If unsure, say N.
 
+config SCSI_UFS_TI_J721E
+       tristate "TI glue layer for Cadence UFS Controller"
+       depends on OF && HAS_IOMEM && (ARCH_K3 || COMPILE_TEST)
+       help
+         This selects driver for TI glue layer for Cadence UFS Host
+         Controller IP.
+
+         Selects this if you have TI platform with UFS controller.
+         If unsure, say N.
+
 config SCSI_UFS_BSG
        bool "Universal Flash Storage BSG device node"
        depends on SCSI_UFSHCD
index 2a90979..94c6c5d 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
 obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
 obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
 obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o
+obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o
diff --git a/drivers/scsi/ufs/ti-j721e-ufs.c b/drivers/scsi/ufs/ti-j721e-ufs.c
new file mode 100644 (file)
index 0000000..5216d22
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+//
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#define TI_UFS_SS_CTRL         0x4
+#define TI_UFS_SS_RST_N_PCS    BIT(0)
+#define TI_UFS_SS_CLK_26MHZ    BIT(4)
+
+static int ti_j721e_ufs_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       unsigned long clk_rate;
+       void __iomem *regbase;
+       struct clk *clk;
+       u32 reg = 0;
+       int ret;
+
+       regbase = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(regbase))
+               return PTR_ERR(regbase);
+
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(dev);
+               return ret;
+       }
+
+       /* Select MPHY refclk frequency */
+       clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(dev, "Cannot claim MPHY clock.\n");
+               return PTR_ERR(clk);
+       }
+       clk_rate = clk_get_rate(clk);
+       if (clk_rate == 26000000)
+               reg |= TI_UFS_SS_CLK_26MHZ;
+       devm_clk_put(dev, clk);
+
+       /*  Take UFS slave device out of reset */
+       reg |= TI_UFS_SS_RST_N_PCS;
+       writel(reg, regbase + TI_UFS_SS_CTRL);
+
+       ret = of_platform_populate(pdev->dev.of_node, NULL, NULL,
+                                  dev);
+       if (ret) {
+               dev_err(dev, "failed to populate child nodes %d\n", ret);
+               pm_runtime_put_sync(dev);
+       }
+
+       return ret;
+}
+
+static int ti_j721e_ufs_remove(struct platform_device *pdev)
+{
+       of_platform_depopulate(&pdev->dev);
+       pm_runtime_put_sync(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id ti_j721e_ufs_of_match[] = {
+       {
+               .compatible = "ti,j721e-ufs",
+       },
+       { },
+};
+
+static struct platform_driver ti_j721e_ufs_driver = {
+       .probe  = ti_j721e_ufs_probe,
+       .remove = ti_j721e_ufs_remove,
+       .driver = {
+               .name   = "ti-j721e-ufs",
+               .of_match_table = ti_j721e_ufs_of_match,
+       },
+};
+module_platform_driver(ti_j721e_ufs_driver);
+
+MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
+MODULE_DESCRIPTION("TI UFS host controller glue driver");
+MODULE_LICENSE("GPL v2");
index 6bbb167..5d64873 100644 (file)
@@ -452,10 +452,7 @@ static int ufs_hisi_get_resource(struct ufs_hisi_host *host)
 
        /* get resource of ufs sys ctrl */
        host->ufs_sys_ctrl = devm_platform_ioremap_resource(pdev, 1);
-       if (IS_ERR(host->ufs_sys_ctrl))
-               return PTR_ERR(host->ufs_sys_ctrl);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(host->ufs_sys_ctrl);
 }
 
 static void ufs_hisi_set_pm_lvl(struct ufs_hba *hba)
index 0f6ff33..83e28ed 100644 (file)
@@ -147,6 +147,9 @@ static int ufs_mtk_init(struct ufs_hba *hba)
        if (err)
                goto out_variant_clear;
 
+       /* Enable runtime autosuspend */
+       hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND;
+
        /*
         * ufshcd_vops_init() is invoked after
         * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
index a5b7148..c69c29a 100644 (file)
@@ -246,6 +246,44 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
        mb();
 }
 
+/**
+ * ufs_qcom_host_reset - reset host controller and PHY
+ */
+static int ufs_qcom_host_reset(struct ufs_hba *hba)
+{
+       int ret = 0;
+       struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+       if (!host->core_reset) {
+               dev_warn(hba->dev, "%s: reset control not set\n", __func__);
+               goto out;
+       }
+
+       ret = reset_control_assert(host->core_reset);
+       if (ret) {
+               dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n",
+                                __func__, ret);
+               goto out;
+       }
+
+       /*
+        * The hardware requirement for delay between assert/deassert
+        * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
+        * ~125us (4/32768). To be on the safe side add 200us delay.
+        */
+       usleep_range(200, 210);
+
+       ret = reset_control_deassert(host->core_reset);
+       if (ret)
+               dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n",
+                                __func__, ret);
+
+       usleep_range(1000, 1100);
+
+out:
+       return ret;
+}
+
 static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
 {
        struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -254,6 +292,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
        bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
                                                        ? true : false;
 
+       /* Reset UFS Host Controller and PHY */
+       ret = ufs_qcom_host_reset(hba);
+       if (ret)
+               dev_warn(hba->dev, "%s: host reset returned %d\n",
+                                 __func__, ret);
+
        if (is_rate_B)
                phy_set_mode(phy, PHY_MODE_UFS_HS_B);
 
@@ -1101,6 +1145,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)
        host->hba = hba;
        ufshcd_set_variant(hba, host);
 
+       /* Setup the reset control of HCI */
+       host->core_reset = devm_reset_control_get(hba->dev, "rst");
+       if (IS_ERR(host->core_reset)) {
+               err = PTR_ERR(host->core_reset);
+               dev_warn(dev, "Failed to get reset control %d\n", err);
+               host->core_reset = NULL;
+               err = 0;
+       }
+
        /* Fire up the reset controller. Failure here is non-fatal. */
        host->rcdev.of_node = dev->of_node;
        host->rcdev.ops = &ufs_qcom_reset_ops;
index d401f17..2d95e7c 100644 (file)
@@ -6,6 +6,7 @@
 #define UFS_QCOM_H_
 
 #include <linux/reset-controller.h>
+#include <linux/reset.h>
 
 #define MAX_UFS_QCOM_HOSTS     1
 #define MAX_U32                 (~(u32)0)
@@ -233,6 +234,8 @@ struct ufs_qcom_host {
        u32 dbg_print_en;
        struct ufs_qcom_testbus testbus;
 
+       /* Reset control of HCI */
+       struct reset_control *core_reset;
        struct reset_controller_dev rcdev;
 
        struct gpio_desc *device_reset;
index 969a36b..ad2abc9 100644 (file)
@@ -126,13 +126,16 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
                return;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
-       if (hba->ahit == ahit)
-               goto out_unlock;
-       hba->ahit = ahit;
-       if (!pm_runtime_suspended(hba->dev))
-               ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER);
-out_unlock:
+       if (hba->ahit != ahit)
+               hba->ahit = ahit;
        spin_unlock_irqrestore(hba->host->host_lock, flags);
+       if (!pm_runtime_suspended(hba->dev)) {
+               pm_runtime_get_sync(hba->dev);
+               ufshcd_hold(hba, false);
+               ufshcd_auto_hibern8_enable(hba);
+               ufshcd_release(hba);
+               pm_runtime_put(hba->dev);
+       }
 }
 
 /* Convert Auto-Hibernate Idle Timer register value to microseconds */
index dc2f6d2..baeecee 100644 (file)
@@ -162,6 +162,7 @@ out:
 
 /**
  * ufs_bsg_remove - detach and remove the added ufs-bsg node
+ * @hba: per adapter object
  *
  * Should be called when unloading the driver.
  */
index fb9e2ff..6a901da 100644 (file)
@@ -80,7 +80,7 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba)
  */
 static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
 {
-       const struct ufshcd_dme_attr_val setup_attrs[] = {
+       static const struct ufshcd_dme_attr_val setup_attrs[] = {
                { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL },
                { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL },
                { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL },
index 8d40dc9..76f9be7 100644 (file)
@@ -402,7 +402,6 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(dev, "IRQ resource not available\n");
                err = -ENODEV;
                goto out;
        }
index 11a87f5..b5966fa 100644 (file)
@@ -88,6 +88,9 @@
 /* Interrupt aggregation default timeout, unit: 40us */
 #define INT_AGGR_DEF_TO        0x02
 
+/* default delay of autosuspend: 2000 ms */
+#define RPM_AUTOSUSPEND_DELAY_MS 2000
+
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)                           \
        ({                                                              \
                int _ret;                                               \
@@ -114,7 +117,7 @@ int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
        if (offset % 4 != 0 || len % 4 != 0) /* keep readl happy */
                return -EINVAL;
 
-       regs = kzalloc(len, GFP_KERNEL);
+       regs = kzalloc(len, GFP_ATOMIC);
        if (!regs)
                return -ENOMEM;
 
@@ -237,7 +240,7 @@ static struct ufs_dev_fix ufs_fixups[] = {
        END_FIX
 };
 
-static void ufshcd_tmc_handler(struct ufs_hba *hba);
+static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
@@ -1607,7 +1610,7 @@ static void ufshcd_gate_work(struct work_struct *work)
         * state to CLKS_ON.
         */
        if (hba->clk_gating.is_suspended ||
-               (hba->clk_gating.state == REQ_CLKS_ON)) {
+               (hba->clk_gating.state != REQ_CLKS_OFF)) {
                hba->clk_gating.state = CLKS_ON;
                trace_ufshcd_clk_gating(dev_name(hba->dev),
                                        hba->clk_gating.state);
@@ -1935,8 +1938,8 @@ int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                        memcpy(hba->dev_cmd.query.descriptor, descp, resp_len);
                } else {
                        dev_warn(hba->dev,
-                               "%s: Response size is bigger than buffer",
-                               __func__);
+                                "%s: rsp size %d is bigger than buffer size %d",
+                                __func__, resp_len, buf_len);
                        return -EINVAL;
                }
        }
@@ -2986,10 +2989,10 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
                goto out_unlock;
        }
 
-       hba->dev_cmd.query.descriptor = NULL;
        *buf_len = be16_to_cpu(response->upiu_res.length);
 
 out_unlock:
+       hba->dev_cmd.query.descriptor = NULL;
        mutex_unlock(&hba->dev_cmd.lock);
 out:
        ufshcd_release(hba);
@@ -3856,6 +3859,9 @@ static int ufshcd_link_recovery(struct ufs_hba *hba)
        ufshcd_set_eh_in_progress(hba);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+       /* Reset the attached device */
+       ufshcd_vops_device_reset(hba);
+
        ret = ufshcd_host_reset_and_restore(hba);
 
        spin_lock_irqsave(hba->host->host_lock, flags);
@@ -3885,15 +3891,24 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
                             ktime_to_us(ktime_sub(ktime_get(), start)), ret);
 
        if (ret) {
+               int err;
+
                dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n",
                        __func__, ret);
 
                /*
-                * If link recovery fails then return error so that caller
-                * don't retry the hibern8 enter again.
+                * If link recovery fails then return error code returned from
+                * ufshcd_link_recovery().
+                * If link recovery succeeds then return -EAGAIN to attempt
+                * hibern8 enter retry again.
                 */
-               if (ufshcd_link_recovery(hba))
-                       ret = -ENOLINK;
+               err = ufshcd_link_recovery(hba);
+               if (err) {
+                       dev_err(hba->dev, "%s: link recovery failed", __func__);
+                       ret = err;
+               } else {
+                       ret = -EAGAIN;
+               }
        } else
                ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER,
                                                                POST_CHANGE);
@@ -3907,7 +3922,7 @@ static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
 
        for (retries = UIC_HIBERN8_ENTER_RETRIES; retries > 0; retries--) {
                ret = __ufshcd_uic_hibern8_enter(hba);
-               if (!ret || ret == -ENOLINK)
+               if (!ret)
                        goto out;
        }
 out:
@@ -3941,7 +3956,7 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
        return ret;
 }
 
-static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
+void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
 {
        unsigned long flags;
 
@@ -4631,9 +4646,14 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth)
  */
 static int ufshcd_slave_configure(struct scsi_device *sdev)
 {
+       struct ufs_hba *hba = shost_priv(sdev->host);
        struct request_queue *q = sdev->request_queue;
 
        blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
+
+       if (ufshcd_is_rpm_autosuspend_allowed(hba))
+               sdev->rpm_autosuspend = 1;
+
        return 0;
 }
 
@@ -4788,19 +4808,29 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
  * @intr_status: interrupt status generated by the controller
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
+       irqreturn_t retval = IRQ_NONE;
+
        if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
                hba->active_uic_cmd->argument2 |=
                        ufshcd_get_uic_cmd_result(hba);
                hba->active_uic_cmd->argument3 =
                        ufshcd_get_dme_attr_val(hba);
                complete(&hba->active_uic_cmd->done);
+               retval = IRQ_HANDLED;
        }
 
-       if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done)
+       if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) {
                complete(hba->uic_async_done);
+               retval = IRQ_HANDLED;
+       }
+       return retval;
 }
 
 /**
@@ -4856,8 +4886,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
 /**
  * ufshcd_transfer_req_compl - handle SCSI and query command completion
  * @hba: per adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
        unsigned long completed_reqs;
        u32 tr_doorbell;
@@ -4876,7 +4910,12 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
        tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
-       __ufshcd_transfer_req_compl(hba, completed_reqs);
+       if (completed_reqs) {
+               __ufshcd_transfer_req_compl(hba, completed_reqs);
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
 }
 
 /**
@@ -5395,61 +5434,77 @@ out:
 /**
  * ufshcd_update_uic_error - check and set fatal UIC error flags.
  * @hba: per-adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_update_uic_error(struct ufs_hba *hba)
+static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
 {
        u32 reg;
+       irqreturn_t retval = IRQ_NONE;
 
        /* PHY layer lane error */
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
        /* Ignore LINERESET indication, as this is not an error */
        if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
-                       (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
+           (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
                /*
                 * To know whether this error is fatal or not, DB timeout
                 * must be checked but this error is handled separately.
                 */
                dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__);
                ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg);
+               retval |= IRQ_HANDLED;
        }
 
        /* PA_INIT_ERROR is fatal and needs UIC reset */
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
-       if (reg)
+       if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
+           (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
                ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg);
 
-       if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
-               hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
-       else if (hba->dev_quirks &
-                  UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
-               if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
-                       hba->uic_error |=
-                               UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
-               else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
-                       hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+               if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
+                       hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
+               else if (hba->dev_quirks &
+                               UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+                       if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
+                               hba->uic_error |=
+                                       UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+                       else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
+                               hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+               }
+               retval |= IRQ_HANDLED;
        }
 
        /* UIC NL/TL/DME errors needs software retry */
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
-       if (reg) {
+       if ((reg & UIC_NETWORK_LAYER_ERROR) &&
+           (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) {
                ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg);
                hba->uic_error |= UFSHCD_UIC_NL_ERROR;
+               retval |= IRQ_HANDLED;
        }
 
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER);
-       if (reg) {
+       if ((reg & UIC_TRANSPORT_LAYER_ERROR) &&
+           (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) {
                ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg);
                hba->uic_error |= UFSHCD_UIC_TL_ERROR;
+               retval |= IRQ_HANDLED;
        }
 
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
-       if (reg) {
+       if ((reg & UIC_DME_ERROR) &&
+           (reg & UIC_DME_ERROR_CODE_MASK)) {
                ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg);
                hba->uic_error |= UFSHCD_UIC_DME_ERROR;
+               retval |= IRQ_HANDLED;
        }
 
        dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n",
                        __func__, hba->uic_error);
+       return retval;
 }
 
 static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
@@ -5472,10 +5527,15 @@ static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
 /**
  * ufshcd_check_errors - Check for errors that need s/w attention
  * @hba: per-adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_check_errors(struct ufs_hba *hba)
+static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba)
 {
        bool queue_eh_work = false;
+       irqreturn_t retval = IRQ_NONE;
 
        if (hba->errors & INT_FATAL_ERRORS) {
                ufshcd_update_reg_hist(&hba->ufs_stats.fatal_err, hba->errors);
@@ -5484,7 +5544,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
 
        if (hba->errors & UIC_ERROR) {
                hba->uic_error = 0;
-               ufshcd_update_uic_error(hba);
+               retval = ufshcd_update_uic_error(hba);
                if (hba->uic_error)
                        queue_eh_work = true;
        }
@@ -5532,6 +5592,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
                        }
                        schedule_work(&hba->eh_work);
                }
+               retval |= IRQ_HANDLED;
        }
        /*
         * if (!queue_eh_work) -
@@ -5539,44 +5600,62 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
         * itself without s/w intervention or errors that will be
         * handled by the SCSI core layer.
         */
+       return retval;
 }
 
 /**
  * ufshcd_tmc_handler - handle task management function completion
  * @hba: per adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_tmc_handler(struct ufs_hba *hba)
+static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
 {
        u32 tm_doorbell;
 
        tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
        hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
-       wake_up(&hba->tm_wq);
+       if (hba->tm_condition) {
+               wake_up(&hba->tm_wq);
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
 }
 
 /**
  * ufshcd_sl_intr - Interrupt service routine
  * @hba: per adapter instance
  * @intr_status: contains interrupts generated by the controller
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
-static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
 {
+       irqreturn_t retval = IRQ_NONE;
+
        hba->errors = UFSHCD_ERROR_MASK & intr_status;
 
        if (ufshcd_is_auto_hibern8_error(hba, intr_status))
                hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
 
        if (hba->errors)
-               ufshcd_check_errors(hba);
+               retval |= ufshcd_check_errors(hba);
 
        if (intr_status & UFSHCD_UIC_MASK)
-               ufshcd_uic_cmd_compl(hba, intr_status);
+               retval |= ufshcd_uic_cmd_compl(hba, intr_status);
 
        if (intr_status & UTP_TASK_REQ_COMPL)
-               ufshcd_tmc_handler(hba);
+               retval |= ufshcd_tmc_handler(hba);
 
        if (intr_status & UTP_TRANSFER_REQ_COMPL)
-               ufshcd_transfer_req_compl(hba);
+               retval |= ufshcd_transfer_req_compl(hba);
+
+       return retval;
 }
 
 /**
@@ -5584,8 +5663,9 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
  * @irq: irq number
  * @__hba: pointer to adapter instance
  *
- * Returns IRQ_HANDLED - If interrupt is valid
- *             IRQ_NONE - If invalid interrupt
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE    - If invalid interrupt
  */
 static irqreturn_t ufshcd_intr(int irq, void *__hba)
 {
@@ -5608,14 +5688,18 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
                        intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
                if (intr_status)
                        ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
-               if (enabled_intr_status) {
-                       ufshcd_sl_intr(hba, enabled_intr_status);
-                       retval = IRQ_HANDLED;
-               }
+               if (enabled_intr_status)
+                       retval |= ufshcd_sl_intr(hba, enabled_intr_status);
 
                intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
        } while (intr_status && --retries);
 
+       if (retval == IRQ_NONE) {
+               dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n",
+                                       __func__, intr_status);
+               ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: ");
+       }
+
        spin_unlock(hba->host->host_lock);
        return retval;
 }
@@ -5760,9 +5844,9 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
  * @hba:       per-adapter instance
  * @req_upiu:  upiu request
  * @rsp_upiu:  upiu reply
- * @msgcode:   message code, one of UPIU Transaction Codes Initiator to Target
  * @desc_buff: pointer to descriptor buffer, NULL if NA
  * @buff_len:  descriptor size, 0 if NA
+ * @cmd_type:  specifies the type (NOP, Query...)
  * @desc_op:   descriptor operation
  *
  * Those type of requests uses UTP Transfer Request Descriptor - utrd.
@@ -5776,7 +5860,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
                                        struct utp_upiu_req *req_upiu,
                                        struct utp_upiu_req *rsp_upiu,
                                        u8 *desc_buff, int *buff_len,
-                                       int cmd_type,
+                                       enum dev_cmd_type cmd_type,
                                        enum query_opcode desc_op)
 {
        struct ufshcd_lrb *lrbp;
@@ -5856,7 +5940,9 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
                        memcpy(desc_buff, descp, resp_len);
                        *buff_len = resp_len;
                } else {
-                       dev_warn(hba->dev, "rsp size is bigger than buffer");
+                       dev_warn(hba->dev,
+                                "%s: rsp size %d is bigger than buffer size %d",
+                                __func__, resp_len, *buff_len);
                        *buff_len = 0;
                        err = -EINVAL;
                }
@@ -5891,7 +5977,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
                             enum query_opcode desc_op)
 {
        int err;
-       int cmd_type = DEV_CMD_TYPE_QUERY;
+       enum dev_cmd_type cmd_type = DEV_CMD_TYPE_QUERY;
        struct utp_task_req_desc treq = { { 0 }, };
        int ocs_value;
        u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC;
@@ -6770,23 +6856,13 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
                &hba->desc_size.geom_desc);
        if (err)
                hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+
        err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
                &hba->desc_size.hlth_desc);
        if (err)
                hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
 }
 
-static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
-{
-       hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
-       hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
-       hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
-       hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
-       hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
-       hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
-       hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
-}
-
 static struct ufs_ref_clk ufs_ref_clk_freqs[] = {
        {19200000, REF_CLK_FREQ_19_2_MHZ},
        {26000000, REF_CLK_FREQ_26_MHZ},
@@ -6881,9 +6957,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        /* UniPro link is active now */
        ufshcd_set_link_active(hba);
 
-       /* Enable Auto-Hibernate if configured */
-       ufshcd_auto_hibern8_enable(hba);
-
        ret = ufshcd_verify_dev_init(hba);
        if (ret)
                goto out;
@@ -6934,6 +7007,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        /* set the state as operational after switching to desired gear */
        hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 
+       /* Enable Auto-Hibernate if configured */
+       ufshcd_auto_hibern8_enable(hba);
+
        /*
         * If we are in error handling context or in power management callbacks
         * context, no need to scan the host
@@ -7069,6 +7145,7 @@ static struct scsi_host_template ufshcd_driver_template = {
        .track_queue_depth      = 1,
        .sdev_groups            = ufshcd_driver_groups,
        .dma_boundary           = PAGE_SIZE - 1,
+       .rpm_autosuspend_delay  = RPM_AUTOSUSPEND_DELAY_MS,
 };
 
 static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
@@ -7950,12 +8027,12 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
        if (hba->clk_scaling.is_allowed)
                ufshcd_resume_clkscaling(hba);
 
-       /* Schedule clock gating in case of no access to UFS device yet */
-       ufshcd_release(hba);
-
        /* Enable Auto-Hibernate if configured */
        ufshcd_auto_hibern8_enable(hba);
 
+       /* Schedule clock gating in case of no access to UFS device yet */
+       ufshcd_release(hba);
+
        goto out;
 
 set_old_link_state:
@@ -8274,9 +8351,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        hba->mmio_base = mmio_base;
        hba->irq = irq;
 
-       /* Set descriptor lengths to specification defaults */
-       ufshcd_def_desc_sizes(hba);
-
        err = ufshcd_hba_init(hba);
        if (err)
                goto out_error;
index c94cfda..2740f69 100644 (file)
@@ -716,6 +716,12 @@ struct ufs_hba {
         * the performance of ongoing read/write operations.
         */
 #define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5)
+       /*
+        * This capability allows host controller driver to automatically
+        * enable runtime power management by itself instead of waiting
+        * for userspace to control the power management.
+        */
+#define UFSHCD_CAP_RPM_AUTOSUSPEND (1 << 6)
 
        struct devfreq *devfreq;
        struct ufs_clk_scaling clk_scaling;
@@ -749,6 +755,10 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
 {
        return hba->caps & UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
 }
+static inline bool ufshcd_is_rpm_autosuspend_allowed(struct ufs_hba *hba)
+{
+       return hba->caps & UFSHCD_CAP_RPM_AUTOSUSPEND;
+}
 
 static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba)
 {
@@ -916,6 +926,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
        enum flag_idn idn, bool *flag_res);
 
+void ufshcd_auto_hibern8_enable(struct ufs_hba *hba);
+
 #define SD_ASCII_STD true
 #define SD_RAW false
 int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
index dbb75cd..c2961d3 100644 (file)
@@ -195,7 +195,7 @@ enum {
 
 /* UECDL - Host UIC Error Code Data Link Layer 3Ch */
 #define UIC_DATA_LINK_LAYER_ERROR              0x80000000
-#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK    0x7FFF
+#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK    0xFFFF
 #define UIC_DATA_LINK_LAYER_ERROR_TCX_REP_TIMER_EXP    0x2
 #define UIC_DATA_LINK_LAYER_ERROR_AFCX_REQ_TIMER_EXP   0x4
 #define UIC_DATA_LINK_LAYER_ERROR_FCX_PRO_TIMER_EXP    0x8
index ca8e3ab..a23a8e5 100644 (file)
@@ -218,7 +218,14 @@ static int fastlane_esp_irq_pending(struct esp *esp)
 static u32 zorro_esp_dma_length_limit(struct esp *esp, u32 dma_addr,
                                        u32 dma_len)
 {
-       return dma_len > 0xFFFF ? 0xFFFF : dma_len;
+       return dma_len > (1U << 16) ? (1U << 16) : dma_len;
+}
+
+static u32 fastlane_esp_dma_length_limit(struct esp *esp, u32 dma_addr,
+                                       u32 dma_len)
+{
+       /* The old driver used 0xfffc as limit, so do that here too */
+       return dma_len > 0xfffc ? 0xfffc : dma_len;
 }
 
 static void zorro_esp_reset_dma(struct esp *esp)
@@ -604,7 +611,7 @@ static const struct esp_driver_ops fastlane_esp_ops = {
        .esp_write8             = zorro_esp_write8,
        .esp_read8              = zorro_esp_read8,
        .irq_pending            = fastlane_esp_irq_pending,
-       .dma_length_limit       = zorro_esp_dma_length_limit,
+       .dma_length_limit       = fastlane_esp_dma_length_limit,
        .reset_dma              = zorro_esp_reset_dma,
        .dma_drain              = zorro_esp_dma_drain,
        .dma_invalidate         = fastlane_esp_dma_invalidate,
index 6d0d04f..01fc0d2 100644 (file)
@@ -40,6 +40,7 @@ static const struct meson_gx_soc_id {
        { "G12A", 0x28 },
        { "G12B", 0x29 },
        { "SM1", 0x2b },
+       { "A1", 0x2c },
 };
 
 static const struct meson_gx_package_id {
@@ -68,6 +69,8 @@ static const struct meson_gx_package_id {
        { "S922X", 0x29, 0x40, 0xf0 },
        { "A311D", 0x29, 0x10, 0xf0 },
        { "S905X3", 0x2b, 0x5, 0xf },
+       { "S905D3", 0x2b, 0xb0, 0xf0 },
+       { "A113L", 0x2c, 0x0, 0xf8 },
 };
 
 static inline unsigned int socinfo_to_major(u32 socinfo)
index 0552813..50caf6d 100644 (file)
@@ -5,3 +5,14 @@ config AT91_SOC_ID
        default ARCH_AT91
        help
          Include support for the SoC bus on the Atmel ARM SoCs.
+
+config AT91_SOC_SFR
+       tristate "Special Function Registers support"
+       depends on ARCH_AT91 || COMPILE_TEST
+       help
+         This is a driver for the Special Function Registers available on
+         Atmel SAMA5Dx SoCs, providing access to specific aspects of the
+         integrated memory, bridge implementations, processor etc.
+
+         This driver can also be built as a module. If so, the module
+         will be called sfr.
index 7ca355d..d849a89 100644 (file)
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_AT91_SOC_ID) += soc.o
+obj-$(CONFIG_AT91_SOC_SFR) += sfr.o
diff --git a/drivers/soc/atmel/sfr.c b/drivers/soc/atmel/sfr.c
new file mode 100644 (file)
index 0000000..0525eef
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sfr.c - driver for special function registers
+ *
+ * Copyright (C) 2019 Bootlin.
+ *
+ */
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/random.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define SFR_SN0                0x4c
+#define SFR_SN_SIZE    8
+
+struct atmel_sfr_priv {
+       struct regmap                   *regmap;
+};
+
+static int atmel_sfr_read(void *context, unsigned int offset,
+                         void *buf, size_t bytes)
+{
+       struct atmel_sfr_priv *priv = context;
+
+       return regmap_bulk_read(priv->regmap, SFR_SN0 + offset,
+                               buf, bytes / 4);
+}
+
+static struct nvmem_config atmel_sfr_nvmem_config = {
+       .name = "atmel-sfr",
+       .read_only = true,
+       .word_size = 4,
+       .stride = 4,
+       .size = SFR_SN_SIZE,
+       .reg_read = atmel_sfr_read,
+};
+
+static int atmel_sfr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct nvmem_device *nvmem;
+       struct atmel_sfr_priv *priv;
+       u8 sn[SFR_SN_SIZE];
+       int ret;
+
+       priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = syscon_node_to_regmap(np);
+       if (IS_ERR(priv->regmap)) {
+               dev_err(dev, "cannot get parent's regmap\n");
+               return PTR_ERR(priv->regmap);
+       }
+
+       atmel_sfr_nvmem_config.dev = dev;
+       atmel_sfr_nvmem_config.priv = priv;
+
+       nvmem = devm_nvmem_register(dev, &atmel_sfr_nvmem_config);
+       if (IS_ERR(nvmem)) {
+               dev_err(dev, "error registering nvmem config\n");
+               return PTR_ERR(nvmem);
+       }
+
+       ret = atmel_sfr_read(priv, 0, sn, SFR_SN_SIZE);
+       if (ret == 0)
+               add_device_randomness(sn, SFR_SN_SIZE);
+
+       return ret;
+}
+
+static const struct of_device_id atmel_sfr_dt_ids[] = {
+       {
+               .compatible = "atmel,sama5d2-sfr",
+       }, {
+               .compatible = "atmel,sama5d4-sfr",
+       }, {
+               /* sentinel */
+       },
+};
+MODULE_DEVICE_TABLE(of, atmel_sfr_dt_ids);
+
+static struct platform_driver atmel_sfr_driver = {
+       .probe = atmel_sfr_probe,
+       .driver = {
+               .name = "atmel-sfr",
+               .of_match_table = atmel_sfr_dt_ids,
+       },
+};
+module_platform_driver(atmel_sfr_driver);
+
+MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
+MODULE_DESCRIPTION("Atmel SFR SN driver for SAMA5D2/4 SoC family");
+MODULE_LICENSE("GPL v2");
index f9ad8ad..4df32bc 100644 (file)
@@ -40,4 +40,14 @@ config DPAA2_CONSOLE
          /dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
          which can be used to dump the Management Complex and AIOP
          firmware logs.
+
+config FSL_RCPM
+       bool "Freescale RCPM support"
+       depends on PM_SLEEP && (ARM || ARM64)
+       help
+         The NXP QorIQ Processors based on ARM Core have RCPM module
+         (Run Control and Power Management), which performs all device-level
+         tasks associated with power management, such as wakeup source control.
+         Note that currently this driver will not support PowerPC based
+         QorIQ processor.
 endmenu
index 71dee8d..906f1cd 100644 (file)
@@ -6,6 +6,7 @@
 obj-$(CONFIG_FSL_DPAA)                 += qbman/
 obj-$(CONFIG_QUICC_ENGINE)             += qe/
 obj-$(CONFIG_CPM)                      += qe/
+obj-$(CONFIG_FSL_RCPM)                 += rcpm.o
 obj-$(CONFIG_FSL_GUTS)                 += guts.o
 obj-$(CONFIG_FSL_MC_DPIO)              += dpio/
 obj-$(CONFIG_DPAA2_CONSOLE)            += dpaa2-console.o
diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c
new file mode 100644 (file)
index 0000000..a093dbe
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// rcpm.c - Freescale QorIQ RCPM driver
+//
+// Copyright 2019 NXP
+//
+// Author: Ran Wang <ran.wang_1@nxp.com>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/kernel.h>
+
+#define RCPM_WAKEUP_CELL_MAX_SIZE      7
+
+struct rcpm {
+       unsigned int    wakeup_cells;
+       void __iomem    *ippdexpcr_base;
+       bool            little_endian;
+};
+
+/**
+ * rcpm_pm_prepare - performs device-level tasks associated with power
+ * management, such as programming related to the wakeup source control.
+ * @dev: Device to handle.
+ *
+ */
+static int rcpm_pm_prepare(struct device *dev)
+{
+       int i, ret, idx;
+       void __iomem *base;
+       struct wakeup_source    *ws;
+       struct rcpm             *rcpm;
+       struct device_node      *np = dev->of_node;
+       u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
+       u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
+
+       rcpm = dev_get_drvdata(dev);
+       if (!rcpm)
+               return -EINVAL;
+
+       base = rcpm->ippdexpcr_base;
+       idx = wakeup_sources_read_lock();
+
+       /* Begin with first registered wakeup source */
+       for_each_wakeup_source(ws) {
+
+               /* skip object which is not attached to device */
+               if (!ws->dev || !ws->dev->parent)
+                       continue;
+
+               ret = device_property_read_u32_array(ws->dev->parent,
+                               "fsl,rcpm-wakeup", value,
+                               rcpm->wakeup_cells + 1);
+
+               /*  Wakeup source should refer to current rcpm device */
+               if (ret || (np->phandle != value[0]))
+                       continue;
+
+               /* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
+                * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
+                * of wakeup source IP contains an integer array: <phandle to
+                * RCPM node, IPPDEXPCR0 setting, IPPDEXPCR1 setting,
+                * IPPDEXPCR2 setting, etc>.
+                *
+                * So we will go thought them to collect setting data.
+                */
+               for (i = 0; i < rcpm->wakeup_cells; i++)
+                       setting[i] |= value[i + 1];
+       }
+
+       wakeup_sources_read_unlock(idx);
+
+       /* Program all IPPDEXPCRn once */
+       for (i = 0; i < rcpm->wakeup_cells; i++) {
+               u32 tmp = setting[i];
+               void __iomem *address = base + i * 4;
+
+               if (!tmp)
+                       continue;
+
+               /* We can only OR related bits */
+               if (rcpm->little_endian) {
+                       tmp |= ioread32(address);
+                       iowrite32(tmp, address);
+               } else {
+                       tmp |= ioread32be(address);
+                       iowrite32be(tmp, address);
+               }
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops rcpm_pm_ops = {
+       .prepare =  rcpm_pm_prepare,
+};
+
+static int rcpm_probe(struct platform_device *pdev)
+{
+       struct device   *dev = &pdev->dev;
+       struct resource *r;
+       struct rcpm     *rcpm;
+       int ret;
+
+       rcpm = devm_kzalloc(dev, sizeof(*rcpm), GFP_KERNEL);
+       if (!rcpm)
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -ENODEV;
+
+       rcpm->ippdexpcr_base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(rcpm->ippdexpcr_base)) {
+               ret =  PTR_ERR(rcpm->ippdexpcr_base);
+               return ret;
+       }
+
+       rcpm->little_endian = device_property_read_bool(
+                       &pdev->dev, "little-endian");
+
+       ret = device_property_read_u32(&pdev->dev,
+                       "#fsl,rcpm-wakeup-cells", &rcpm->wakeup_cells);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(&pdev->dev, rcpm);
+
+       return 0;
+}
+
+static const struct of_device_id rcpm_of_match[] = {
+       { .compatible = "fsl,qoriq-rcpm-2.1+", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, rcpm_of_match);
+
+static struct platform_driver rcpm_driver = {
+       .driver = {
+               .name = "rcpm",
+               .of_match_table = rcpm_of_match,
+               .pm     = &rcpm_pm_ops,
+       },
+       .probe = rcpm_probe,
+};
+
+module_platform_driver(rcpm_driver);
index c68882e..fb70b8a 100644 (file)
@@ -33,12 +33,10 @@ struct imx_sc_msg_misc_get_soc_uid {
        u32 uid_high;
 } __packed;
 
-static ssize_t soc_uid_show(struct device *dev,
-                           struct device_attribute *attr, char *buf)
+static int imx_scu_soc_uid(u64 *soc_uid)
 {
        struct imx_sc_msg_misc_get_soc_uid msg;
        struct imx_sc_rpc_msg *hdr = &msg.hdr;
-       u64 soc_uid;
        int ret;
 
        hdr->ver = IMX_SC_RPC_VERSION;
@@ -52,15 +50,13 @@ static ssize_t soc_uid_show(struct device *dev,
                return ret;
        }
 
-       soc_uid = msg.uid_high;
-       soc_uid <<= 32;
-       soc_uid |= msg.uid_low;
+       *soc_uid = msg.uid_high;
+       *soc_uid <<= 32;
+       *soc_uid |= msg.uid_low;
 
-       return sprintf(buf, "%016llX\n", soc_uid);
+       return 0;
 }
 
-static DEVICE_ATTR_RO(soc_uid);
-
 static int imx_scu_soc_id(void)
 {
        struct imx_sc_msg_misc_get_soc_id msg;
@@ -89,6 +85,7 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
        struct soc_device_attribute *soc_dev_attr;
        struct soc_device *soc_dev;
        int id, ret;
+       u64 uid = 0;
        u32 val;
 
        ret = imx_scu_get_handle(&soc_ipc_handle);
@@ -112,6 +109,10 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
        if (id < 0)
                return -EINVAL;
 
+       ret = imx_scu_soc_uid(&uid);
+       if (ret < 0)
+               return -EINVAL;
+
        /* format soc_id value passed from SCU firmware */
        val = id & 0x1f;
        soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val);
@@ -130,19 +131,22 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
                goto free_soc_id;
        }
 
+       soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", uid);
+       if (!soc_dev_attr->serial_number) {
+               ret = -ENOMEM;
+               goto free_revision;
+       }
+
        soc_dev = soc_device_register(soc_dev_attr);
        if (IS_ERR(soc_dev)) {
                ret = PTR_ERR(soc_dev);
-               goto free_revision;
+               goto free_serial_number;
        }
 
-       ret = device_create_file(soc_device_to_device(soc_dev),
-                                &dev_attr_soc_uid);
-       if (ret)
-               goto free_revision;
-
        return 0;
 
+free_serial_number:
+       kfree(soc_dev_attr->serial_number);
 free_revision:
        kfree(soc_dev_attr->revision);
 free_soc_id:
index b983157..d84ed73 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include <linux/platform_device.h>
+#include <linux/arm-smccc.h>
 #include <linux/of.h>
 
 #define REV_B1                         0x21
@@ -16,6 +17,8 @@
 #define IMX8MQ_SW_INFO_B1              0x40
 #define IMX8MQ_SW_MAGIC_B1             0xff0055aa
 
+#define IMX_SIP_GET_SOC_INFO           0xc2000006
+
 #define OCOTP_UID_LOW                  0x410
 #define OCOTP_UID_HIGH                 0x420
 
@@ -29,13 +32,21 @@ struct imx8_soc_data {
 
 static u64 soc_uid;
 
-static ssize_t soc_uid_show(struct device *dev,
-                           struct device_attribute *attr, char *buf)
+#ifdef CONFIG_HAVE_ARM_SMCCC
+static u32 imx8mq_soc_revision_from_atf(void)
 {
-       return sprintf(buf, "%016llX\n", soc_uid);
-}
+       struct arm_smccc_res res;
 
-static DEVICE_ATTR_RO(soc_uid);
+       arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
+
+       if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+               return 0;
+       else
+               return res.a0 & 0xff;
+}
+#else
+static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; };
+#endif
 
 static u32 __init imx8mq_soc_revision(void)
 {
@@ -51,9 +62,16 @@ static u32 __init imx8mq_soc_revision(void)
        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;
+       /*
+        * SOC revision on older imx8mq is not available in fuses so query
+        * the value from ATF instead.
+        */
+       rev = imx8mq_soc_revision_from_atf();
+       if (!rev) {
+               magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
+               if (magic == IMX8MQ_SW_MAGIC_B1)
+                       rev = REV_B1;
+       }
 
        soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
        soc_uid <<= 32;
@@ -174,22 +192,25 @@ static int __init imx8_soc_init(void)
                goto free_soc;
        }
 
+       soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);
+       if (!soc_dev_attr->serial_number) {
+               ret = -ENOMEM;
+               goto free_rev;
+       }
+
        soc_dev = soc_device_register(soc_dev_attr);
        if (IS_ERR(soc_dev)) {
                ret = PTR_ERR(soc_dev);
-               goto free_rev;
+               goto free_serial_number;
        }
 
-       ret = device_create_file(soc_device_to_device(soc_dev),
-                                &dev_attr_soc_uid);
-       if (ret)
-               goto free_rev;
-
        if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
                platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
 
        return 0;
 
+free_serial_number:
+       kfree(soc_dev_attr->serial_number);
 free_rev:
        if (strcmp(soc_dev_attr->revision, "unknown"))
                kfree(soc_dev_attr->revision);
index 503222d..f669d37 100644 (file)
@@ -21,7 +21,7 @@
 #include <dt-bindings/power/mt8173-power.h>
 
 #define MTK_POLL_DELAY_US   10
-#define MTK_POLL_TIMEOUT    (jiffies_to_usecs(HZ))
+#define MTK_POLL_TIMEOUT    USEC_PER_SEC
 
 #define MTK_SCPD_ACTIVE_WAKEUP         BIT(0)
 #define MTK_SCPD_FWAIT_SRAM            BIT(1)
@@ -108,6 +108,17 @@ static const char * const clk_names[] = {
 
 #define MAX_CLKS       3
 
+/**
+ * struct scp_domain_data - scp domain data for power on/off flow
+ * @name: The domain name.
+ * @sta_mask: The mask for power on/off status bit.
+ * @ctl_offs: The offset for main power control register.
+ * @sram_pdn_bits: The mask for sram power control bits.
+ * @sram_pdn_ack_bits: The mask for sram power control acked bits.
+ * @bus_prot_mask: The mask for single step bus protection.
+ * @clk_id: The basic clocks required by this power domain.
+ * @caps: The flag for active wake-up action.
+ */
 struct scp_domain_data {
        const char *name;
        u32 sta_mask;
@@ -180,32 +191,132 @@ static int scpsys_domain_is_on(struct scp_domain *scpd)
        return -EINVAL;
 }
 
+static int scpsys_regulator_enable(struct scp_domain *scpd)
+{
+       if (!scpd->supply)
+               return 0;
+
+       return regulator_enable(scpd->supply);
+}
+
+static int scpsys_regulator_disable(struct scp_domain *scpd)
+{
+       if (!scpd->supply)
+               return 0;
+
+       return regulator_disable(scpd->supply);
+}
+
+static void scpsys_clk_disable(struct clk *clk[], int max_num)
+{
+       int i;
+
+       for (i = max_num - 1; i >= 0; i--)
+               clk_disable_unprepare(clk[i]);
+}
+
+static int scpsys_clk_enable(struct clk *clk[], int max_num)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < max_num && clk[i]; i++) {
+               ret = clk_prepare_enable(clk[i]);
+               if (ret) {
+                       scpsys_clk_disable(clk, i);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
+{
+       u32 val;
+       u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
+       int tmp;
+
+       val = readl(ctl_addr);
+       val &= ~scpd->data->sram_pdn_bits;
+       writel(val, ctl_addr);
+
+       /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
+       if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
+               /*
+                * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
+                * MT7622_POWER_DOMAIN_WB and thus just a trivial setup
+                * is applied here.
+                */
+               usleep_range(12000, 12100);
+       } else {
+               /* Either wait until SRAM_PDN_ACK all 1 or 0 */
+               int ret = readl_poll_timeout(ctl_addr, tmp,
+                               (tmp & pdn_ack) == 0,
+                               MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
+{
+       u32 val;
+       u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
+       int tmp;
+
+       val = readl(ctl_addr);
+       val |= scpd->data->sram_pdn_bits;
+       writel(val, ctl_addr);
+
+       /* Either wait until SRAM_PDN_ACK all 1 or 0 */
+       return readl_poll_timeout(ctl_addr, tmp,
+                       (tmp & pdn_ack) == pdn_ack,
+                       MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+}
+
+static int scpsys_bus_protect_enable(struct scp_domain *scpd)
+{
+       struct scp *scp = scpd->scp;
+
+       if (!scpd->data->bus_prot_mask)
+               return 0;
+
+       return mtk_infracfg_set_bus_protection(scp->infracfg,
+                       scpd->data->bus_prot_mask,
+                       scp->bus_prot_reg_update);
+}
+
+static int scpsys_bus_protect_disable(struct scp_domain *scpd)
+{
+       struct scp *scp = scpd->scp;
+
+       if (!scpd->data->bus_prot_mask)
+               return 0;
+
+       return mtk_infracfg_clear_bus_protection(scp->infracfg,
+                       scpd->data->bus_prot_mask,
+                       scp->bus_prot_reg_update);
+}
+
 static int scpsys_power_on(struct generic_pm_domain *genpd)
 {
        struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
        struct scp *scp = scpd->scp;
        void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
-       u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
        u32 val;
        int ret, tmp;
-       int i;
 
-       if (scpd->supply) {
-               ret = regulator_enable(scpd->supply);
-               if (ret)
-                       return ret;
-       }
-
-       for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
-               ret = clk_prepare_enable(scpd->clk[i]);
-               if (ret) {
-                       for (--i; i >= 0; i--)
-                               clk_disable_unprepare(scpd->clk[i]);
+       ret = scpsys_regulator_enable(scpd);
+       if (ret < 0)
+               return ret;
 
-                       goto err_clk;
-               }
-       }
+       ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
+       if (ret)
+               goto err_clk;
 
+       /* subsys power on */
        val = readl(ctl_addr);
        val |= PWR_ON_BIT;
        writel(val, ctl_addr);
@@ -227,43 +338,20 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
        val |= PWR_RST_B_BIT;
        writel(val, ctl_addr);
 
-       val &= ~scpd->data->sram_pdn_bits;
-       writel(val, ctl_addr);
-
-       /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
-       if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
-               /*
-                * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
-                * MT7622_POWER_DOMAIN_WB and thus just a trivial setup is
-                * applied here.
-                */
-               usleep_range(12000, 12100);
-
-       } else {
-               ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0,
-                                        MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
-               if (ret < 0)
-                       goto err_pwr_ack;
-       }
+       ret = scpsys_sram_enable(scpd, ctl_addr);
+       if (ret < 0)
+               goto err_pwr_ack;
 
-       if (scpd->data->bus_prot_mask) {
-               ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
-                               scpd->data->bus_prot_mask,
-                               scp->bus_prot_reg_update);
-               if (ret)
-                       goto err_pwr_ack;
-       }
+       ret = scpsys_bus_protect_disable(scpd);
+       if (ret < 0)
+               goto err_pwr_ack;
 
        return 0;
 
 err_pwr_ack:
-       for (i = MAX_CLKS - 1; i >= 0; i--) {
-               if (scpd->clk[i])
-                       clk_disable_unprepare(scpd->clk[i]);
-       }
+       scpsys_clk_disable(scpd->clk, MAX_CLKS);
 err_clk:
-       if (scpd->supply)
-               regulator_disable(scpd->supply);
+       scpsys_regulator_disable(scpd);
 
        dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
 
@@ -275,29 +363,19 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
        struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
        struct scp *scp = scpd->scp;
        void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
-       u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
        u32 val;
        int ret, tmp;
-       int i;
-
-       if (scpd->data->bus_prot_mask) {
-               ret = mtk_infracfg_set_bus_protection(scp->infracfg,
-                               scpd->data->bus_prot_mask,
-                               scp->bus_prot_reg_update);
-               if (ret)
-                       goto out;
-       }
 
-       val = readl(ctl_addr);
-       val |= scpd->data->sram_pdn_bits;
-       writel(val, ctl_addr);
+       ret = scpsys_bus_protect_enable(scpd);
+       if (ret < 0)
+               goto out;
 
-       /* wait until SRAM_PDN_ACK all 1 */
-       ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
-                                MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+       ret = scpsys_sram_disable(scpd, ctl_addr);
        if (ret < 0)
                goto out;
 
+       /* subsys power off */
+       val = readl(ctl_addr);
        val |= PWR_ISO_BIT;
        writel(val, ctl_addr);
 
@@ -319,11 +397,11 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
        if (ret < 0)
                goto out;
 
-       for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
-               clk_disable_unprepare(scpd->clk[i]);
+       scpsys_clk_disable(scpd->clk, MAX_CLKS);
 
-       if (scpd->supply)
-               regulator_disable(scpd->supply);
+       ret = scpsys_regulator_disable(scpd);
+       if (ret < 0)
+               goto out;
 
        return 0;
 
index 661e47a..c6df8b4 100644 (file)
@@ -58,17 +58,9 @@ config QCOM_LLCC
        depends on ARCH_QCOM || COMPILE_TEST
        help
          Qualcomm Technologies, Inc. platform specific
-         Last Level Cache Controller(LLCC) driver. This provides interfaces
-         to clients that use the LLCC. Say yes here to enable LLCC slice
-         driver.
-
-config QCOM_SDM845_LLCC
-       tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver"
-       depends on QCOM_LLCC
-       help
-         Say yes here to enable the LLCC driver for SDM845. This provides
-         data required to configure LLCC so that clients can start using the
-         LLCC slices.
+         Last Level Cache Controller(LLCC) driver for platforms such as,
+         SDM845. This provides interfaces to clients that use the LLCC.
+         Say yes here to enable LLCC slice driver.
 
 config QCOM_MDT_LOADER
        tristate
index 1627887..2559fe9 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_QCOM_SMSM)       += smsm.o
 obj-$(CONFIG_QCOM_SOCINFO)     += socinfo.o
 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
 obj-$(CONFIG_QCOM_APR) += apr.o
-obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
-obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
+obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
 obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
new file mode 100644 (file)
index 0000000..429b5a6
--- /dev/null
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/llcc-qcom.h>
+
+#define ACTIVATE                      BIT(0)
+#define DEACTIVATE                    BIT(1)
+#define ACT_CTRL_OPCODE_ACTIVATE      BIT(0)
+#define ACT_CTRL_OPCODE_DEACTIVATE    BIT(1)
+#define ACT_CTRL_ACT_TRIG             BIT(0)
+#define ACT_CTRL_OPCODE_SHIFT         0x01
+#define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
+#define ATTR1_FIXED_SIZE_SHIFT        0x03
+#define ATTR1_PRIORITY_SHIFT          0x04
+#define ATTR1_MAX_CAP_SHIFT           0x10
+#define ATTR0_RES_WAYS_MASK           GENMASK(11, 0)
+#define ATTR0_BONUS_WAYS_MASK         GENMASK(27, 16)
+#define ATTR0_BONUS_WAYS_SHIFT        0x10
+#define LLCC_STATUS_READ_DELAY        100
+
+#define CACHE_LINE_SIZE_SHIFT         6
+
+#define LLCC_COMMON_STATUS0           0x0003000c
+#define LLCC_LB_CNT_MASK              GENMASK(31, 28)
+#define LLCC_LB_CNT_SHIFT             28
+
+#define MAX_CAP_TO_BYTES(n)           (n * SZ_1K)
+#define LLCC_TRP_ACT_CTRLn(n)         (n * SZ_4K)
+#define LLCC_TRP_STATUSn(n)           (4 + n * SZ_4K)
+#define LLCC_TRP_ATTR0_CFGn(n)        (0x21000 + SZ_8 * n)
+#define LLCC_TRP_ATTR1_CFGn(n)        (0x21004 + SZ_8 * n)
+
+#define BANK_OFFSET_STRIDE           0x80000
+
+/**
+ * llcc_slice_config - Data associated with the llcc slice
+ * @usecase_id: Unique id for the client's use case
+ * @slice_id: llcc slice id for each client
+ * @max_cap: The maximum capacity of the cache slice provided in KB
+ * @priority: Priority of the client used to select victim line for replacement
+ * @fixed_size: Boolean indicating if the slice has a fixed capacity
+ * @bonus_ways: Bonus ways are additional ways to be used for any slice,
+ *             if client ends up using more than reserved cache ways. Bonus
+ *             ways are allocated only if they are not reserved for some
+ *             other client.
+ * @res_ways: Reserved ways for the cache slice, the reserved ways cannot
+ *             be used by any other client than the one its assigned to.
+ * @cache_mode: Each slice operates as a cache, this controls the mode of the
+ *             slice: normal or TCM(Tightly Coupled Memory)
+ * @probe_target_ways: Determines what ways to probe for access hit. When
+ *                    configured to 1 only bonus and reserved ways are probed.
+ *                    When configured to 0 all ways in llcc are probed.
+ * @dis_cap_alloc: Disable capacity based allocation for a client
+ * @retain_on_pc: If this bit is set and client has maintained active vote
+ *               then the ways assigned to this client are not flushed on power
+ *               collapse.
+ * @activate_on_init: Activate the slice immediately after it is programmed
+ */
+struct llcc_slice_config {
+       u32 usecase_id;
+       u32 slice_id;
+       u32 max_cap;
+       u32 priority;
+       bool fixed_size;
+       u32 bonus_ways;
+       u32 res_ways;
+       u32 cache_mode;
+       u32 probe_target_ways;
+       bool dis_cap_alloc;
+       bool retain_on_pc;
+       bool activate_on_init;
+};
+
+struct qcom_llcc_config {
+       const struct llcc_slice_config *sct_data;
+       int size;
+};
+
+static const struct llcc_slice_config sc7180_data[] =  {
+       { LLCC_CPUSS,    1,  256, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 1 },
+       { LLCC_MDM,      8,  128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
+       { LLCC_GPUHTW,   11, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
+       { LLCC_GPU,      12, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
+};
+
+static const struct llcc_slice_config sdm845_data[] =  {
+       { LLCC_CPUSS,    1,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 1 },
+       { LLCC_VIDSC0,   2,  512,  2, 1, 0x0,   0x0f0, 0, 0, 1, 1, 0 },
+       { LLCC_VIDSC1,   3,  512,  2, 1, 0x0,   0x0f0, 0, 0, 1, 1, 0 },
+       { LLCC_ROTATOR,  4,  563,  2, 1, 0x0,   0x00e, 2, 0, 1, 1, 0 },
+       { LLCC_VOICE,    5,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_AUDIO,    6,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_MDMHPGRW, 7,  1024, 2, 0, 0xfc,  0xf00, 0, 0, 1, 1, 0 },
+       { LLCC_MDM,      8,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_CMPT,     10, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_GPUHTW,   11, 512,  1, 1, 0xc,   0x0,   0, 0, 1, 1, 0 },
+       { LLCC_GPU,      12, 2304, 1, 0, 0xff0, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_MMUHWT,   13, 256,  2, 0, 0x0,   0x1,   0, 0, 1, 0, 1 },
+       { LLCC_CMPTDMA,  15, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_DISP,     16, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_VIDFW,    17, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+       { LLCC_MDMHPFX,  20, 1024, 2, 1, 0x0,   0xf00, 0, 0, 1, 1, 0 },
+       { LLCC_MDMPNG,   21, 1024, 0, 1, 0x1e,  0x0,   0, 0, 1, 1, 0 },
+       { LLCC_AUDHW,    22, 1024, 1, 1, 0xffc, 0x2,   0, 0, 1, 1, 0 },
+};
+
+static const struct qcom_llcc_config sc7180_cfg = {
+       .sct_data       = sc7180_data,
+       .size           = ARRAY_SIZE(sc7180_data),
+};
+
+static const struct qcom_llcc_config sdm845_cfg = {
+       .sct_data       = sdm845_data,
+       .size           = ARRAY_SIZE(sdm845_data),
+};
+
+static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
+
+/**
+ * llcc_slice_getd - get llcc slice descriptor
+ * @uid: usecase_id for the client
+ *
+ * A pointer to llcc slice descriptor will be returned on success and
+ * and error pointer is returned on failure
+ */
+struct llcc_slice_desc *llcc_slice_getd(u32 uid)
+{
+       const struct llcc_slice_config *cfg;
+       struct llcc_slice_desc *desc;
+       u32 sz, count;
+
+       if (IS_ERR(drv_data))
+               return ERR_CAST(drv_data);
+
+       cfg = drv_data->cfg;
+       sz = drv_data->cfg_size;
+
+       for (count = 0; cfg && count < sz; count++, cfg++)
+               if (cfg->usecase_id == uid)
+                       break;
+
+       if (count == sz || !cfg)
+               return ERR_PTR(-ENODEV);
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return ERR_PTR(-ENOMEM);
+
+       desc->slice_id = cfg->slice_id;
+       desc->slice_size = cfg->max_cap;
+
+       return desc;
+}
+EXPORT_SYMBOL_GPL(llcc_slice_getd);
+
+/**
+ * llcc_slice_putd - llcc slice descritpor
+ * @desc: Pointer to llcc slice descriptor
+ */
+void llcc_slice_putd(struct llcc_slice_desc *desc)
+{
+       if (!IS_ERR_OR_NULL(desc))
+               kfree(desc);
+}
+EXPORT_SYMBOL_GPL(llcc_slice_putd);
+
+static int llcc_update_act_ctrl(u32 sid,
+                               u32 act_ctrl_reg_val, u32 status)
+{
+       u32 act_ctrl_reg;
+       u32 status_reg;
+       u32 slice_status;
+       int ret;
+
+       if (IS_ERR(drv_data))
+               return PTR_ERR(drv_data);
+
+       act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
+       status_reg = LLCC_TRP_STATUSn(sid);
+
+       /* Set the ACTIVE trigger */
+       act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
+       ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
+                               act_ctrl_reg_val);
+       if (ret)
+               return ret;
+
+       /* Clear the ACTIVE trigger */
+       act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
+       ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
+                               act_ctrl_reg_val);
+       if (ret)
+               return ret;
+
+       ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
+                                     slice_status, !(slice_status & status),
+                                     0, LLCC_STATUS_READ_DELAY);
+       return ret;
+}
+
+/**
+ * llcc_slice_activate - Activate the llcc slice
+ * @desc: Pointer to llcc slice descriptor
+ *
+ * A value of zero will be returned on success and a negative errno will
+ * be returned in error cases
+ */
+int llcc_slice_activate(struct llcc_slice_desc *desc)
+{
+       int ret;
+       u32 act_ctrl_val;
+
+       if (IS_ERR(drv_data))
+               return PTR_ERR(drv_data);
+
+       if (IS_ERR_OR_NULL(desc))
+               return -EINVAL;
+
+       mutex_lock(&drv_data->lock);
+       if (test_bit(desc->slice_id, drv_data->bitmap)) {
+               mutex_unlock(&drv_data->lock);
+               return 0;
+       }
+
+       act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT;
+
+       ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
+                                 DEACTIVATE);
+       if (ret) {
+               mutex_unlock(&drv_data->lock);
+               return ret;
+       }
+
+       __set_bit(desc->slice_id, drv_data->bitmap);
+       mutex_unlock(&drv_data->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(llcc_slice_activate);
+
+/**
+ * llcc_slice_deactivate - Deactivate the llcc slice
+ * @desc: Pointer to llcc slice descriptor
+ *
+ * A value of zero will be returned on success and a negative errno will
+ * be returned in error cases
+ */
+int llcc_slice_deactivate(struct llcc_slice_desc *desc)
+{
+       u32 act_ctrl_val;
+       int ret;
+
+       if (IS_ERR(drv_data))
+               return PTR_ERR(drv_data);
+
+       if (IS_ERR_OR_NULL(desc))
+               return -EINVAL;
+
+       mutex_lock(&drv_data->lock);
+       if (!test_bit(desc->slice_id, drv_data->bitmap)) {
+               mutex_unlock(&drv_data->lock);
+               return 0;
+       }
+       act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
+
+       ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
+                                 ACTIVATE);
+       if (ret) {
+               mutex_unlock(&drv_data->lock);
+               return ret;
+       }
+
+       __clear_bit(desc->slice_id, drv_data->bitmap);
+       mutex_unlock(&drv_data->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
+
+/**
+ * llcc_get_slice_id - return the slice id
+ * @desc: Pointer to llcc slice descriptor
+ */
+int llcc_get_slice_id(struct llcc_slice_desc *desc)
+{
+       if (IS_ERR_OR_NULL(desc))
+               return -EINVAL;
+
+       return desc->slice_id;
+}
+EXPORT_SYMBOL_GPL(llcc_get_slice_id);
+
+/**
+ * llcc_get_slice_size - return the slice id
+ * @desc: Pointer to llcc slice descriptor
+ */
+size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
+{
+       if (IS_ERR_OR_NULL(desc))
+               return 0;
+
+       return desc->slice_size;
+}
+EXPORT_SYMBOL_GPL(llcc_get_slice_size);
+
+static int qcom_llcc_cfg_program(struct platform_device *pdev)
+{
+       int i;
+       u32 attr1_cfg;
+       u32 attr0_cfg;
+       u32 attr1_val;
+       u32 attr0_val;
+       u32 max_cap_cacheline;
+       u32 sz;
+       int ret = 0;
+       const struct llcc_slice_config *llcc_table;
+       struct llcc_slice_desc desc;
+
+       sz = drv_data->cfg_size;
+       llcc_table = drv_data->cfg;
+
+       for (i = 0; i < sz; i++) {
+               attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
+               attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
+
+               attr1_val = llcc_table[i].cache_mode;
+               attr1_val |= llcc_table[i].probe_target_ways <<
+                               ATTR1_PROBE_TARGET_WAYS_SHIFT;
+               attr1_val |= llcc_table[i].fixed_size <<
+                               ATTR1_FIXED_SIZE_SHIFT;
+               attr1_val |= llcc_table[i].priority <<
+                               ATTR1_PRIORITY_SHIFT;
+
+               max_cap_cacheline = MAX_CAP_TO_BYTES(llcc_table[i].max_cap);
+
+               /* LLCC instances can vary for each target.
+                * The SW writes to broadcast register which gets propagated
+                * to each llcc instace (llcc0,.. llccN).
+                * Since the size of the memory is divided equally amongst the
+                * llcc instances, we need to configure the max cap accordingly.
+                */
+               max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
+               max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
+               attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
+
+               attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
+               attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
+
+               ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
+                                       attr1_val);
+               if (ret)
+                       return ret;
+               ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
+                                       attr0_val);
+               if (ret)
+                       return ret;
+               if (llcc_table[i].activate_on_init) {
+                       desc.slice_id = llcc_table[i].slice_id;
+                       ret = llcc_slice_activate(&desc);
+               }
+       }
+       return ret;
+}
+
+static int qcom_llcc_remove(struct platform_device *pdev)
+{
+       /* Set the global pointer to a error code to avoid referencing it */
+       drv_data = ERR_PTR(-ENODEV);
+       return 0;
+}
+
+static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
+               const char *name)
+{
+       struct resource *res;
+       void __iomem *base;
+       struct regmap_config llcc_regmap_config = {
+               .reg_bits = 32,
+               .reg_stride = 4,
+               .val_bits = 32,
+               .fast_io = true,
+       };
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (!res)
+               return ERR_PTR(-ENODEV);
+
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return ERR_CAST(base);
+
+       llcc_regmap_config.name = name;
+       return devm_regmap_init_mmio(&pdev->dev, base, &llcc_regmap_config);
+}
+
+static int qcom_llcc_probe(struct platform_device *pdev)
+{
+       u32 num_banks;
+       struct device *dev = &pdev->dev;
+       int ret, i;
+       struct platform_device *llcc_edac;
+       const struct qcom_llcc_config *cfg;
+       const struct llcc_slice_config *llcc_cfg;
+       u32 sz;
+
+       drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       drv_data->regmap = qcom_llcc_init_mmio(pdev, "llcc_base");
+       if (IS_ERR(drv_data->regmap)) {
+               ret = PTR_ERR(drv_data->regmap);
+               goto err;
+       }
+
+       drv_data->bcast_regmap =
+               qcom_llcc_init_mmio(pdev, "llcc_broadcast_base");
+       if (IS_ERR(drv_data->bcast_regmap)) {
+               ret = PTR_ERR(drv_data->bcast_regmap);
+               goto err;
+       }
+
+       ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
+                                               &num_banks);
+       if (ret)
+               goto err;
+
+       num_banks &= LLCC_LB_CNT_MASK;
+       num_banks >>= LLCC_LB_CNT_SHIFT;
+       drv_data->num_banks = num_banks;
+
+       cfg = of_device_get_match_data(&pdev->dev);
+       llcc_cfg = cfg->sct_data;
+       sz = cfg->size;
+
+       for (i = 0; i < sz; i++)
+               if (llcc_cfg[i].slice_id > drv_data->max_slices)
+                       drv_data->max_slices = llcc_cfg[i].slice_id;
+
+       drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32),
+                                                       GFP_KERNEL);
+       if (!drv_data->offsets) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       for (i = 0; i < num_banks; i++)
+               drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
+
+       drv_data->bitmap = devm_kcalloc(dev,
+       BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
+                                               GFP_KERNEL);
+       if (!drv_data->bitmap) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       drv_data->cfg = llcc_cfg;
+       drv_data->cfg_size = sz;
+       mutex_init(&drv_data->lock);
+       platform_set_drvdata(pdev, drv_data);
+
+       ret = qcom_llcc_cfg_program(pdev);
+       if (ret)
+               goto err;
+
+       drv_data->ecc_irq = platform_get_irq(pdev, 0);
+       if (drv_data->ecc_irq >= 0) {
+               llcc_edac = platform_device_register_data(&pdev->dev,
+                                               "qcom_llcc_edac", -1, drv_data,
+                                               sizeof(*drv_data));
+               if (IS_ERR(llcc_edac))
+                       dev_err(dev, "Failed to register llcc edac driver\n");
+       }
+
+       return 0;
+err:
+       drv_data = ERR_PTR(-ENODEV);
+       return ret;
+}
+
+static const struct of_device_id qcom_llcc_of_match[] = {
+       { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg },
+       { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
+       { }
+};
+
+static struct platform_driver qcom_llcc_driver = {
+       .driver = {
+               .name = "qcom-llcc",
+               .of_match_table = qcom_llcc_of_match,
+       },
+       .probe = qcom_llcc_probe,
+       .remove = qcom_llcc_remove,
+};
+module_platform_driver(qcom_llcc_driver);
+
+MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c
deleted file mode 100644 (file)
index 86600d9..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/soc/qcom/llcc-qcom.h>
-
-/*
- * SCT(System Cache Table) entry contains of the following members:
- * usecase_id: Unique id for the client's use case
- * slice_id: llcc slice id for each client
- * max_cap: The maximum capacity of the cache slice provided in KB
- * priority: Priority of the client used to select victim line for replacement
- * fixed_size: Boolean indicating if the slice has a fixed capacity
- * bonus_ways: Bonus ways are additional ways to be used for any slice,
- *             if client ends up using more than reserved cache ways. Bonus
- *             ways are allocated only if they are not reserved for some
- *             other client.
- * res_ways: Reserved ways for the cache slice, the reserved ways cannot
- *             be used by any other client than the one its assigned to.
- * cache_mode: Each slice operates as a cache, this controls the mode of the
- *             slice: normal or TCM(Tightly Coupled Memory)
- * probe_target_ways: Determines what ways to probe for access hit. When
- *                    configured to 1 only bonus and reserved ways are probed.
- *                    When configured to 0 all ways in llcc are probed.
- * dis_cap_alloc: Disable capacity based allocation for a client
- * retain_on_pc: If this bit is set and client has maintained active vote
- *               then the ways assigned to this client are not flushed on power
- *               collapse.
- * activate_on_init: Activate the slice immediately after the SCT is programmed
- */
-#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \
-       {                                       \
-               .usecase_id = uid,              \
-               .slice_id = sid,                \
-               .max_cap = mc,                  \
-               .priority = p,                  \
-               .fixed_size = fs,               \
-               .bonus_ways = bway,             \
-               .res_ways = rway,               \
-               .cache_mode = cmod,             \
-               .probe_target_ways = ptw,       \
-               .dis_cap_alloc = dca,           \
-               .retain_on_pc = rp,             \
-               .activate_on_init = a,          \
-       }
-
-static struct llcc_slice_config sdm845_data[] =  {
-       SCT_ENTRY(LLCC_CPUSS,    1,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 1),
-       SCT_ENTRY(LLCC_VIDSC0,   2,  512,  2, 1, 0x0,   0x0f0, 0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_VIDSC1,   3,  512,  2, 1, 0x0,   0x0f0, 0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_ROTATOR,  4,  563,  2, 1, 0x0,   0x00e, 2, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_VOICE,    5,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_AUDIO,    6,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_MDMHPGRW, 7,  1024, 2, 0, 0xfc,  0xf00, 0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_MDM,      8,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_CMPT,     10, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_GPUHTW,   11, 512,  1, 1, 0xc,   0x0,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_GPU,      12, 2304, 1, 0, 0xff0, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_MMUHWT,   13, 256,  2, 0, 0x0,   0x1,   0, 0, 1, 0, 1),
-       SCT_ENTRY(LLCC_CMPTDMA,  15, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_DISP,     16, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_VIDFW,    17, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_MDMHPFX,  20, 1024, 2, 1, 0x0,   0xf00, 0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_MDMPNG,   21, 1024, 0, 1, 0x1e,  0x0,   0, 0, 1, 1, 0),
-       SCT_ENTRY(LLCC_AUDHW,    22, 1024, 1, 1, 0xffc, 0x2,   0, 0, 1, 1, 0),
-};
-
-static int sdm845_qcom_llcc_remove(struct platform_device *pdev)
-{
-       return qcom_llcc_remove(pdev);
-}
-
-static int sdm845_qcom_llcc_probe(struct platform_device *pdev)
-{
-       return qcom_llcc_probe(pdev, sdm845_data, ARRAY_SIZE(sdm845_data));
-}
-
-static const struct of_device_id sdm845_qcom_llcc_of_match[] = {
-       { .compatible = "qcom,sdm845-llcc", },
-       { }
-};
-
-static struct platform_driver sdm845_qcom_llcc_driver = {
-       .driver = {
-               .name = "sdm845-llcc",
-               .of_match_table = sdm845_qcom_llcc_of_match,
-       },
-       .probe = sdm845_qcom_llcc_probe,
-       .remove = sdm845_qcom_llcc_remove,
-};
-module_platform_driver(sdm845_qcom_llcc_driver);
-
-MODULE_DESCRIPTION("QCOM sdm845 LLCC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c
deleted file mode 100644 (file)
index 9090ea1..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- *
- */
-
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-#include <linux/soc/qcom/llcc-qcom.h>
-
-#define ACTIVATE                      BIT(0)
-#define DEACTIVATE                    BIT(1)
-#define ACT_CTRL_OPCODE_ACTIVATE      BIT(0)
-#define ACT_CTRL_OPCODE_DEACTIVATE    BIT(1)
-#define ACT_CTRL_ACT_TRIG             BIT(0)
-#define ACT_CTRL_OPCODE_SHIFT         0x01
-#define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
-#define ATTR1_FIXED_SIZE_SHIFT        0x03
-#define ATTR1_PRIORITY_SHIFT          0x04
-#define ATTR1_MAX_CAP_SHIFT           0x10
-#define ATTR0_RES_WAYS_MASK           GENMASK(11, 0)
-#define ATTR0_BONUS_WAYS_MASK         GENMASK(27, 16)
-#define ATTR0_BONUS_WAYS_SHIFT        0x10
-#define LLCC_STATUS_READ_DELAY        100
-
-#define CACHE_LINE_SIZE_SHIFT         6
-
-#define LLCC_COMMON_STATUS0           0x0003000c
-#define LLCC_LB_CNT_MASK              GENMASK(31, 28)
-#define LLCC_LB_CNT_SHIFT             28
-
-#define MAX_CAP_TO_BYTES(n)           (n * SZ_1K)
-#define LLCC_TRP_ACT_CTRLn(n)         (n * SZ_4K)
-#define LLCC_TRP_STATUSn(n)           (4 + n * SZ_4K)
-#define LLCC_TRP_ATTR0_CFGn(n)        (0x21000 + SZ_8 * n)
-#define LLCC_TRP_ATTR1_CFGn(n)        (0x21004 + SZ_8 * n)
-
-#define BANK_OFFSET_STRIDE           0x80000
-
-static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
-
-static const struct regmap_config llcc_regmap_config = {
-       .reg_bits = 32,
-       .reg_stride = 4,
-       .val_bits = 32,
-       .fast_io = true,
-};
-
-/**
- * llcc_slice_getd - get llcc slice descriptor
- * @uid: usecase_id for the client
- *
- * A pointer to llcc slice descriptor will be returned on success and
- * and error pointer is returned on failure
- */
-struct llcc_slice_desc *llcc_slice_getd(u32 uid)
-{
-       const struct llcc_slice_config *cfg;
-       struct llcc_slice_desc *desc;
-       u32 sz, count;
-
-       if (IS_ERR(drv_data))
-               return ERR_CAST(drv_data);
-
-       cfg = drv_data->cfg;
-       sz = drv_data->cfg_size;
-
-       for (count = 0; cfg && count < sz; count++, cfg++)
-               if (cfg->usecase_id == uid)
-                       break;
-
-       if (count == sz || !cfg)
-               return ERR_PTR(-ENODEV);
-
-       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return ERR_PTR(-ENOMEM);
-
-       desc->slice_id = cfg->slice_id;
-       desc->slice_size = cfg->max_cap;
-
-       return desc;
-}
-EXPORT_SYMBOL_GPL(llcc_slice_getd);
-
-/**
- * llcc_slice_putd - llcc slice descritpor
- * @desc: Pointer to llcc slice descriptor
- */
-void llcc_slice_putd(struct llcc_slice_desc *desc)
-{
-       if (!IS_ERR_OR_NULL(desc))
-               kfree(desc);
-}
-EXPORT_SYMBOL_GPL(llcc_slice_putd);
-
-static int llcc_update_act_ctrl(u32 sid,
-                               u32 act_ctrl_reg_val, u32 status)
-{
-       u32 act_ctrl_reg;
-       u32 status_reg;
-       u32 slice_status;
-       int ret;
-
-       if (IS_ERR(drv_data))
-               return PTR_ERR(drv_data);
-
-       act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
-       status_reg = LLCC_TRP_STATUSn(sid);
-
-       /* Set the ACTIVE trigger */
-       act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
-       ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
-                               act_ctrl_reg_val);
-       if (ret)
-               return ret;
-
-       /* Clear the ACTIVE trigger */
-       act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
-       ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
-                               act_ctrl_reg_val);
-       if (ret)
-               return ret;
-
-       ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
-                                     slice_status, !(slice_status & status),
-                                     0, LLCC_STATUS_READ_DELAY);
-       return ret;
-}
-
-/**
- * llcc_slice_activate - Activate the llcc slice
- * @desc: Pointer to llcc slice descriptor
- *
- * A value of zero will be returned on success and a negative errno will
- * be returned in error cases
- */
-int llcc_slice_activate(struct llcc_slice_desc *desc)
-{
-       int ret;
-       u32 act_ctrl_val;
-
-       if (IS_ERR(drv_data))
-               return PTR_ERR(drv_data);
-
-       if (IS_ERR_OR_NULL(desc))
-               return -EINVAL;
-
-       mutex_lock(&drv_data->lock);
-       if (test_bit(desc->slice_id, drv_data->bitmap)) {
-               mutex_unlock(&drv_data->lock);
-               return 0;
-       }
-
-       act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT;
-
-       ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
-                                 DEACTIVATE);
-       if (ret) {
-               mutex_unlock(&drv_data->lock);
-               return ret;
-       }
-
-       __set_bit(desc->slice_id, drv_data->bitmap);
-       mutex_unlock(&drv_data->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(llcc_slice_activate);
-
-/**
- * llcc_slice_deactivate - Deactivate the llcc slice
- * @desc: Pointer to llcc slice descriptor
- *
- * A value of zero will be returned on success and a negative errno will
- * be returned in error cases
- */
-int llcc_slice_deactivate(struct llcc_slice_desc *desc)
-{
-       u32 act_ctrl_val;
-       int ret;
-
-       if (IS_ERR(drv_data))
-               return PTR_ERR(drv_data);
-
-       if (IS_ERR_OR_NULL(desc))
-               return -EINVAL;
-
-       mutex_lock(&drv_data->lock);
-       if (!test_bit(desc->slice_id, drv_data->bitmap)) {
-               mutex_unlock(&drv_data->lock);
-               return 0;
-       }
-       act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
-
-       ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
-                                 ACTIVATE);
-       if (ret) {
-               mutex_unlock(&drv_data->lock);
-               return ret;
-       }
-
-       __clear_bit(desc->slice_id, drv_data->bitmap);
-       mutex_unlock(&drv_data->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
-
-/**
- * llcc_get_slice_id - return the slice id
- * @desc: Pointer to llcc slice descriptor
- */
-int llcc_get_slice_id(struct llcc_slice_desc *desc)
-{
-       if (IS_ERR_OR_NULL(desc))
-               return -EINVAL;
-
-       return desc->slice_id;
-}
-EXPORT_SYMBOL_GPL(llcc_get_slice_id);
-
-/**
- * llcc_get_slice_size - return the slice id
- * @desc: Pointer to llcc slice descriptor
- */
-size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
-{
-       if (IS_ERR_OR_NULL(desc))
-               return 0;
-
-       return desc->slice_size;
-}
-EXPORT_SYMBOL_GPL(llcc_get_slice_size);
-
-static int qcom_llcc_cfg_program(struct platform_device *pdev)
-{
-       int i;
-       u32 attr1_cfg;
-       u32 attr0_cfg;
-       u32 attr1_val;
-       u32 attr0_val;
-       u32 max_cap_cacheline;
-       u32 sz;
-       int ret = 0;
-       const struct llcc_slice_config *llcc_table;
-       struct llcc_slice_desc desc;
-
-       sz = drv_data->cfg_size;
-       llcc_table = drv_data->cfg;
-
-       for (i = 0; i < sz; i++) {
-               attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
-               attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
-
-               attr1_val = llcc_table[i].cache_mode;
-               attr1_val |= llcc_table[i].probe_target_ways <<
-                               ATTR1_PROBE_TARGET_WAYS_SHIFT;
-               attr1_val |= llcc_table[i].fixed_size <<
-                               ATTR1_FIXED_SIZE_SHIFT;
-               attr1_val |= llcc_table[i].priority <<
-                               ATTR1_PRIORITY_SHIFT;
-
-               max_cap_cacheline = MAX_CAP_TO_BYTES(llcc_table[i].max_cap);
-
-               /* LLCC instances can vary for each target.
-                * The SW writes to broadcast register which gets propagated
-                * to each llcc instace (llcc0,.. llccN).
-                * Since the size of the memory is divided equally amongst the
-                * llcc instances, we need to configure the max cap accordingly.
-                */
-               max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
-               max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
-               attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
-
-               attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
-               attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
-
-               ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
-                                       attr1_val);
-               if (ret)
-                       return ret;
-               ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
-                                       attr0_val);
-               if (ret)
-                       return ret;
-               if (llcc_table[i].activate_on_init) {
-                       desc.slice_id = llcc_table[i].slice_id;
-                       ret = llcc_slice_activate(&desc);
-               }
-       }
-       return ret;
-}
-
-int qcom_llcc_remove(struct platform_device *pdev)
-{
-       /* Set the global pointer to a error code to avoid referencing it */
-       drv_data = ERR_PTR(-ENODEV);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_llcc_remove);
-
-static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
-               const char *name)
-{
-       struct resource *res;
-       void __iomem *base;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-       if (!res)
-               return ERR_PTR(-ENODEV);
-
-       base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(base))
-               return ERR_CAST(base);
-
-       return devm_regmap_init_mmio(&pdev->dev, base, &llcc_regmap_config);
-}
-
-int qcom_llcc_probe(struct platform_device *pdev,
-                     const struct llcc_slice_config *llcc_cfg, u32 sz)
-{
-       u32 num_banks;
-       struct device *dev = &pdev->dev;
-       int ret, i;
-       struct platform_device *llcc_edac;
-
-       drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
-       if (!drv_data) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       drv_data->regmap = qcom_llcc_init_mmio(pdev, "llcc_base");
-       if (IS_ERR(drv_data->regmap)) {
-               ret = PTR_ERR(drv_data->regmap);
-               goto err;
-       }
-
-       drv_data->bcast_regmap =
-               qcom_llcc_init_mmio(pdev, "llcc_broadcast_base");
-       if (IS_ERR(drv_data->bcast_regmap)) {
-               ret = PTR_ERR(drv_data->bcast_regmap);
-               goto err;
-       }
-
-       ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
-                                               &num_banks);
-       if (ret)
-               goto err;
-
-       num_banks &= LLCC_LB_CNT_MASK;
-       num_banks >>= LLCC_LB_CNT_SHIFT;
-       drv_data->num_banks = num_banks;
-
-       for (i = 0; i < sz; i++)
-               if (llcc_cfg[i].slice_id > drv_data->max_slices)
-                       drv_data->max_slices = llcc_cfg[i].slice_id;
-
-       drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32),
-                                                       GFP_KERNEL);
-       if (!drv_data->offsets) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       for (i = 0; i < num_banks; i++)
-               drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
-
-       drv_data->bitmap = devm_kcalloc(dev,
-       BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
-                                               GFP_KERNEL);
-       if (!drv_data->bitmap) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       drv_data->cfg = llcc_cfg;
-       drv_data->cfg_size = sz;
-       mutex_init(&drv_data->lock);
-       platform_set_drvdata(pdev, drv_data);
-
-       ret = qcom_llcc_cfg_program(pdev);
-       if (ret)
-               goto err;
-
-       drv_data->ecc_irq = platform_get_irq(pdev, 0);
-       if (drv_data->ecc_irq >= 0) {
-               llcc_edac = platform_device_register_data(&pdev->dev,
-                                               "qcom_llcc_edac", -1, drv_data,
-                                               sizeof(*drv_data));
-               if (IS_ERR(llcc_edac))
-                       dev_err(dev, "Failed to register llcc edac driver\n");
-       }
-
-       return 0;
-err:
-       drv_data = ERR_PTR(-ENODEV);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(qcom_llcc_probe);
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller");
index 33a27e6..006ac40 100644 (file)
@@ -44,7 +44,7 @@
 
 #define QMP_NUM_COOLING_RESOURCES      2
 
-static bool qmp_cdev_init_state = 1;
+static bool qmp_cdev_max_state = 1;
 
 struct qmp_cooling_device {
        struct thermal_cooling_device *cdev;
@@ -402,7 +402,7 @@ static void qmp_pd_remove(struct qmp *qmp)
 static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev,
                                  unsigned long *state)
 {
-       *state = qmp_cdev_init_state;
+       *state = qmp_cdev_max_state;
        return 0;
 }
 
@@ -432,7 +432,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
        snprintf(buf, sizeof(buf),
                 "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
                        qmp_cdev->name,
-                       cdev_state ? "off" : "on");
+                       cdev_state ? "on" : "off");
 
        ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf));
 
@@ -455,7 +455,7 @@ static int qmp_cooling_device_add(struct qmp *qmp,
        char *cdev_name = (char *)node->name;
 
        qmp_cdev->qmp = qmp;
-       qmp_cdev->state = qmp_cdev_init_state;
+       qmp_cdev->state = !qmp_cdev_max_state;
        qmp_cdev->name = cdev_name;
        qmp_cdev->cdev = devm_thermal_of_cooling_device_register
                                (qmp->dev, node,
index 3c1a55c..2b1834c 100644 (file)
@@ -115,6 +115,28 @@ struct rpmpd_desc {
 
 static DEFINE_MUTEX(rpmpd_lock);
 
+/* msm8976 RPM Power Domains */
+DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2);
+DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6);
+
+DEFINE_RPMPD_VFL(msm8976, vddcx_vfl, RWSC, 2);
+DEFINE_RPMPD_VFL(msm8976, vddmx_vfl, RWSM, 6);
+
+static struct rpmpd *msm8976_rpmpds[] = {
+       [MSM8976_VDDCX] =       &msm8976_vddcx,
+       [MSM8976_VDDCX_AO] =    &msm8976_vddcx_ao,
+       [MSM8976_VDDCX_VFL] =   &msm8976_vddcx_vfl,
+       [MSM8976_VDDMX] =       &msm8976_vddmx,
+       [MSM8976_VDDMX_AO] =    &msm8976_vddmx_ao,
+       [MSM8976_VDDMX_VFL] =   &msm8976_vddmx_vfl,
+};
+
+static const struct rpmpd_desc msm8976_desc = {
+       .rpmpds = msm8976_rpmpds,
+       .num_pds = ARRAY_SIZE(msm8976_rpmpds),
+       .max_state = RPM_SMD_LEVEL_TURBO_HIGH,
+};
+
 /* msm8996 RPM Power domains */
 DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1);
 DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2);
@@ -198,6 +220,7 @@ static const struct rpmpd_desc qcs404_desc = {
 };
 
 static const struct of_device_id rpmpd_match_table[] = {
+       { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
        { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
        { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
        { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
index fa9dd12..005dd30 100644 (file)
 /**
  * struct qcom_smd_rpm - state of the rpm device driver
  * @rpm_channel:       reference to the smd channel
+ * @icc:               interconnect proxy device
  * @ack:               completion for acks
  * @lock:              mutual exclusion around the send/complete pair
  * @ack_status:                result of the rpm request
  */
 struct qcom_smd_rpm {
        struct rpmsg_endpoint *rpm_channel;
+       struct platform_device *icc;
        struct device *dev;
 
        struct completion ack;
@@ -193,6 +195,7 @@ static int qcom_smd_rpm_callback(struct rpmsg_device *rpdev,
 static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
 {
        struct qcom_smd_rpm *rpm;
+       int ret;
 
        rpm = devm_kzalloc(&rpdev->dev, sizeof(*rpm), GFP_KERNEL);
        if (!rpm)
@@ -205,11 +208,23 @@ static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
        rpm->rpm_channel = rpdev->ept;
        dev_set_drvdata(&rpdev->dev, rpm);
 
-       return of_platform_populate(rpdev->dev.of_node, NULL, NULL, &rpdev->dev);
+       rpm->icc = platform_device_register_data(&rpdev->dev, "icc_smd_rpm", -1,
+                                                NULL, 0);
+       if (IS_ERR(rpm->icc))
+               return PTR_ERR(rpm->icc);
+
+       ret = of_platform_populate(rpdev->dev.of_node, NULL, NULL, &rpdev->dev);
+       if (ret)
+               platform_device_unregister(rpm->icc);
+
+       return ret;
 }
 
 static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
 {
+       struct qcom_smd_rpm *rpm = dev_get_drvdata(&rpdev->dev);
+
+       platform_device_unregister(rpm->icc);
        of_platform_depopulate(&rpdev->dev);
 }
 
@@ -217,6 +232,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
        { .compatible = "qcom,rpm-apq8084" },
        { .compatible = "qcom,rpm-msm8916" },
        { .compatible = "qcom,rpm-msm8974" },
+       { .compatible = "qcom,rpm-msm8976" },
        { .compatible = "qcom,rpm-msm8996" },
        { .compatible = "qcom,rpm-msm8998" },
        { .compatible = "qcom,rpm-sdm660" },
index a39ea50..7864b75 100644 (file)
@@ -198,6 +198,8 @@ static const struct soc_id soc_id[] = {
        { 310, "MSM8996AU" },
        { 311, "APQ8096AU" },
        { 312, "APQ8096SG" },
+       { 321, "SDM845" },
+       { 341, "SDA845" },
 };
 
 static const char *socinfo_machine(struct device *dev, unsigned int id)
index 3c5e017..f93492b 100644 (file)
@@ -178,6 +178,13 @@ config ARCH_R8A774A1
        help
          This enables support for the Renesas RZ/G2M SoC.
 
+config ARCH_R8A774B1
+       bool "Renesas RZ/G2N SoC Platform"
+       select ARCH_RCAR_GEN3
+       select SYSC_R8A774B1
+       help
+         This enables support for the Renesas RZ/G2N SoC.
+
 config ARCH_R8A774C0
        bool "Renesas RZ/G2E SoC Platform"
        select ARCH_RCAR_GEN3
@@ -192,13 +199,24 @@ config ARCH_R8A7795
        help
          This enables support for the Renesas R-Car H3 SoC.
 
+config ARCH_R8A77960
+       bool
+       select ARCH_RCAR_GEN3
+       select SYSC_R8A77960
+
 config ARCH_R8A7796
        bool "Renesas R-Car M3-W SoC Platform"
-       select ARCH_RCAR_GEN3
-       select SYSC_R8A7796
+       select ARCH_R8A77960
        help
          This enables support for the Renesas R-Car M3-W SoC.
 
+config ARCH_R8A77961
+       bool "Renesas R-Car M3-W+ SoC Platform"
+       select ARCH_RCAR_GEN3
+       select SYSC_R8A77961
+       help
+         This enables support for the Renesas R-Car M3-W+ SoC.
+
 config ARCH_R8A77965
        bool "Renesas R-Car M3-N SoC Platform"
        select ARCH_RCAR_GEN3
@@ -253,6 +271,10 @@ config SYSC_R8A774A1
        bool "RZ/G2M System Controller support" if COMPILE_TEST
        select SYSC_RCAR
 
+config SYSC_R8A774B1
+       bool "RZ/G2N System Controller support" if COMPILE_TEST
+       select SYSC_RCAR
+
 config SYSC_R8A774C0
        bool "RZ/G2E System Controller support" if COMPILE_TEST
        select SYSC_RCAR
@@ -281,10 +303,14 @@ config SYSC_R8A7795
        bool "R-Car H3 System Controller support" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7796
+config SYSC_R8A77960
        bool "R-Car M3-W System Controller support" if COMPILE_TEST
        select SYSC_RCAR
 
+config SYSC_R8A77961
+       bool "R-Car M3-W+ System Controller support" if COMPILE_TEST
+       select SYSC_RCAR
+
 config SYSC_R8A77965
        bool "R-Car M3-N System Controller support" if COMPILE_TEST
        select SYSC_RCAR
index 00764d5..e595c3c 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_SYSC_R8A7743)      += r8a7743-sysc.o
 obj-$(CONFIG_SYSC_R8A7745)     += r8a7745-sysc.o
 obj-$(CONFIG_SYSC_R8A77470)    += r8a77470-sysc.o
 obj-$(CONFIG_SYSC_R8A774A1)    += r8a774a1-sysc.o
+obj-$(CONFIG_SYSC_R8A774B1)    += r8a774b1-sysc.o
 obj-$(CONFIG_SYSC_R8A774C0)    += r8a774c0-sysc.o
 obj-$(CONFIG_SYSC_R8A7779)     += r8a7779-sysc.o
 obj-$(CONFIG_SYSC_R8A7790)     += r8a7790-sysc.o
@@ -14,7 +15,8 @@ obj-$(CONFIG_SYSC_R8A7791)    += r8a7791-sysc.o
 obj-$(CONFIG_SYSC_R8A7792)     += r8a7792-sysc.o
 obj-$(CONFIG_SYSC_R8A7794)     += r8a7794-sysc.o
 obj-$(CONFIG_SYSC_R8A7795)     += r8a7795-sysc.o
-obj-$(CONFIG_SYSC_R8A7796)     += r8a7796-sysc.o
+obj-$(CONFIG_SYSC_R8A77960)    += r8a7796-sysc.o
+obj-$(CONFIG_SYSC_R8A77961)    += r8a7796-sysc.o
 obj-$(CONFIG_SYSC_R8A77965)    += r8a77965-sysc.o
 obj-$(CONFIG_SYSC_R8A77970)    += r8a77970-sysc.o
 obj-$(CONFIG_SYSC_R8A77980)    += r8a77980-sysc.o
index edf6436..4e2c0ab 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Cogent Embedded Inc.
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7743-sysc.h>
index 65dc6b0..865821a 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Cogent Embedded Inc.
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7745-sysc.h>
index cfa015e..1eeb801 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2018 Renesas Electronics Corp.
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a77470-sysc.h>
index 9db51ff..38ac2c6 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 2016 Glider bvba
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a774a1-sysc.h>
diff --git a/drivers/soc/renesas/r8a774b1-sysc.c b/drivers/soc/renesas/r8a774b1-sysc.c
new file mode 100644 (file)
index 0000000..5f97ff2
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2N System Controller
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ *
+ * Based on Renesas R-Car M3-W System Controller
+ * Copyright (C) 2016 Glider bvba
+ */
+
+#include <linux/bits.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/power/r8a774b1-sysc.h>
+
+#include "rcar-sysc.h"
+
+static const struct rcar_sysc_area r8a774b1_areas[] __initconst = {
+       { "always-on",      0, 0, R8A774B1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+       { "ca57-scu",   0x1c0, 0, R8A774B1_PD_CA57_SCU, R8A774B1_PD_ALWAYS_ON,
+         PD_SCU },
+       { "ca57-cpu0",   0x80, 0, R8A774B1_PD_CA57_CPU0, R8A774B1_PD_CA57_SCU,
+         PD_CPU_NOCR },
+       { "ca57-cpu1",   0x80, 1, R8A774B1_PD_CA57_CPU1, R8A774B1_PD_CA57_SCU,
+         PD_CPU_NOCR },
+       { "a3vc",       0x380, 0, R8A774B1_PD_A3VC,     R8A774B1_PD_ALWAYS_ON },
+       { "a3vp",       0x340, 0, R8A774B1_PD_A3VP,     R8A774B1_PD_ALWAYS_ON },
+       { "a2vc1",      0x3c0, 1, R8A774B1_PD_A2VC1,    R8A774B1_PD_A3VC },
+       { "3dg-a",      0x100, 0, R8A774B1_PD_3DG_A,    R8A774B1_PD_ALWAYS_ON },
+       { "3dg-b",      0x100, 1, R8A774B1_PD_3DG_B,    R8A774B1_PD_3DG_A },
+};
+
+const struct rcar_sysc_info r8a774b1_sysc_info __initconst = {
+       .areas = r8a774b1_areas,
+       .num_areas = ARRAY_SIZE(r8a774b1_areas),
+       .extmask_offs = 0x2f8,
+       .extmask_val = BIT(0),
+};
index 11050e1..c1c216f 100644 (file)
@@ -6,7 +6,7 @@
  * Based on Renesas R-Car E3 System Controller
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/sys_soc.h>
 
@@ -50,4 +50,6 @@ const struct rcar_sysc_info r8a774c0_sysc_info __initconst = {
        .init = r8a774c0_sysc_init,
        .areas = r8a774c0_areas,
        .num_areas = ARRAY_SIZE(r8a774c0_areas),
+       .extmask_offs = 0x2f8,
+       .extmask_val = BIT(0),
 };
index 517aa40..e24a715 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Glider bvba
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7779-sysc.h>
index 9b5a6bb..b9afe7f 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Glider bvba
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7790-sysc.h>
index acf545c..f00fa24 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Glider bvba
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7791-sysc.h>
index 05b7852..60aae24 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Cogent Embedded Inc.
  */
 
-#include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 
index 0d42637..72ef4e8 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2016 Glider bvba
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7794-sysc.h>
index cda27a6..9107441 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2016-2017 Glider bvba
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/sys_soc.h>
 
@@ -51,25 +51,46 @@ static struct rcar_sysc_area r8a7795_areas[] __initdata = {
 
 
        /*
-        * Fixups for R-Car H3 revisions after ES1.x
+        * Fixups for R-Car H3 revisions
         */
 
-static const struct soc_device_attribute r8a7795es1[] __initconst = {
-       { .soc_id = "r8a7795", .revision = "ES1.*" },
+#define HAS_A2VC0      BIT(0)          /* Power domain A2VC0 is present */
+#define NO_EXTMASK     BIT(1)          /* Missing SYSCEXTMASK register */
+
+static const struct soc_device_attribute r8a7795_quirks_match[] __initconst = {
+       {
+               .soc_id = "r8a7795", .revision = "ES1.*",
+               .data = (void *)(HAS_A2VC0 | NO_EXTMASK),
+       }, {
+               .soc_id = "r8a7795", .revision = "ES2.*",
+               .data = (void *)(NO_EXTMASK),
+       },
        { /* sentinel */ }
 };
 
 static int __init r8a7795_sysc_init(void)
 {
-       if (!soc_device_match(r8a7795es1))
+       const struct soc_device_attribute *attr;
+       u32 quirks = 0;
+
+       attr = soc_device_match(r8a7795_quirks_match);
+       if (attr)
+               quirks = (uintptr_t)attr->data;
+
+       if (!(quirks & HAS_A2VC0))
                rcar_sysc_nullify(r8a7795_areas, ARRAY_SIZE(r8a7795_areas),
                                  R8A7795_PD_A2VC0);
 
+       if (quirks & NO_EXTMASK)
+               r8a7795_sysc_info.extmask_val = 0;
+
        return 0;
 }
 
-const struct rcar_sysc_info r8a7795_sysc_info __initconst = {
+struct rcar_sysc_info r8a7795_sysc_info __initdata = {
        .init = r8a7795_sysc_init,
        .areas = r8a7795_areas,
        .num_areas = ARRAY_SIZE(r8a7795_areas),
+       .extmask_offs = 0x2f8,
+       .extmask_val = BIT(0),
 };
index 1b06f86..471bd5b 100644 (file)
@@ -1,18 +1,19 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Renesas R-Car M3-W System Controller
+ * Renesas R-Car M3-W/W+ System Controller
  *
  * Copyright (C) 2016 Glider bvba
+ * Copyright (C) 2018-2019 Renesas Electronics Corporation
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a7796-sysc.h>
 
 #include "rcar-sysc.h"
 
-static const struct rcar_sysc_area r8a7796_areas[] __initconst = {
+static struct rcar_sysc_area r8a7796_areas[] __initdata = {
        { "always-on",      0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
        { "ca57-scu",   0x1c0, 0, R8A7796_PD_CA57_SCU,  R8A7796_PD_ALWAYS_ON,
          PD_SCU },
@@ -39,7 +40,28 @@ static const struct rcar_sysc_area r8a7796_areas[] __initconst = {
        { "a3ir",       0x180, 0, R8A7796_PD_A3IR,      R8A7796_PD_ALWAYS_ON },
 };
 
-const struct rcar_sysc_info r8a7796_sysc_info __initconst = {
+
+#ifdef CONFIG_SYSC_R8A77960
+const struct rcar_sysc_info r8a77960_sysc_info __initconst = {
+       .areas = r8a7796_areas,
+       .num_areas = ARRAY_SIZE(r8a7796_areas),
+};
+#endif /* CONFIG_SYSC_R8A77960 */
+
+#ifdef CONFIG_SYSC_R8A77961
+static int __init r8a77961_sysc_init(void)
+{
+       rcar_sysc_nullify(r8a7796_areas, ARRAY_SIZE(r8a7796_areas),
+                         R8A7796_PD_A2VC0);
+
+       return 0;
+}
+
+const struct rcar_sysc_info r8a77961_sysc_info __initconst = {
+       .init = r8a77961_sysc_init,
        .areas = r8a7796_areas,
        .num_areas = ARRAY_SIZE(r8a7796_areas),
+       .extmask_offs = 0x2f8,
+       .extmask_val = BIT(0),
 };
+#endif /* CONFIG_SYSC_R8A77961 */
index e0533be..ff0b0d1 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2016 Glider bvba
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a77965-sysc.h>
@@ -33,4 +33,6 @@ static const struct rcar_sysc_area r8a77965_areas[] __initconst = {
 const struct rcar_sysc_info r8a77965_sysc_info __initconst = {
        .areas = r8a77965_areas,
        .num_areas = ARRAY_SIZE(r8a77965_areas),
+       .extmask_offs = 0x2f8,
+       .extmask_val = BIT(0),
 };
index 280c48b..7062582 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2017 Cogent Embedded Inc.
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a77970-sysc.h>
@@ -32,4 +32,6 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = {
 const struct rcar_sysc_info r8a77970_sysc_info __initconst = {
        .areas = r8a77970_areas,
        .num_areas = ARRAY_SIZE(r8a77970_areas),
+       .extmask_offs = 0x1b0,
+       .extmask_val = BIT(0),
 };
index a8dbe55..39ca84a 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2018 Cogent Embedded, Inc.
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a77980-sysc.h>
@@ -49,4 +49,6 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = {
 const struct rcar_sysc_info r8a77980_sysc_info __initconst = {
        .areas = r8a77980_areas,
        .num_areas = ARRAY_SIZE(r8a77980_areas),
+       .extmask_offs = 0x138,
+       .extmask_val = BIT(0),
 };
index 664b244..9f92737 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2018 Renesas Electronics Corp.
  */
 
-#include <linux/bug.h>
+#include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/sys_soc.h>
 
@@ -50,4 +50,6 @@ const struct rcar_sysc_info r8a77990_sysc_info __initconst = {
        .init = r8a77990_sysc_init,
        .areas = r8a77990_areas,
        .num_areas = ARRAY_SIZE(r8a77990_areas),
+       .extmask_offs = 0x2f8,
+       .extmask_val = BIT(0),
 };
index 6243aaa..efcc67e 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2017 Glider bvba
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include <dt-bindings/power/r8a77995-sysc.h>
index d183c38..14d05a0 100644 (file)
@@ -45,6 +45,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
        { .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 },
        /* RZ/G2 is handled like R-Car Gen3 */
        { .compatible = "renesas,r8a774a1-rst", .data = &rcar_rst_gen3 },
+       { .compatible = "renesas,r8a774b1-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a774c0-rst", .data = &rcar_rst_gen3 },
        /* R-Car Gen1 */
        { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 },
@@ -58,6 +59,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
        /* R-Car Gen3 */
        { .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen3 },
+       { .compatible = "renesas,r8a77961-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a77965-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
index 59b5e6b..f0b291e 100644 (file)
@@ -63,6 +63,7 @@ struct rcar_sysc_ch {
 
 static void __iomem *rcar_sysc_base;
 static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
+static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val;
 
 static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
 {
@@ -105,6 +106,14 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
 
        spin_lock_irqsave(&rcar_sysc_lock, flags);
 
+       /*
+        * Mask external power requests for CPU or 3DG domains
+        */
+       if (rcar_sysc_extmask_val) {
+               iowrite32(rcar_sysc_extmask_val,
+                         rcar_sysc_base + rcar_sysc_extmask_offs);
+       }
+
        /*
         * The interrupt source needs to be enabled, but masked, to prevent the
         * CPU from receiving it.
@@ -148,6 +157,9 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
        iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
 
  out:
+       if (rcar_sysc_extmask_val)
+               iowrite32(0, rcar_sysc_base + rcar_sysc_extmask_offs);
+
        spin_unlock_irqrestore(&rcar_sysc_lock, flags);
 
        pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
@@ -275,6 +287,9 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = {
 #ifdef CONFIG_SYSC_R8A774A1
        { .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
 #endif
+#ifdef CONFIG_SYSC_R8A774B1
+       { .compatible = "renesas,r8a774b1-sysc", .data = &r8a774b1_sysc_info },
+#endif
 #ifdef CONFIG_SYSC_R8A774C0
        { .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
 #endif
@@ -298,8 +313,11 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = {
 #ifdef CONFIG_SYSC_R8A7795
        { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
 #endif
-#ifdef CONFIG_SYSC_R8A7796
-       { .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
+#ifdef CONFIG_SYSC_R8A77960
+       { .compatible = "renesas,r8a7796-sysc", .data = &r8a77960_sysc_info },
+#endif
+#ifdef CONFIG_SYSC_R8A77961
+       { .compatible = "renesas,r8a77961-sysc", .data = &r8a77961_sysc_info },
 #endif
 #ifdef CONFIG_SYSC_R8A77965
        { .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info },
@@ -360,6 +378,10 @@ static int __init rcar_sysc_pd_init(void)
 
        rcar_sysc_base = base;
 
+       /* Optional External Request Mask Register */
+       rcar_sysc_extmask_offs = info->extmask_offs;
+       rcar_sysc_extmask_val = info->extmask_val;
+
        domains = kzalloc(sizeof(*domains), GFP_KERNEL);
        if (!domains) {
                error = -ENOMEM;
index 485520a..8d07448 100644 (file)
@@ -44,20 +44,25 @@ struct rcar_sysc_info {
        int (*init)(void);      /* Optional */
        const struct rcar_sysc_area *areas;
        unsigned int num_areas;
+       /* Optional External Request Mask Register */
+       u32 extmask_offs;       /* SYSCEXTMASK register offset */
+       u32 extmask_val;        /* SYSCEXTMASK register mask value */
 };
 
 extern const struct rcar_sysc_info r8a7743_sysc_info;
 extern const struct rcar_sysc_info r8a7745_sysc_info;
 extern const struct rcar_sysc_info r8a77470_sysc_info;
 extern const struct rcar_sysc_info r8a774a1_sysc_info;
+extern const struct rcar_sysc_info r8a774b1_sysc_info;
 extern const struct rcar_sysc_info r8a774c0_sysc_info;
 extern const struct rcar_sysc_info r8a7779_sysc_info;
 extern const struct rcar_sysc_info r8a7790_sysc_info;
 extern const struct rcar_sysc_info r8a7791_sysc_info;
 extern const struct rcar_sysc_info r8a7792_sysc_info;
 extern const struct rcar_sysc_info r8a7794_sysc_info;
-extern const struct rcar_sysc_info r8a7795_sysc_info;
-extern const struct rcar_sysc_info r8a7796_sysc_info;
+extern struct rcar_sysc_info r8a7795_sysc_info;
+extern const struct rcar_sysc_info r8a77960_sysc_info;
+extern const struct rcar_sysc_info r8a77961_sysc_info;
 extern const struct rcar_sysc_info r8a77965_sysc_info;
 extern const struct rcar_sysc_info r8a77970_sysc_info;
 extern const struct rcar_sysc_info r8a77980_sysc_info;
index 3299cf5..850f573 100644 (file)
@@ -116,6 +116,11 @@ static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
        .id     = 0x52,
 };
 
+static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = {
+       .family = &fam_rzg2,
+       .id     = 0x55,
+};
+
 static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
        .family = &fam_rzg2,
        .id     = 0x57,
@@ -227,6 +232,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
 #ifdef CONFIG_ARCH_R8A774A1
        { .compatible = "renesas,r8a774a1",     .data = &soc_rz_g2m },
 #endif
+#ifdef CONFIG_ARCH_R8A774B1
+       { .compatible = "renesas,r8a774b1",     .data = &soc_rz_g2n },
+#endif
 #ifdef CONFIG_ARCH_R8A774C0
        { .compatible = "renesas,r8a774c0",     .data = &soc_rz_g2e },
 #endif
@@ -254,9 +262,12 @@ static const struct of_device_id renesas_socs[] __initconst = {
 #ifdef CONFIG_ARCH_R8A7795
        { .compatible = "renesas,r8a7795",      .data = &soc_rcar_h3 },
 #endif
-#ifdef CONFIG_ARCH_R8A7796
+#ifdef CONFIG_ARCH_R8A77960
        { .compatible = "renesas,r8a7796",      .data = &soc_rcar_m3_w },
 #endif
+#ifdef CONFIG_ARCH_R8A77961
+       { .compatible = "renesas,r8a77961",     .data = &soc_rcar_m3_w },
+#endif
 #ifdef CONFIG_ARCH_R8A77965
        { .compatible = "renesas,r8a77965",     .data = &soc_rcar_m3_n },
 #endif
@@ -326,7 +337,7 @@ static int __init renesas_soc_init(void)
        if (np) {
                chipid = of_iomap(np, 0);
                of_node_put(np);
-       } else if (soc->id) {
+       } else if (soc->id && family->reg) {
                chipid = ioremap(family->reg, 4);
        }
        if (chipid) {
index 33ad0de..27fc59b 100644 (file)
@@ -7,6 +7,16 @@ menuconfig SOC_SAMSUNG
 
 if SOC_SAMSUNG
 
+config EXYNOS_ASV
+       bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST
+       depends on (ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST
+       select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS
+
+# There is no need to enable these drivers for ARMv8
+config EXYNOS_ASV_ARM
+       bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST
+       depends on EXYNOS_ASV
+
 config EXYNOS_CHIPID
        bool "Exynos Chipid controller driver" if COMPILE_TEST
        depends on ARCH_EXYNOS || COMPILE_TEST
index 3b6a879..edd1d6e 100644 (file)
@@ -1,5 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
+obj-$(CONFIG_EXYNOS_ASV)       += exynos-asv.o
+obj-$(CONFIG_EXYNOS_ASV_ARM)   += exynos5422-asv.o
+
 obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
 obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
 
diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
new file mode 100644 (file)
index 0000000..30bb7b7
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Samsung Exynos SoC Adaptive Supply Voltage support
+ */
+
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regmap.h>
+#include <linux/soc/samsung/exynos-chipid.h>
+
+#include "exynos-asv.h"
+#include "exynos5422-asv.h"
+
+#define MHZ 1000000U
+
+static int exynos_asv_update_cpu_opps(struct exynos_asv *asv,
+                                     struct device *cpu)
+{
+       struct exynos_asv_subsys *subsys = NULL;
+       struct dev_pm_opp *opp;
+       unsigned int opp_freq;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(asv->subsys); i++) {
+               if (of_device_is_compatible(cpu->of_node,
+                                           asv->subsys[i].cpu_dt_compat)) {
+                       subsys = &asv->subsys[i];
+                       break;
+               }
+       }
+       if (!subsys)
+               return -EINVAL;
+
+       for (i = 0; i < subsys->table.num_rows; i++) {
+               unsigned int new_volt, volt;
+               int ret;
+
+               opp_freq = exynos_asv_opp_get_frequency(subsys, i);
+
+               opp = dev_pm_opp_find_freq_exact(cpu, opp_freq * MHZ, true);
+               if (IS_ERR(opp)) {
+                       dev_info(asv->dev, "cpu%d opp%d, freq: %u missing\n",
+                                cpu->id, i, opp_freq);
+
+                       continue;
+               }
+
+               volt = dev_pm_opp_get_voltage(opp);
+               new_volt = asv->opp_get_voltage(subsys, i, volt);
+               dev_pm_opp_put(opp);
+
+               if (new_volt == volt)
+                       continue;
+
+               ret = dev_pm_opp_adjust_voltage(cpu, opp_freq * MHZ,
+                                               new_volt, new_volt, new_volt);
+               if (ret < 0)
+                       dev_err(asv->dev,
+                               "Failed to adjust OPP %u Hz/%u uV for cpu%d\n",
+                               opp_freq, new_volt, cpu->id);
+               else
+                       dev_dbg(asv->dev,
+                               "Adjusted OPP %u Hz/%u -> %u uV, cpu%d\n",
+                               opp_freq, volt, new_volt, cpu->id);
+       }
+
+       return 0;
+}
+
+static int exynos_asv_update_opps(struct exynos_asv *asv)
+{
+       struct opp_table *last_opp_table = NULL;
+       struct device *cpu;
+       int ret, cpuid;
+
+       for_each_possible_cpu(cpuid) {
+               struct opp_table *opp_table;
+
+               cpu = get_cpu_device(cpuid);
+               if (!cpu)
+                       continue;
+
+               opp_table = dev_pm_opp_get_opp_table(cpu);
+               if (IS_ERR_OR_NULL(opp_table))
+                       continue;
+
+               if (!last_opp_table || opp_table != last_opp_table) {
+                       last_opp_table = opp_table;
+
+                       ret = exynos_asv_update_cpu_opps(asv, cpu);
+                       if (ret < 0)
+                               dev_err(asv->dev, "Couldn't udate OPPs for cpu%d\n",
+                                       cpuid);
+               }
+
+               dev_pm_opp_put_opp_table(opp_table);
+       }
+
+       return  0;
+}
+
+static int exynos_asv_probe(struct platform_device *pdev)
+{
+       int (*probe_func)(struct exynos_asv *asv);
+       struct exynos_asv *asv;
+       struct device *cpu_dev;
+       u32 product_id = 0;
+       int ret, i;
+
+       cpu_dev = get_cpu_device(0);
+       ret = dev_pm_opp_get_opp_count(cpu_dev);
+       if (ret < 0)
+               return -EPROBE_DEFER;
+
+       asv = devm_kzalloc(&pdev->dev, sizeof(*asv), GFP_KERNEL);
+       if (!asv)
+               return -ENOMEM;
+
+       asv->chipid_regmap = device_node_to_regmap(pdev->dev.of_node);
+       if (IS_ERR(asv->chipid_regmap)) {
+               dev_err(&pdev->dev, "Could not find syscon regmap\n");
+               return PTR_ERR(asv->chipid_regmap);
+       }
+
+       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);
+
+       switch (product_id & EXYNOS_MASK) {
+       case 0xE5422000:
+               probe_func = exynos5422_asv_init;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin",
+                                  &asv->of_bin);
+       if (ret < 0)
+               asv->of_bin = -EINVAL;
+
+       asv->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, asv);
+
+       for (i = 0; i < ARRAY_SIZE(asv->subsys); i++)
+               asv->subsys[i].asv = asv;
+
+       ret = probe_func(asv);
+       if (ret < 0)
+               return ret;
+
+       return exynos_asv_update_opps(asv);
+}
+
+static const struct of_device_id exynos_asv_of_device_ids[] = {
+       { .compatible = "samsung,exynos4210-chipid" },
+       {}
+};
+
+static struct platform_driver exynos_asv_driver = {
+       .driver = {
+               .name = "exynos-asv",
+               .of_match_table = exynos_asv_of_device_ids,
+       },
+       .probe  = exynos_asv_probe,
+};
+module_platform_driver(exynos_asv_driver);
diff --git a/drivers/soc/samsung/exynos-asv.h b/drivers/soc/samsung/exynos-asv.h
new file mode 100644 (file)
index 0000000..3fd1f2a
--- /dev/null
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Samsung Exynos SoC Adaptive Supply Voltage support
+ */
+#ifndef __LINUX_SOC_EXYNOS_ASV_H
+#define __LINUX_SOC_EXYNOS_ASV_H
+
+struct regmap;
+
+/* HPM, IDS values to select target group */
+struct asv_limit_entry {
+       unsigned int hpm;
+       unsigned int ids;
+};
+
+struct exynos_asv_table {
+       unsigned int num_rows;
+       unsigned int num_cols;
+       u32 *buf;
+};
+
+struct exynos_asv_subsys {
+       struct exynos_asv *asv;
+       const char *cpu_dt_compat;
+       int id;
+       struct exynos_asv_table table;
+
+       unsigned int base_volt;
+       unsigned int offset_volt_h;
+       unsigned int offset_volt_l;
+};
+
+struct exynos_asv {
+       struct device *dev;
+       struct regmap *chipid_regmap;
+       struct exynos_asv_subsys subsys[2];
+
+       int (*opp_get_voltage)(const struct exynos_asv_subsys *subs,
+                              int level, unsigned int voltage);
+       unsigned int group;
+       unsigned int table;
+
+       /* True if SG fields from PKG_ID register should be used */
+       bool use_sg;
+       /* ASV bin read from DT */
+       int of_bin;
+};
+
+static inline u32 __asv_get_table_entry(const struct exynos_asv_table *table,
+                                       unsigned int row, unsigned int col)
+{
+       return table->buf[row * (table->num_cols) + col];
+}
+
+static inline u32 exynos_asv_opp_get_voltage(const struct exynos_asv_subsys *subsys,
+                                       unsigned int level, unsigned int group)
+{
+       return __asv_get_table_entry(&subsys->table, level, group + 1);
+}
+
+static inline u32 exynos_asv_opp_get_frequency(const struct exynos_asv_subsys *subsys,
+                                       unsigned int level)
+{
+       return __asv_get_table_entry(&subsys->table, level, 0);
+}
+
+#endif /* __LINUX_SOC_EXYNOS_ASV_H */
index c55a47c..b89c26a 100644 (file)
@@ -45,17 +45,25 @@ static const char * __init product_id_to_soc_id(unsigned int product_id)
        return NULL;
 }
 
-int __init exynos_chipid_early_init(void)
+static int __init exynos_chipid_early_init(void)
 {
        struct soc_device_attribute *soc_dev_attr;
        struct soc_device *soc_dev;
        struct device_node *root;
+       struct device_node *syscon;
        struct regmap *regmap;
        u32 product_id;
        u32 revision;
        int ret;
 
-       regmap = syscon_regmap_lookup_by_compatible("samsung,exynos4210-chipid");
+       syscon = of_find_compatible_node(NULL, NULL,
+                                        "samsung,exynos4210-chipid");
+       if (!syscon)
+               return ENODEV;
+
+       regmap = device_node_to_regmap(syscon);
+       of_node_put(syscon);
+
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
diff --git a/drivers/soc/samsung/exynos5422-asv.c b/drivers/soc/samsung/exynos5422-asv.c
new file mode 100644 (file)
index 0000000..01bb305
--- /dev/null
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ *
+ * Samsung Exynos 5422 SoC Adaptive Supply Voltage support
+ */
+
+#include <linux/bitrev.h>
+#include <linux/errno.h>
+#include <linux/regmap.h>
+#include <linux/soc/samsung/exynos-chipid.h>
+#include <linux/slab.h>
+
+#include "exynos-asv.h"
+#include "exynos5422-asv.h"
+
+#define ASV_GROUPS_NUM         14
+#define ASV_ARM_DVFS_NUM       20
+#define ASV_ARM_BIN2_DVFS_NUM  17
+#define ASV_KFC_DVFS_NUM       14
+#define ASV_KFC_BIN2_DVFS_NUM  12
+
+/*
+ * This array is a set of 4 ASV data tables, first column of each ASV table
+ * contains frequency value in MHz and subsequent columns contain the CPU
+ * cluster's supply voltage values in uV.
+ * In order to create a set of OPPs for specific SoC revision one of the voltage
+ * columns (1...14) from one of the tables (0...3) is selected during
+ * initialization. There are separate ASV tables for the big (ARM) and little
+ * (KFC) CPU cluster. Only OPPs which are already defined in devicetree
+ * will be updated.
+ */
+
+static const u32 asv_arm_table[][ASV_ARM_DVFS_NUM][ASV_GROUPS_NUM + 1] = {
+{
+       /* ARM 0, 1 */
+       { 2100,    1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000,
+         1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
+       { 2000,    1312500, 1312500, 1300000, 1287500, 1275000, 1262500, 1250000,
+         1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+       { 1900,    1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000,
+         1162500, 1150000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+       { 1800,    1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000,
+         1112500, 1100000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+       { 1700,    1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500,
+         1075000, 1062500, 1075000, 1062500, 1050000, 1037500, 1025000 },
+       { 1600,    1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000,
+         1037500, 1025000, 1037500, 1025000, 1012500, 1000000, 987500 },
+       { 1500,    1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500,
+         1000000, 987500,  1000000, 987500,  975000,  962500,  950000 },
+       { 1400,    1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
+         975000,  962500,  975000,  962500,  950000,  937500,  925000 },
+       { 1300,    1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
+         962500,  950000,  962500,  950000,  937500,  925000,  912500 },
+       { 1200,    1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
+         937500,  925000,  937500,  925000,  912500,  900000,  900000 },
+       { 1100,    1000000, 987500,  975000,  962500,  950000,  937500,  925000,
+         912500,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 1000,    975000,  962500,  950000,  937500,  925000,  912500,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 900,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 800,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 700,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}, {
+       /* ARM 2 */
+       { 2100,    1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000,
+         1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
+       { 2000,    1312500, 1312500, 1312500, 1300000, 1275000, 1262500, 1250000,
+         1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+       { 1900,    1262500, 1250000, 1250000, 1237500, 1212500, 1200000, 1187500,
+         1175000, 1162500, 1175000, 1162500, 1150000, 1137500, 1125000 },
+       { 1800,    1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500,
+         1125000, 1112500, 1125000, 1112500, 1100000, 1087500, 1075000 },
+       { 1700,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
+         1087500, 1075000, 1087500, 1075000, 1062500, 1050000, 1037500 },
+       { 1600,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
+         1050000, 1037500, 1050000, 1037500, 1025000, 1012500, 1000000 },
+       { 1500,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
+         1012500, 1000000, 1012500, 1000000, 987500,  975000,  962500 },
+       { 1400,    1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000,
+         987500,  975000,  987500,  975000,  962500,  950000,  937500 },
+       { 1300,    1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
+         962500,  950000,  962500,  950000,  937500,  925000,  912500 },
+       { 1200,    1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
+         937500,  925000,  937500,  925000,  912500,  900000,  900000 },
+       { 1100,    1000000, 987500,  975000,  962500,  950000,  937500,  925000,
+         912500,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 1000,    975000,  962500,  950000,  937500,  925000,  912500,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 900,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 800,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 700,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}, {
+       /* ARM 3 */
+       { 2100,    1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000,
+         1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
+       { 2000,    1312500, 1312500, 1300000, 1287500, 1275000, 1262500, 1250000,
+         1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+       { 1900,    1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500,
+         1175000, 1162500, 1175000, 1162500, 1150000, 1137500, 1125000 },
+       { 1800,    1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500,
+         1125000, 1112500, 1125000, 1112500, 1100000, 1087500, 1075000 },
+       { 1700,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
+         1087500, 1075000, 1087500, 1075000, 1062500, 1050000, 1037500 },
+       { 1600,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
+         1050000, 1037500, 1050000, 1037500, 1025000, 1012500, 1000000 },
+       { 1500,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
+         1012500, 1000000, 1012500, 1000000, 987500,  975000,  962500 },
+       { 1400,    1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000,
+         987500,  975000,  987500,  975000,  962500,  950000,  937500 },
+       { 1300,    1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
+         962500,  950000,  962500,  950000,  937500,  925000,  912500 },
+       { 1200,    1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
+         937500,  925000,  937500,  925000,  912500,  900000,  900000 },
+       { 1100,    1000000, 987500,  975000,  962500,  950000,  937500,  925000,
+         912500,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 1000,    975000,  962500,  950000,  937500,  925000,  912500,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 900,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 800,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 700,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}, {
+       /* ARM bin 2 */
+       { 1800,    1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500,
+         1150000, 1137500, 1150000, 1137500, 1125000, 1112500, 1100000 },
+       { 1700,    1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000,
+         1112500, 1100000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+       { 1600,    1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500,
+         1075000, 1062500, 1075000, 1062500, 1050000, 1037500, 1025000 },
+       { 1500,    1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000,
+         1037500, 1025000, 1037500, 1025000, 1012500, 1000000, 987500 },
+       { 1400,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
+         1012500, 1000000, 1012500, 1000000, 987500,  975000,  962500 },
+       { 1300,    1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500,
+         1000000, 987500,  1000000, 987500,  975000,  962500,  950000 },
+       { 1200,    1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
+         975000,  962500,  975000,  962500,  950000,  937500,  925000 },
+       { 1100,    1037500, 1025000, 1012500, 1000000, 987500,  975000,  962500,
+         950000,  937500,  950000,  937500,  925000,  912500,  900000 },
+       { 1000,    1012500, 1000000, 987500,  975000,  962500,  950000,  937500,
+         925000,  912500,  925000,  912500,  900000,  900000,  900000 },
+       { 900,     987500,  975000,  962500,  950000,  937500,  925000,  912500,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 800,     962500,  950000,  937500,  925000,  912500,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 700,     937500,  925000,  912500,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}
+};
+
+static const u32 asv_kfc_table[][ASV_KFC_DVFS_NUM][ASV_GROUPS_NUM + 1] = {
+{
+       /* KFC 0, 1 */
+       { 1500000, 1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000,
+         1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+       { 1400000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000,
+         1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+       { 1300000, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000,
+         1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+       { 1200000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
+         1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
+       { 1100000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
+         1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000 },
+       { 1000000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
+         1012500, 1000000, 987500,  975000,  962500,  950000,  937500 },
+       { 900000,  1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
+         975000,  962500,  950000,  937500,  925000,  912500,  900000 },
+       { 800000,  1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
+         937500,  925000,  912500,  900000,  900000,  900000,  900000 },
+       { 700000,  987500,  975000,  962500,  950000,  937500,  925000,  912500,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600000,  950000,  937500,  925000,  912500,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500000,  912500,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400000,  900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300000,  900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200000,  900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}, {
+       /* KFC 2 */
+       { 1500,    1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000,
+         1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+       { 1400,    1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000,
+         1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+       { 1300,    1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000,
+         1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+       { 1200,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
+         1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
+       { 1100,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
+         1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000 },
+       { 1000,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
+         1012500, 1000000, 987500,  975000,  962500,  950000,  937500 },
+       { 900,     1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
+         975000,  962500,  950000,  937500,  925000,  912500,  900000 },
+       { 800,     1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
+         937500,  925000,  912500,  900000,  900000,  900000,  900000 },
+       { 700,     987500,  975000,  962500,  950000,  937500,  925000,  912500,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     912500,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}, {
+       /* KFC 3 */
+       { 1500,    1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000,
+         1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+       { 1400,    1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000,
+         1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+       { 1300,    1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000,
+         1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+       { 1200,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
+         1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
+       { 1100,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
+         1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000 },
+       { 1000,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
+         1012500, 1000000, 987500,  975000,  962500,  950000,  937500 },
+       { 900,     1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
+         975000,  962500,  950000,  937500,  925000,  912500,  900000 },
+       { 800,     1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
+         937500,  925000,  912500,  900000,  900000,  900000,  900000 },
+       { 700,     987500,  975000,  962500,  950000,  937500,  925000,  912500,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     912500,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}, {
+       /* KFC bin 2 */
+       { 1300,    1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000,
+         1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500 },
+       { 1200,    1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000,
+         1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500 },
+       { 1100,    1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500,
+         1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000 },
+       { 1000,    1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000,
+         1037500, 1025000, 1012500, 1000000, 987500,  975000,  962500 },
+       { 900,     1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500,
+         1000000, 987500,  975000,  962500,  950000,  937500,  925000 },
+       { 800,     1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
+         962500,  950000,  937500,  925000,  912500,  900000,  900000 },
+       { 700,     1012500, 1000000, 987500,  975000,  962500,  950000,  937500,
+         925000,  912500,  900000,  900000,  900000,  900000,  900000 },
+       { 600,     975000,  962500,  950000,  937500,  925000,  912500,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 500,     937500,  925000,  912500,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 400,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
+         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
+}
+};
+
+static const struct asv_limit_entry __asv_limits[ASV_GROUPS_NUM] = {
+       { 13, 55 },
+       { 21, 65 },
+       { 25, 69 },
+       { 30, 72 },
+       { 36, 74 },
+       { 43, 76 },
+       { 51, 78 },
+       { 65, 80 },
+       { 81, 82 },
+       { 98, 84 },
+       { 119, 87 },
+       { 135, 89 },
+       { 150, 92 },
+       { 999, 999 },
+};
+
+static int exynos5422_asv_get_group(struct exynos_asv *asv)
+{
+       unsigned int pkgid_reg, auxi_reg;
+       int hpm, ids, i;
+
+       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PKG_ID, &pkgid_reg);
+       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_AUX_INFO, &auxi_reg);
+
+       if (asv->use_sg) {
+               u32 sga = (pkgid_reg >> EXYNOS5422_SG_A_OFFSET) &
+                          EXYNOS5422_SG_A_MASK;
+
+               u32 sgb = (pkgid_reg >> EXYNOS5422_SG_B_OFFSET) &
+                          EXYNOS5422_SG_B_MASK;
+
+               if ((pkgid_reg >> EXYNOS5422_SG_BSIGN_OFFSET) &
+                    EXYNOS5422_SG_BSIGN_MASK)
+                       return sga + sgb;
+               else
+                       return sga - sgb;
+       }
+
+       hpm = (auxi_reg >> EXYNOS5422_TMCB_OFFSET) & EXYNOS5422_TMCB_MASK;
+       ids = (pkgid_reg >> EXYNOS5422_IDS_OFFSET) & EXYNOS5422_IDS_MASK;
+
+       for (i = 0; i < ASV_GROUPS_NUM; i++) {
+               if (ids <= __asv_limits[i].ids)
+                       break;
+               if (hpm <= __asv_limits[i].hpm)
+                       break;
+       }
+       if (i < ASV_GROUPS_NUM)
+               return i;
+
+       return 0;
+}
+
+static int __asv_offset_voltage(unsigned int index)
+{
+       switch (index) {
+       case 1:
+               return 12500;
+       case 2:
+               return 50000;
+       case 3:
+               return 25000;
+       default:
+               return 0;
+       };
+}
+
+static void exynos5422_asv_offset_voltage_setup(struct exynos_asv *asv)
+{
+       struct exynos_asv_subsys *subsys;
+       unsigned int reg, value;
+
+       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_AUX_INFO, &reg);
+
+       /* ARM offset voltage setup */
+       subsys = &asv->subsys[EXYNOS_ASV_SUBSYS_ID_ARM];
+
+       subsys->base_volt = 1000000;
+
+       value = (reg >> EXYNOS5422_ARM_UP_OFFSET) & EXYNOS5422_ARM_UP_MASK;
+       subsys->offset_volt_h = __asv_offset_voltage(value);
+
+       value = (reg >> EXYNOS5422_ARM_DN_OFFSET) & EXYNOS5422_ARM_DN_MASK;
+       subsys->offset_volt_l = __asv_offset_voltage(value);
+
+       /* KFC offset voltage setup */
+       subsys = &asv->subsys[EXYNOS_ASV_SUBSYS_ID_KFC];
+
+       subsys->base_volt = 1000000;
+
+       value = (reg >> EXYNOS5422_KFC_UP_OFFSET) & EXYNOS5422_KFC_UP_MASK;
+       subsys->offset_volt_h = __asv_offset_voltage(value);
+
+       value = (reg >> EXYNOS5422_KFC_DN_OFFSET) & EXYNOS5422_KFC_DN_MASK;
+       subsys->offset_volt_l = __asv_offset_voltage(value);
+}
+
+static int exynos5422_asv_opp_get_voltage(const struct exynos_asv_subsys *subsys,
+                                         int level, unsigned int volt)
+{
+       unsigned int asv_volt;
+
+       if (level >= subsys->table.num_rows)
+               return volt;
+
+       asv_volt = exynos_asv_opp_get_voltage(subsys, level,
+                                             subsys->asv->group);
+
+       if (volt > subsys->base_volt)
+               asv_volt += subsys->offset_volt_h;
+       else
+               asv_volt += subsys->offset_volt_l;
+
+       return asv_volt;
+}
+
+static unsigned int exynos5422_asv_parse_table(unsigned int pkg_id)
+{
+       return (pkg_id >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
+}
+
+static bool exynos5422_asv_parse_bin2(unsigned int pkg_id)
+{
+       return (pkg_id >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;
+}
+
+static bool exynos5422_asv_parse_sg(unsigned int pkg_id)
+{
+       return (pkg_id >> EXYNOS5422_USESG_OFFSET) & EXYNOS5422_USESG_MASK;
+}
+
+int exynos5422_asv_init(struct exynos_asv *asv)
+{
+       struct exynos_asv_subsys *subsys;
+       unsigned int table_index;
+       unsigned int pkg_id;
+       bool bin2;
+
+       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PKG_ID, &pkg_id);
+
+       if (asv->of_bin == 2) {
+               bin2 = true;
+               asv->use_sg = false;
+       } else {
+               asv->use_sg = exynos5422_asv_parse_sg(pkg_id);
+               bin2 = exynos5422_asv_parse_bin2(pkg_id);
+       }
+
+       asv->group = exynos5422_asv_get_group(asv);
+       asv->table = exynos5422_asv_parse_table(pkg_id);
+
+       exynos5422_asv_offset_voltage_setup(asv);
+
+       if (bin2) {
+               table_index = 3;
+       } else {
+               if (asv->table == 2 || asv->table == 3)
+                       table_index = asv->table - 1;
+               else
+                       table_index = 0;
+       }
+
+       subsys = &asv->subsys[EXYNOS_ASV_SUBSYS_ID_ARM];
+       subsys->cpu_dt_compat = "arm,cortex-a15";
+       if (bin2)
+               subsys->table.num_rows = ASV_ARM_BIN2_DVFS_NUM;
+       else
+               subsys->table.num_rows = ASV_ARM_DVFS_NUM;
+       subsys->table.num_cols = ASV_GROUPS_NUM + 1;
+       subsys->table.buf = (u32 *)asv_arm_table[table_index];
+
+       subsys = &asv->subsys[EXYNOS_ASV_SUBSYS_ID_KFC];
+       subsys->cpu_dt_compat = "arm,cortex-a7";
+       if (bin2)
+               subsys->table.num_rows = ASV_KFC_BIN2_DVFS_NUM;
+       else
+               subsys->table.num_rows = ASV_KFC_DVFS_NUM;
+       subsys->table.num_cols = ASV_GROUPS_NUM + 1;
+       subsys->table.buf = (u32 *)asv_kfc_table[table_index];
+
+       asv->opp_get_voltage = exynos5422_asv_opp_get_voltage;
+
+       return 0;
+}
diff --git a/drivers/soc/samsung/exynos5422-asv.h b/drivers/soc/samsung/exynos5422-asv.h
new file mode 100644 (file)
index 0000000..95a5fb1
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ *
+ * Samsung Exynos 5422 SoC Adaptive Supply Voltage support
+ */
+
+#ifndef __LINUX_SOC_EXYNOS5422_ASV_H
+#define __LINUX_SOC_EXYNOS5422_ASV_H
+
+#include <linux/errno.h>
+
+enum {
+       EXYNOS_ASV_SUBSYS_ID_ARM,
+       EXYNOS_ASV_SUBSYS_ID_KFC,
+       EXYNOS_ASV_SUBSYS_ID_MAX
+};
+
+struct exynos_asv;
+
+#ifdef CONFIG_EXYNOS_ASV_ARM
+int exynos5422_asv_init(struct exynos_asv *asv);
+#else
+static inline int exynos5422_asv_init(struct exynos_asv *asv)
+{
+       return -ENOTSUPP;
+}
+#endif
+
+#endif /* __LINUX_SOC_EXYNOS5422_ASV_H */
index c8ef05d..84bd615 100644 (file)
@@ -15,6 +15,7 @@ config ARCH_TEGRA_2x_SOC
        select PL310_ERRATA_769419 if CACHE_L2X0
        select SOC_TEGRA_FLOWCTRL
        select SOC_TEGRA_PMC
+       select SOC_TEGRA20_VOLTAGE_COUPLER
        select TEGRA_TIMER
        help
          Support for NVIDIA Tegra AP20 and T20 processors, based on the
@@ -28,6 +29,7 @@ config ARCH_TEGRA_3x_SOC
        select PL310_ERRATA_769419 if CACHE_L2X0
        select SOC_TEGRA_FLOWCTRL
        select SOC_TEGRA_PMC
+       select SOC_TEGRA30_VOLTAGE_COUPLER
        select TEGRA_TIMER
        help
          Support for NVIDIA Tegra T30 processor family, based on the
@@ -135,3 +137,11 @@ config SOC_TEGRA_POWERGATE_BPMP
        def_bool y
        depends on PM_GENERIC_DOMAINS
        depends on TEGRA_BPMP
+
+config SOC_TEGRA20_VOLTAGE_COUPLER
+       bool "Voltage scaling support for Tegra20 SoCs"
+       depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
+
+config SOC_TEGRA30_VOLTAGE_COUPLER
+       bool "Voltage scaling support for Tegra30 SoCs"
+       depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
index 902759f..9c809c1 100644 (file)
@@ -5,3 +5,5 @@ obj-y += common.o
 obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
 obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
 obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
+obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
+obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o
index b6bdeef..eb96a30 100644 (file)
@@ -91,8 +91,23 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid)
                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
                /* clear wfi bitmap */
                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
-               /* pwr gating on wfi */
-               reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
+
+               if (tegra_get_chip_id() == TEGRA30) {
+                       /*
+                        * The wfi doesn't work well on Tegra30 because
+                        * CPU hangs under some odd circumstances after
+                        * power-gating (like memory running off PLLP),
+                        * hence use wfe that is working perfectly fine.
+                        * Note that Tegra30 TRM doc clearly stands that
+                        * wfi should be used for the "Cluster Switching",
+                        * while wfe for the power-gating, just like it
+                        * is done on Tegra20.
+                        */
+                       reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
+               } else {
+                       /* pwr gating on wfi */
+                       reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
+               }
                break;
        }
        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr flag */
index 3eb44e6..4d719d4 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/kobject.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/nvmem-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -31,50 +33,6 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
        [TEGRA_REVISION_A04]     = "A04",
 };
 
-static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset)
-{
-       u32 val;
-
-       val = fuse->read(fuse, round_down(offset, 4));
-       val >>= (offset % 4) * 8;
-       val &= 0xff;
-
-       return val;
-}
-
-static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
-                        struct bin_attribute *attr, char *buf,
-                        loff_t pos, size_t size)
-{
-       struct device *dev = kobj_to_dev(kobj);
-       struct tegra_fuse *fuse = dev_get_drvdata(dev);
-       int i;
-
-       if (pos < 0 || pos >= attr->size)
-               return 0;
-
-       if (size > attr->size - pos)
-               size = attr->size - pos;
-
-       for (i = 0; i < size; i++)
-               buf[i] = fuse_readb(fuse, pos + i);
-
-       return i;
-}
-
-static struct bin_attribute fuse_bin_attr = {
-       .attr = { .name = "fuse", .mode = S_IRUGO, },
-       .read = fuse_read,
-};
-
-static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size,
-                                  const struct tegra_fuse_info *info)
-{
-       fuse_bin_attr.size = size;
-
-       return device_create_bin_file(dev, &fuse_bin_attr);
-}
-
 static const struct of_device_id car_match[] __initconst = {
        { .compatible = "nvidia,tegra20-car", },
        { .compatible = "nvidia,tegra30-car", },
@@ -115,9 +73,111 @@ static const struct of_device_id tegra_fuse_match[] = {
        { /* sentinel */ }
 };
 
+static int tegra_fuse_read(void *priv, unsigned int offset, void *value,
+                          size_t bytes)
+{
+       unsigned int count = bytes / 4, i;
+       struct tegra_fuse *fuse = priv;
+       u32 *buffer = value;
+
+       for (i = 0; i < count; i++)
+               buffer[i] = fuse->read(fuse, offset + i * 4);
+
+       return 0;
+}
+
+static const struct nvmem_cell_info tegra_fuse_cells[] = {
+       {
+               .name = "tsensor-cpu1",
+               .offset = 0x084,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-cpu2",
+               .offset = 0x088,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-cpu0",
+               .offset = 0x098,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "xusb-pad-calibration",
+               .offset = 0x0f0,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-cpu3",
+               .offset = 0x12c,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "sata-calibration",
+               .offset = 0x124,
+               .bytes = 1,
+               .bit_offset = 0,
+               .nbits = 2,
+       }, {
+               .name = "tsensor-gpu",
+               .offset = 0x154,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-mem0",
+               .offset = 0x158,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-mem1",
+               .offset = 0x15c,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-pllx",
+               .offset = 0x160,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-common",
+               .offset = 0x180,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "tsensor-realignment",
+               .offset = 0x1fc,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "gpu-calibration",
+               .offset = 0x204,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       }, {
+               .name = "xusb-pad-calibration-ext",
+               .offset = 0x250,
+               .bytes = 4,
+               .bit_offset = 0,
+               .nbits = 32,
+       },
+};
+
 static int tegra_fuse_probe(struct platform_device *pdev)
 {
        void __iomem *base = fuse->base;
+       struct nvmem_config nvmem;
        struct resource *res;
        int err;
 
@@ -146,20 +206,42 @@ static int tegra_fuse_probe(struct platform_device *pdev)
 
        if (fuse->soc->probe) {
                err = fuse->soc->probe(fuse);
-               if (err < 0) {
-                       fuse->base = base;
-                       return err;
-               }
+               if (err < 0)
+                       goto restore;
        }
 
-       if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
-                                   fuse->soc->info))
-               return -ENODEV;
+       memset(&nvmem, 0, sizeof(nvmem));
+       nvmem.dev = &pdev->dev;
+       nvmem.name = "fuse";
+       nvmem.id = -1;
+       nvmem.owner = THIS_MODULE;
+       nvmem.cells = tegra_fuse_cells;
+       nvmem.ncells = ARRAY_SIZE(tegra_fuse_cells);
+       nvmem.type = NVMEM_TYPE_OTP;
+       nvmem.read_only = true;
+       nvmem.root_only = true;
+       nvmem.reg_read = tegra_fuse_read;
+       nvmem.size = fuse->soc->info->size;
+       nvmem.word_size = 4;
+       nvmem.stride = 4;
+       nvmem.priv = fuse;
+
+       fuse->nvmem = devm_nvmem_register(&pdev->dev, &nvmem);
+       if (IS_ERR(fuse->nvmem)) {
+               err = PTR_ERR(fuse->nvmem);
+               dev_err(&pdev->dev, "failed to register NVMEM device: %d\n",
+                       err);
+               goto restore;
+       }
 
        /* release the early I/O memory mapping */
        iounmap(base);
 
        return 0;
+
+restore:
+       fuse->base = base;
+       return err;
 }
 
 static struct platform_driver tegra_fuse_driver = {
@@ -186,9 +268,12 @@ u32 __init tegra_fuse_read_early(unsigned int offset)
 
 int tegra_fuse_readl(unsigned long offset, u32 *value)
 {
-       if (!fuse->read)
+       if (!fuse->read || !fuse->clk)
                return -EPROBE_DEFER;
 
+       if (IS_ERR(fuse->clk))
+               return PTR_ERR(fuse->clk);
+
        *value = fuse->read(fuse, offset);
 
        return 0;
@@ -338,6 +423,15 @@ static int __init tegra_init_fuse(void)
        pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
                 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
 
+       if (fuse->soc->lookups) {
+               size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
+
+               fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
+               if (!fuse->lookups)
+                       return -ENOMEM;
+
+               nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
+       }
 
        return 0;
 }
index be9424a..b8daaf5 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -127,6 +128,70 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
 #endif
 
 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
+static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
+       {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration",
+               .dev_id = "7009f000.padctl",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "sata-calibration",
+               .dev_id = "70020000.sata",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-common",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "common",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-realignment",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "realignment",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu0",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu0",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu1",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu1",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu2",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu2",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu3",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu3",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-mem0",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "mem0",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-mem1",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "mem1",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-gpu",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "gpu",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-pllx",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "pllx",
+       },
+};
+
 static const struct tegra_fuse_info tegra124_fuse_info = {
        .read = tegra30_fuse_read,
        .size = 0x300,
@@ -137,10 +202,81 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
        .init = tegra30_fuse_init,
        .speedo_init = tegra124_init_speedo_data,
        .info = &tegra124_fuse_info,
+       .lookups = tegra124_fuse_lookups,
+       .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
 };
 #endif
 
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
+static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
+       {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu1",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu1",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu2",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu2",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu0",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu0",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration",
+               .dev_id = "7009f000.padctl",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-cpu3",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "cpu3",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "sata-calibration",
+               .dev_id = "70020000.sata",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-gpu",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "gpu",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-mem0",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "mem0",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-mem1",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "mem1",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-pllx",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "pllx",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "tsensor-common",
+               .dev_id = "700e2000.thermal-sensor",
+               .con_id = "common",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "gpu-calibration",
+               .dev_id = "57000000.gpu",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration-ext",
+               .dev_id = "7009f000.padctl",
+               .con_id = "calibration-ext",
+       },
+};
+
 static const struct tegra_fuse_info tegra210_fuse_info = {
        .read = tegra30_fuse_read,
        .size = 0x300,
@@ -151,10 +287,26 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
        .init = tegra30_fuse_init,
        .speedo_init = tegra210_init_speedo_data,
        .info = &tegra210_fuse_info,
+       .lookups = tegra210_fuse_lookups,
+       .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
 };
 #endif
 
 #if defined(CONFIG_ARCH_TEGRA_186_SOC)
+static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
+       {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration",
+               .dev_id = "3520000.padctl",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration-ext",
+               .dev_id = "3520000.padctl",
+               .con_id = "calibration-ext",
+       },
+};
+
 static const struct tegra_fuse_info tegra186_fuse_info = {
        .read = tegra30_fuse_read,
        .size = 0x300,
@@ -164,5 +316,7 @@ static const struct tegra_fuse_info tegra186_fuse_info = {
 const struct tegra_fuse_soc tegra186_fuse_soc = {
        .init = tegra30_fuse_init,
        .info = &tegra186_fuse_info,
+       .lookups = tegra186_fuse_lookups,
+       .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
 };
 #endif
index 7230cb3..0f74c2c 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/dmaengine.h>
 #include <linux/types.h>
 
+struct nvmem_cell_lookup;
+struct nvmem_device;
 struct tegra_fuse;
 
 struct tegra_fuse_info {
@@ -27,6 +29,9 @@ struct tegra_fuse_soc {
        int (*probe)(struct tegra_fuse *fuse);
 
        const struct tegra_fuse_info *info;
+
+       const struct nvmem_cell_lookup *lookups;
+       unsigned int num_lookups;
 };
 
 struct tegra_fuse {
@@ -48,6 +53,9 @@ struct tegra_fuse {
                dma_addr_t phys;
                u32 *virt;
        } apbdma;
+
+       struct nvmem_device *nvmem;
+       struct nvmem_cell_lookup *lookups;
 };
 
 void tegra_init_revision(void);
index 9f9c1c6..8db63cf 100644 (file)
 #define  PMC_CNTRL_SIDE_EFFECT_LP0     BIT(14) /* LP0 when CPU pwr gated */
 #define  PMC_CNTRL_SYSCLK_OE           BIT(11) /* system clock enable */
 #define  PMC_CNTRL_SYSCLK_POLARITY     BIT(10) /* sys clk polarity */
+#define  PMC_CNTRL_PWRREQ_POLARITY     BIT(8)
 #define  PMC_CNTRL_MAIN_RST            BIT(4)
 
+#define PMC_WAKE_MASK                  0x0c
+#define PMC_WAKE_LEVEL                 0x10
+#define PMC_WAKE_STATUS                        0x14
+#define PMC_SW_WAKE_STATUS             0x18
+
 #define DPD_SAMPLE                     0x020
 #define  DPD_SAMPLE_ENABLE             BIT(0)
 #define  DPD_SAMPLE_DISABLE            (0 << 0)
 
 #define PMC_CPUPWRGOOD_TIMER           0xc8
 #define PMC_CPUPWROFF_TIMER            0xcc
+#define PMC_COREPWRGOOD_TIMER          0x3c
+#define PMC_COREPWROFF_TIMER           0xe0
 
 #define PMC_PWR_DET_VALUE              0xe4
 
 #define PMC_SCRATCH41                  0x140
 
+#define PMC_WAKE2_MASK                 0x160
+#define PMC_WAKE2_LEVEL                        0x164
+#define PMC_WAKE2_STATUS               0x168
+#define PMC_SW_WAKE2_STATUS            0x16c
+
 #define PMC_SENSOR_CTRL                        0x1b0
 #define  PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
 #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
@@ -226,6 +239,8 @@ struct tegra_pmc_soc {
        void (*setup_irq_polarity)(struct tegra_pmc *pmc,
                                   struct device_node *np,
                                   bool invert);
+       int (*irq_set_wake)(struct irq_data *data, unsigned int on);
+       int (*irq_set_type)(struct irq_data *data, unsigned int type);
 
        const char * const *reset_sources;
        unsigned int num_reset_sources;
@@ -309,6 +324,7 @@ static const char * const tegra210_reset_sources[] = {
  * @pctl_dev: pin controller exposed by the PMC
  * @domain: IRQ domain provided by the PMC
  * @irq: chip implementation for the IRQ domain
+ * @clk_nb: pclk clock changes handler
  */
 struct tegra_pmc {
        struct device *dev;
@@ -344,6 +360,8 @@ struct tegra_pmc {
 
        struct irq_domain *domain;
        struct irq_chip irq;
+
+       struct notifier_block clk_nb;
 };
 
 static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -1192,7 +1210,7 @@ static int tegra_io_pad_prepare(struct tegra_pmc *pmc, enum tegra_io_pad id,
                return err;
 
        if (pmc->clk) {
-               rate = clk_get_rate(pmc->clk);
+               rate = pmc->rate;
                if (!rate) {
                        dev_err(pmc->dev, "failed to get clock rate\n");
                        return -ENODEV;
@@ -1433,6 +1451,7 @@ void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
 void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
 {
        unsigned long long rate = 0;
+       u64 ticks;
        u32 value;
 
        switch (mode) {
@@ -1441,7 +1460,7 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
                break;
 
        case TEGRA_SUSPEND_LP2:
-               rate = clk_get_rate(pmc->clk);
+               rate = pmc->rate;
                break;
 
        default:
@@ -1451,21 +1470,13 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
        if (WARN_ON_ONCE(rate == 0))
                rate = 100000000;
 
-       if (rate != pmc->rate) {
-               u64 ticks;
-
-               ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
-               do_div(ticks, USEC_PER_SEC);
-               tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER);
+       ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
+       do_div(ticks, USEC_PER_SEC);
+       tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER);
 
-               ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
-               do_div(ticks, USEC_PER_SEC);
-               tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER);
-
-               wmb();
-
-               pmc->rate = rate;
-       }
+       ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
+       do_div(ticks, USEC_PER_SEC);
+       tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER);
 
        value = tegra_pmc_readl(pmc, PMC_CNTRL);
        value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
@@ -1899,6 +1910,20 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
                                                            event->id,
                                                            &pmc->irq, pmc);
 
+                       /*
+                        * GPIOs don't have an equivalent interrupt in the
+                        * parent controller (GIC). However some code, such
+                        * as the one in irq_get_irqchip_state(), require a
+                        * valid IRQ chip to be set. Make sure that's the
+                        * case by passing NULL here, which will install a
+                        * dummy IRQ chip for the interrupt in the parent
+                        * domain.
+                        */
+                       if (domain->parent)
+                               irq_domain_set_hwirq_and_chip(domain->parent,
+                                                             virq, 0, NULL,
+                                                             NULL);
+
                        break;
                }
        }
@@ -1908,10 +1933,22 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
         * dummy hardware IRQ number. This is used in the ->irq_set_type()
         * and ->irq_set_wake() callbacks to return early for these IRQs.
         */
-       if (i == soc->num_wake_events)
+       if (i == soc->num_wake_events) {
                err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX,
                                                    &pmc->irq, pmc);
 
+               /*
+                * Interrupts without a wake event don't have a corresponding
+                * interrupt in the parent controller (GIC). Pass NULL for the
+                * chip here, which causes a dummy IRQ chip to be installed
+                * for the interrupt in the parent domain, to make this
+                * explicit.
+                */
+               if (domain->parent)
+                       irq_domain_set_hwirq_and_chip(domain->parent, virq, 0,
+                                                     NULL, NULL);
+       }
+
        return err;
 }
 
@@ -1920,7 +1957,87 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
        .alloc = tegra_pmc_irq_alloc,
 };
 
-static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
+       unsigned int offset, bit;
+       u32 value;
+
+       if (data->hwirq == ULONG_MAX)
+               return 0;
+
+       offset = data->hwirq / 32;
+       bit = data->hwirq % 32;
+
+       /* clear wake status */
+       tegra_pmc_writel(pmc, 0, PMC_SW_WAKE_STATUS);
+       tegra_pmc_writel(pmc, 0, PMC_SW_WAKE2_STATUS);
+
+       tegra_pmc_writel(pmc, 0, PMC_WAKE_STATUS);
+       tegra_pmc_writel(pmc, 0, PMC_WAKE2_STATUS);
+
+       /* enable PMC wake */
+       if (data->hwirq >= 32)
+               offset = PMC_WAKE2_MASK;
+       else
+               offset = PMC_WAKE_MASK;
+
+       value = tegra_pmc_readl(pmc, offset);
+
+       if (on)
+               value |= BIT(bit);
+       else
+               value &= ~BIT(bit);
+
+       tegra_pmc_writel(pmc, value, offset);
+
+       return 0;
+}
+
+static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
+       unsigned int offset, bit;
+       u32 value;
+
+       if (data->hwirq == ULONG_MAX)
+               return 0;
+
+       offset = data->hwirq / 32;
+       bit = data->hwirq % 32;
+
+       if (data->hwirq >= 32)
+               offset = PMC_WAKE2_LEVEL;
+       else
+               offset = PMC_WAKE_LEVEL;
+
+       value = tegra_pmc_readl(pmc, offset);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+       case IRQ_TYPE_LEVEL_HIGH:
+               value |= BIT(bit);
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+       case IRQ_TYPE_LEVEL_LOW:
+               value &= ~BIT(bit);
+               break;
+
+       case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
+               value ^= BIT(bit);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       tegra_pmc_writel(pmc, value, offset);
+
+       return 0;
+}
+
+static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
 {
        struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
        unsigned int offset, bit;
@@ -1952,7 +2069,7 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
        return 0;
 }
 
-static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
 {
        struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
        u32 value;
@@ -2006,8 +2123,8 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
        pmc->irq.irq_unmask = irq_chip_unmask_parent;
        pmc->irq.irq_eoi = irq_chip_eoi_parent;
        pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
-       pmc->irq.irq_set_type = tegra_pmc_irq_set_type;
-       pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake;
+       pmc->irq.irq_set_type = pmc->soc->irq_set_type;
+       pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
 
        pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
                                               &tegra_pmc_irq_domain_ops, pmc);
@@ -2019,6 +2136,33 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
        return 0;
 }
 
+static int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
+                                  unsigned long action, void *ptr)
+{
+       struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, clk_nb);
+       struct clk_notifier_data *data = ptr;
+
+       switch (action) {
+       case PRE_RATE_CHANGE:
+               mutex_lock(&pmc->powergates_lock);
+               break;
+
+       case POST_RATE_CHANGE:
+               pmc->rate = data->new_rate;
+               /* fall through */
+
+       case ABORT_RATE_CHANGE:
+               mutex_unlock(&pmc->powergates_lock);
+               break;
+
+       default:
+               WARN_ON_ONCE(1);
+               return notifier_from_errno(-EINVAL);
+       }
+
+       return NOTIFY_OK;
+}
+
 static int tegra_pmc_probe(struct platform_device *pdev)
 {
        void __iomem *base;
@@ -2082,6 +2226,23 @@ static int tegra_pmc_probe(struct platform_device *pdev)
                pmc->clk = NULL;
        }
 
+       /*
+        * PCLK clock rate can't be retrieved using CLK API because it
+        * causes lockup if CPU enters LP2 idle state from some other
+        * CLK notifier, hence we're caching the rate's value locally.
+        */
+       if (pmc->clk) {
+               pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb;
+               err = clk_notifier_register(pmc->clk, &pmc->clk_nb);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "failed to register clk notifier\n");
+                       return err;
+               }
+
+               pmc->rate = clk_get_rate(pmc->clk);
+       }
+
        pmc->dev = &pdev->dev;
 
        tegra_pmc_init(pmc);
@@ -2133,6 +2294,8 @@ cleanup_debugfs:
 cleanup_sysfs:
        device_remove_file(&pdev->dev, &dev_attr_reset_reason);
        device_remove_file(&pdev->dev, &dev_attr_reset_level);
+       clk_notifier_unregister(pmc->clk, &pmc->clk_nb);
+
        return err;
 }
 
@@ -2184,7 +2347,7 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
 
 static void tegra20_pmc_init(struct tegra_pmc *pmc)
 {
-       u32 value;
+       u32 value, osc, pmu, off;
 
        /* Always enable CPU power request */
        value = tegra_pmc_readl(pmc, PMC_CNTRL);
@@ -2198,6 +2361,11 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
        else
                value |= PMC_CNTRL_SYSCLK_POLARITY;
 
+       if (pmc->corereq_high)
+               value &= ~PMC_CNTRL_PWRREQ_POLARITY;
+       else
+               value |= PMC_CNTRL_PWRREQ_POLARITY;
+
        /* configure the output polarity while the request is tristated */
        tegra_pmc_writel(pmc, value, PMC_CNTRL);
 
@@ -2205,6 +2373,16 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
        value = tegra_pmc_readl(pmc, PMC_CNTRL);
        value |= PMC_CNTRL_SYSCLK_OE;
        tegra_pmc_writel(pmc, value, PMC_CNTRL);
+
+       /* program core timings which are applicable only for suspend state */
+       if (pmc->suspend_mode != TEGRA_SUSPEND_NONE) {
+               osc = DIV_ROUND_UP(pmc->core_osc_time * 8192, 1000000);
+               pmu = DIV_ROUND_UP(pmc->core_pmu_time * 32768, 1000000);
+               off = DIV_ROUND_UP(pmc->core_off_time * 32768, 1000000);
+               tegra_pmc_writel(pmc, ((osc << 8) & 0xff00) | (pmu & 0xff),
+                                PMC_COREPWRGOOD_TIMER);
+               tegra_pmc_writel(pmc, off, PMC_COREPWROFF_TIMER);
+       }
 }
 
 static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
@@ -2538,6 +2716,10 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
        TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
 };
 
+static const struct tegra_wake_event tegra210_wake_events[] = {
+       TEGRA_WAKE_IRQ("rtc", 16, 2),
+};
+
 static const struct tegra_pmc_soc tegra210_pmc_soc = {
        .num_powergates = ARRAY_SIZE(tegra210_powergates),
        .powergates = tegra210_powergates,
@@ -2555,10 +2737,14 @@ 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,
+       .irq_set_wake = tegra210_pmc_irq_set_wake,
+       .irq_set_type = tegra210_pmc_irq_set_type,
        .reset_sources = tegra210_reset_sources,
        .num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
+       .num_wake_events = ARRAY_SIZE(tegra210_wake_events),
+       .wake_events = tegra210_wake_events,
 };
 
 #define TEGRA186_IO_PAD_TABLE(_pad)                                         \
@@ -2680,6 +2866,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
        .regs = &tegra186_pmc_regs,
        .init = NULL,
        .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+       .irq_set_wake = tegra186_pmc_irq_set_wake,
+       .irq_set_type = tegra186_pmc_irq_set_type,
        .reset_sources = tegra186_reset_sources,
        .num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
        .reset_levels = tegra186_reset_levels,
diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c
new file mode 100644 (file)
index 0000000..ea0eede
--- /dev/null
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Voltage regulators coupler for NVIDIA Tegra20
+ * Copyright (C) 2019 GRATE-DRIVER project
+ *
+ * Voltage constraints borrowed from downstream kernel sources
+ * Copyright (C) 2010-2011 NVIDIA Corporation
+ */
+
+#define pr_fmt(fmt)    "tegra voltage-coupler: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/coupler.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+struct tegra_regulator_coupler {
+       struct regulator_coupler coupler;
+       struct regulator_dev *core_rdev;
+       struct regulator_dev *cpu_rdev;
+       struct regulator_dev *rtc_rdev;
+       int core_min_uV;
+};
+
+static inline struct tegra_regulator_coupler *
+to_tegra_coupler(struct regulator_coupler *coupler)
+{
+       return container_of(coupler, struct tegra_regulator_coupler, coupler);
+}
+
+static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
+                             struct regulator_dev *core_rdev)
+{
+       int core_min_uV = 0;
+       int core_max_uV;
+       int core_cur_uV;
+       int err;
+
+       if (tegra->core_min_uV > 0)
+               return tegra->core_min_uV;
+
+       core_cur_uV = regulator_get_voltage_rdev(core_rdev);
+       if (core_cur_uV < 0)
+               return core_cur_uV;
+
+       core_max_uV = max(core_cur_uV, 1200000);
+
+       err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+       if (err)
+               return err;
+
+       /*
+        * Limit minimum CORE voltage to a value left from bootloader or,
+        * if it's unreasonably low value, to the most common 1.2v or to
+        * whatever maximum value defined via board's device-tree.
+        */
+       tegra->core_min_uV = core_max_uV;
+
+       pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
+
+       return tegra->core_min_uV;
+}
+
+static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev,
+                                      struct regulator_dev *rtc_rdev)
+{
+       struct coupling_desc *c_desc = &core_rdev->coupling_desc;
+       struct regulator_dev *rdev;
+       int max_spread;
+       unsigned int i;
+
+       for (i = 1; i < c_desc->n_coupled; i++) {
+               max_spread = core_rdev->constraints->max_spread[i - 1];
+               rdev = c_desc->coupled_rdevs[i];
+
+               if (rdev == rtc_rdev && max_spread)
+                       return max_spread;
+       }
+
+       pr_err_once("rtc-core max-spread is undefined in device-tree\n");
+
+       return 150000;
+}
+
+static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
+                                  struct regulator_dev *core_rdev,
+                                  struct regulator_dev *rtc_rdev,
+                                  int cpu_uV, int cpu_min_uV)
+{
+       int core_min_uV, core_max_uV = INT_MAX;
+       int rtc_min_uV, rtc_max_uV = INT_MAX;
+       int core_target_uV;
+       int rtc_target_uV;
+       int max_spread;
+       int core_uV;
+       int rtc_uV;
+       int err;
+
+       /*
+        * RTC and CORE voltages should be no more than 170mV from each other,
+        * CPU should be below RTC and CORE by at least 120mV. This applies
+        * to all Tegra20 SoC's.
+        */
+       max_spread = tegra20_core_rtc_max_spread(core_rdev, rtc_rdev);
+
+       /*
+        * The core voltage scaling is currently not hooked up in drivers,
+        * hence we will limit the minimum core voltage to a reasonable value.
+        * This should be good enough for the time being.
+        */
+       core_min_uV = tegra20_core_limit(tegra, core_rdev);
+       if (core_min_uV < 0)
+               return core_min_uV;
+
+       err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+       if (err)
+               return err;
+
+       err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
+                                       PM_SUSPEND_ON);
+       if (err)
+               return err;
+
+       core_uV = regulator_get_voltage_rdev(core_rdev);
+       if (core_uV < 0)
+               return core_uV;
+
+       core_min_uV = max(cpu_min_uV + 125000, core_min_uV);
+       if (core_min_uV > core_max_uV)
+               return -EINVAL;
+
+       if (cpu_uV + 120000 > core_uV)
+               pr_err("core-cpu voltage constraint violated: %d %d\n",
+                      core_uV, cpu_uV + 120000);
+
+       rtc_uV = regulator_get_voltage_rdev(rtc_rdev);
+       if (rtc_uV < 0)
+               return rtc_uV;
+
+       if (cpu_uV + 120000 > rtc_uV)
+               pr_err("rtc-cpu voltage constraint violated: %d %d\n",
+                      rtc_uV, cpu_uV + 120000);
+
+       if (abs(core_uV - rtc_uV) > 170000)
+               pr_err("core-rtc voltage constraint violated: %d %d\n",
+                      core_uV, rtc_uV);
+
+       rtc_min_uV = max(cpu_min_uV + 125000, core_min_uV - max_spread);
+
+       err = regulator_check_voltage(rtc_rdev, &rtc_min_uV, &rtc_max_uV);
+       if (err)
+               return err;
+
+       while (core_uV != core_min_uV || rtc_uV != rtc_min_uV) {
+               if (core_uV < core_min_uV) {
+                       core_target_uV = min(core_uV + max_spread, core_min_uV);
+                       core_target_uV = min(rtc_uV + max_spread, core_target_uV);
+               } else {
+                       core_target_uV = max(core_uV - max_spread, core_min_uV);
+                       core_target_uV = max(rtc_uV - max_spread, core_target_uV);
+               }
+
+               err = regulator_set_voltage_rdev(core_rdev,
+                                                core_target_uV,
+                                                core_max_uV,
+                                                PM_SUSPEND_ON);
+               if (err)
+                       return err;
+
+               core_uV = core_target_uV;
+
+               if (rtc_uV < rtc_min_uV) {
+                       rtc_target_uV = min(rtc_uV + max_spread, rtc_min_uV);
+                       rtc_target_uV = min(core_uV + max_spread, rtc_target_uV);
+               } else {
+                       rtc_target_uV = max(rtc_uV - max_spread, rtc_min_uV);
+                       rtc_target_uV = max(core_uV - max_spread, rtc_target_uV);
+               }
+
+               err = regulator_set_voltage_rdev(rtc_rdev,
+                                                rtc_target_uV,
+                                                rtc_max_uV,
+                                                PM_SUSPEND_ON);
+               if (err)
+                       return err;
+
+               rtc_uV = rtc_target_uV;
+       }
+
+       return 0;
+}
+
+static int tegra20_core_voltage_update(struct tegra_regulator_coupler *tegra,
+                                      struct regulator_dev *cpu_rdev,
+                                      struct regulator_dev *core_rdev,
+                                      struct regulator_dev *rtc_rdev)
+{
+       int cpu_uV;
+
+       cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
+       if (cpu_uV < 0)
+               return cpu_uV;
+
+       return tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
+                                      cpu_uV, cpu_uV);
+}
+
+static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
+                                     struct regulator_dev *cpu_rdev,
+                                     struct regulator_dev *core_rdev,
+                                     struct regulator_dev *rtc_rdev)
+{
+       int cpu_min_uV_consumers = 0;
+       int cpu_max_uV = INT_MAX;
+       int cpu_min_uV = 0;
+       int cpu_uV;
+       int err;
+
+       err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
+       if (err)
+               return err;
+
+       err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
+                                       PM_SUSPEND_ON);
+       if (err)
+               return err;
+
+       err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
+                                       &cpu_max_uV, PM_SUSPEND_ON);
+       if (err)
+               return err;
+
+       cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
+       if (cpu_uV < 0)
+               return cpu_uV;
+
+       /*
+        * CPU's regulator may not have any consumers, hence the voltage
+        * must not be changed in that case because CPU simply won't
+        * survive the voltage drop if it's running on a higher frequency.
+        */
+       if (!cpu_min_uV_consumers)
+               cpu_min_uV = cpu_uV;
+
+       if (cpu_min_uV > cpu_uV) {
+               err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
+                                             cpu_uV, cpu_min_uV);
+               if (err)
+                       return err;
+
+               err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
+                                                cpu_max_uV, PM_SUSPEND_ON);
+               if (err)
+                       return err;
+       } else if (cpu_min_uV < cpu_uV)  {
+               err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
+                                                cpu_max_uV, PM_SUSPEND_ON);
+               if (err)
+                       return err;
+
+               err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
+                                             cpu_uV, cpu_min_uV);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
+                                            struct regulator_dev *rdev,
+                                            suspend_state_t state)
+{
+       struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+       struct regulator_dev *core_rdev = tegra->core_rdev;
+       struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
+       struct regulator_dev *rtc_rdev = tegra->rtc_rdev;
+
+       if ((core_rdev != rdev && cpu_rdev != rdev && rtc_rdev != rdev) ||
+           state != PM_SUSPEND_ON) {
+               pr_err("regulators are not coupled properly\n");
+               return -EINVAL;
+       }
+
+       if (rdev == cpu_rdev)
+               return tegra20_cpu_voltage_update(tegra, cpu_rdev,
+                                                 core_rdev, rtc_rdev);
+
+       if (rdev == core_rdev)
+               return tegra20_core_voltage_update(tegra, cpu_rdev,
+                                                  core_rdev, rtc_rdev);
+
+       pr_err("changing %s voltage not permitted\n", rdev_get_name(rtc_rdev));
+
+       return -EPERM;
+}
+
+static int tegra20_regulator_attach(struct regulator_coupler *coupler,
+                                   struct regulator_dev *rdev)
+{
+       struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+       struct device_node *np = rdev->dev.of_node;
+
+       if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
+           !tegra->core_rdev) {
+               tegra->core_rdev = rdev;
+               return 0;
+       }
+
+       if (of_property_read_bool(np, "nvidia,tegra-rtc-regulator") &&
+           !tegra->rtc_rdev) {
+               tegra->rtc_rdev = rdev;
+               return 0;
+       }
+
+       if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
+           !tegra->cpu_rdev) {
+               tegra->cpu_rdev = rdev;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int tegra20_regulator_detach(struct regulator_coupler *coupler,
+                                   struct regulator_dev *rdev)
+{
+       struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+
+       if (tegra->core_rdev == rdev) {
+               tegra->core_rdev = NULL;
+               return 0;
+       }
+
+       if (tegra->rtc_rdev == rdev) {
+               tegra->rtc_rdev = NULL;
+               return 0;
+       }
+
+       if (tegra->cpu_rdev == rdev) {
+               tegra->cpu_rdev = NULL;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static struct tegra_regulator_coupler tegra20_coupler = {
+       .coupler = {
+               .attach_regulator = tegra20_regulator_attach,
+               .detach_regulator = tegra20_regulator_detach,
+               .balance_voltage = tegra20_regulator_balance_voltage,
+       },
+};
+
+static int __init tegra_regulator_coupler_init(void)
+{
+       if (!of_machine_is_compatible("nvidia,tegra20"))
+               return 0;
+
+       return regulator_coupler_register(&tegra20_coupler.coupler);
+}
+arch_initcall(tegra_regulator_coupler_init);
diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c
new file mode 100644 (file)
index 0000000..8e623ff
--- /dev/null
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Voltage regulators coupler for NVIDIA Tegra30
+ * Copyright (C) 2019 GRATE-DRIVER project
+ *
+ * Voltage constraints borrowed from downstream kernel sources
+ * Copyright (C) 2010-2011 NVIDIA Corporation
+ */
+
+#define pr_fmt(fmt)    "tegra voltage-coupler: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/coupler.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <soc/tegra/fuse.h>
+
+struct tegra_regulator_coupler {
+       struct regulator_coupler coupler;
+       struct regulator_dev *core_rdev;
+       struct regulator_dev *cpu_rdev;
+       int core_min_uV;
+};
+
+static inline struct tegra_regulator_coupler *
+to_tegra_coupler(struct regulator_coupler *coupler)
+{
+       return container_of(coupler, struct tegra_regulator_coupler, coupler);
+}
+
+static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
+                             struct regulator_dev *core_rdev)
+{
+       int core_min_uV = 0;
+       int core_max_uV;
+       int core_cur_uV;
+       int err;
+
+       if (tegra->core_min_uV > 0)
+               return tegra->core_min_uV;
+
+       core_cur_uV = regulator_get_voltage_rdev(core_rdev);
+       if (core_cur_uV < 0)
+               return core_cur_uV;
+
+       core_max_uV = max(core_cur_uV, 1200000);
+
+       err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+       if (err)
+               return err;
+
+       /*
+        * Limit minimum CORE voltage to a value left from bootloader or,
+        * if it's unreasonably low value, to the most common 1.2v or to
+        * whatever maximum value defined via board's device-tree.
+        */
+       tegra->core_min_uV = core_max_uV;
+
+       pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
+
+       return tegra->core_min_uV;
+}
+
+static int tegra30_core_cpu_limit(int cpu_uV)
+{
+       if (cpu_uV < 800000)
+               return 950000;
+
+       if (cpu_uV < 900000)
+               return 1000000;
+
+       if (cpu_uV < 1000000)
+               return 1100000;
+
+       if (cpu_uV < 1100000)
+               return 1200000;
+
+       if (cpu_uV < 1250000) {
+               switch (tegra_sku_info.cpu_speedo_id) {
+               case 0 ... 1:
+               case 4:
+               case 7 ... 8:
+                       return 1200000;
+
+               default:
+                       return 1300000;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
+                                 struct regulator_dev *cpu_rdev,
+                                 struct regulator_dev *core_rdev)
+{
+       int core_min_uV, core_max_uV = INT_MAX;
+       int cpu_min_uV, cpu_max_uV = INT_MAX;
+       int cpu_min_uV_consumers = 0;
+       int core_min_limited_uV;
+       int core_target_uV;
+       int cpu_target_uV;
+       int core_max_step;
+       int cpu_max_step;
+       int max_spread;
+       int core_uV;
+       int cpu_uV;
+       int err;
+
+       /*
+        * CPU voltage should not got lower than 300mV from the CORE.
+        * CPU voltage should stay below the CORE by 100mV+, depending
+        * by the CORE voltage. This applies to all Tegra30 SoC's.
+        */
+       max_spread = cpu_rdev->constraints->max_spread[0];
+       cpu_max_step = cpu_rdev->constraints->max_uV_step;
+       core_max_step = core_rdev->constraints->max_uV_step;
+
+       if (!max_spread) {
+               pr_err_once("cpu-core max-spread is undefined in device-tree\n");
+               max_spread = 300000;
+       }
+
+       if (!cpu_max_step) {
+               pr_err_once("cpu max-step is undefined in device-tree\n");
+               cpu_max_step = 150000;
+       }
+
+       if (!core_max_step) {
+               pr_err_once("core max-step is undefined in device-tree\n");
+               core_max_step = 150000;
+       }
+
+       /*
+        * The CORE voltage scaling is currently not hooked up in drivers,
+        * hence we will limit the minimum CORE voltage to a reasonable value.
+        * This should be good enough for the time being.
+        */
+       core_min_uV = tegra30_core_limit(tegra, core_rdev);
+       if (core_min_uV < 0)
+               return core_min_uV;
+
+       err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
+                                       PM_SUSPEND_ON);
+       if (err)
+               return err;
+
+       core_uV = regulator_get_voltage_rdev(core_rdev);
+       if (core_uV < 0)
+               return core_uV;
+
+       cpu_min_uV = core_min_uV - max_spread;
+
+       err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
+                                       PM_SUSPEND_ON);
+       if (err)
+               return err;
+
+       err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
+                                       &cpu_max_uV, PM_SUSPEND_ON);
+       if (err)
+               return err;
+
+       err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
+       if (err)
+               return err;
+
+       cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
+       if (cpu_uV < 0)
+               return cpu_uV;
+
+       /*
+        * CPU's regulator may not have any consumers, hence the voltage
+        * must not be changed in that case because CPU simply won't
+        * survive the voltage drop if it's running on a higher frequency.
+        */
+       if (!cpu_min_uV_consumers)
+               cpu_min_uV = cpu_uV;
+
+       /*
+        * Bootloader shall set up voltages correctly, but if it
+        * happens that there is a violation, then try to fix it
+        * at first.
+        */
+       core_min_limited_uV = tegra30_core_cpu_limit(cpu_uV);
+       if (core_min_limited_uV < 0)
+               return core_min_limited_uV;
+
+       core_min_uV = max(core_min_uV, tegra30_core_cpu_limit(cpu_min_uV));
+
+       err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+       if (err)
+               return err;
+
+       if (core_min_limited_uV > core_uV) {
+               pr_err("core voltage constraint violated: %d %d %d\n",
+                      core_uV, core_min_limited_uV, cpu_uV);
+               goto update_core;
+       }
+
+       while (cpu_uV != cpu_min_uV || core_uV != core_min_uV) {
+               if (cpu_uV < cpu_min_uV) {
+                       cpu_target_uV = min(cpu_uV + cpu_max_step, cpu_min_uV);
+               } else {
+                       cpu_target_uV = max(cpu_uV - cpu_max_step, cpu_min_uV);
+                       cpu_target_uV = max(core_uV - max_spread, cpu_target_uV);
+               }
+
+               err = regulator_set_voltage_rdev(cpu_rdev,
+                                                cpu_target_uV,
+                                                cpu_max_uV,
+                                                PM_SUSPEND_ON);
+               if (err)
+                       return err;
+
+               cpu_uV = cpu_target_uV;
+update_core:
+               core_min_limited_uV = tegra30_core_cpu_limit(cpu_uV);
+               if (core_min_limited_uV < 0)
+                       return core_min_limited_uV;
+
+               core_target_uV = max(core_min_limited_uV, core_min_uV);
+
+               if (core_uV < core_target_uV) {
+                       core_target_uV = min(core_target_uV, core_uV + core_max_step);
+                       core_target_uV = min(core_target_uV, cpu_uV + max_spread);
+               } else {
+                       core_target_uV = max(core_target_uV, core_uV - core_max_step);
+               }
+
+               err = regulator_set_voltage_rdev(core_rdev,
+                                                core_target_uV,
+                                                core_max_uV,
+                                                PM_SUSPEND_ON);
+               if (err)
+                       return err;
+
+               core_uV = core_target_uV;
+       }
+
+       return 0;
+}
+
+static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
+                                            struct regulator_dev *rdev,
+                                            suspend_state_t state)
+{
+       struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+       struct regulator_dev *core_rdev = tegra->core_rdev;
+       struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
+
+       if ((core_rdev != rdev && cpu_rdev != rdev) || state != PM_SUSPEND_ON) {
+               pr_err("regulators are not coupled properly\n");
+               return -EINVAL;
+       }
+
+       return tegra30_voltage_update(tegra, cpu_rdev, core_rdev);
+}
+
+static int tegra30_regulator_attach(struct regulator_coupler *coupler,
+                                   struct regulator_dev *rdev)
+{
+       struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+       struct device_node *np = rdev->dev.of_node;
+
+       if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
+           !tegra->core_rdev) {
+               tegra->core_rdev = rdev;
+               return 0;
+       }
+
+       if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
+           !tegra->cpu_rdev) {
+               tegra->cpu_rdev = rdev;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int tegra30_regulator_detach(struct regulator_coupler *coupler,
+                                   struct regulator_dev *rdev)
+{
+       struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+
+       if (tegra->core_rdev == rdev) {
+               tegra->core_rdev = NULL;
+               return 0;
+       }
+
+       if (tegra->cpu_rdev == rdev) {
+               tegra->cpu_rdev = NULL;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static struct tegra_regulator_coupler tegra30_coupler = {
+       .coupler = {
+               .attach_regulator = tegra30_regulator_attach,
+               .detach_regulator = tegra30_regulator_detach,
+               .balance_voltage = tegra30_regulator_balance_voltage,
+       },
+};
+
+static int __init tegra_regulator_coupler_init(void)
+{
+       if (!of_machine_is_compatible("nvidia,tegra30"))
+               return 0;
+
+       return regulator_coupler_register(&tegra30_coupler.coupler);
+}
+arch_initcall(tegra_regulator_coupler_init);
index b3868d3..788b5cd 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS)   += knav_qmss.o
 knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
 obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)   += knav_dma.o
 obj-$(CONFIG_AMX3_PM)                  += pm33xx.o
+obj-$(CONFIG_ARCH_OMAP2PLUS)           += omap_prm.o
 obj-$(CONFIG_WKUP_M3_IPC)              += wkup_m3_ipc.o
 obj-$(CONFIG_TI_SCI_PM_DOMAINS)                += ti_sci_pm_domains.o
 obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN)   += ti_sci_inta_msi.o
diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
new file mode 100644 (file)
index 0000000..96c6f77
--- /dev/null
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OMAP2+ PRM driver
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ *     Tero Kristo <t-kristo@ti.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/delay.h>
+
+#include <linux/platform_data/ti-prm.h>
+
+struct omap_rst_map {
+       s8 rst;
+       s8 st;
+};
+
+struct omap_prm_data {
+       u32 base;
+       const char *name;
+       const char *clkdm_name;
+       u16 rstctrl;
+       u16 rstst;
+       const struct omap_rst_map *rstmap;
+       u8 flags;
+};
+
+struct omap_prm {
+       const struct omap_prm_data *data;
+       void __iomem *base;
+};
+
+struct omap_reset_data {
+       struct reset_controller_dev rcdev;
+       struct omap_prm *prm;
+       u32 mask;
+       spinlock_t lock;
+       struct clockdomain *clkdm;
+       struct device *dev;
+};
+
+#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
+
+#define OMAP_MAX_RESETS                8
+#define OMAP_RESET_MAX_WAIT    10000
+
+#define OMAP_PRM_HAS_RSTCTRL   BIT(0)
+#define OMAP_PRM_HAS_RSTST     BIT(1)
+#define OMAP_PRM_HAS_NO_CLKDM  BIT(2)
+
+#define OMAP_PRM_HAS_RESETS    (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
+
+static const struct omap_rst_map rst_map_0[] = {
+       { .rst = 0, .st = 0 },
+       { .rst = -1 },
+};
+
+static const struct omap_rst_map rst_map_01[] = {
+       { .rst = 0, .st = 0 },
+       { .rst = 1, .st = 1 },
+       { .rst = -1 },
+};
+
+static const struct omap_rst_map rst_map_012[] = {
+       { .rst = 0, .st = 0 },
+       { .rst = 1, .st = 1 },
+       { .rst = 2, .st = 2 },
+       { .rst = -1 },
+};
+
+static const struct omap_prm_data omap4_prm_data[] = {
+       { .name = "tesla", .base = 0x4a306400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "core", .base = 0x4a306700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", .rstmap = rst_map_012 },
+       { .name = "ivahd", .base = 0x4a306f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 },
+       { .name = "device", .base = 0x4a307b00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
+       { },
+};
+
+static const struct omap_prm_data omap5_prm_data[] = {
+       { .name = "dsp", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu", .rstmap = rst_map_012 },
+       { .name = "iva", .base = 0x4ae07200, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 },
+       { .name = "device", .base = 0x4ae07c00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
+       { },
+};
+
+static const struct omap_prm_data dra7_prm_data[] = {
+       { .name = "dsp1", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "ipu", .base = 0x4ae06500, .rstctrl = 0x10, .rstst = 0x14, .clkdm_name = "ipu1", .rstmap = rst_map_012 },
+       { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu2", .rstmap = rst_map_012 },
+       { .name = "iva", .base = 0x4ae06f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 },
+       { .name = "dsp2", .base = 0x4ae07b00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "eve1", .base = 0x4ae07b40, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "eve2", .base = 0x4ae07b80, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "eve3", .base = 0x4ae07bc0, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { .name = "eve4", .base = 0x4ae07c00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 },
+       { },
+};
+
+static const struct omap_rst_map am3_per_rst_map[] = {
+       { .rst = 1 },
+       { .rst = -1 },
+};
+
+static const struct omap_rst_map am3_wkup_rst_map[] = {
+       { .rst = 3, .st = 5 },
+       { .rst = -1 },
+};
+
+static const struct omap_prm_data am3_prm_data[] = {
+       { .name = "per", .base = 0x44e00c00, .rstctrl = 0x0, .rstmap = am3_per_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp" },
+       { .name = "wkup", .base = 0x44e00d00, .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
+       { .name = "device", .base = 0x44e00f00, .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
+       { .name = "gfx", .base = 0x44e01100, .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" },
+       { },
+};
+
+static const struct omap_rst_map am4_per_rst_map[] = {
+       { .rst = 1, .st = 0 },
+       { .rst = -1 },
+};
+
+static const struct omap_rst_map am4_device_rst_map[] = {
+       { .rst = 0, .st = 1 },
+       { .rst = 1, .st = 0 },
+       { .rst = -1 },
+};
+
+static const struct omap_prm_data am4_prm_data[] = {
+       { .name = "gfx", .base = 0x44df0400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" },
+       { .name = "per", .base = 0x44df0800, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map, .clkdm_name = "pruss_ocp" },
+       { .name = "wkup", .base = 0x44df2000, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_NO_CLKDM },
+       { .name = "device", .base = 0x44df4000, .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM },
+       { },
+};
+
+static const struct of_device_id omap_prm_id_table[] = {
+       { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
+       { .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data },
+       { .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data },
+       { .compatible = "ti,am3-prm-inst", .data = am3_prm_data },
+       { .compatible = "ti,am4-prm-inst", .data = am4_prm_data },
+       { },
+};
+
+static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id)
+{
+       if (reset->mask & BIT(id))
+               return true;
+
+       return false;
+}
+
+static int omap_reset_get_st_bit(struct omap_reset_data *reset,
+                                unsigned long id)
+{
+       const struct omap_rst_map *map = reset->prm->data->rstmap;
+
+       while (map->rst >= 0) {
+               if (map->rst == id)
+                       return map->st;
+
+               map++;
+       }
+
+       return id;
+}
+
+static int omap_reset_status(struct reset_controller_dev *rcdev,
+                            unsigned long id)
+{
+       struct omap_reset_data *reset = to_omap_reset_data(rcdev);
+       u32 v;
+       int st_bit = omap_reset_get_st_bit(reset, id);
+       bool has_rstst = reset->prm->data->rstst ||
+               (reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
+
+       /* Check if we have rstst */
+       if (!has_rstst)
+               return -ENOTSUPP;
+
+       /* Check if hw reset line is asserted */
+       v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
+       if (v & BIT(id))
+               return 1;
+
+       /*
+        * Check reset status, high value means reset sequence has been
+        * completed successfully so we can return 0 here (reset deasserted)
+        */
+       v = readl_relaxed(reset->prm->base + reset->prm->data->rstst);
+       v >>= st_bit;
+       v &= 1;
+
+       return !v;
+}
+
+static int omap_reset_assert(struct reset_controller_dev *rcdev,
+                            unsigned long id)
+{
+       struct omap_reset_data *reset = to_omap_reset_data(rcdev);
+       u32 v;
+       unsigned long flags;
+
+       /* assert the reset control line */
+       spin_lock_irqsave(&reset->lock, flags);
+       v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
+       v |= 1 << id;
+       writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
+       spin_unlock_irqrestore(&reset->lock, flags);
+
+       return 0;
+}
+
+static int omap_reset_deassert(struct reset_controller_dev *rcdev,
+                              unsigned long id)
+{
+       struct omap_reset_data *reset = to_omap_reset_data(rcdev);
+       u32 v;
+       int st_bit;
+       bool has_rstst;
+       unsigned long flags;
+       struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev);
+       int ret = 0;
+
+       has_rstst = reset->prm->data->rstst ||
+               (reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
+
+       if (has_rstst) {
+               st_bit = omap_reset_get_st_bit(reset, id);
+
+               /* Clear the reset status by writing 1 to the status bit */
+               v = 1 << st_bit;
+               writel_relaxed(v, reset->prm->base + reset->prm->data->rstst);
+       }
+
+       if (reset->clkdm)
+               pdata->clkdm_deny_idle(reset->clkdm);
+
+       /* de-assert the reset control line */
+       spin_lock_irqsave(&reset->lock, flags);
+       v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
+       v &= ~(1 << id);
+       writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
+       spin_unlock_irqrestore(&reset->lock, flags);
+
+       if (!has_rstst)
+               goto exit;
+
+       /* wait for the status to be set */
+       ret = readl_relaxed_poll_timeout(reset->prm->base +
+                                        reset->prm->data->rstst,
+                                        v, v & BIT(st_bit), 1,
+                                        OMAP_RESET_MAX_WAIT);
+       if (ret)
+               pr_err("%s: timedout waiting for %s:%lu\n", __func__,
+                      reset->prm->data->name, id);
+
+exit:
+       if (reset->clkdm)
+               pdata->clkdm_allow_idle(reset->clkdm);
+
+       return ret;
+}
+
+static const struct reset_control_ops omap_reset_ops = {
+       .assert         = omap_reset_assert,
+       .deassert       = omap_reset_deassert,
+       .status         = omap_reset_status,
+};
+
+static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
+                               const struct of_phandle_args *reset_spec)
+{
+       struct omap_reset_data *reset = to_omap_reset_data(rcdev);
+
+       if (!_is_valid_reset(reset, reset_spec->args[0]))
+               return -EINVAL;
+
+       return reset_spec->args[0];
+}
+
+static int omap_prm_reset_init(struct platform_device *pdev,
+                              struct omap_prm *prm)
+{
+       struct omap_reset_data *reset;
+       const struct omap_rst_map *map;
+       struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       char buf[32];
+
+       /*
+        * Check if we have controllable resets. If either rstctrl is non-zero
+        * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
+        * for the domain.
+        */
+       if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
+               return 0;
+
+       /* Check if we have the pdata callbacks in place */
+       if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
+           !pdata->clkdm_allow_idle)
+               return -EINVAL;
+
+       map = prm->data->rstmap;
+       if (!map)
+               return -EINVAL;
+
+       reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+       if (!reset)
+               return -ENOMEM;
+
+       reset->rcdev.owner = THIS_MODULE;
+       reset->rcdev.ops = &omap_reset_ops;
+       reset->rcdev.of_node = pdev->dev.of_node;
+       reset->rcdev.nr_resets = OMAP_MAX_RESETS;
+       reset->rcdev.of_xlate = omap_prm_reset_xlate;
+       reset->rcdev.of_reset_n_cells = 1;
+       reset->dev = &pdev->dev;
+       spin_lock_init(&reset->lock);
+
+       reset->prm = prm;
+
+       sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
+               prm->data->name);
+
+       if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
+               reset->clkdm = pdata->clkdm_lookup(buf);
+               if (!reset->clkdm)
+                       return -EINVAL;
+       }
+
+       while (map->rst >= 0) {
+               reset->mask |= BIT(map->rst);
+               map++;
+       }
+
+       return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
+}
+
+static int omap_prm_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       const struct omap_prm_data *data;
+       struct omap_prm *prm;
+       const struct of_device_id *match;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       match = of_match_device(omap_prm_id_table, &pdev->dev);
+       if (!match)
+               return -ENOTSUPP;
+
+       prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
+       if (!prm)
+               return -ENOMEM;
+
+       data = match->data;
+
+       while (data->base != res->start) {
+               if (!data->base)
+                       return -EINVAL;
+               data++;
+       }
+
+       prm->data = data;
+
+       prm->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(prm->base))
+               return PTR_ERR(prm->base);
+
+       return omap_prm_reset_init(pdev, prm);
+}
+
+static struct platform_driver omap_prm_driver = {
+       .probe = omap_prm_probe,
+       .driver = {
+               .name           = KBUILD_MODNAME,
+               .of_match_table = omap_prm_id_table,
+       },
+};
+builtin_platform_driver(omap_prm_driver);
index 600f57c..23d90cb 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * ZynqMP Generic PM domain support
  *
- *  Copyright (C) 2015-2018 Xilinx, Inc.
+ *  Copyright (C) 2015-2019 Xilinx, Inc.
  *
  *  Davorin Mista <davorin.mista@aggios.com>
  *  Jolly Shah <jollys@xilinx.com>
@@ -25,6 +25,8 @@
 
 static const struct zynqmp_eemi_ops *eemi_ops;
 
+static int min_capability;
+
 /**
  * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
  * @gpd:               Generic power domain
@@ -106,7 +108,7 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
        int ret;
        struct pm_domain_data *pdd, *tmp;
        struct zynqmp_pm_domain *pd;
-       u32 capabilities = 0;
+       u32 capabilities = min_capability;
        bool may_wakeup;
 
        if (!eemi_ops->set_requirement)
@@ -283,6 +285,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
        if (!domains)
                return -ENOMEM;
 
+       if (!of_device_is_compatible(dev->parent->of_node,
+                                    "xlnx,zynqmp-firmware"))
+               min_capability = ZYNQMP_PM_CAPABILITY_UNUSABLE;
+
        for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++, pd++) {
                pd->node_id = 0;
                pd->gpd.name = kasprintf(GFP_KERNEL, "domain%d", i);
index 50d87c7..9ea9c88 100644 (file)
@@ -13,9 +13,6 @@
 /* The maximum devices per each type. */
 #define GASKET_DEV_MAX 256
 
-/* The number of supported (and possible) PCI BARs. */
-#define GASKET_NUM_BARS 6
-
 /* The number of supported Gasket page tables per device. */
 #define GASKET_MAX_NUM_PAGE_TABLES 1
 
index 13179f0..cd8be80 100644 (file)
@@ -371,7 +371,7 @@ static int gasket_setup_pci(struct pci_dev *pci_dev,
 {
        int i, mapped_bars, ret;
 
-       for (i = 0; i < GASKET_NUM_BARS; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                ret = gasket_map_pci_bar(gasket_dev, i);
                if (ret) {
                        mapped_bars = i;
@@ -393,7 +393,7 @@ static void gasket_cleanup_pci(struct gasket_dev *gasket_dev)
 {
        int i;
 
-       for (i = 0; i < GASKET_NUM_BARS; i++)
+       for (i = 0; i < PCI_STD_NUM_BARS; i++)
                gasket_unmap_pci_bar(gasket_dev, i);
 }
 
@@ -493,7 +493,7 @@ static ssize_t gasket_sysfs_data_show(struct device *device,
                (enum gasket_sysfs_attribute_type)gasket_attr->data.attr_type;
        switch (sysfs_type) {
        case ATTR_BAR_OFFSETS:
-               for (i = 0; i < GASKET_NUM_BARS; i++) {
+               for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                        bar_desc = &driver_desc->bar_descriptions[i];
                        if (bar_desc->size == 0)
                                continue;
@@ -505,7 +505,7 @@ static ssize_t gasket_sysfs_data_show(struct device *device,
                }
                break;
        case ATTR_BAR_SIZES:
-               for (i = 0; i < GASKET_NUM_BARS; i++) {
+               for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                        bar_desc = &driver_desc->bar_descriptions[i];
                        if (bar_desc->size == 0)
                                continue;
@@ -556,7 +556,7 @@ static ssize_t gasket_sysfs_data_show(struct device *device,
                ret = snprintf(buf, PAGE_SIZE, "%d\n", gasket_dev->reset_count);
                break;
        case ATTR_USER_MEM_RANGES:
-               for (i = 0; i < GASKET_NUM_BARS; ++i) {
+               for (i = 0; i < PCI_STD_NUM_BARS; ++i) {
                        current_written =
                                gasket_write_mappable_regions(buf, driver_desc,
                                                              i);
@@ -736,7 +736,7 @@ static int gasket_get_bar_index(const struct gasket_dev *gasket_dev,
        const struct gasket_driver_desc *driver_desc;
 
        driver_desc = gasket_dev->internal_desc->driver_desc;
-       for (i = 0; i < GASKET_NUM_BARS; ++i) {
+       for (i = 0; i < PCI_STD_NUM_BARS; ++i) {
                struct gasket_bar_desc bar_desc =
                        driver_desc->bar_descriptions[i];
 
index be44ac1..c417aca 100644 (file)
@@ -268,7 +268,7 @@ struct gasket_dev {
        char kobj_name[GASKET_NAME_MAX];
 
        /* Virtual address of mapped BAR memory range. */
-       struct gasket_bar_data bar_data[GASKET_NUM_BARS];
+       struct gasket_bar_data bar_data[PCI_STD_NUM_BARS];
 
        /* Coherent buffer. */
        struct gasket_coherent_buffer coherent_buffer;
@@ -369,7 +369,7 @@ struct gasket_driver_desc {
        /* Set of 6 bar descriptions that describe all PCIe bars.
         * Note that BUS/AXI devices (i.e. non PCI devices) use those.
         */
-       struct gasket_bar_desc bar_descriptions[GASKET_NUM_BARS];
+       struct gasket_bar_desc bar_descriptions[PCI_STD_NUM_BARS];
 
        /*
         * Coherent buffer description.
index 54bb1eb..af35251 100644 (file)
@@ -297,7 +297,6 @@ int cxgbit_ddp_init(struct cxgbit_device *cdev)
        struct cxgb4_lld_info *lldi = &cdev->lldi;
        struct net_device *ndev = cdev->lldi.ports[0];
        struct cxgbi_tag_format tformat;
-       unsigned int ppmax;
        int ret, i;
 
        if (!lldi->vr->iscsi.size) {
@@ -305,8 +304,6 @@ int cxgbit_ddp_init(struct cxgbit_device *cdev)
                return -EACCES;
        }
 
-       ppmax = lldi->vr->iscsi.size >> PPOD_SIZE_SHIFT;
-
        memset(&tformat, 0, sizeof(struct cxgbi_tag_format));
        for (i = 0; i < 4; i++)
                tformat.pgsz_order[i] = (lldi->iscsi_pgsz_order >> (i << 3))
index d19e051..7251a87 100644 (file)
@@ -1165,7 +1165,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
                conn->cid);
 
-       target_get_sess_cmd(&cmd->se_cmd, true);
+       if (target_get_sess_cmd(&cmd->se_cmd, true) < 0)
+               return iscsit_add_reject_cmd(cmd,
+                               ISCSI_REASON_WAITING_FOR_LOGOUT, buf);
 
        cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd,
                                                     scsilun_to_int(&hdr->lun));
@@ -2002,7 +2004,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                              conn->sess->se_sess, 0, DMA_NONE,
                              TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
 
-       target_get_sess_cmd(&cmd->se_cmd, true);
+       if (target_get_sess_cmd(&cmd->se_cmd, true) < 0)
+               return iscsit_add_reject_cmd(cmd,
+                               ISCSI_REASON_WAITING_FOR_LOGOUT, buf);
 
        /*
         * TASK_REASSIGN for ERL=2 / connection stays inside of
@@ -2189,24 +2193,22 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                }
                goto empty_sendtargets;
        }
-       if (strncmp("SendTargets", text_in, 11) != 0) {
+       if (strncmp("SendTargets=", text_in, 12) != 0) {
                pr_err("Received Text Data that is not"
                        " SendTargets, cannot continue.\n");
                goto reject;
        }
+       /* '=' confirmed in strncmp */
        text_ptr = strchr(text_in, '=');
-       if (!text_ptr) {
-               pr_err("No \"=\" separator found in Text Data,"
-                       "  cannot continue.\n");
-               goto reject;
-       }
-       if (!strncmp("=All", text_ptr, 4)) {
+       BUG_ON(!text_ptr);
+       if (!strncmp("=All", text_ptr, 5)) {
                cmd->cmd_flags |= ICF_SENDTARGETS_ALL;
        } else if (!strncmp("=iqn.", text_ptr, 5) ||
                   !strncmp("=eui.", text_ptr, 5)) {
                cmd->cmd_flags |= ICF_SENDTARGETS_SINGLE;
        } else {
-               pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr);
+               pr_err("Unable to locate valid SendTargets%s value\n",
+                      text_ptr);
                goto reject;
        }
 
@@ -4232,6 +4234,8 @@ int iscsit_close_connection(
         * must wait until they have completed.
         */
        iscsit_check_conn_usage_count(conn);
+       target_sess_cmd_list_set_waiting(sess->se_sess);
+       target_wait_for_sess_cmds(sess->se_sess);
 
        ahash_request_free(conn->conn_tx_hash);
        if (conn->conn_rx_hash) {
index 51ddca2..0e54627 100644 (file)
 #include "iscsi_target_nego.h"
 #include "iscsi_target_auth.h"
 
+static char *chap_get_digest_name(const int digest_type)
+{
+       switch (digest_type) {
+       case CHAP_DIGEST_MD5:
+               return "md5";
+       case CHAP_DIGEST_SHA1:
+               return "sha1";
+       case CHAP_DIGEST_SHA256:
+               return "sha256";
+       case CHAP_DIGEST_SHA3_256:
+               return "sha3-256";
+       default:
+               return NULL;
+       }
+}
+
 static int chap_gen_challenge(
        struct iscsi_conn *conn,
        int caller,
@@ -25,16 +41,21 @@ static int chap_gen_challenge(
        unsigned int *c_len)
 {
        int ret;
-       unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
+       unsigned char *challenge_asciihex;
        struct iscsi_chap *chap = conn->auth_protocol;
 
-       memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
+       challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL);
+       if (!challenge_asciihex)
+               return -ENOMEM;
 
-       ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH);
+       memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN);
+
+       ret = get_random_bytes_wait(chap->challenge, chap->challenge_len);
        if (unlikely(ret))
-               return ret;
+               goto out;
+
        bin2hex(challenge_asciihex, chap->challenge,
-                               CHAP_CHALLENGE_LENGTH);
+                               chap->challenge_len);
        /*
         * Set CHAP_C, and copy the generated challenge into c_str.
         */
@@ -43,12 +64,29 @@ static int chap_gen_challenge(
 
        pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
                        challenge_asciihex);
+
+out:
+       kfree(challenge_asciihex);
+       return ret;
+}
+
+static int chap_test_algorithm(const char *name)
+{
+       struct crypto_shash *tfm;
+
+       tfm = crypto_alloc_shash(name, 0, 0);
+       if (IS_ERR(tfm))
+               return -1;
+
+       crypto_free_shash(tfm);
        return 0;
 }
 
 static int chap_check_algorithm(const char *a_str)
 {
-       char *tmp, *orig, *token;
+       char *tmp, *orig, *token, *digest_name;
+       long digest_type;
+       int r = CHAP_DIGEST_UNKNOWN;
 
        tmp = kstrdup(a_str, GFP_KERNEL);
        if (!tmp) {
@@ -70,15 +108,24 @@ static int chap_check_algorithm(const char *a_str)
                if (!token)
                        goto out;
 
-               if (!strncmp(token, "5", 1)) {
-                       pr_debug("Selected MD5 Algorithm\n");
-                       kfree(orig);
-                       return CHAP_DIGEST_MD5;
+               if (kstrtol(token, 10, &digest_type))
+                       continue;
+
+               digest_name = chap_get_digest_name(digest_type);
+               if (!digest_name)
+                       continue;
+
+               pr_debug("Selected %s Algorithm\n", digest_name);
+               if (chap_test_algorithm(digest_name) < 0) {
+                       pr_err("failed to allocate %s algo\n", digest_name);
+               } else {
+                       r = digest_type;
+                       goto out;
                }
        }
 out:
        kfree(orig);
-       return CHAP_DIGEST_UNKNOWN;
+       return r;
 }
 
 static void chap_close(struct iscsi_conn *conn)
@@ -94,7 +141,7 @@ static struct iscsi_chap *chap_server_open(
        char *aic_str,
        unsigned int *aic_len)
 {
-       int ret;
+       int digest_type;
        struct iscsi_chap *chap;
 
        if (!(auth->naf_flags & NAF_USERID_SET) ||
@@ -109,17 +156,19 @@ static struct iscsi_chap *chap_server_open(
                return NULL;
 
        chap = conn->auth_protocol;
-       ret = chap_check_algorithm(a_str);
-       switch (ret) {
+       digest_type = chap_check_algorithm(a_str);
+       switch (digest_type) {
        case CHAP_DIGEST_MD5:
-               pr_debug("[server] Got CHAP_A=5\n");
-               /*
-                * Send back CHAP_A set to MD5.
-               */
-               *aic_len = sprintf(aic_str, "CHAP_A=5");
-               *aic_len += 1;
-               chap->digest_type = CHAP_DIGEST_MD5;
-               pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
+               chap->digest_size = MD5_SIGNATURE_SIZE;
+               break;
+       case CHAP_DIGEST_SHA1:
+               chap->digest_size = SHA1_SIGNATURE_SIZE;
+               break;
+       case CHAP_DIGEST_SHA256:
+               chap->digest_size = SHA256_SIGNATURE_SIZE;
+               break;
+       case CHAP_DIGEST_SHA3_256:
+               chap->digest_size = SHA3_256_SIGNATURE_SIZE;
                break;
        case CHAP_DIGEST_UNKNOWN:
        default:
@@ -128,6 +177,16 @@ static struct iscsi_chap *chap_server_open(
                return NULL;
        }
 
+       chap->digest_name = chap_get_digest_name(digest_type);
+
+       /* Tie the challenge length to the digest size */
+       chap->challenge_len = chap->digest_size;
+
+       pr_debug("[server] Got CHAP_A=%d\n", digest_type);
+       *aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type);
+       *aic_len += 1;
+       pr_debug("[server] Sending CHAP_A=%d\n", digest_type);
+
        /*
         * Set Identifier.
         */
@@ -146,7 +205,7 @@ static struct iscsi_chap *chap_server_open(
        return chap;
 }
 
-static int chap_server_compute_md5(
+static int chap_server_compute_hash(
        struct iscsi_conn *conn,
        struct iscsi_node_auth *auth,
        char *nr_in_ptr,
@@ -155,36 +214,57 @@ static int chap_server_compute_md5(
 {
        unsigned long id;
        unsigned char id_as_uchar;
-       unsigned char digest[MD5_SIGNATURE_SIZE];
-       unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2];
-       unsigned char identifier[10], *challenge = NULL;
-       unsigned char *challenge_binhex = NULL;
-       unsigned char client_digest[MD5_SIGNATURE_SIZE];
-       unsigned char server_digest[MD5_SIGNATURE_SIZE];
+       unsigned char type;
+       unsigned char identifier[10], *initiatorchg = NULL;
+       unsigned char *initiatorchg_binhex = NULL;
+       unsigned char *digest = NULL;
+       unsigned char *response = NULL;
+       unsigned char *client_digest = NULL;
+       unsigned char *server_digest = NULL;
        unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
        size_t compare_len;
        struct iscsi_chap *chap = conn->auth_protocol;
        struct crypto_shash *tfm = NULL;
        struct shash_desc *desc = NULL;
-       int auth_ret = -1, ret, challenge_len;
+       int auth_ret = -1, ret, initiatorchg_len;
+
+       digest = kzalloc(chap->digest_size, GFP_KERNEL);
+       if (!digest) {
+               pr_err("Unable to allocate the digest buffer\n");
+               goto out;
+       }
+
+       response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL);
+       if (!response) {
+               pr_err("Unable to allocate the response buffer\n");
+               goto out;
+       }
+
+       client_digest = kzalloc(chap->digest_size, GFP_KERNEL);
+       if (!client_digest) {
+               pr_err("Unable to allocate the client_digest buffer\n");
+               goto out;
+       }
+
+       server_digest = kzalloc(chap->digest_size, GFP_KERNEL);
+       if (!server_digest) {
+               pr_err("Unable to allocate the server_digest buffer\n");
+               goto out;
+       }
 
        memset(identifier, 0, 10);
        memset(chap_n, 0, MAX_CHAP_N_SIZE);
        memset(chap_r, 0, MAX_RESPONSE_LENGTH);
-       memset(digest, 0, MD5_SIGNATURE_SIZE);
-       memset(response, 0, MD5_SIGNATURE_SIZE * 2 + 2);
-       memset(client_digest, 0, MD5_SIGNATURE_SIZE);
-       memset(server_digest, 0, MD5_SIGNATURE_SIZE);
 
-       challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
-       if (!challenge) {
+       initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
+       if (!initiatorchg) {
                pr_err("Unable to allocate challenge buffer\n");
                goto out;
        }
 
-       challenge_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
-       if (!challenge_binhex) {
-               pr_err("Unable to allocate challenge_binhex buffer\n");
+       initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
+       if (!initiatorchg_binhex) {
+               pr_err("Unable to allocate initiatorchg_binhex buffer\n");
                goto out;
        }
        /*
@@ -219,18 +299,18 @@ static int chap_server_compute_md5(
                pr_err("Could not find CHAP_R.\n");
                goto out;
        }
-       if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) {
+       if (strlen(chap_r) != chap->digest_size * 2) {
                pr_err("Malformed CHAP_R\n");
                goto out;
        }
-       if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) {
+       if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) {
                pr_err("Malformed CHAP_R\n");
                goto out;
        }
 
        pr_debug("[server] Got CHAP_R=%s\n", chap_r);
 
-       tfm = crypto_alloc_shash("md5", 0, 0);
+       tfm = crypto_alloc_shash(chap->digest_name, 0, 0);
        if (IS_ERR(tfm)) {
                tfm = NULL;
                pr_err("Unable to allocate struct crypto_shash\n");
@@ -265,21 +345,23 @@ static int chap_server_compute_md5(
        }
 
        ret = crypto_shash_finup(desc, chap->challenge,
-                                CHAP_CHALLENGE_LENGTH, server_digest);
+                                chap->challenge_len, server_digest);
        if (ret < 0) {
                pr_err("crypto_shash_finup() failed for challenge\n");
                goto out;
        }
 
-       bin2hex(response, server_digest, MD5_SIGNATURE_SIZE);
-       pr_debug("[server] MD5 Server Digest: %s\n", response);
+       bin2hex(response, server_digest, chap->digest_size);
+       pr_debug("[server] %s Server Digest: %s\n",
+               chap->digest_name, response);
 
-       if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) {
-               pr_debug("[server] MD5 Digests do not match!\n\n");
+       if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
+               pr_debug("[server] %s Digests do not match!\n\n",
+                       chap->digest_name);
                goto out;
        } else
-               pr_debug("[server] MD5 Digests match, CHAP connection"
-                               " successful.\n\n");
+               pr_debug("[server] %s Digests match, CHAP connection"
+                               " successful.\n\n", chap->digest_name);
        /*
         * One way authentication has succeeded, return now if mutual
         * authentication is not enabled.
@@ -317,7 +399,7 @@ static int chap_server_compute_md5(
         * Get CHAP_C.
         */
        if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
-                       challenge, &type) < 0) {
+                       initiatorchg, &type) < 0) {
                pr_err("Could not find CHAP_C.\n");
                goto out;
        }
@@ -326,26 +408,28 @@ static int chap_server_compute_md5(
                pr_err("Could not find CHAP_C.\n");
                goto out;
        }
-       challenge_len = DIV_ROUND_UP(strlen(challenge), 2);
-       if (!challenge_len) {
+       initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2);
+       if (!initiatorchg_len) {
                pr_err("Unable to convert incoming challenge\n");
                goto out;
        }
-       if (challenge_len > 1024) {
+       if (initiatorchg_len > 1024) {
                pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
                goto out;
        }
-       if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) {
+       if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) {
                pr_err("Malformed CHAP_C\n");
                goto out;
        }
-       pr_debug("[server] Got CHAP_C=%s\n", challenge);
+       pr_debug("[server] Got CHAP_C=%s\n", initiatorchg);
        /*
         * During mutual authentication, the CHAP_C generated by the
         * initiator must not match the original CHAP_C generated by
         * the target.
         */
-       if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) {
+       if (initiatorchg_len == chap->challenge_len &&
+                               !memcmp(initiatorchg_binhex, chap->challenge,
+                               initiatorchg_len)) {
                pr_err("initiator CHAP_C matches target CHAP_C, failing"
                       " login attempt\n");
                goto out;
@@ -377,7 +461,7 @@ static int chap_server_compute_md5(
        /*
         * Convert received challenge to binary hex.
         */
-       ret = crypto_shash_finup(desc, challenge_binhex, challenge_len,
+       ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len,
                                 digest);
        if (ret < 0) {
                pr_err("crypto_shash_finup() failed for ma challenge\n");
@@ -393,7 +477,7 @@ static int chap_server_compute_md5(
        /*
         * Convert response from binary hex to ascii hext.
         */
-       bin2hex(response, digest, MD5_SIGNATURE_SIZE);
+       bin2hex(response, digest, chap->digest_size);
        *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
                        response);
        *nr_out_len += 1;
@@ -403,33 +487,15 @@ out:
        kzfree(desc);
        if (tfm)
                crypto_free_shash(tfm);
-       kfree(challenge);
-       kfree(challenge_binhex);
+       kfree(initiatorchg);
+       kfree(initiatorchg_binhex);
+       kfree(digest);
+       kfree(response);
+       kfree(server_digest);
+       kfree(client_digest);
        return auth_ret;
 }
 
-static int chap_got_response(
-       struct iscsi_conn *conn,
-       struct iscsi_node_auth *auth,
-       char *nr_in_ptr,
-       char *nr_out_ptr,
-       unsigned int *nr_out_len)
-{
-       struct iscsi_chap *chap = conn->auth_protocol;
-
-       switch (chap->digest_type) {
-       case CHAP_DIGEST_MD5:
-               if (chap_server_compute_md5(conn, auth, nr_in_ptr,
-                               nr_out_ptr, nr_out_len) < 0)
-                       return -1;
-               return 0;
-       default:
-               pr_err("Unknown CHAP digest type %d!\n",
-                               chap->digest_type);
-               return -1;
-       }
-}
-
 u32 chap_main_loop(
        struct iscsi_conn *conn,
        struct iscsi_node_auth *auth,
@@ -448,7 +514,7 @@ u32 chap_main_loop(
                return 0;
        } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
                convert_null_to_semi(in_text, *in_len);
-               if (chap_got_response(conn, auth, in_text, out_text,
+               if (chap_server_compute_hash(conn, auth, in_text, out_text,
                                out_len) < 0) {
                        chap_close(conn);
                        return 2;
index d5600ac..fc75c1c 100644 (file)
@@ -6,14 +6,19 @@
 
 #define CHAP_DIGEST_UNKNOWN    0
 #define CHAP_DIGEST_MD5                5
-#define CHAP_DIGEST_SHA                6
+#define CHAP_DIGEST_SHA1       6
+#define CHAP_DIGEST_SHA256     7
+#define CHAP_DIGEST_SHA3_256   8
 
-#define CHAP_CHALLENGE_LENGTH  16
+#define MAX_CHAP_CHALLENGE_LEN 32
 #define CHAP_CHALLENGE_STR_LEN 4096
-#define MAX_RESPONSE_LENGTH    64      /* sufficient for MD5 */
+#define MAX_RESPONSE_LENGTH    128     /* sufficient for SHA3 256 */
 #define        MAX_CHAP_N_SIZE         512
 
 #define MD5_SIGNATURE_SIZE     16      /* 16 bytes in a MD5 message digest */
+#define SHA1_SIGNATURE_SIZE    20      /* 20 bytes in a SHA1 message digest */
+#define SHA256_SIGNATURE_SIZE  32      /* 32 bytes in a SHA256 message digest */
+#define SHA3_256_SIGNATURE_SIZE        32      /* 32 bytes in a SHA3 256 message digest */
 
 #define CHAP_STAGE_CLIENT_A    1
 #define CHAP_STAGE_SERVER_AIC  2
@@ -28,9 +33,11 @@ extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *,
                                int *, int *);
 
 struct iscsi_chap {
-       unsigned char   digest_type;
        unsigned char   id;
-       unsigned char   challenge[CHAP_CHALLENGE_LENGTH];
+       unsigned char   challenge[MAX_CHAP_CHALLENGE_LEN];
+       unsigned int    challenge_len;
+       unsigned char   *digest_name;
+       unsigned int    digest_size;
        unsigned int    authenticate_target;
        unsigned int    chap_state;
 } ____cacheline_aligned;
index daf47f3..240c4c4 100644 (file)
@@ -93,9 +93,6 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
 #define OFMARKER                       "OFMarker"
 #define IFMARKINT                      "IFMarkInt"
 #define OFMARKINT                      "OFMarkInt"
-#define X_EXTENSIONKEY                 "X-com.sbei.version"
-#define X_EXTENSIONKEY_CISCO_NEW       "X-com.cisco.protocol"
-#define X_EXTENSIONKEY_CISCO_OLD       "X-com.cisco.iscsi.draft"
 
 /*
  * Parameter names of iSCSI Extentions for RDMA (iSER).  See RFC-5046
index 3c79411..6b4b354 100644 (file)
@@ -118,7 +118,7 @@ static int srp_get_pr_transport_id(
        memset(buf + 8, 0, leading_zero_bytes);
        rc = hex2bin(buf + 8 + leading_zero_bytes, p, count);
        if (rc < 0) {
-               pr_debug("hex2bin failed for %s: %d\n", __func__, rc);
+               pr_debug("hex2bin failed for %s: %d\n", p, rc);
                return rc;
        }
 
index e5a71ad..d24e0a3 100644 (file)
@@ -32,9 +32,6 @@
 
 extern struct se_device *g_lun0_dev;
 
-static DEFINE_SPINLOCK(tpg_lock);
-static LIST_HEAD(tpg_list);
-
 /*     __core_tpg_get_initiator_node_acl():
  *
  *     mutex_lock(&tpg->acl_node_mutex); must be held when calling
@@ -475,7 +472,6 @@ int core_tpg_register(
        se_tpg->se_tpg_wwn = se_wwn;
        atomic_set(&se_tpg->tpg_pr_ref_count, 0);
        INIT_LIST_HEAD(&se_tpg->acl_node_list);
-       INIT_LIST_HEAD(&se_tpg->se_tpg_node);
        INIT_LIST_HEAD(&se_tpg->tpg_sess_list);
        spin_lock_init(&se_tpg->session_lock);
        mutex_init(&se_tpg->tpg_lun_mutex);
@@ -494,10 +490,6 @@ int core_tpg_register(
                }
        }
 
-       spin_lock_bh(&tpg_lock);
-       list_add_tail(&se_tpg->se_tpg_node, &tpg_list);
-       spin_unlock_bh(&tpg_lock);
-
        pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "
                 "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->fabric_name,
                se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ?
@@ -519,10 +511,6 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
                tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL,
                se_tpg->proto_id, tfo->tpg_get_tag(se_tpg));
 
-       spin_lock_bh(&tpg_lock);
-       list_del(&se_tpg->se_tpg_node);
-       spin_unlock_bh(&tpg_lock);
-
        while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0)
                cpu_relax();
 
index 7f06a62..ea482d4 100644 (file)
@@ -584,6 +584,15 @@ void transport_free_session(struct se_session *se_sess)
 }
 EXPORT_SYMBOL(transport_free_session);
 
+static int target_release_res(struct se_device *dev, void *data)
+{
+       struct se_session *sess = data;
+
+       if (dev->reservation_holder == sess)
+               target_release_reservation(dev);
+       return 0;
+}
+
 void transport_deregister_session(struct se_session *se_sess)
 {
        struct se_portal_group *se_tpg = se_sess->se_tpg;
@@ -600,6 +609,12 @@ void transport_deregister_session(struct se_session *se_sess)
        se_sess->fabric_sess_ptr = NULL;
        spin_unlock_irqrestore(&se_tpg->session_lock, flags);
 
+       /*
+        * Since the session is being removed, release SPC-2
+        * reservations held by the session that is disappearing.
+        */
+       target_for_each_device(target_release_res, se_sess);
+
        pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
                se_tpg->se_tpg_tfo->fabric_name);
        /*
@@ -1243,6 +1258,19 @@ target_check_max_data_sg_nents(struct se_cmd *cmd, struct se_device *dev,
        return TCM_NO_SENSE;
 }
 
+/**
+ * target_cmd_size_check - Check whether there will be a residual.
+ * @cmd: SCSI command.
+ * @size: Data buffer size derived from CDB. The data buffer size provided by
+ *   the SCSI transport driver is available in @cmd->data_length.
+ *
+ * Compare the data buffer size from the CDB with the data buffer limit from the transport
+ * header. Set @cmd->residual_count and SCF_OVERFLOW_BIT or SCF_UNDERFLOW_BIT if necessary.
+ *
+ * Note: target drivers set @cmd->data_length by calling transport_init_se_cmd().
+ *
+ * Return: TCM_NO_SENSE
+ */
 sense_reason_t
 target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
 {
index 35be1be..0b9dfa6 100644 (file)
@@ -499,7 +499,7 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev,
                        schedule_delayed_work(&tcmu_unmap_work, 0);
 
                /* try to get new page from the mm */
-               page = alloc_page(GFP_KERNEL);
+               page = alloc_page(GFP_NOIO);
                if (!page)
                        goto err_alloc;
 
@@ -573,7 +573,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
        struct tcmu_dev *udev = TCMU_DEV(se_dev);
        struct tcmu_cmd *tcmu_cmd;
 
-       tcmu_cmd = kmem_cache_zalloc(tcmu_cmd_cache, GFP_KERNEL);
+       tcmu_cmd = kmem_cache_zalloc(tcmu_cmd_cache, GFP_NOIO);
        if (!tcmu_cmd)
                return NULL;
 
@@ -584,7 +584,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
        tcmu_cmd_reset_dbi_cur(tcmu_cmd);
        tcmu_cmd->dbi_cnt = tcmu_cmd_get_block_cnt(tcmu_cmd);
        tcmu_cmd->dbi = kcalloc(tcmu_cmd->dbi_cnt, sizeof(uint32_t),
-                               GFP_KERNEL);
+                               GFP_NOIO);
        if (!tcmu_cmd->dbi) {
                kmem_cache_free(tcmu_cmd_cache, tcmu_cmd);
                return NULL;
index b9b1e92..425c107 100644 (file)
@@ -467,7 +467,6 @@ int target_xcopy_setup_pt(void)
        }
 
        memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group));
-       INIT_LIST_HEAD(&xcopy_pt_tpg.se_tpg_node);
        INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list);
        INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list);
 
index 001a21a..59b79fc 100644 (file)
@@ -144,6 +144,7 @@ config THERMAL_GOV_USER_SPACE
 
 config THERMAL_GOV_POWER_ALLOCATOR
        bool "Power allocator thermal governor"
+       depends on ENERGY_MODEL
        help
          Enable this to manage platform thermals by dynamically
          allocating and limiting power to devices.
@@ -348,6 +349,17 @@ config MTK_THERMAL
          Enable this option if you want to have support for thermal management
          controller present in Mediatek SoCs
 
+config AMLOGIC_THERMAL
+       tristate "Amlogic Thermal Support"
+       default ARCH_MESON
+       depends on OF && ARCH_MESON
+       help
+         If you say yes here you get support for Amlogic Thermal
+         for G12 SoC Family.
+
+         This driver can also be built as a module. If so, the module will
+         be called amlogic_thermal.
+
 menu "Intel thermal drivers"
 depends on X86 || X86_INTEL_QUARK || COMPILE_TEST
 source "drivers/thermal/intel/Kconfig"
index 74a37c7..baeb70b 100644 (file)
@@ -54,3 +54,4 @@ obj-$(CONFIG_MTK_THERMAL)     += mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)      += thermal-generic-adc.o
 obj-$(CONFIG_ZX2967_THERMAL)   += zx2967_thermal.o
 obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
+obj-$(CONFIG_AMLOGIC_THERMAL)     += amlogic_thermal.o
diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c
new file mode 100644 (file)
index 0000000..8a9e9bc
--- /dev/null
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic Thermal Sensor Driver
+ *
+ * Copyright (C) 2017 Huan Biao <huan.biao@amlogic.com>
+ * Copyright (C) 2019 Guillaume La Roque <glaroque@baylibre.com>
+ *
+ * Register value to celsius temperature formulas:
+ *     Read_Val            m * U
+ * U = ---------, Uptat = ---------
+ *     2^16              1 + n * U
+ *
+ * Temperature = A * ( Uptat + u_efuse / 2^16 )- B
+ *
+ *  A B m n : calibration parameters
+ *  u_efuse : fused calibration value, it's a signed 16 bits value
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+#define TSENSOR_CFG_REG1                       0x4
+       #define TSENSOR_CFG_REG1_RSET_VBG       BIT(12)
+       #define TSENSOR_CFG_REG1_RSET_ADC       BIT(11)
+       #define TSENSOR_CFG_REG1_VCM_EN         BIT(10)
+       #define TSENSOR_CFG_REG1_VBG_EN         BIT(9)
+       #define TSENSOR_CFG_REG1_OUT_CTL        BIT(6)
+       #define TSENSOR_CFG_REG1_FILTER_EN      BIT(5)
+       #define TSENSOR_CFG_REG1_DEM_EN         BIT(3)
+       #define TSENSOR_CFG_REG1_CH_SEL         GENMASK(1, 0)
+       #define TSENSOR_CFG_REG1_ENABLE         \
+               (TSENSOR_CFG_REG1_FILTER_EN |   \
+                TSENSOR_CFG_REG1_VCM_EN |      \
+                TSENSOR_CFG_REG1_VBG_EN |      \
+                TSENSOR_CFG_REG1_DEM_EN |      \
+                TSENSOR_CFG_REG1_CH_SEL)
+
+#define TSENSOR_STAT0                  0x40
+
+#define TSENSOR_STAT9                  0x64
+
+#define TSENSOR_READ_TEMP_MASK         GENMASK(15, 0)
+#define TSENSOR_TEMP_MASK              GENMASK(11, 0)
+
+#define TSENSOR_TRIM_SIGN_MASK         BIT(15)
+#define TSENSOR_TRIM_TEMP_MASK         GENMASK(14, 0)
+#define TSENSOR_TRIM_VERSION_MASK      GENMASK(31, 24)
+
+#define TSENSOR_TRIM_VERSION(_version) \
+       FIELD_GET(TSENSOR_TRIM_VERSION_MASK, _version)
+
+#define TSENSOR_TRIM_CALIB_VALID_MASK  (GENMASK(3, 2) | BIT(7))
+
+#define TSENSOR_CALIB_OFFSET   1
+#define TSENSOR_CALIB_SHIFT    4
+
+/**
+ * struct amlogic_thermal_soc_calib_data
+ * @A, B, m, n: calibration parameters
+ * This structure is required for configuration of amlogic thermal driver.
+ */
+struct amlogic_thermal_soc_calib_data {
+       int A;
+       int B;
+       int m;
+       int n;
+};
+
+/**
+ * struct amlogic_thermal_data
+ * @u_efuse_off: register offset to read fused calibration value
+ * @calibration_parameters: calibration parameters structure pointer
+ * @regmap_config: regmap config for the device
+ * This structure is required for configuration of amlogic thermal driver.
+ */
+struct amlogic_thermal_data {
+       int u_efuse_off;
+       const struct amlogic_thermal_soc_calib_data *calibration_parameters;
+       const struct regmap_config *regmap_config;
+};
+
+struct amlogic_thermal {
+       struct platform_device *pdev;
+       const struct amlogic_thermal_data *data;
+       struct regmap *regmap;
+       struct regmap *sec_ao_map;
+       struct clk *clk;
+       struct thermal_zone_device *tzd;
+       u32 trim_info;
+};
+
+/*
+ * Calculate a temperature value from a temperature code.
+ * The unit of the temperature is degree milliCelsius.
+ */
+static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata,
+                                               int temp_code)
+{
+       const struct amlogic_thermal_soc_calib_data *param =
+                                       pdata->data->calibration_parameters;
+       int temp;
+       s64 factor, Uptat, uefuse;
+
+       uefuse = pdata->trim_info & TSENSOR_TRIM_SIGN_MASK ?
+                            ~(pdata->trim_info & TSENSOR_TRIM_TEMP_MASK) + 1 :
+                            (pdata->trim_info & TSENSOR_TRIM_TEMP_MASK);
+
+       factor = param->n * temp_code;
+       factor = div_s64(factor, 100);
+
+       Uptat = temp_code * param->m;
+       Uptat = div_s64(Uptat, 100);
+       Uptat = Uptat * BIT(16);
+       Uptat = div_s64(Uptat, BIT(16) + factor);
+
+       temp = (Uptat + uefuse) * param->A;
+       temp = div_s64(temp, BIT(16));
+       temp = (temp - param->B) * 100;
+
+       return temp;
+}
+
+static int amlogic_thermal_initialize(struct amlogic_thermal *pdata)
+{
+       int ret = 0;
+       int ver;
+
+       regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off,
+                   &pdata->trim_info);
+
+       ver = TSENSOR_TRIM_VERSION(pdata->trim_info);
+
+       if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) {
+               ret = -EINVAL;
+               dev_err(&pdata->pdev->dev,
+                       "tsensor thermal calibration not supported: 0x%x!\n",
+                       ver);
+       }
+
+       return ret;
+}
+
+static int amlogic_thermal_enable(struct amlogic_thermal *data)
+{
+       int ret;
+
+       ret = clk_prepare_enable(data->clk);
+       if (ret)
+               return ret;
+
+       regmap_update_bits(data->regmap, TSENSOR_CFG_REG1,
+                          TSENSOR_CFG_REG1_ENABLE, TSENSOR_CFG_REG1_ENABLE);
+
+       return 0;
+}
+
+static int amlogic_thermal_disable(struct amlogic_thermal *data)
+{
+       regmap_update_bits(data->regmap, TSENSOR_CFG_REG1,
+                          TSENSOR_CFG_REG1_ENABLE, 0);
+       clk_disable_unprepare(data->clk);
+
+       return 0;
+}
+
+static int amlogic_thermal_get_temp(void *data, int *temp)
+{
+       unsigned int tval;
+       struct amlogic_thermal *pdata = data;
+
+       if (!data)
+               return -EINVAL;
+
+       regmap_read(pdata->regmap, TSENSOR_STAT0, &tval);
+       *temp =
+          amlogic_thermal_code_to_millicelsius(pdata,
+                                               tval & TSENSOR_READ_TEMP_MASK);
+
+       return 0;
+}
+
+static const struct thermal_zone_of_device_ops amlogic_thermal_ops = {
+       .get_temp       = amlogic_thermal_get_temp,
+};
+
+static const struct regmap_config amlogic_thermal_regmap_config_g12a = {
+       .reg_bits = 8,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = TSENSOR_STAT9,
+};
+
+static const struct amlogic_thermal_soc_calib_data amlogic_thermal_g12a = {
+       .A = 9411,
+       .B = 3159,
+       .m = 424,
+       .n = 324,
+};
+
+static const struct amlogic_thermal_data amlogic_thermal_g12a_cpu_param = {
+       .u_efuse_off = 0x128,
+       .calibration_parameters = &amlogic_thermal_g12a,
+       .regmap_config = &amlogic_thermal_regmap_config_g12a,
+};
+
+static const struct amlogic_thermal_data amlogic_thermal_g12a_ddr_param = {
+       .u_efuse_off = 0xf0,
+       .calibration_parameters = &amlogic_thermal_g12a,
+       .regmap_config = &amlogic_thermal_regmap_config_g12a,
+};
+
+static const struct of_device_id of_amlogic_thermal_match[] = {
+       {
+               .compatible = "amlogic,g12a-ddr-thermal",
+               .data = &amlogic_thermal_g12a_ddr_param,
+       },
+       {
+               .compatible = "amlogic,g12a-cpu-thermal",
+               .data = &amlogic_thermal_g12a_cpu_param,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match);
+
+static int amlogic_thermal_probe(struct platform_device *pdev)
+{
+       struct amlogic_thermal *pdata;
+       struct device *dev = &pdev->dev;
+       void __iomem *base;
+       int ret;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       pdata->data = of_device_get_match_data(dev);
+       pdata->pdev = pdev;
+       platform_set_drvdata(pdev, pdata);
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base)) {
+               dev_err(dev, "failed to get io address\n");
+               return PTR_ERR(base);
+       }
+
+       pdata->regmap = devm_regmap_init_mmio(dev, base,
+                                             pdata->data->regmap_config);
+       if (IS_ERR(pdata->regmap))
+               return PTR_ERR(pdata->regmap);
+
+       pdata->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(pdata->clk)) {
+               if (PTR_ERR(pdata->clk) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get clock\n");
+               return PTR_ERR(pdata->clk);
+       }
+
+       pdata->sec_ao_map = syscon_regmap_lookup_by_phandle
+               (pdev->dev.of_node, "amlogic,ao-secure");
+       if (IS_ERR(pdata->sec_ao_map)) {
+               dev_err(dev, "syscon regmap lookup failed.\n");
+               return PTR_ERR(pdata->sec_ao_map);
+       }
+
+       pdata->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
+                                                         0,
+                                                         pdata,
+                                                         &amlogic_thermal_ops);
+       if (IS_ERR(pdata->tzd)) {
+               ret = PTR_ERR(pdata->tzd);
+               dev_err(dev, "Failed to register tsensor: %d\n", ret);
+               return ret;
+       }
+
+       ret = amlogic_thermal_initialize(pdata);
+       if (ret)
+               return ret;
+
+       ret = amlogic_thermal_enable(pdata);
+
+       return ret;
+}
+
+static int amlogic_thermal_remove(struct platform_device *pdev)
+{
+       struct amlogic_thermal *data = platform_get_drvdata(pdev);
+
+       return amlogic_thermal_disable(data);
+}
+
+static int __maybe_unused amlogic_thermal_suspend(struct device *dev)
+{
+       struct amlogic_thermal *data = dev_get_drvdata(dev);
+
+       return amlogic_thermal_disable(data);
+}
+
+static int __maybe_unused amlogic_thermal_resume(struct device *dev)
+{
+       struct amlogic_thermal *data = dev_get_drvdata(dev);
+
+       return amlogic_thermal_enable(data);
+}
+
+static SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops,
+                        amlogic_thermal_suspend, amlogic_thermal_resume);
+
+static struct platform_driver amlogic_thermal_driver = {
+       .driver = {
+               .name           = "amlogic_thermal",
+               .pm             = &amlogic_thermal_pm_ops,
+               .of_match_table = of_amlogic_thermal_match,
+       },
+       .probe  = amlogic_thermal_probe,
+       .remove = amlogic_thermal_remove,
+};
+
+module_platform_driver(amlogic_thermal_driver);
+
+MODULE_AUTHOR("Guillaume La Roque <glaroque@baylibre.com>");
+MODULE_DESCRIPTION("Amlogic thermal driver");
+MODULE_LICENSE("GPL v2");
index 6b9865c..52569b2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/cpu_cooling.h>
+#include <linux/energy_model.h>
 
 #include <trace/events/thermal.h>
 
  *     ...
  */
 
-/**
- * struct freq_table - frequency table along with power entries
- * @frequency: frequency in KHz
- * @power:     power in mW
- *
- * This structure is built when the cooling device registers and helps
- * in translating frequency to power and vice versa.
- */
-struct freq_table {
-       u32 frequency;
-       u32 power;
-};
-
 /**
  * struct time_in_idle - Idle time stats
  * @time: previous reading of the absolute time that this cpu was idle
@@ -69,7 +57,7 @@ struct time_in_idle {
  *     cooling devices.
  * @max_level: maximum cooling level. One less than total number of valid
  *     cpufreq frequencies.
- * @freq_table: Freq table in descending order of frequencies
+ * @em: Reference on the Energy Model of the device
  * @cdev: thermal_cooling_device pointer to keep track of the
  *     registered cooling device.
  * @policy: cpufreq policy.
@@ -84,7 +72,7 @@ struct cpufreq_cooling_device {
        u32 last_load;
        unsigned int cpufreq_state;
        unsigned int max_level;
-       struct freq_table *freq_table;  /* In descending order */
+       struct em_perf_domain *em;
        struct cpufreq_policy *policy;
        struct list_head node;
        struct time_in_idle *idle_time;
@@ -95,8 +83,7 @@ static DEFINE_IDA(cpufreq_ida);
 static DEFINE_MUTEX(cooling_list_lock);
 static LIST_HEAD(cpufreq_cdev_list);
 
-/* Below code defines functions to be used for cpufreq as cooling device */
-
+#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
 /**
  * get_level: Find the level for a particular frequency
  * @cpufreq_cdev: cpufreq_cdev for which the property is required
@@ -107,114 +94,40 @@ static LIST_HEAD(cpufreq_cdev_list);
 static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
                               unsigned int freq)
 {
-       struct freq_table *freq_table = cpufreq_cdev->freq_table;
-       unsigned long level;
+       int i;
 
-       for (level = 1; level <= cpufreq_cdev->max_level; level++)
-               if (freq > freq_table[level].frequency)
+       for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
+               if (freq > cpufreq_cdev->em->table[i].frequency)
                        break;
-
-       return level - 1;
-}
-
-/**
- * update_freq_table() - Update the freq table with power numbers
- * @cpufreq_cdev:      the cpufreq cooling device in which to update the table
- * @capacitance: dynamic power coefficient for these cpus
- *
- * Update the freq table with power numbers.  This table will be used in
- * cpu_power_to_freq() and cpu_freq_to_power() to convert between power and
- * frequency efficiently.  Power is stored in mW, frequency in KHz.  The
- * resulting table is in descending order.
- *
- * Return: 0 on success, -EINVAL if there are no OPPs for any CPUs,
- * or -ENOMEM if we run out of memory.
- */
-static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev,
-                            u32 capacitance)
-{
-       struct freq_table *freq_table = cpufreq_cdev->freq_table;
-       struct dev_pm_opp *opp;
-       struct device *dev = NULL;
-       int num_opps = 0, cpu = cpufreq_cdev->policy->cpu, i;
-
-       dev = get_cpu_device(cpu);
-       if (unlikely(!dev)) {
-               pr_warn("No cpu device for cpu %d\n", cpu);
-               return -ENODEV;
        }
 
-       num_opps = dev_pm_opp_get_opp_count(dev);
-       if (num_opps < 0)
-               return num_opps;
-
-       /*
-        * The cpufreq table is also built from the OPP table and so the count
-        * should match.
-        */
-       if (num_opps != cpufreq_cdev->max_level + 1) {
-               dev_warn(dev, "Number of OPPs not matching with max_levels\n");
-               return -EINVAL;
-       }
-
-       for (i = 0; i <= cpufreq_cdev->max_level; i++) {
-               unsigned long freq = freq_table[i].frequency * 1000;
-               u32 freq_mhz = freq_table[i].frequency / 1000;
-               u64 power;
-               u32 voltage_mv;
-
-               /*
-                * Find ceil frequency as 'freq' may be slightly lower than OPP
-                * freq due to truncation while converting to kHz.
-                */
-               opp = dev_pm_opp_find_freq_ceil(dev, &freq);
-               if (IS_ERR(opp)) {
-                       dev_err(dev, "failed to get opp for %lu frequency\n",
-                               freq);
-                       return -EINVAL;
-               }
-
-               voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
-               dev_pm_opp_put(opp);
-
-               /*
-                * Do the multiplication with MHz and millivolt so as
-                * to not overflow.
-                */
-               power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv;
-               do_div(power, 1000000000);
-
-               /* power is stored in mW */
-               freq_table[i].power = power;
-       }
-
-       return 0;
+       return cpufreq_cdev->max_level - i - 1;
 }
 
 static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 freq)
 {
        int i;
-       struct freq_table *freq_table = cpufreq_cdev->freq_table;
 
-       for (i = 1; i <= cpufreq_cdev->max_level; i++)
-               if (freq > freq_table[i].frequency)
+       for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
+               if (freq > cpufreq_cdev->em->table[i].frequency)
                        break;
+       }
 
-       return freq_table[i - 1].power;
+       return cpufreq_cdev->em->table[i + 1].power;
 }
 
 static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 power)
 {
        int i;
-       struct freq_table *freq_table = cpufreq_cdev->freq_table;
 
-       for (i = 1; i <= cpufreq_cdev->max_level; i++)
-               if (power > freq_table[i].power)
+       for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
+               if (power > cpufreq_cdev->em->table[i].power)
                        break;
+       }
 
-       return freq_table[i - 1].frequency;
+       return cpufreq_cdev->em->table[i + 1].frequency;
 }
 
 /**
@@ -265,76 +178,6 @@ static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_cdev,
        return (raw_cpu_power * cpufreq_cdev->last_load) / 100;
 }
 
-/* cpufreq cooling device callback functions are defined below */
-
-/**
- * cpufreq_get_max_state - callback function to get the max cooling state.
- * @cdev: thermal cooling device pointer.
- * @state: fill this variable with the max cooling state.
- *
- * Callback for the thermal cooling device to return the cpufreq
- * max cooling state.
- *
- * Return: 0 on success, an error code otherwise.
- */
-static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
-                                unsigned long *state)
-{
-       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
-
-       *state = cpufreq_cdev->max_level;
-       return 0;
-}
-
-/**
- * cpufreq_get_cur_state - callback function to get the current cooling state.
- * @cdev: thermal cooling device pointer.
- * @state: fill this variable with the current cooling state.
- *
- * Callback for the thermal cooling device to return the cpufreq
- * current cooling state.
- *
- * Return: 0 on success, an error code otherwise.
- */
-static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
-                                unsigned long *state)
-{
-       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
-
-       *state = cpufreq_cdev->cpufreq_state;
-
-       return 0;
-}
-
-/**
- * cpufreq_set_cur_state - callback function to set the current cooling state.
- * @cdev: thermal cooling device pointer.
- * @state: set this variable to the current cooling state.
- *
- * Callback for the thermal cooling device to change the cpufreq
- * current cooling state.
- *
- * Return: 0 on success, an error code otherwise.
- */
-static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
-                                unsigned long state)
-{
-       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
-
-       /* Request state should be less than max_level */
-       if (WARN_ON(state > cpufreq_cdev->max_level))
-               return -EINVAL;
-
-       /* Check if the old cooling action is same as new cooling action */
-       if (cpufreq_cdev->cpufreq_state == state)
-               return 0;
-
-       cpufreq_cdev->cpufreq_state = state;
-
-       return freq_qos_update_request(&cpufreq_cdev->qos_req,
-                               cpufreq_cdev->freq_table[state].frequency);
-}
-
 /**
  * cpufreq_get_requested_power() - get the current power
  * @cdev:      &thermal_cooling_device pointer
@@ -425,7 +268,7 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
                               struct thermal_zone_device *tz,
                               unsigned long state, u32 *power)
 {
-       unsigned int freq, num_cpus;
+       unsigned int freq, num_cpus, idx;
        struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 
        /* Request state should be less than max_level */
@@ -434,7 +277,8 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
 
        num_cpus = cpumask_weight(cpufreq_cdev->policy->cpus);
 
-       freq = cpufreq_cdev->freq_table[state].frequency;
+       idx = cpufreq_cdev->max_level - state;
+       freq = cpufreq_cdev->em->table[idx].frequency;
        *power = cpu_freq_to_power(cpufreq_cdev, freq) * num_cpus;
 
        return 0;
@@ -479,43 +323,142 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
        return 0;
 }
 
-/* Bind cpufreq callbacks to thermal cooling device ops */
+static inline bool em_is_sane(struct cpufreq_cooling_device *cpufreq_cdev,
+                             struct em_perf_domain *em) {
+       struct cpufreq_policy *policy;
+       unsigned int nr_levels;
 
-static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
-       .get_max_state = cpufreq_get_max_state,
-       .get_cur_state = cpufreq_get_cur_state,
-       .set_cur_state = cpufreq_set_cur_state,
-};
+       if (!em)
+               return false;
 
-static struct thermal_cooling_device_ops cpufreq_power_cooling_ops = {
-       .get_max_state          = cpufreq_get_max_state,
-       .get_cur_state          = cpufreq_get_cur_state,
-       .set_cur_state          = cpufreq_set_cur_state,
-       .get_requested_power    = cpufreq_get_requested_power,
-       .state2power            = cpufreq_state2power,
-       .power2state            = cpufreq_power2state,
-};
+       policy = cpufreq_cdev->policy;
+       if (!cpumask_equal(policy->related_cpus, to_cpumask(em->cpus))) {
+               pr_err("The span of pd %*pbl is misaligned with cpufreq policy %*pbl\n",
+                       cpumask_pr_args(to_cpumask(em->cpus)),
+                       cpumask_pr_args(policy->related_cpus));
+               return false;
+       }
 
-static unsigned int find_next_max(struct cpufreq_frequency_table *table,
-                                 unsigned int prev_max)
+       nr_levels = cpufreq_cdev->max_level + 1;
+       if (em->nr_cap_states != nr_levels) {
+               pr_err("The number of cap states in pd %*pbl (%u) doesn't match the number of cooling levels (%u)\n",
+                       cpumask_pr_args(to_cpumask(em->cpus)),
+                       em->nr_cap_states, nr_levels);
+               return false;
+       }
+
+       return true;
+}
+#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
+
+static unsigned int get_state_freq(struct cpufreq_cooling_device *cpufreq_cdev,
+                                  unsigned long state)
 {
-       struct cpufreq_frequency_table *pos;
-       unsigned int max = 0;
+       struct cpufreq_policy *policy;
+       unsigned long idx;
 
-       cpufreq_for_each_valid_entry(pos, table) {
-               if (pos->frequency > max && pos->frequency < prev_max)
-                       max = pos->frequency;
+#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
+       /* Use the Energy Model table if available */
+       if (cpufreq_cdev->em) {
+               idx = cpufreq_cdev->max_level - state;
+               return cpufreq_cdev->em->table[idx].frequency;
        }
+#endif
+
+       /* Otherwise, fallback on the CPUFreq table */
+       policy = cpufreq_cdev->policy;
+       if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
+               idx = cpufreq_cdev->max_level - state;
+       else
+               idx = state;
+
+       return policy->freq_table[idx].frequency;
+}
+
+/* cpufreq cooling device callback functions are defined below */
+
+/**
+ * cpufreq_get_max_state - callback function to get the max cooling state.
+ * @cdev: thermal cooling device pointer.
+ * @state: fill this variable with the max cooling state.
+ *
+ * Callback for the thermal cooling device to return the cpufreq
+ * max cooling state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+                                unsigned long *state)
+{
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
+
+       *state = cpufreq_cdev->max_level;
+       return 0;
+}
+
+/**
+ * cpufreq_get_cur_state - callback function to get the current cooling state.
+ * @cdev: thermal cooling device pointer.
+ * @state: fill this variable with the current cooling state.
+ *
+ * Callback for the thermal cooling device to return the cpufreq
+ * current cooling state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
+                                unsigned long *state)
+{
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 
-       return max;
+       *state = cpufreq_cdev->cpufreq_state;
+
+       return 0;
 }
 
+/**
+ * cpufreq_set_cur_state - callback function to set the current cooling state.
+ * @cdev: thermal cooling device pointer.
+ * @state: set this variable to the current cooling state.
+ *
+ * Callback for the thermal cooling device to change the cpufreq
+ * current cooling state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+                                unsigned long state)
+{
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
+
+       /* Request state should be less than max_level */
+       if (WARN_ON(state > cpufreq_cdev->max_level))
+               return -EINVAL;
+
+       /* Check if the old cooling action is same as new cooling action */
+       if (cpufreq_cdev->cpufreq_state == state)
+               return 0;
+
+       cpufreq_cdev->cpufreq_state = state;
+
+       return freq_qos_update_request(&cpufreq_cdev->qos_req,
+                               get_state_freq(cpufreq_cdev, state));
+}
+
+/* Bind cpufreq callbacks to thermal cooling device ops */
+
+static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
+       .get_max_state          = cpufreq_get_max_state,
+       .get_cur_state          = cpufreq_get_cur_state,
+       .set_cur_state          = cpufreq_set_cur_state,
+};
+
 /**
  * __cpufreq_cooling_register - helper function to create cpufreq cooling device
  * @np: a valid struct device_node to the cooling device device tree node
  * @policy: cpufreq policy
  * Normally this should be same as cpufreq policy->related_cpus.
- * @capacitance: dynamic power coefficient for these cpus
+ * @em: Energy Model of the cpufreq policy
  *
  * This interface function registers the cpufreq cooling device with the name
  * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -527,12 +470,13 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
  */
 static struct thermal_cooling_device *
 __cpufreq_cooling_register(struct device_node *np,
-                       struct cpufreq_policy *policy, u32 capacitance)
+                       struct cpufreq_policy *policy,
+                       struct em_perf_domain *em)
 {
        struct thermal_cooling_device *cdev;
        struct cpufreq_cooling_device *cpufreq_cdev;
        char dev_name[THERMAL_NAME_LENGTH];
-       unsigned int freq, i, num_cpus;
+       unsigned int i, num_cpus;
        struct device *dev;
        int ret;
        struct thermal_cooling_device_ops *cooling_ops;
@@ -573,51 +517,36 @@ __cpufreq_cooling_register(struct device_node *np,
        /* max_level is an index, not a counter */
        cpufreq_cdev->max_level = i - 1;
 
-       cpufreq_cdev->freq_table = kmalloc_array(i,
-                                       sizeof(*cpufreq_cdev->freq_table),
-                                       GFP_KERNEL);
-       if (!cpufreq_cdev->freq_table) {
-               cdev = ERR_PTR(-ENOMEM);
-               goto free_idle_time;
-       }
-
        ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
        if (ret < 0) {
                cdev = ERR_PTR(ret);
-               goto free_table;
+               goto free_idle_time;
        }
        cpufreq_cdev->id = ret;
 
        snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
                 cpufreq_cdev->id);
 
-       /* Fill freq-table in descending order of frequencies */
-       for (i = 0, freq = -1; i <= cpufreq_cdev->max_level; i++) {
-               freq = find_next_max(policy->freq_table, freq);
-               cpufreq_cdev->freq_table[i].frequency = freq;
-
-               /* Warn for duplicate entries */
-               if (!freq)
-                       pr_warn("%s: table has duplicate entries\n", __func__);
-               else
-                       pr_debug("%s: freq:%u KHz\n", __func__, freq);
-       }
-
-       if (capacitance) {
-               ret = update_freq_table(cpufreq_cdev, capacitance);
-               if (ret) {
-                       cdev = ERR_PTR(ret);
-                       goto remove_ida;
-               }
-
-               cooling_ops = &cpufreq_power_cooling_ops;
-       } else {
-               cooling_ops = &cpufreq_cooling_ops;
+       cooling_ops = &cpufreq_cooling_ops;
+
+#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
+       if (em_is_sane(cpufreq_cdev, em)) {
+               cpufreq_cdev->em = em;
+               cooling_ops->get_requested_power = cpufreq_get_requested_power;
+               cooling_ops->state2power = cpufreq_state2power;
+               cooling_ops->power2state = cpufreq_power2state;
+       } else
+#endif
+       if (policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED) {
+               pr_err("%s: unsorted frequency tables are not supported\n",
+                      __func__);
+               cdev = ERR_PTR(-EINVAL);
+               goto remove_ida;
        }
 
        ret = freq_qos_add_request(&policy->constraints,
                                   &cpufreq_cdev->qos_req, FREQ_QOS_MAX,
-                                  cpufreq_cdev->freq_table[0].frequency);
+                                  get_state_freq(cpufreq_cdev, 0));
        if (ret < 0) {
                pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
                       ret);
@@ -640,8 +569,6 @@ remove_qos_req:
        freq_qos_remove_request(&cpufreq_cdev->qos_req);
 remove_ida:
        ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
-free_table:
-       kfree(cpufreq_cdev->freq_table);
 free_idle_time:
        kfree(cpufreq_cdev->idle_time);
 free_cdev:
@@ -663,7 +590,7 @@ free_cdev:
 struct thermal_cooling_device *
 cpufreq_cooling_register(struct cpufreq_policy *policy)
 {
-       return __cpufreq_cooling_register(NULL, policy, 0);
+       return __cpufreq_cooling_register(NULL, policy, NULL);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
 
@@ -691,7 +618,6 @@ of_cpufreq_cooling_register(struct cpufreq_policy *policy)
 {
        struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
        struct thermal_cooling_device *cdev = NULL;
-       u32 capacitance = 0;
 
        if (!np) {
                pr_err("cpu_cooling: OF node not available for cpu%d\n",
@@ -700,10 +626,9 @@ of_cpufreq_cooling_register(struct cpufreq_policy *policy)
        }
 
        if (of_find_property(np, "#cooling-cells", NULL)) {
-               of_property_read_u32(np, "dynamic-power-coefficient",
-                                    &capacitance);
+               struct em_perf_domain *em = em_cpu_get(policy->cpu);
 
-               cdev = __cpufreq_cooling_register(np, policy, capacitance);
+               cdev = __cpufreq_cooling_register(np, policy, em);
                if (IS_ERR(cdev)) {
                        pr_err("cpu_cooling: cpu%d failed to register as cooling device: %ld\n",
                               policy->cpu, PTR_ERR(cdev));
@@ -739,7 +664,6 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
        freq_qos_remove_request(&cpufreq_cdev->qos_req);
        ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
        kfree(cpufreq_cdev->idle_time);
-       kfree(cpufreq_cdev->freq_table);
        kfree(cpufreq_cdev);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
index 5716b62..f75271b 100644 (file)
@@ -6,6 +6,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
@@ -103,6 +104,7 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
        int status;
        u32 temp_out;
        u32 out;
+       unsigned long update_ptps;
        u32 store_ptps;
        u32 store_ptmc;
        u32 store_te_out;
@@ -120,8 +122,10 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
        if (status)
                return status;
 
-       out = (store_ptps & ~(0xFF << (thres_index * 8)));
-       out |= (temp_out & 0xFF) << (thres_index * 8);
+       update_ptps = store_ptps;
+       bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8);
+       out = update_ptps;
+
        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
                                SOC_DTS_OFFSET_PTPS, out);
        if (status)
@@ -223,6 +227,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
        u32 out;
        struct intel_soc_dts_sensor_entry *dts;
        struct intel_soc_dts_sensors *sensors;
+       unsigned long raw;
 
        dts = tzd->devdata;
        sensors = dts->sensors;
@@ -231,8 +236,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
        if (status)
                return status;
 
-       out = (out & dts->temp_mask) >> dts->temp_shift;
-       out -= SOC_DTS_TJMAX_ENCODING;
+       raw = out;
+       out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING;
        *temp = sensors->tj_max - out * 1000;
 
        return 0;
@@ -280,11 +285,14 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
                                int read_only_trip_cnt)
 {
        char name[10];
+       unsigned long trip;
        int trip_count = 0;
        int trip_mask = 0;
+       int writable_trip_cnt = 0;
+       unsigned long ptps;
        u32 store_ptps;
+       unsigned long i;
        int ret;
-       int i;
 
        /* Store status to restor on exit */
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
@@ -293,11 +301,10 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
                goto err_ret;
 
        dts->id = id;
-       dts->temp_mask = 0x00FF << (id * 8);
-       dts->temp_shift = id * 8;
        if (notification_support) {
                trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
-               trip_mask = BIT(trip_count - read_only_trip_cnt) - 1;
+               writable_trip_cnt = trip_count - read_only_trip_cnt;
+               trip_mask = GENMASK(writable_trip_cnt - 1, 0);
        }
 
        /* Check if the writable trip we provide is not used by BIOS */
@@ -306,11 +313,9 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
        if (ret)
                trip_mask = 0;
        else {
-               for (i = 0; i < trip_count; ++i) {
-                       if (trip_mask & BIT(i))
-                               if (store_ptps & (0xff << (i * 8)))
-                                       trip_mask &= ~BIT(i);
-               }
+               ptps = store_ptps;
+               for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8)
+                       trip_mask &= ~BIT(i / 8);
        }
        dts->trip_mask = trip_mask;
        dts->trip_count = trip_count;
index adfb09a..c549457 100644 (file)
@@ -24,8 +24,6 @@ struct intel_soc_dts_sensors;
 
 struct intel_soc_dts_sensor_entry {
        int id;
-       u32 temp_mask;
-       u32 temp_shift;
        u32 store_status;
        u32 trip_mask;
        u32 trip_count;
index e46a4e3..fb77acb 100644 (file)
@@ -245,11 +245,11 @@ 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_priv *priv, int id, int *temp)
+static int get_temp_8960(struct tsens_sensor *s, int *temp)
 {
        int ret;
        u32 code, trdy;
-       const struct tsens_sensor *s = &priv->sensor[id];
+       struct tsens_priv *priv = s->priv;
        unsigned long timeout;
 
        timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
index 528df88..c8d57ee 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/debugfs.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/regmap.h>
 #include "tsens.h"
 
+/**
+ * struct tsens_irq_data - IRQ status and temperature violations
+ * @up_viol:        upper threshold violated
+ * @up_thresh:      upper threshold temperature value
+ * @up_irq_mask:    mask register for upper threshold irqs
+ * @up_irq_clear:   clear register for uppper threshold irqs
+ * @low_viol:       lower threshold violated
+ * @low_thresh:     lower threshold temperature value
+ * @low_irq_mask:   mask register for lower threshold irqs
+ * @low_irq_clear:  clear register for lower threshold irqs
+ *
+ * Structure containing data about temperature threshold settings and
+ * irq status if they were violated.
+ */
+struct tsens_irq_data {
+       u32 up_viol;
+       int up_thresh;
+       u32 up_irq_mask;
+       u32 up_irq_clear;
+       u32 low_viol;
+       int low_thresh;
+       u32 low_irq_mask;
+       u32 low_irq_clear;
+};
+
 char *qfprom_read(struct device *dev, const char *cname)
 {
        struct nvmem_cell *cell;
@@ -42,8 +68,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
 
        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]);
+                       "%s: sensor%d - data_point1:%#x data_point2:%#x\n",
+                       __func__, i, p1[i], p2[i]);
 
                priv->sensor[i].slope = SLOPE_DEFAULT;
                if (mode == TWO_PT_CALIB) {
@@ -60,10 +86,18 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
                priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
                                (CAL_DEGC_PT1 *
                                priv->sensor[i].slope);
-               dev_dbg(priv->dev, "offset:%d\n", priv->sensor[i].offset);
+               dev_dbg(priv->dev, "%s: offset:%d\n", __func__, priv->sensor[i].offset);
        }
 }
 
+static inline u32 degc_to_code(int degc, const struct tsens_sensor *s)
+{
+       u64 code = div_u64(((u64)degc * s->slope + s->offset), SLOPE_FACTOR);
+
+       pr_debug("%s: raw_code: 0x%llx, degc:%d\n", __func__, code, degc);
+       return clamp_val(code, THRESHOLD_MIN_ADC_CODE, THRESHOLD_MAX_ADC_CODE);
+}
+
 static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
 {
        int degc, num, den;
@@ -83,12 +117,353 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
        return degc;
 }
 
-int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp)
+/**
+ * tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
+ * @s:     Pointer to sensor struct
+ * @field: Index into regmap_field array pointing to temperature data
+ *
+ * This function handles temperature returned in ADC code or deciCelsius
+ * depending on IP version.
+ *
+ * Return: Temperature in milliCelsius on success, a negative errno will
+ * be returned in error cases
+ */
+static int tsens_hw_to_mC(struct tsens_sensor *s, int field)
+{
+       struct tsens_priv *priv = s->priv;
+       u32 resolution;
+       u32 temp = 0;
+       int ret;
+
+       resolution = priv->fields[LAST_TEMP_0].msb -
+               priv->fields[LAST_TEMP_0].lsb;
+
+       ret = regmap_field_read(priv->rf[field], &temp);
+       if (ret)
+               return ret;
+
+       /* Convert temperature from ADC code to milliCelsius */
+       if (priv->feat->adc)
+               return code_to_degc(temp, s) * 1000;
+
+       /* deciCelsius -> milliCelsius along with sign extension */
+       return sign_extend32(temp, resolution) * 100;
+}
+
+/**
+ * tsens_mC_to_hw - Convert temperature to hardware register value
+ * @s: Pointer to sensor struct
+ * @temp: temperature in milliCelsius to be programmed to hardware
+ *
+ * This function outputs the value to be written to hardware in ADC code
+ * or deciCelsius depending on IP version.
+ *
+ * Return: ADC code or temperature in deciCelsius.
+ */
+static int tsens_mC_to_hw(struct tsens_sensor *s, int temp)
+{
+       struct tsens_priv *priv = s->priv;
+
+       /* milliC to adc code */
+       if (priv->feat->adc)
+               return degc_to_code(temp / 1000, s);
+
+       /* milliC to deciC */
+       return temp / 100;
+}
+
+static inline enum tsens_ver tsens_version(struct tsens_priv *priv)
+{
+       return priv->feat->ver_major;
+}
+
+static void tsens_set_interrupt_v1(struct tsens_priv *priv, u32 hw_id,
+                                  enum tsens_irq_type irq_type, bool enable)
+{
+       u32 index = 0;
+
+       switch (irq_type) {
+       case UPPER:
+               index = UP_INT_CLEAR_0 + hw_id;
+               break;
+       case LOWER:
+               index = LOW_INT_CLEAR_0 + hw_id;
+               break;
+       }
+       regmap_field_write(priv->rf[index], enable ? 0 : 1);
+}
+
+static void tsens_set_interrupt_v2(struct tsens_priv *priv, u32 hw_id,
+                                  enum tsens_irq_type irq_type, bool enable)
+{
+       u32 index_mask = 0, index_clear = 0;
+
+       /*
+        * To enable the interrupt flag for a sensor:
+        *    - clear the mask bit
+        * To disable the interrupt flag for a sensor:
+        *    - Mask further interrupts for this sensor
+        *    - Write 1 followed by 0 to clear the interrupt
+        */
+       switch (irq_type) {
+       case UPPER:
+               index_mask  = UP_INT_MASK_0 + hw_id;
+               index_clear = UP_INT_CLEAR_0 + hw_id;
+               break;
+       case LOWER:
+               index_mask  = LOW_INT_MASK_0 + hw_id;
+               index_clear = LOW_INT_CLEAR_0 + hw_id;
+               break;
+       }
+
+       if (enable) {
+               regmap_field_write(priv->rf[index_mask], 0);
+       } else {
+               regmap_field_write(priv->rf[index_mask],  1);
+               regmap_field_write(priv->rf[index_clear], 1);
+               regmap_field_write(priv->rf[index_clear], 0);
+       }
+}
+
+/**
+ * tsens_set_interrupt - Set state of an interrupt
+ * @priv: Pointer to tsens controller private data
+ * @hw_id: Hardware ID aka. sensor number
+ * @irq_type: irq_type from enum tsens_irq_type
+ * @enable: false = disable, true = enable
+ *
+ * Call IP-specific function to set state of an interrupt
+ *
+ * Return: void
+ */
+static void tsens_set_interrupt(struct tsens_priv *priv, u32 hw_id,
+                               enum tsens_irq_type irq_type, bool enable)
+{
+       dev_dbg(priv->dev, "[%u] %s: %s -> %s\n", hw_id, __func__,
+               irq_type ? ((irq_type == 1) ? "UP" : "CRITICAL") : "LOW",
+               enable ? "en" : "dis");
+       if (tsens_version(priv) > VER_1_X)
+               tsens_set_interrupt_v2(priv, hw_id, irq_type, enable);
+       else
+               tsens_set_interrupt_v1(priv, hw_id, irq_type, enable);
+}
+
+/**
+ * tsens_threshold_violated - Check if a sensor temperature violated a preset threshold
+ * @priv: Pointer to tsens controller private data
+ * @hw_id: Hardware ID aka. sensor number
+ * @d: Pointer to irq state data
+ *
+ * Return: 0 if threshold was not violated, 1 if it was violated and negative
+ * errno in case of errors
+ */
+static int tsens_threshold_violated(struct tsens_priv *priv, u32 hw_id,
+                                   struct tsens_irq_data *d)
 {
-       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[UPPER_STATUS_0 + hw_id], &d->up_viol);
+       if (ret)
+               return ret;
+       ret = regmap_field_read(priv->rf[LOWER_STATUS_0 + hw_id], &d->low_viol);
+       if (ret)
+               return ret;
+       if (d->up_viol || d->low_viol)
+               return 1;
+
+       return 0;
+}
+
+static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
+                               struct tsens_sensor *s, struct tsens_irq_data *d)
+{
+       int ret;
+
+       ret = regmap_field_read(priv->rf[UP_INT_CLEAR_0 + hw_id], &d->up_irq_clear);
+       if (ret)
+               return ret;
+       ret = regmap_field_read(priv->rf[LOW_INT_CLEAR_0 + hw_id], &d->low_irq_clear);
+       if (ret)
+               return ret;
+       if (tsens_version(priv) > VER_1_X) {
+               ret = regmap_field_read(priv->rf[UP_INT_MASK_0 + hw_id], &d->up_irq_mask);
+               if (ret)
+                       return ret;
+               ret = regmap_field_read(priv->rf[LOW_INT_MASK_0 + hw_id], &d->low_irq_mask);
+               if (ret)
+                       return ret;
+       } else {
+               /* No mask register on older TSENS */
+               d->up_irq_mask = 0;
+               d->low_irq_mask = 0;
+       }
+
+       d->up_thresh  = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id);
+       d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id);
+
+       dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u) | clr(%u|%u) | mask(%u|%u)\n",
+               hw_id, __func__, (d->up_viol || d->low_viol) ? "(V)" : "",
+               d->low_viol, d->up_viol, d->low_irq_clear, d->up_irq_clear,
+               d->low_irq_mask, d->up_irq_mask);
+       dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d)\n", hw_id, __func__,
+               (d->up_viol || d->low_viol) ? "(violation)" : "",
+               d->low_thresh, d->up_thresh);
+
+       return 0;
+}
+
+static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
+{
+       if (ver > VER_1_X)
+               return mask & (1 << hw_id);
+
+       /* v1, v0.1 don't have a irq mask register */
+       return 0;
+}
+
+/**
+ * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
+ * @irq: irq number
+ * @data: tsens controller private data
+ *
+ * Check all sensors to find ones that violated their threshold limits. If the
+ * temperature is still outside the limits, call thermal_zone_device_update() to
+ * update the thresholds, else re-enable the interrupts.
+ *
+ * The level-triggered interrupt might deassert if the temperature returned to
+ * within the threshold limits by the time the handler got scheduled. We
+ * consider the irq to have been handled in that case.
+ *
+ * Return: IRQ_HANDLED
+ */
+irqreturn_t tsens_irq_thread(int irq, void *data)
+{
+       struct tsens_priv *priv = data;
+       struct tsens_irq_data d;
+       bool enable = true, disable = false;
+       unsigned long flags;
+       int temp, ret, i;
+
+       for (i = 0; i < priv->num_sensors; i++) {
+               bool trigger = false;
+               struct tsens_sensor *s = &priv->sensor[i];
+               u32 hw_id = s->hw_id;
+
+               if (IS_ERR(priv->sensor[i].tzd))
+                       continue;
+               if (!tsens_threshold_violated(priv, hw_id, &d))
+                       continue;
+               ret = get_temp_tsens_valid(s, &temp);
+               if (ret) {
+                       dev_err(priv->dev, "[%u] %s: error reading sensor\n", hw_id, __func__);
+                       continue;
+               }
+
+               spin_lock_irqsave(&priv->ul_lock, flags);
+
+               tsens_read_irq_state(priv, hw_id, s, &d);
+
+               if (d.up_viol &&
+                   !masked_irq(hw_id, d.up_irq_mask, tsens_version(priv))) {
+                       tsens_set_interrupt(priv, hw_id, UPPER, disable);
+                       if (d.up_thresh > temp) {
+                               dev_dbg(priv->dev, "[%u] %s: re-arm upper\n",
+                                       priv->sensor[i].hw_id, __func__);
+                               tsens_set_interrupt(priv, hw_id, UPPER, enable);
+                       } else {
+                               trigger = true;
+                               /* Keep irq masked */
+                       }
+               } else if (d.low_viol &&
+                          !masked_irq(hw_id, d.low_irq_mask, tsens_version(priv))) {
+                       tsens_set_interrupt(priv, hw_id, LOWER, disable);
+                       if (d.low_thresh < temp) {
+                               dev_dbg(priv->dev, "[%u] %s: re-arm low\n",
+                                       priv->sensor[i].hw_id, __func__);
+                               tsens_set_interrupt(priv, hw_id, LOWER, enable);
+                       } else {
+                               trigger = true;
+                               /* Keep irq masked */
+                       }
+               }
+
+               spin_unlock_irqrestore(&priv->ul_lock, flags);
+
+               if (trigger) {
+                       dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n",
+                               hw_id, __func__, temp);
+                       thermal_zone_device_update(priv->sensor[i].tzd,
+                                                  THERMAL_EVENT_UNSPECIFIED);
+               } else {
+                       dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
+                               hw_id, __func__, temp);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+int tsens_set_trips(void *_sensor, int low, int high)
+{
+       struct tsens_sensor *s = _sensor;
+       struct tsens_priv *priv = s->priv;
+       struct device *dev = priv->dev;
+       struct tsens_irq_data d;
+       unsigned long flags;
+       int high_val, low_val, cl_high, cl_low;
+       u32 hw_id = s->hw_id;
+
+       dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
+               hw_id, __func__, low, high);
+
+       cl_high = clamp_val(high, -40000, 120000);
+       cl_low  = clamp_val(low, -40000, 120000);
+
+       high_val = tsens_mC_to_hw(s, cl_high);
+       low_val  = tsens_mC_to_hw(s, cl_low);
+
+       spin_lock_irqsave(&priv->ul_lock, flags);
+
+       tsens_read_irq_state(priv, hw_id, s, &d);
+
+       /* Write the new thresholds and clear the status */
+       regmap_field_write(priv->rf[LOW_THRESH_0 + hw_id], low_val);
+       regmap_field_write(priv->rf[UP_THRESH_0 + hw_id], high_val);
+       tsens_set_interrupt(priv, hw_id, LOWER, true);
+       tsens_set_interrupt(priv, hw_id, UPPER, true);
+
+       spin_unlock_irqrestore(&priv->ul_lock, flags);
+
+       dev_dbg(dev, "[%u] %s: (%d:%d)->(%d:%d)\n",
+               s->hw_id, __func__, d.low_thresh, d.up_thresh, cl_low, cl_high);
+
+       return 0;
+}
+
+int tsens_enable_irq(struct tsens_priv *priv)
+{
+       int ret;
+       int val = tsens_version(priv) > VER_1_X ? 7 : 1;
+
+       ret = regmap_field_write(priv->rf[INT_EN], val);
+       if (ret < 0)
+               dev_err(priv->dev, "%s: failed to enable interrupts\n", __func__);
+
+       return ret;
+}
+
+void tsens_disable_irq(struct tsens_priv *priv)
+{
+       regmap_field_write(priv->rf[INT_EN], 0);
+}
+
+int get_temp_tsens_valid(struct tsens_sensor *s, int *temp)
+{
+       struct tsens_priv *priv = s->priv;
+       int hw_id = s->hw_id;
+       u32 temp_idx = LAST_TEMP_0 + hw_id;
+       u32 valid_idx = VALID_0 + hw_id;
+       u32 valid;
        int ret;
 
        ret = regmap_field_read(priv->rf[valid_idx], &valid);
@@ -106,29 +481,18 @@ int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp)
        }
 
        /* 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;
-       }
+       *temp = tsens_hw_to_mC(s, temp_idx);
 
        return 0;
 }
 
-int get_temp_common(struct tsens_priv *priv, int i, int *temp)
+int get_temp_common(struct tsens_sensor *s, int *temp)
 {
-       struct tsens_sensor *s = &priv->sensor[i];
+       struct tsens_priv *priv = s->priv;
+       int hw_id = s->hw_id;
        int last_temp = 0, ret;
 
-       ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp);
+       ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
        if (ret)
                return ret;
 
@@ -137,6 +501,77 @@ int get_temp_common(struct tsens_priv *priv, int i, int *temp)
        return 0;
 }
 
+#ifdef CONFIG_DEBUG_FS
+static int dbg_sensors_show(struct seq_file *s, void *data)
+{
+       struct platform_device *pdev = s->private;
+       struct tsens_priv *priv = platform_get_drvdata(pdev);
+       int i;
+
+       seq_printf(s, "max: %2d\nnum: %2d\n\n",
+                  priv->feat->max_sensors, priv->num_sensors);
+
+       seq_puts(s, "      id    slope   offset\n--------------------------\n");
+       for (i = 0;  i < priv->num_sensors; i++) {
+               seq_printf(s, "%8d %8d %8d\n", priv->sensor[i].hw_id,
+                          priv->sensor[i].slope, priv->sensor[i].offset);
+       }
+
+       return 0;
+}
+
+static int dbg_version_show(struct seq_file *s, void *data)
+{
+       struct platform_device *pdev = s->private;
+       struct tsens_priv *priv = platform_get_drvdata(pdev);
+       u32 maj_ver, min_ver, step_ver;
+       int ret;
+
+       if (tsens_version(priv) > VER_0_1) {
+               ret = regmap_field_read(priv->rf[VER_MAJOR], &maj_ver);
+               if (ret)
+                       return ret;
+               ret = regmap_field_read(priv->rf[VER_MINOR], &min_ver);
+               if (ret)
+                       return ret;
+               ret = regmap_field_read(priv->rf[VER_STEP], &step_ver);
+               if (ret)
+                       return ret;
+               seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver);
+       } else {
+               seq_puts(s, "0.1.0\n");
+       }
+
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(dbg_version);
+DEFINE_SHOW_ATTRIBUTE(dbg_sensors);
+
+static void tsens_debug_init(struct platform_device *pdev)
+{
+       struct tsens_priv *priv = platform_get_drvdata(pdev);
+       struct dentry *root, *file;
+
+       root = debugfs_lookup("tsens", NULL);
+       if (!root)
+               priv->debug_root = debugfs_create_dir("tsens", NULL);
+       else
+               priv->debug_root = root;
+
+       file = debugfs_lookup("version", priv->debug_root);
+       if (!file)
+               debugfs_create_file("version", 0444, priv->debug_root,
+                                   pdev, &dbg_version_fops);
+
+       /* A directory for each instance of the TSENS IP */
+       priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root);
+       debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops);
+}
+#else
+static inline void tsens_debug_init(struct platform_device *pdev) {}
+#endif
+
 static const struct regmap_config tsens_config = {
        .name           = "tm",
        .reg_bits       = 32,
@@ -197,6 +632,15 @@ int __init init_common(struct tsens_priv *priv)
                goto err_put_device;
        }
 
+       if (tsens_version(priv) > VER_0_1) {
+               for (i = VER_MAJOR; i <= VER_STEP; i++) {
+                       priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
+                                                             priv->fields[i]);
+                       if (IS_ERR(priv->rf[i]))
+                               return PTR_ERR(priv->rf[i]);
+               }
+       }
+
        priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
                                                     priv->fields[TSENS_EN]);
        if (IS_ERR(priv->rf[TSENS_EN])) {
@@ -207,7 +651,7 @@ int __init init_common(struct tsens_priv *priv)
        if (ret)
                goto err_put_device;
        if (!enabled) {
-               dev_err(dev, "tsens device is not enabled\n");
+               dev_err(dev, "%s: device not enabled\n", __func__);
                ret = -ENODEV;
                goto err_put_device;
        }
@@ -218,24 +662,31 @@ int __init init_common(struct tsens_priv *priv)
                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;
-               }
+       priv->rf[INT_EN] = devm_regmap_field_alloc(dev, priv->tm_map,
+                                                  priv->fields[INT_EN]);
+       if (IS_ERR(priv->rf[INT_EN])) {
+               ret = PTR_ERR(priv->rf[INT_EN]);
+               goto err_put_device;
        }
-       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;
+
+       /* This loop might need changes if enum regfield_ids is reordered */
+       for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
+               for (i = 0; i < priv->feat->max_sensors; i++) {
+                       int idx = j + i;
+
+                       priv->rf[idx] = devm_regmap_field_alloc(dev, priv->tm_map,
+                                                               priv->fields[idx]);
+                       if (IS_ERR(priv->rf[idx])) {
+                               ret = PTR_ERR(priv->rf[idx]);
+                               goto err_put_device;
+                       }
                }
        }
 
+       spin_lock_init(&priv->ul_lock);
+       tsens_enable_irq(priv);
+       tsens_debug_init(op);
+
        return 0;
 
 err_put_device:
index 055647b..4b8dd6d 100644 (file)
@@ -347,9 +347,20 @@ static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
        /* INTERRUPT ENABLE */
        [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0),
 
+       /* UPPER/LOWER TEMPERATURE THRESHOLDS */
+       REG_FIELD_FOR_EACH_SENSOR11(LOW_THRESH,    TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF,  0,  9),
+       REG_FIELD_FOR_EACH_SENSOR11(UP_THRESH,     TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 10, 19),
+
+       /* UPPER/LOWER INTERRUPTS [CLEAR/STATUS] */
+       REG_FIELD_FOR_EACH_SENSOR11(LOW_INT_CLEAR, TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 20, 20),
+       REG_FIELD_FOR_EACH_SENSOR11(UP_INT_CLEAR,  TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 21, 21),
+
+       /* NO CRITICAL INTERRUPT SUPPORT on v0.1 */
+
        /* Sn_STATUS */
        REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP,    TM_Sn_STATUS_OFF,  0,  9),
        /* No VALID field on v0.1 */
+       /* xxx_STATUS bits: 1 == threshold violated */
        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),
index 870f502..bd2ddb6 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/bitops.h>
 #include <linux/regmap.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 #include "tsens.h"
 
 /* ----- SROT ------ */
 #define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF      0x0004
 #define TM_Sn_STATUS_OFF                       0x0044
 #define TM_TRDY_OFF                            0x0084
+#define TM_HIGH_LOW_INT_STATUS_OFF             0x0088
+#define TM_HIGH_LOW_Sn_INT_THRESHOLD_OFF       0x0090
+
+/* eeprom layout data for msm8956/76 (v1) */
+#define MSM8976_BASE0_MASK     0xff
+#define MSM8976_BASE1_MASK     0xff
+#define MSM8976_BASE1_SHIFT    8
+
+#define MSM8976_S0_P1_MASK     0x3f00
+#define MSM8976_S1_P1_MASK     0x3f00000
+#define MSM8976_S2_P1_MASK     0x3f
+#define MSM8976_S3_P1_MASK     0x3f000
+#define MSM8976_S4_P1_MASK     0x3f00
+#define MSM8976_S5_P1_MASK     0x3f00000
+#define MSM8976_S6_P1_MASK     0x3f
+#define MSM8976_S7_P1_MASK     0x3f000
+#define MSM8976_S8_P1_MASK     0x1f8
+#define MSM8976_S9_P1_MASK     0x1f8000
+#define MSM8976_S10_P1_MASK    0xf8000000
+#define MSM8976_S10_P1_MASK_1  0x1
+
+#define MSM8976_S0_P2_MASK     0xfc000
+#define MSM8976_S1_P2_MASK     0xfc000000
+#define MSM8976_S2_P2_MASK     0xfc0
+#define MSM8976_S3_P2_MASK     0xfc0000
+#define MSM8976_S4_P2_MASK     0xfc000
+#define MSM8976_S5_P2_MASK     0xfc000000
+#define MSM8976_S6_P2_MASK     0xfc0
+#define MSM8976_S7_P2_MASK     0xfc0000
+#define MSM8976_S8_P2_MASK     0x7e00
+#define MSM8976_S9_P2_MASK     0x7e00000
+#define MSM8976_S10_P2_MASK    0x7e
+
+#define MSM8976_S0_P1_SHIFT    8
+#define MSM8976_S1_P1_SHIFT    20
+#define MSM8976_S2_P1_SHIFT    0
+#define MSM8976_S3_P1_SHIFT    12
+#define MSM8976_S4_P1_SHIFT    8
+#define MSM8976_S5_P1_SHIFT    20
+#define MSM8976_S6_P1_SHIFT    0
+#define MSM8976_S7_P1_SHIFT    12
+#define MSM8976_S8_P1_SHIFT    3
+#define MSM8976_S9_P1_SHIFT    15
+#define MSM8976_S10_P1_SHIFT   27
+#define MSM8976_S10_P1_SHIFT_1 0
+
+#define MSM8976_S0_P2_SHIFT    14
+#define MSM8976_S1_P2_SHIFT    26
+#define MSM8976_S2_P2_SHIFT    6
+#define MSM8976_S3_P2_SHIFT    18
+#define MSM8976_S4_P2_SHIFT    14
+#define MSM8976_S5_P2_SHIFT    26
+#define MSM8976_S6_P2_SHIFT    6
+#define MSM8976_S7_P2_SHIFT    18
+#define MSM8976_S8_P2_SHIFT    9
+#define MSM8976_S9_P2_SHIFT    21
+#define MSM8976_S10_P2_SHIFT   1
+
+#define MSM8976_CAL_SEL_MASK   0x3
+
+#define MSM8976_CAL_DEGC_PT1   30
+#define MSM8976_CAL_DEGC_PT2   120
+#define MSM8976_SLOPE_FACTOR   1000
+#define MSM8976_SLOPE_DEFAULT  3200
 
 /* eeprom layout data for qcs404/405 (v1) */
 #define BASE0_MASK     0x000007f8
 #define CAL_SEL_MASK   7
 #define CAL_SEL_SHIFT  0
 
+static void compute_intercept_slope_8976(struct tsens_priv *priv,
+                             u32 *p1, u32 *p2, u32 mode)
+{
+       int i;
+
+       priv->sensor[0].slope = 3313;
+       priv->sensor[1].slope = 3275;
+       priv->sensor[2].slope = 3320;
+       priv->sensor[3].slope = 3246;
+       priv->sensor[4].slope = 3279;
+       priv->sensor[5].slope = 3257;
+       priv->sensor[6].slope = 3234;
+       priv->sensor[7].slope = 3269;
+       priv->sensor[8].slope = 3255;
+       priv->sensor[9].slope = 3239;
+       priv->sensor[10].slope = 3286;
+
+       for (i = 0; i < priv->num_sensors; i++) {
+               priv->sensor[i].offset = (p1[i] * MSM8976_SLOPE_FACTOR) -
+                               (MSM8976_CAL_DEGC_PT1 *
+                               priv->sensor[i].slope);
+       }
+}
+
 static int calibrate_v1(struct tsens_priv *priv)
 {
        u32 base0 = 0, base1 = 0;
@@ -143,7 +232,72 @@ static int calibrate_v1(struct tsens_priv *priv)
        return 0;
 }
 
-/* v1.x: qcs404,405 */
+static int calibrate_8976(struct tsens_priv *priv)
+{
+       int base0 = 0, base1 = 0, i;
+       u32 p1[11], p2[11];
+       int mode = 0, tmp = 0;
+       u32 *qfprom_cdata;
+
+       qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
+       if (IS_ERR(qfprom_cdata))
+               return PTR_ERR(qfprom_cdata);
+
+       mode = (qfprom_cdata[4] & MSM8976_CAL_SEL_MASK);
+       dev_dbg(priv->dev, "calibration mode is %d\n", mode);
+
+       switch (mode) {
+       case TWO_PT_CALIB:
+               base1 = (qfprom_cdata[2] & MSM8976_BASE1_MASK) >> MSM8976_BASE1_SHIFT;
+               p2[0] = (qfprom_cdata[0] & MSM8976_S0_P2_MASK) >> MSM8976_S0_P2_SHIFT;
+               p2[1] = (qfprom_cdata[0] & MSM8976_S1_P2_MASK) >> MSM8976_S1_P2_SHIFT;
+               p2[2] = (qfprom_cdata[1] & MSM8976_S2_P2_MASK) >> MSM8976_S2_P2_SHIFT;
+               p2[3] = (qfprom_cdata[1] & MSM8976_S3_P2_MASK) >> MSM8976_S3_P2_SHIFT;
+               p2[4] = (qfprom_cdata[2] & MSM8976_S4_P2_MASK) >> MSM8976_S4_P2_SHIFT;
+               p2[5] = (qfprom_cdata[2] & MSM8976_S5_P2_MASK) >> MSM8976_S5_P2_SHIFT;
+               p2[6] = (qfprom_cdata[3] & MSM8976_S6_P2_MASK) >> MSM8976_S6_P2_SHIFT;
+               p2[7] = (qfprom_cdata[3] & MSM8976_S7_P2_MASK) >> MSM8976_S7_P2_SHIFT;
+               p2[8] = (qfprom_cdata[4] & MSM8976_S8_P2_MASK) >> MSM8976_S8_P2_SHIFT;
+               p2[9] = (qfprom_cdata[4] & MSM8976_S9_P2_MASK) >> MSM8976_S9_P2_SHIFT;
+               p2[10] = (qfprom_cdata[5] & MSM8976_S10_P2_MASK) >> MSM8976_S10_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[0] & MSM8976_BASE0_MASK;
+               p1[0] = (qfprom_cdata[0] & MSM8976_S0_P1_MASK) >> MSM8976_S0_P1_SHIFT;
+               p1[1] = (qfprom_cdata[0] & MSM8976_S1_P1_MASK) >> MSM8976_S1_P1_SHIFT;
+               p1[2] = (qfprom_cdata[1] & MSM8976_S2_P1_MASK) >> MSM8976_S2_P1_SHIFT;
+               p1[3] = (qfprom_cdata[1] & MSM8976_S3_P1_MASK) >> MSM8976_S3_P1_SHIFT;
+               p1[4] = (qfprom_cdata[2] & MSM8976_S4_P1_MASK) >> MSM8976_S4_P1_SHIFT;
+               p1[5] = (qfprom_cdata[2] & MSM8976_S5_P1_MASK) >> MSM8976_S5_P1_SHIFT;
+               p1[6] = (qfprom_cdata[3] & MSM8976_S6_P1_MASK) >> MSM8976_S6_P1_SHIFT;
+               p1[7] = (qfprom_cdata[3] & MSM8976_S7_P1_MASK) >> MSM8976_S7_P1_SHIFT;
+               p1[8] = (qfprom_cdata[4] & MSM8976_S8_P1_MASK) >> MSM8976_S8_P1_SHIFT;
+               p1[9] = (qfprom_cdata[4] & MSM8976_S9_P1_MASK) >> MSM8976_S9_P1_SHIFT;
+               p1[10] = (qfprom_cdata[4] & MSM8976_S10_P1_MASK) >> MSM8976_S10_P1_SHIFT;
+               tmp = (qfprom_cdata[5] & MSM8976_S10_P1_MASK_1) << MSM8976_S10_P1_SHIFT_1;
+               p1[10] |= tmp;
+
+               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_8976(priv, p1, p2, mode);
+       kfree(qfprom_cdata);
+
+       return 0;
+}
+
+/* v1.x: msm8956,8976,qcs404,405 */
 
 static const struct tsens_features tsens_v1_feat = {
        .ver_major      = VER_1_X,
@@ -168,9 +322,36 @@ static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
        /* INTERRUPT ENABLE */
        [INT_EN]     = REG_FIELD(TM_INT_EN_OFF, 0, 0),
 
+       /* UPPER/LOWER TEMPERATURE THRESHOLDS */
+       REG_FIELD_FOR_EACH_SENSOR11(LOW_THRESH,    TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF,  0,  9),
+       REG_FIELD_FOR_EACH_SENSOR11(UP_THRESH,     TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 10, 19),
+
+       /* UPPER/LOWER INTERRUPTS [CLEAR/STATUS] */
+       REG_FIELD_FOR_EACH_SENSOR11(LOW_INT_CLEAR, TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 20, 20),
+       REG_FIELD_FOR_EACH_SENSOR11(UP_INT_CLEAR,  TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 21, 21),
+       [LOW_INT_STATUS_0] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  0,  0),
+       [LOW_INT_STATUS_1] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  1,  1),
+       [LOW_INT_STATUS_2] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  2,  2),
+       [LOW_INT_STATUS_3] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  3,  3),
+       [LOW_INT_STATUS_4] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  4,  4),
+       [LOW_INT_STATUS_5] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  5,  5),
+       [LOW_INT_STATUS_6] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  6,  6),
+       [LOW_INT_STATUS_7] = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  7,  7),
+       [UP_INT_STATUS_0]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  8,  8),
+       [UP_INT_STATUS_1]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF,  9,  9),
+       [UP_INT_STATUS_2]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF, 10, 10),
+       [UP_INT_STATUS_3]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF, 11, 11),
+       [UP_INT_STATUS_4]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF, 12, 12),
+       [UP_INT_STATUS_5]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF, 13, 13),
+       [UP_INT_STATUS_6]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF, 14, 14),
+       [UP_INT_STATUS_7]  = REG_FIELD(TM_HIGH_LOW_INT_STATUS_OFF, 15, 15),
+
+       /* NO CRITICAL INTERRUPT SUPPORT on v1 */
+
        /* 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),
+       /* xxx_STATUS bits: 1 == threshold violated */
        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),
@@ -192,3 +373,18 @@ const struct tsens_plat_data data_tsens_v1 = {
        .feat           = &tsens_v1_feat,
        .fields = tsens_v1_regfields,
 };
+
+static const struct tsens_ops ops_8976 = {
+       .init           = init_common,
+       .calibrate      = calibrate_8976,
+       .get_temp       = get_temp_tsens_valid,
+};
+
+/* Valid for both MSM8956 and MSM8976. Sensor ID 3 is unused. */
+const struct tsens_plat_data data_8976 = {
+       .num_sensors    = 11,
+       .ops            = &ops_8976,
+       .hw_ids         = (unsigned int[]){0, 1, 2, 4, 5, 6, 7, 8, 9, 10},
+       .feat           = &tsens_v1_feat,
+       .fields         = tsens_v1_regfields,
+};
index 0a4f2b8..a4d15e1 100644 (file)
@@ -50,9 +50,22 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
        /* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */
        [INT_EN]  = REG_FIELD(TM_INT_EN_OFF, 0, 2),
 
+       /* TEMPERATURE THRESHOLDS */
+       REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF,  0,  11),
+       REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH,  TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12,  23),
+
+       /* INTERRUPTS [CLEAR/STATUS/MASK] */
+       REG_FIELD_SPLIT_BITS_0_15(LOW_INT_STATUS,  TM_UPPER_LOWER_INT_STATUS_OFF),
+       REG_FIELD_SPLIT_BITS_0_15(LOW_INT_CLEAR,   TM_UPPER_LOWER_INT_CLEAR_OFF),
+       REG_FIELD_SPLIT_BITS_0_15(LOW_INT_MASK,    TM_UPPER_LOWER_INT_MASK_OFF),
+       REG_FIELD_SPLIT_BITS_16_31(UP_INT_STATUS,  TM_UPPER_LOWER_INT_STATUS_OFF),
+       REG_FIELD_SPLIT_BITS_16_31(UP_INT_CLEAR,   TM_UPPER_LOWER_INT_CLEAR_OFF),
+       REG_FIELD_SPLIT_BITS_16_31(UP_INT_MASK,    TM_UPPER_LOWER_INT_MASK_OFF),
+
        /* 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),
+       /* xxx_STATUS bits: 1 == threshold violated */
        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),
index 0627d86..015e7d2 100644 (file)
@@ -3,9 +3,11 @@
  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/debugfs.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 
 static int tsens_get_temp(void *data, int *temp)
 {
-       const struct tsens_sensor *s = data;
+       struct tsens_sensor *s = data;
        struct tsens_priv *priv = s->priv;
 
-       return priv->ops->get_temp(priv, s->id, temp);
+       return priv->ops->get_temp(s, temp);
 }
 
 static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend)
 {
-       const struct tsens_sensor *s = data;
+       struct tsens_sensor *s = data;
        struct tsens_priv *priv = s->priv;
 
        if (priv->ops->get_trend)
-               return priv->ops->get_trend(priv, s->id, trend);
+               return priv->ops->get_trend(s, trend);
 
        return -ENOTSUPP;
 }
@@ -60,6 +62,9 @@ static const struct of_device_id tsens_table[] = {
        }, {
                .compatible = "qcom,msm8974-tsens",
                .data = &data_8974,
+       }, {
+               .compatible = "qcom,msm8976-tsens",
+               .data = &data_8976,
        }, {
                .compatible = "qcom,msm8996-tsens",
                .data = &data_8996,
@@ -77,17 +82,18 @@ MODULE_DEVICE_TABLE(of, tsens_table);
 static const struct thermal_zone_of_device_ops tsens_of_ops = {
        .get_temp = tsens_get_temp,
        .get_trend = tsens_get_trend,
+       .set_trips = tsens_set_trips,
 };
 
 static int tsens_register(struct tsens_priv *priv)
 {
-       int i;
+       int i, ret, irq;
        struct thermal_zone_device *tzd;
+       struct platform_device *pdev;
 
        for (i = 0;  i < priv->num_sensors; i++) {
                priv->sensor[i].priv = priv;
-               priv->sensor[i].id = i;
-               tzd = devm_thermal_zone_of_sensor_register(priv->dev, i,
+               tzd = devm_thermal_zone_of_sensor_register(priv->dev, priv->sensor[i].hw_id,
                                                           &priv->sensor[i],
                                                           &tsens_of_ops);
                if (IS_ERR(tzd))
@@ -96,7 +102,31 @@ static int tsens_register(struct tsens_priv *priv)
                if (priv->ops->enable)
                        priv->ops->enable(priv, i);
        }
-       return 0;
+
+       pdev = of_find_device_by_node(priv->dev->of_node);
+       if (!pdev)
+               return -ENODEV;
+
+       irq = platform_get_irq_byname(pdev, "uplow");
+       if (irq < 0) {
+               ret = irq;
+               goto err_put_device;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, irq,
+                                       NULL, tsens_irq_thread,
+                                       IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                       dev_name(&pdev->dev), priv);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to get irq\n", __func__);
+               goto err_put_device;
+       }
+
+       enable_irq_wake(irq);
+
+err_put_device:
+       put_device(&pdev->dev);
+       return ret;
 }
 
 static int tsens_probe(struct platform_device *pdev)
@@ -128,7 +158,7 @@ static int tsens_probe(struct platform_device *pdev)
                of_property_read_u32(np, "#qcom,sensors", &num_sensors);
 
        if (num_sensors <= 0) {
-               dev_err(dev, "invalid number of sensors\n");
+               dev_err(dev, "%s: invalid number of sensors\n", __func__);
                return -EINVAL;
        }
 
@@ -150,12 +180,14 @@ static int tsens_probe(struct platform_device *pdev)
        priv->feat = data->feat;
        priv->fields = data->fields;
 
+       platform_set_drvdata(pdev, priv);
+
        if (!priv->ops || !priv->ops->init || !priv->ops->get_temp)
                return -EINVAL;
 
        ret = priv->ops->init(priv);
        if (ret < 0) {
-               dev_err(dev, "tsens init failed\n");
+               dev_err(dev, "%s: init failed\n", __func__);
                return ret;
        }
 
@@ -163,22 +195,20 @@ static int tsens_probe(struct platform_device *pdev)
                ret = priv->ops->calibrate(priv);
                if (ret < 0) {
                        if (ret != -EPROBE_DEFER)
-                               dev_err(dev, "tsens calibration failed\n");
+                               dev_err(dev, "%s: calibration failed\n", __func__);
                        return ret;
                }
        }
 
-       ret = tsens_register(priv);
-
-       platform_set_drvdata(pdev, priv);
-
-       return ret;
+       return tsens_register(priv);
 }
 
 static int tsens_remove(struct platform_device *pdev)
 {
        struct tsens_priv *priv = platform_get_drvdata(pdev);
 
+       debugfs_remove_recursive(priv->debug_root);
+       tsens_disable_irq(priv);
        if (priv->ops->disable)
                priv->ops->disable(priv);
 
index b89083b..e24a865 100644 (file)
 #define CAL_DEGC_PT2           120
 #define SLOPE_FACTOR           1000
 #define SLOPE_DEFAULT          3200
+#define THRESHOLD_MAX_ADC_CODE 0x3ff
+#define THRESHOLD_MIN_ADC_CODE 0x0
 
-
+#include <linux/interrupt.h>
 #include <linux/thermal.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
@@ -27,12 +29,16 @@ enum tsens_ver {
        VER_2_X,
 };
 
+enum tsens_irq_type {
+       LOWER,
+       UPPER,
+};
+
 /**
  * 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
@@ -41,7 +47,6 @@ struct tsens_sensor {
        struct tsens_priv               *priv;
        struct thermal_zone_device      *tzd;
        int                             offset;
-       unsigned int                    id;
        unsigned int                    hw_id;
        int                             slope;
        u32                             status;
@@ -62,13 +67,13 @@ struct tsens_ops {
        /* mandatory callbacks */
        int (*init)(struct tsens_priv *priv);
        int (*calibrate)(struct tsens_priv *priv);
-       int (*get_temp)(struct tsens_priv *priv, int i, int *temp);
+       int (*get_temp)(struct tsens_sensor *s, int *temp);
        /* optional callbacks */
        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);
+       int (*get_trend)(struct tsens_sensor *s, enum thermal_trend *trend);
 };
 
 #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
@@ -102,22 +107,66 @@ struct tsens_ops {
        [_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 */
+#define REG_FIELD_SPLIT_BITS_0_15(_name, _offset)              \
+       [_name##_##0]  = REG_FIELD(_offset,  0,  0),            \
+       [_name##_##1]  = REG_FIELD(_offset,  1,  1),    \
+       [_name##_##2]  = REG_FIELD(_offset,  2,  2),    \
+       [_name##_##3]  = REG_FIELD(_offset,  3,  3),    \
+       [_name##_##4]  = REG_FIELD(_offset,  4,  4),    \
+       [_name##_##5]  = REG_FIELD(_offset,  5,  5),    \
+       [_name##_##6]  = REG_FIELD(_offset,  6,  6),    \
+       [_name##_##7]  = REG_FIELD(_offset,  7,  7),    \
+       [_name##_##8]  = REG_FIELD(_offset,  8,  8),    \
+       [_name##_##9]  = REG_FIELD(_offset,  9,  9),    \
+       [_name##_##10] = REG_FIELD(_offset, 10, 10),    \
+       [_name##_##11] = REG_FIELD(_offset, 11, 11),    \
+       [_name##_##12] = REG_FIELD(_offset, 12, 12),    \
+       [_name##_##13] = REG_FIELD(_offset, 13, 13),    \
+       [_name##_##14] = REG_FIELD(_offset, 14, 14),    \
+       [_name##_##15] = REG_FIELD(_offset, 15, 15)
+
+#define REG_FIELD_SPLIT_BITS_16_31(_name, _offset)             \
+       [_name##_##0]  = REG_FIELD(_offset, 16, 16),            \
+       [_name##_##1]  = REG_FIELD(_offset, 17, 17),    \
+       [_name##_##2]  = REG_FIELD(_offset, 18, 18),    \
+       [_name##_##3]  = REG_FIELD(_offset, 19, 19),    \
+       [_name##_##4]  = REG_FIELD(_offset, 20, 20),    \
+       [_name##_##5]  = REG_FIELD(_offset, 21, 21),    \
+       [_name##_##6]  = REG_FIELD(_offset, 22, 22),    \
+       [_name##_##7]  = REG_FIELD(_offset, 23, 23),    \
+       [_name##_##8]  = REG_FIELD(_offset, 24, 24),    \
+       [_name##_##9]  = REG_FIELD(_offset, 25, 25),    \
+       [_name##_##10] = REG_FIELD(_offset, 26, 26),    \
+       [_name##_##11] = REG_FIELD(_offset, 27, 27),    \
+       [_name##_##12] = REG_FIELD(_offset, 28, 28),    \
+       [_name##_##13] = REG_FIELD(_offset, 29, 29),    \
+       [_name##_##14] = REG_FIELD(_offset, 30, 30),    \
+       [_name##_##15] = REG_FIELD(_offset, 31, 31)
+
+/*
+ * reg_field IDs to use as an index into an array
+ * If you change the order of the entries, check the devm_regmap_field_alloc()
+ * calls in init_common()
+ */
 enum regfield_ids {
        /* ----- SROT ------ */
        /* HW_VER */
-       VER_MAJOR = 0,
+       VER_MAJOR,
        VER_MINOR,
        VER_STEP,
        /* CTRL_OFFSET */
-       TSENS_EN =  3,
+       TSENS_EN,
        TSENS_SW_RST,
        SENSOR_EN,
        CODE_OR_TEMP,
 
        /* ----- TM ------ */
+       /* TRDY */
+       TRDY,
+       /* INTERRUPT ENABLE */
+       INT_EN, /* v2+ has separate enables for crit, upper and lower irq */
        /* STATUS */
-       LAST_TEMP_0 = 7,        /* Last temperature reading */
+       LAST_TEMP_0,    /* Last temperature reading */
        LAST_TEMP_1,
        LAST_TEMP_2,
        LAST_TEMP_3,
@@ -133,7 +182,7 @@ enum regfield_ids {
        LAST_TEMP_13,
        LAST_TEMP_14,
        LAST_TEMP_15,
-       VALID_0 = 23,           /* VALID reading or not */
+       VALID_0,                /* VALID reading or not */
        VALID_1,
        VALID_2,
        VALID_3,
@@ -149,38 +198,6 @@ enum regfield_ids {
        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,
@@ -197,6 +214,70 @@ enum regfield_ids {
        LOWER_STATUS_13,
        LOWER_STATUS_14,
        LOWER_STATUS_15,
+       LOW_INT_STATUS_0,       /* LOWER interrupt status */
+       LOW_INT_STATUS_1,
+       LOW_INT_STATUS_2,
+       LOW_INT_STATUS_3,
+       LOW_INT_STATUS_4,
+       LOW_INT_STATUS_5,
+       LOW_INT_STATUS_6,
+       LOW_INT_STATUS_7,
+       LOW_INT_STATUS_8,
+       LOW_INT_STATUS_9,
+       LOW_INT_STATUS_10,
+       LOW_INT_STATUS_11,
+       LOW_INT_STATUS_12,
+       LOW_INT_STATUS_13,
+       LOW_INT_STATUS_14,
+       LOW_INT_STATUS_15,
+       LOW_INT_CLEAR_0,        /* LOWER interrupt clear */
+       LOW_INT_CLEAR_1,
+       LOW_INT_CLEAR_2,
+       LOW_INT_CLEAR_3,
+       LOW_INT_CLEAR_4,
+       LOW_INT_CLEAR_5,
+       LOW_INT_CLEAR_6,
+       LOW_INT_CLEAR_7,
+       LOW_INT_CLEAR_8,
+       LOW_INT_CLEAR_9,
+       LOW_INT_CLEAR_10,
+       LOW_INT_CLEAR_11,
+       LOW_INT_CLEAR_12,
+       LOW_INT_CLEAR_13,
+       LOW_INT_CLEAR_14,
+       LOW_INT_CLEAR_15,
+       LOW_INT_MASK_0, /* LOWER interrupt mask */
+       LOW_INT_MASK_1,
+       LOW_INT_MASK_2,
+       LOW_INT_MASK_3,
+       LOW_INT_MASK_4,
+       LOW_INT_MASK_5,
+       LOW_INT_MASK_6,
+       LOW_INT_MASK_7,
+       LOW_INT_MASK_8,
+       LOW_INT_MASK_9,
+       LOW_INT_MASK_10,
+       LOW_INT_MASK_11,
+       LOW_INT_MASK_12,
+       LOW_INT_MASK_13,
+       LOW_INT_MASK_14,
+       LOW_INT_MASK_15,
+       LOW_THRESH_0,           /* LOWER threshold values */
+       LOW_THRESH_1,
+       LOW_THRESH_2,
+       LOW_THRESH_3,
+       LOW_THRESH_4,
+       LOW_THRESH_5,
+       LOW_THRESH_6,
+       LOW_THRESH_7,
+       LOW_THRESH_8,
+       LOW_THRESH_9,
+       LOW_THRESH_10,
+       LOW_THRESH_11,
+       LOW_THRESH_12,
+       LOW_THRESH_13,
+       LOW_THRESH_14,
+       LOW_THRESH_15,
        UPPER_STATUS_0, /* UPPER threshold violated */
        UPPER_STATUS_1,
        UPPER_STATUS_2,
@@ -213,6 +294,70 @@ enum regfield_ids {
        UPPER_STATUS_13,
        UPPER_STATUS_14,
        UPPER_STATUS_15,
+       UP_INT_STATUS_0,        /* UPPER interrupt status */
+       UP_INT_STATUS_1,
+       UP_INT_STATUS_2,
+       UP_INT_STATUS_3,
+       UP_INT_STATUS_4,
+       UP_INT_STATUS_5,
+       UP_INT_STATUS_6,
+       UP_INT_STATUS_7,
+       UP_INT_STATUS_8,
+       UP_INT_STATUS_9,
+       UP_INT_STATUS_10,
+       UP_INT_STATUS_11,
+       UP_INT_STATUS_12,
+       UP_INT_STATUS_13,
+       UP_INT_STATUS_14,
+       UP_INT_STATUS_15,
+       UP_INT_CLEAR_0, /* UPPER interrupt clear */
+       UP_INT_CLEAR_1,
+       UP_INT_CLEAR_2,
+       UP_INT_CLEAR_3,
+       UP_INT_CLEAR_4,
+       UP_INT_CLEAR_5,
+       UP_INT_CLEAR_6,
+       UP_INT_CLEAR_7,
+       UP_INT_CLEAR_8,
+       UP_INT_CLEAR_9,
+       UP_INT_CLEAR_10,
+       UP_INT_CLEAR_11,
+       UP_INT_CLEAR_12,
+       UP_INT_CLEAR_13,
+       UP_INT_CLEAR_14,
+       UP_INT_CLEAR_15,
+       UP_INT_MASK_0,          /* UPPER interrupt mask */
+       UP_INT_MASK_1,
+       UP_INT_MASK_2,
+       UP_INT_MASK_3,
+       UP_INT_MASK_4,
+       UP_INT_MASK_5,
+       UP_INT_MASK_6,
+       UP_INT_MASK_7,
+       UP_INT_MASK_8,
+       UP_INT_MASK_9,
+       UP_INT_MASK_10,
+       UP_INT_MASK_11,
+       UP_INT_MASK_12,
+       UP_INT_MASK_13,
+       UP_INT_MASK_14,
+       UP_INT_MASK_15,
+       UP_THRESH_0,            /* UPPER threshold values */
+       UP_THRESH_1,
+       UP_THRESH_2,
+       UP_THRESH_3,
+       UP_THRESH_4,
+       UP_THRESH_5,
+       UP_THRESH_6,
+       UP_THRESH_7,
+       UP_THRESH_8,
+       UP_THRESH_9,
+       UP_THRESH_10,
+       UP_THRESH_11,
+       UP_THRESH_12,
+       UP_THRESH_13,
+       UP_THRESH_14,
+       UP_THRESH_15,
        CRITICAL_STATUS_0,      /* CRITICAL threshold violated */
        CRITICAL_STATUS_1,
        CRITICAL_STATUS_2,
@@ -229,13 +374,38 @@ enum regfield_ids {
        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 */
+       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,
 
        /* Keep last */
        MAX_REGFIELDS
@@ -295,6 +465,8 @@ struct tsens_context {
  * @feat: features of the IP
  * @fields: bitfield locations
  * @ops: pointer to list of callbacks supported by this device
+ * @debug_root: pointer to debugfs dentry for all tsens
+ * @debug: pointer to debugfs dentry for tsens controller
  * @sensor: list of sensors attached to this device
  */
 struct tsens_priv {
@@ -303,19 +475,31 @@ struct tsens_priv {
        struct regmap                   *tm_map;
        struct regmap                   *srot_map;
        u32                             tm_offset;
+
+       /* lock for upper/lower threshold interrupts */
+       spinlock_t                      ul_lock;
+
        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 dentry                   *debug_root;
+       struct dentry                   *debug;
+
        struct tsens_sensor             sensor[0];
 };
 
 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);
+int get_temp_tsens_valid(struct tsens_sensor *s, int *temp);
+int get_temp_common(struct tsens_sensor *s, int *temp);
+int tsens_enable_irq(struct tsens_priv *priv);
+void tsens_disable_irq(struct tsens_priv *priv);
+int tsens_set_trips(void *_sensor, int low, int high);
+irqreturn_t tsens_irq_thread(int irq, void *data);
 
 /* TSENS target */
 extern const struct tsens_plat_data data_8960;
@@ -324,7 +508,7 @@ extern const struct tsens_plat_data data_8960;
 extern const struct tsens_plat_data data_8916, data_8974;
 
 /* TSENS v1 targets */
-extern const struct tsens_plat_data data_tsens_v1;
+extern const struct tsens_plat_data data_tsens_v1, data_8976;
 
 /* TSENS v2 targets */
 extern const struct tsens_plat_data data_8996, data_tsens_v2;
index 39542c6..45e9fcb 100644 (file)
 
 #include "thermal_core.h"
 
-#define SITES_MAX      16
+#define SITES_MAX              16
+#define TMR_DISABLE            0x0
+#define TMR_ME                 0x80000000
+#define TMR_ALPF               0x0c000000
+#define TMR_ALPF_V2            0x03000000
+#define TMTMIR_DEFAULT 0x0000000f
+#define TIER_DISABLE   0x0
+#define TEUMR0_V2              0x51009c00
+#define TMU_VER1               0x1
+#define TMU_VER2               0x2
 
 /*
  * QorIQ TMU Registers
@@ -24,17 +33,12 @@ struct qoriq_tmu_site_regs {
        u8 res0[0x8];
 };
 
-struct qoriq_tmu_regs {
+struct qoriq_tmu_regs_v1 {
        u32 tmr;                /* Mode Register */
-#define TMR_DISABLE    0x0
-#define TMR_ME         0x80000000
-#define TMR_ALPF       0x0c000000
        u32 tsr;                /* Status Register */
        u32 tmtmir;             /* Temperature measurement interval Register */
-#define TMTMIR_DEFAULT 0x0000000f
        u8 res0[0x14];
        u32 tier;               /* Interrupt Enable Register */
-#define TIER_DISABLE   0x0
        u32 tidr;               /* Interrupt Detect Register */
        u32 tiscr;              /* Interrupt Site Capture Register */
        u32 ticscr;             /* Interrupt Critical Site Capture Register */
@@ -54,10 +58,50 @@ struct qoriq_tmu_regs {
        u32 ipbrr0;             /* IP Block Revision Register 0 */
        u32 ipbrr1;             /* IP Block Revision Register 1 */
        u8 res6[0x310];
-       u32 ttr0cr;             /* Temperature Range 0 Control Register */
-       u32 ttr1cr;             /* Temperature Range 1 Control Register */
-       u32 ttr2cr;             /* Temperature Range 2 Control Register */
-       u32 ttr3cr;             /* Temperature Range 3 Control Register */
+       u32 ttrcr[4];           /* Temperature Range Control Register */
+};
+
+struct qoriq_tmu_regs_v2 {
+       u32 tmr;                /* Mode Register */
+       u32 tsr;                /* Status Register */
+       u32 tmsr;               /* monitor site register */
+       u32 tmtmir;             /* Temperature measurement interval Register */
+       u8 res0[0x10];
+       u32 tier;               /* Interrupt Enable Register */
+       u32 tidr;               /* Interrupt Detect Register */
+       u8 res1[0x8];
+       u32 tiiscr;             /* interrupt immediate site capture register */
+       u32 tiascr;             /* interrupt average site capture register */
+       u32 ticscr;             /* Interrupt Critical Site Capture Register */
+       u32 res2;
+       u32 tmhtcr;             /* monitor high temperature capture register */
+       u32 tmltcr;             /* monitor low temperature capture register */
+       u32 tmrtrcr;    /* monitor rising temperature rate capture register */
+       u32 tmftrcr;    /* monitor falling temperature rate capture register */
+       u32 tmhtitr;    /* High Temperature Immediate Threshold */
+       u32 tmhtatr;    /* High Temperature Average Threshold */
+       u32 tmhtactr;   /* High Temperature Average Crit Threshold */
+       u32 res3;
+       u32 tmltitr;    /* monitor low temperature immediate threshold */
+       u32 tmltatr;    /* monitor low temperature average threshold register */
+       u32 tmltactr;   /* monitor low temperature average critical threshold */
+       u32 res4;
+       u32 tmrtrctr;   /* monitor rising temperature rate critical threshold */
+       u32 tmftrctr;   /* monitor falling temperature rate critical threshold*/
+       u8 res5[0x8];
+       u32 ttcfgr;     /* Temperature Configuration Register */
+       u32 tscfgr;     /* Sensor Configuration Register */
+       u8 res6[0x78];
+       struct qoriq_tmu_site_regs site[SITES_MAX];
+       u8 res7[0x9f8];
+       u32 ipbrr0;             /* IP Block Revision Register 0 */
+       u32 ipbrr1;             /* IP Block Revision Register 1 */
+       u8 res8[0x300];
+       u32 teumr0;
+       u32 teumr1;
+       u32 teumr2;
+       u32 res9;
+       u32 ttrcr[4];   /* Temperature Range Control Register */
 };
 
 struct qoriq_tmu_data;
@@ -72,7 +116,9 @@ struct qoriq_sensor {
 };
 
 struct qoriq_tmu_data {
-       struct qoriq_tmu_regs __iomem *regs;
+       int ver;
+       struct qoriq_tmu_regs_v1 __iomem *regs;
+       struct qoriq_tmu_regs_v2 __iomem *regs_v2;
        struct clk *clk;
        bool little_endian;
        struct qoriq_sensor     *sensor[SITES_MAX];
@@ -132,12 +178,23 @@ static int qoriq_tmu_register_tmu_zone(struct platform_device *pdev)
                                return PTR_ERR(qdata->sensor[id]->tzd);
                }
 
-               sites |= 0x1 << (15 - id);
+               if (qdata->ver == TMU_VER1)
+                       sites |= 0x1 << (15 - id);
+               else
+                       sites |= 0x1 << id;
        }
 
        /* Enable monitoring */
-       if (sites != 0)
-               tmu_write(qdata, sites | TMR_ME | TMR_ALPF, &qdata->regs->tmr);
+       if (sites != 0) {
+               if (qdata->ver == TMU_VER1) {
+                       tmu_write(qdata, sites | TMR_ME | TMR_ALPF,
+                                       &qdata->regs->tmr);
+               } else {
+                       tmu_write(qdata, sites, &qdata->regs_v2->tmsr);
+                       tmu_write(qdata, TMR_ME | TMR_ALPF_V2,
+                                       &qdata->regs_v2->tmr);
+               }
+       }
 
        return 0;
 }
@@ -150,16 +207,21 @@ static int qoriq_tmu_calibration(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
 
-       if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) {
-               dev_err(&pdev->dev, "missing calibration range.\n");
-               return -ENODEV;
+       len = of_property_count_u32_elems(np, "fsl,tmu-range");
+       if (len < 0 || len > 4) {
+               dev_err(&pdev->dev, "invalid range data.\n");
+               return len;
+       }
+
+       val = of_property_read_u32_array(np, "fsl,tmu-range", range, len);
+       if (val != 0) {
+               dev_err(&pdev->dev, "failed to read range data.\n");
+               return val;
        }
 
        /* Init temperature range registers */
-       tmu_write(data, range[0], &data->regs->ttr0cr);
-       tmu_write(data, range[1], &data->regs->ttr1cr);
-       tmu_write(data, range[2], &data->regs->ttr2cr);
-       tmu_write(data, range[3], &data->regs->ttr3cr);
+       for (i = 0; i < len; i++)
+               tmu_write(data, range[i], &data->regs->ttrcr[i]);
 
        calibration = of_get_property(np, "fsl,tmu-calibration", &len);
        if (calibration == NULL || len % 8) {
@@ -183,7 +245,12 @@ static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
        tmu_write(data, TIER_DISABLE, &data->regs->tier);
 
        /* Set update_interval */
-       tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
+       if (data->ver == TMU_VER1) {
+               tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
+       } else {
+               tmu_write(data, TMTMIR_DEFAULT, &data->regs_v2->tmtmir);
+               tmu_write(data, TEUMR0_V2, &data->regs_v2->teumr0);
+       }
 
        /* Disable monitoring */
        tmu_write(data, TMR_DISABLE, &data->regs->tmr);
@@ -192,6 +259,7 @@ static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
 static int qoriq_tmu_probe(struct platform_device *pdev)
 {
        int ret;
+       u32 ver;
        struct qoriq_tmu_data *data;
        struct device_node *np = pdev->dev.of_node;
 
@@ -220,6 +288,12 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* version register offset at: 0xbf8 on both v1 and v2 */
+       ver = tmu_read(data, &data->regs->ipbrr0);
+       data->ver = (ver >> 8) & 0xff;
+       if (data->ver == TMU_VER2)
+               data->regs_v2 = (void __iomem *)data->regs;
+
        qoriq_tmu_init_device(data);    /* TMU initialization */
 
        ret = qoriq_tmu_calibration(pdev);      /* TMU calibration */
index 755d2b5..1460cf9 100644 (file)
@@ -314,6 +314,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
                .compatible = "renesas,r8a774a1-thermal",
                .data = &rcar_gen3_ths_tj_1_m3_w,
        },
+       {
+               .compatible = "renesas,r8a774b1-thermal",
+               .data = &rcar_gen3_ths_tj_1,
+       },
        {
                .compatible = "renesas,r8a7795-thermal",
                .data = &rcar_gen3_ths_tj_1,
index dcecf2e..ae5743c 100644 (file)
@@ -134,7 +134,8 @@ static int gadc_thermal_probe(struct platform_device *pdev)
        gti->channel = devm_iio_channel_get(&pdev->dev, "sensor-channel");
        if (IS_ERR(gti->channel)) {
                ret = PTR_ERR(gti->channel);
-               dev_err(&pdev->dev, "IIO channel not found: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "IIO channel not found: %d\n", ret);
                return ret;
        }
 
@@ -142,8 +143,10 @@ static int gadc_thermal_probe(struct platform_device *pdev)
                                                           &gadc_thermal_ops);
        if (IS_ERR(gti->tz_dev)) {
                ret = PTR_ERR(gti->tz_dev);
-               dev_err(&pdev->dev, "Thermal zone sensor register failed: %d\n",
-                       ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "Thermal zone sensor register failed: %d\n",
+                               ret);
                return ret;
        }
 
index d4481cc..9a321dc 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/reboot.h>
 #include <linux/string.h>
 #include <linux/of.h>
-#include <net/netlink.h>
-#include <net/genetlink.h>
 #include <linux/suspend.h>
 
 #define CREATE_TRACE_POINTS
@@ -304,7 +302,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
                                 &tz->poll_queue,
                                 msecs_to_jiffies(delay));
        else
-               cancel_delayed_work_sync(&tz->poll_queue);
+               cancel_delayed_work(&tz->poll_queue);
 }
 
 static void monitor_thermal_zone(struct thermal_zone_device *tz)
@@ -1414,7 +1412,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 
        mutex_unlock(&thermal_list_lock);
 
-       thermal_zone_device_set_polling(tz, 0);
+       cancel_delayed_work_sync(&tz->poll_queue);
 
        thermal_set_governor(tz, NULL);
 
@@ -1464,97 +1462,6 @@ exit:
 }
 EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
 
-#ifdef CONFIG_NET
-static const struct genl_multicast_group thermal_event_mcgrps[] = {
-       { .name = THERMAL_GENL_MCAST_GROUP_NAME, },
-};
-
-static struct genl_family thermal_event_genl_family __ro_after_init = {
-       .module = THIS_MODULE,
-       .name = THERMAL_GENL_FAMILY_NAME,
-       .version = THERMAL_GENL_VERSION,
-       .maxattr = THERMAL_GENL_ATTR_MAX,
-       .mcgrps = thermal_event_mcgrps,
-       .n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps),
-};
-
-int thermal_generate_netlink_event(struct thermal_zone_device *tz,
-                                  enum events event)
-{
-       struct sk_buff *skb;
-       struct nlattr *attr;
-       struct thermal_genl_event *thermal_event;
-       void *msg_header;
-       int size;
-       int result;
-       static unsigned int thermal_event_seqnum;
-
-       if (!tz)
-               return -EINVAL;
-
-       /* allocate memory */
-       size = nla_total_size(sizeof(struct thermal_genl_event)) +
-              nla_total_size(0);
-
-       skb = genlmsg_new(size, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       /* add the genetlink message header */
-       msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
-                                &thermal_event_genl_family, 0,
-                                THERMAL_GENL_CMD_EVENT);
-       if (!msg_header) {
-               nlmsg_free(skb);
-               return -ENOMEM;
-       }
-
-       /* fill the data */
-       attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
-                          sizeof(struct thermal_genl_event));
-
-       if (!attr) {
-               nlmsg_free(skb);
-               return -EINVAL;
-       }
-
-       thermal_event = nla_data(attr);
-       if (!thermal_event) {
-               nlmsg_free(skb);
-               return -EINVAL;
-       }
-
-       memset(thermal_event, 0, sizeof(struct thermal_genl_event));
-
-       thermal_event->orig = tz->id;
-       thermal_event->event = event;
-
-       /* send multicast genetlink message */
-       genlmsg_end(skb, msg_header);
-
-       result = genlmsg_multicast(&thermal_event_genl_family, skb, 0,
-                                  0, GFP_ATOMIC);
-       if (result)
-               dev_err(&tz->device, "Failed to send netlink event:%d", result);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(thermal_generate_netlink_event);
-
-static int __init genetlink_init(void)
-{
-       return genl_register_family(&thermal_event_genl_family);
-}
-
-static void genetlink_exit(void)
-{
-       genl_unregister_family(&thermal_event_genl_family);
-}
-#else /* !CONFIG_NET */
-static inline int genetlink_init(void) { return 0; }
-static inline void genetlink_exit(void) {}
-#endif /* !CONFIG_NET */
-
 static int thermal_pm_notify(struct notifier_block *nb,
                             unsigned long mode, void *_unused)
 {
@@ -1607,13 +1514,9 @@ static int __init thermal_init(void)
        if (result)
                goto unregister_governors;
 
-       result = genetlink_init();
-       if (result)
-               goto unregister_class;
-
        result = of_parse_thermal_zones();
        if (result)
-               goto exit_netlink;
+               goto unregister_class;
 
        result = register_pm_notifier(&thermal_pm_nb);
        if (result)
@@ -1622,8 +1525,6 @@ static int __init thermal_init(void)
 
        return 0;
 
-exit_netlink:
-       genetlink_exit();
 unregister_class:
        class_unregister(&thermal_class);
 unregister_governors:
@@ -1636,4 +1537,4 @@ error:
        mutex_destroy(&poweroff_lock);
        return result;
 }
-fs_initcall(thermal_init);
+core_initcall(thermal_init);
index 40524fa..d0bdf1e 100644 (file)
@@ -110,7 +110,6 @@ 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),
        },
 };
index c7623f9..a312cb3 100644 (file)
@@ -82,20 +82,20 @@ config HW_CONSOLE
        default y
 
 config VT_HW_CONSOLE_BINDING
-       bool "Support for binding and unbinding console drivers"
-       depends on HW_CONSOLE
-       ---help---
-         The virtual terminal is the device that interacts with the physical
-         terminal through console drivers. On these systems, at least one
-         console driver is loaded. In other configurations, additional console
-         drivers may be enabled, such as the framebuffer console. If more than
-         1 console driver is enabled, setting this to 'y' will allow you to
-         select the console driver that will serve as the backend for the
-         virtual terminals.
-
-        See <file:Documentation/driver-api/console.rst> for more
-        information. For framebuffer console users, please refer to
-        <file:Documentation/fb/fbcon.rst>.
+       bool "Support for binding and unbinding console drivers"
+       depends on HW_CONSOLE
+       ---help---
+         The virtual terminal is the device that interacts with the physical
+         terminal through console drivers. On these systems, at least one
+         console driver is loaded. In other configurations, additional console
+         drivers may be enabled, such as the framebuffer console. If more than
+         1 console driver is enabled, setting this to 'y' will allow you to
+         select the console driver that will serve as the backend for the
+         virtual terminals.
+
+         See <file:Documentation/driver-api/console.rst> for more
+         information. For framebuffer console users, please refer to
+         <file:Documentation/fb/fbcon.rst>.
 
 config UNIX98_PTYS
        bool "Unix98 PTY support" if EXPERT
@@ -173,15 +173,15 @@ config ROCKETPORT
        depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
        help
          This driver supports Comtrol RocketPort and RocketModem PCI boards.   
-          These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
-          modems.  For information about the RocketPort/RocketModem  boards
-          and this driver read <file:Documentation/driver-api/serial/rocket.rst>.
+         These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
+         modems.  For information about the RocketPort/RocketModem  boards
+         and this driver read <file:Documentation/driver-api/serial/rocket.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called rocket.
 
          If you want to compile this driver into the kernel, say Y here.  If
-          you don't have a Comtrol RocketPort/RocketModem card installed, say N.
+         you don't have a Comtrol RocketPort/RocketModem card installed, say N.
 
 config CYCLADES
        tristate "Cyclades async mux support"
@@ -437,8 +437,8 @@ config MIPS_EJTAG_FDC_KGDB
        depends on MIPS_EJTAG_FDC_TTY && KGDB
        default y
        help
-          This enables the use of KGDB over an FDC channel, allowing KGDB to be
-          used remotely or when a serial port isn't available.
+         This enables the use of KGDB over an FDC channel, allowing KGDB to be
+         used remotely or when a serial port isn't available.
 
 config MIPS_EJTAG_FDC_KGDB_CHAN
        int "KGDB FDC channel"
index 8330fd8..13f63c0 100644 (file)
  *
  */
 
-/*
- * Serial driver configuration section.  Here are the various options:
- *
- * SERIAL_PARANOIA_CHECK
- *             Check the magic number for the async_structure where
- *             ever possible.
- */
-
 #include <linux/delay.h>
 
-#undef SERIAL_PARANOIA_CHECK
-
 /* Set of debugging defines */
 
 #undef SERIAL_DEBUG_INTR
@@ -132,28 +122,6 @@ static struct serial_state rs_table[1];
 
 #define serial_isroot()        (capable(CAP_SYS_ADMIN))
 
-
-static inline int serial_paranoia_check(struct serial_state *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char *badmagic =
-               "Warning: bad magic number for serial struct (%s) in %s\n";
-       static const char *badinfo =
-               "Warning: null async_struct for (%s) in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
 /* some serial hardware definitions */
 #define SDR_OVRUN   (1<<15)
 #define SDR_RBF     (1<<14)
@@ -189,9 +157,6 @@ static void rs_stop(struct tty_struct *tty)
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-
        local_irq_save(flags);
        if (info->IER & UART_IER_THRI) {
                info->IER &= ~UART_IER_THRI;
@@ -209,9 +174,6 @@ static void rs_start(struct tty_struct *tty)
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_start"))
-               return;
-
        local_irq_save(flags);
        if (info->xmit.head != info->xmit.tail
            && info->xmit.buf
@@ -783,9 +745,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 
        info = tty->driver_data;
 
-       if (serial_paranoia_check(info, tty->name, "rs_put_char"))
-               return 0;
-
        if (!info->xmit.buf)
                return 0;
 
@@ -808,9 +767,6 @@ static void rs_flush_chars(struct tty_struct *tty)
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-               return;
-
        if (info->xmit.head == info->xmit.tail
            || tty->stopped
            || tty->hw_stopped
@@ -833,9 +789,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
        if (!info->xmit.buf)
                return 0;
 
@@ -878,8 +831,6 @@ static int rs_write_room(struct tty_struct *tty)
 {
        struct serial_state *info = tty->driver_data;
 
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
        return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
@@ -887,8 +838,6 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 {
        struct serial_state *info = tty->driver_data;
 
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
        return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
@@ -897,8 +846,6 @@ static void rs_flush_buffer(struct tty_struct *tty)
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
        local_irq_save(flags);
        info->xmit.head = info->xmit.tail = 0;
        local_irq_restore(flags);
@@ -914,9 +861,6 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
        struct serial_state *info = tty->driver_data;
         unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_send_xchar"))
-               return;
-
        info->x_char = ch;
        if (ch) {
                /* Make sure transmit interrupts are on */
@@ -952,9 +896,6 @@ static void rs_throttle(struct tty_struct * tty)
        printk("throttle %s ....\n", tty_name(tty));
 #endif
 
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-
        if (I_IXOFF(tty))
                rs_send_xchar(tty, STOP_CHAR(tty));
 
@@ -974,9 +915,6 @@ static void rs_unthrottle(struct tty_struct * tty)
        printk("unthrottle %s ....\n", tty_name(tty));
 #endif
 
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-
        if (I_IXOFF(tty)) {
                if (info->x_char)
                        info->x_char = 0;
@@ -1109,8 +1047,6 @@ static int rs_tiocmget(struct tty_struct *tty)
        unsigned char control, status;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
        if (tty_io_error(tty))
                return -EIO;
 
@@ -1131,8 +1067,6 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
        if (tty_io_error(tty))
                return -EIO;
 
@@ -1155,12 +1089,8 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
  */
 static int rs_break(struct tty_struct *tty, int break_state)
 {
-       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_break"))
-               return -EINVAL;
-
        local_irq_save(flags);
        if (break_state == -1)
          custom.adkcon = AC_SETCLR | AC_UARTBRK;
@@ -1212,9 +1142,6 @@ static int rs_ioctl(struct tty_struct *tty,
        DEFINE_WAIT(wait);
        int ret;
 
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
        if ((cmd != TIOCSERCONFIG) &&
            (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
                if (tty_io_error(tty))
@@ -1333,9 +1260,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        struct serial_state *state = tty->driver_data;
        struct tty_port *port = &state->tport;
 
-       if (serial_paranoia_check(state, tty->name, "rs_close"))
-               return;
-
        if (tty_port_close_start(port, tty, filp) == 0)
                return;
 
@@ -1379,9 +1303,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
        unsigned long orig_jiffies, char_time;
        int lsr;
 
-       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-               return;
-
        if (info->xmit_fifo_size == 0)
                return; /* Just in case.... */
 
@@ -1440,9 +1361,6 @@ static void rs_hangup(struct tty_struct *tty)
 {
        struct serial_state *info = tty->driver_data;
 
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-
        rs_flush_buffer(tty);
        shutdown(tty, info);
        info->tport.count = 0;
@@ -1467,8 +1385,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
        port->tty = tty;
        tty->driver_data = info;
        tty->port = port;
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
 
        port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
index 4487a6b..6a3c97d 100644 (file)
@@ -70,22 +70,22 @@ config HVC_XEN_FRONTEND
          Xen driver for secondary virtual consoles
 
 config HVC_UDBG
-       bool "udbg based fake hypervisor console"
-       depends on PPC
-       select HVC_DRIVER
-       help
-         This is meant to be used during HW bring up or debugging when
-        no other console mechanism exist but udbg, to get you a quick
-        console for userspace. Do NOT enable in production kernels. 
+       bool "udbg based fake hypervisor console"
+       depends on PPC
+       select HVC_DRIVER
+       help
+         This is meant to be used during HW bring up or debugging when
+         no other console mechanism exist but udbg, to get you a quick
+         console for userspace. Do NOT enable in production kernels.
 
 config HVC_DCC
-       bool "ARM JTAG DCC console"
-       depends on ARM || ARM64
-       select HVC_DRIVER
-       help
-         This console uses the JTAG DCC on ARM to create a console under the HVC
-        driver. This console is used through a JTAG only on ARM. If you don't have
-        a JTAG then you probably don't want this option.
+       bool "ARM JTAG DCC console"
+       depends on ARM || ARM64
+       select HVC_DRIVER
+       help
+         This console uses the JTAG DCC on ARM to create a console under the HVC
+         driver. This console is used through a JTAG only on ARM. If you don't have
+         a JTAG then you probably don't want this option.
 
 config HVC_RISCV_SBI
        bool "RISC-V SBI console support"
index 02629a1..8e0edb7 100644 (file)
@@ -1,7 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.  */
 
+#include <linux/console.h>
 #include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
 
 #include <asm/dcc.h>
 #include <asm/processor.h>
 #define DCC_STATUS_RX          (1 << 30)
 #define DCC_STATUS_TX          (1 << 29)
 
+static void dcc_uart_console_putchar(struct uart_port *port, int ch)
+{
+       while (__dcc_getstatus() & DCC_STATUS_TX)
+               cpu_relax();
+
+       __dcc_putchar(ch);
+}
+
+static void dcc_early_write(struct console *con, const char *s, unsigned n)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, n, dcc_uart_console_putchar);
+}
+
+static int __init dcc_early_console_setup(struct earlycon_device *device,
+                                         const char *opt)
+{
+       device->con->write = dcc_early_write;
+
+       return 0;
+}
+
+EARLYCON_DECLARE(dcc, dcc_early_console_setup);
+
 static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
 {
        int i;
index 5ba6816..fbaa4ec 100644 (file)
@@ -1222,22 +1222,28 @@ static int set_config(struct tty_struct *tty, struct r_port *info,
  */
 static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
 {
-       struct rocket_ports tmp;
-       int board;
+       struct rocket_ports *tmp;
+       int board, ret = 0;
 
-       memset(&tmp, 0, sizeof (tmp));
-       tmp.tty_major = rocket_driver->major;
+       tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       tmp->tty_major = rocket_driver->major;
 
        for (board = 0; board < 4; board++) {
-               tmp.rocketModel[board].model = rocketModel[board].model;
-               strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
-               tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
-               tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
-               tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
-       }
-       if (copy_to_user(retports, &tmp, sizeof (*retports)))
-               return -EFAULT;
-       return 0;
+               tmp->rocketModel[board].model = rocketModel[board].model;
+               strcpy(tmp->rocketModel[board].modelString,
+                      rocketModel[board].modelString);
+               tmp->rocketModel[board].numPorts = rocketModel[board].numPorts;
+               tmp->rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
+               tmp->rocketModel[board].startingPortNumber =
+                       rocketModel[board].startingPortNumber;
+       }
+       if (copy_to_user(retports, tmp, sizeof(*retports)))
+               ret = -EFAULT;
+       kfree(tmp);
+       return ret;
 }
 
 static int reset_rm2(struct r_port *info, void __user *arg)
index a0ac16e..226adee 100644 (file)
@@ -552,16 +552,97 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
 }
 
 #ifdef CONFIG_ACPI
+
+#define SERDEV_ACPI_MAX_SCAN_DEPTH 32
+
+struct acpi_serdev_lookup {
+       acpi_handle device_handle;
+       acpi_handle controller_handle;
+       int n;
+       int index;
+};
+
+static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data)
+{
+       struct acpi_serdev_lookup *lookup = data;
+       struct acpi_resource_uart_serialbus *sb;
+       acpi_status status;
+
+       if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+               return 1;
+
+       if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART)
+               return 1;
+
+       if (lookup->index != -1 && lookup->n++ != lookup->index)
+               return 1;
+
+       sb = &ares->data.uart_serial_bus;
+
+       status = acpi_get_handle(lookup->device_handle,
+                                sb->resource_source.string_ptr,
+                                &lookup->controller_handle);
+       if (ACPI_FAILURE(status))
+               return 1;
+
+       /*
+        * NOTE: Ideally, we would also want to retreive other properties here,
+        * once setting them before opening the device is supported by serdev.
+        */
+
+       return 1;
+}
+
+static int acpi_serdev_do_lookup(struct acpi_device *adev,
+                                 struct acpi_serdev_lookup *lookup)
+{
+       struct list_head resource_list;
+       int ret;
+
+       lookup->device_handle = acpi_device_handle(adev);
+       lookup->controller_handle = NULL;
+       lookup->n = 0;
+
+       INIT_LIST_HEAD(&resource_list);
+       ret = acpi_dev_get_resources(adev, &resource_list,
+                                    acpi_serdev_parse_resource, lookup);
+       acpi_dev_free_resource_list(&resource_list);
+
+       if (ret < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int acpi_serdev_check_resources(struct serdev_controller *ctrl,
+                                      struct acpi_device *adev)
+{
+       struct acpi_serdev_lookup lookup;
+       int ret;
+
+       if (acpi_bus_get_status(adev) || !adev->status.present)
+               return -EINVAL;
+
+       /* Look for UARTSerialBusV2 resource */
+       lookup.index = -1;      // we only care for the last device
+
+       ret = acpi_serdev_do_lookup(adev, &lookup);
+       if (ret)
+               return ret;
+
+       /* Make sure controller and ResourceSource handle match */
+       if (ACPI_HANDLE(ctrl->dev.parent) != lookup.controller_handle)
+               return -ENODEV;
+
+       return 0;
+}
+
 static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl,
-                                           struct acpi_device *adev)
+                                              struct acpi_device *adev)
 {
-       struct serdev_device *serdev = NULL;
+       struct serdev_device *serdev;
        int err;
 
-       if (acpi_bus_get_status(adev) || !adev->status.present ||
-           acpi_device_enumerated(adev))
-               return AE_OK;
-
        serdev = serdev_device_alloc(ctrl);
        if (!serdev) {
                dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n",
@@ -583,7 +664,7 @@ static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl,
 }
 
 static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
-                                      void *data, void **return_value)
+                                         void *data, void **return_value)
 {
        struct serdev_controller *ctrl = data;
        struct acpi_device *adev;
@@ -591,22 +672,28 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
        if (acpi_bus_get_device(handle, &adev))
                return AE_OK;
 
+       if (acpi_device_enumerated(adev))
+               return AE_OK;
+
+       if (acpi_serdev_check_resources(ctrl, adev))
+               return AE_OK;
+
        return acpi_serdev_register_device(ctrl, adev);
 }
 
+
 static int acpi_serdev_register_devices(struct serdev_controller *ctrl)
 {
        acpi_status status;
-       acpi_handle handle;
 
-       handle = ACPI_HANDLE(ctrl->dev.parent);
-       if (!handle)
+       if (!has_acpi_companion(ctrl->dev.parent))
                return -ENODEV;
 
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                                    SERDEV_ACPI_MAX_SCAN_DEPTH,
                                     acpi_serdev_add_device, NULL, ctrl, NULL);
        if (ACPI_FAILURE(status))
-               dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n");
+               dev_warn(&ctrl->dev, "failed to enumerate serdev slaves\n");
 
        if (!ctrl->serdev)
                return -ENODEV;
index 0438d9a..6e67fd8 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/clk.h>
@@ -22,6 +24,7 @@
 
 #define ASPEED_VUART_GCRA              0x20
 #define ASPEED_VUART_GCRA_VUART_EN             BIT(0)
+#define ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY   BIT(1)
 #define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
 #define ASPEED_VUART_GCRB              0x24
 #define ASPEED_VUART_GCRB_HOST_SIRQ_MASK       GENMASK(7, 4)
@@ -131,8 +134,53 @@ static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR_RW(sirq);
 
+static ssize_t sirq_polarity_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct aspeed_vuart *vuart = dev_get_drvdata(dev);
+       u8 reg;
+
+       reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+       reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
+
+       return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0);
+}
+
+static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart,
+                                          bool polarity)
+{
+       u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+
+       if (polarity)
+               reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
+       else
+               reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
+
+       writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+}
+
+static ssize_t sirq_polarity_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct aspeed_vuart *vuart = dev_get_drvdata(dev);
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 0, &val);
+       if (err)
+               return err;
+
+       aspeed_vuart_set_sirq_polarity(vuart, val != 0);
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(sirq_polarity);
+
 static struct attribute *aspeed_vuart_attrs[] = {
        &dev_attr_sirq.attr,
+       &dev_attr_sirq_polarity.attr,
        &dev_attr_lpc_address.attr,
        NULL,
 };
@@ -302,8 +350,30 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
        return 1;
 }
 
+static void aspeed_vuart_auto_configure_sirq_polarity(
+       struct aspeed_vuart *vuart, struct device_node *syscon_np,
+       u32 reg_offset, u32 reg_mask)
+{
+       struct regmap *regmap;
+       u32 value;
+
+       regmap = syscon_node_to_regmap(syscon_np);
+       if (IS_ERR(regmap)) {
+               dev_warn(vuart->dev,
+                        "could not get regmap for aspeed,sirq-polarity-sense\n");
+               return;
+       }
+       if (regmap_read(regmap, reg_offset, &value)) {
+               dev_warn(vuart->dev, "could not read hw strap table\n");
+               return;
+       }
+
+       aspeed_vuart_set_sirq_polarity(vuart, (value & reg_mask) == 0);
+}
+
 static int aspeed_vuart_probe(struct platform_device *pdev)
 {
+       struct of_phandle_args sirq_polarity_sense_args;
        struct uart_8250_port port;
        struct aspeed_vuart *vuart;
        struct device_node *np;
@@ -402,6 +472,20 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
 
        vuart->line = rc;
 
+       rc = of_parse_phandle_with_fixed_args(
+               np, "aspeed,sirq-polarity-sense", 2, 0,
+               &sirq_polarity_sense_args);
+       if (rc < 0) {
+               dev_dbg(&pdev->dev,
+                       "aspeed,sirq-polarity-sense property not found\n");
+       } else {
+               aspeed_vuart_auto_configure_sirq_polarity(
+                       vuart, sirq_polarity_sense_args.np,
+                       sirq_polarity_sense_args.args[0],
+                       BIT(sirq_polarity_sense_args.args[1]));
+               of_node_put(sirq_polarity_sense_args.np);
+       }
+
        aspeed_vuart_set_enabled(vuart, true);
        aspeed_vuart_set_host_tx_discard(vuart, true);
        platform_set_drvdata(pdev, vuart);
index 1c72fdc..aab3ccc 100644 (file)
@@ -280,9 +280,6 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
        long rate;
        int ret;
 
-       if (IS_ERR(d->clk))
-               goto out;
-
        clk_disable_unprepare(d->clk);
        rate = clk_round_rate(d->clk, baud * 16);
        if (rate < 0)
@@ -293,8 +290,10 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
                ret = clk_set_rate(d->clk, rate);
        clk_prepare_enable(d->clk);
 
-       if (!ret)
-               p->uartclk = rate;
+       if (ret)
+               goto out;
+
+       p->uartclk = rate;
 
 out:
        p->status &= ~UPSTAT_AUTOCTS;
@@ -386,10 +385,10 @@ static int dw8250_probe(struct platform_device *pdev)
 {
        struct uart_8250_port uart = {}, *up = &uart;
        struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       int irq = platform_get_irq(pdev, 0);
        struct uart_port *p = &up->port;
        struct device *dev = &pdev->dev;
        struct dw8250_data *data;
+       int irq;
        int err;
        u32 val;
 
@@ -398,11 +397,9 @@ static int dw8250_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       if (irq < 0) {
-               if (irq != -EPROBE_DEFER)
-                       dev_err(dev, "cannot get irq\n");
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
                return irq;
-       }
 
        spin_lock_init(&p->lock);
        p->mapbase      = regs->start;
@@ -472,19 +469,18 @@ static int dw8250_probe(struct platform_device *pdev)
        device_property_read_u32(dev, "clock-frequency", &p->uartclk);
 
        /* If there is separate baudclk, get the rate from it. */
-       data->clk = devm_clk_get(dev, "baudclk");
-       if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
-               data->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
-       if (!IS_ERR_OR_NULL(data->clk)) {
-               err = clk_prepare_enable(data->clk);
-               if (err)
-                       dev_warn(dev, "could not enable optional baudclk: %d\n",
-                                err);
-               else
-                       p->uartclk = clk_get_rate(data->clk);
-       }
+       data->clk = devm_clk_get_optional(dev, "baudclk");
+       if (data->clk == NULL)
+               data->clk = devm_clk_get_optional(dev, NULL);
+       if (IS_ERR(data->clk))
+               return PTR_ERR(data->clk);
+
+       err = clk_prepare_enable(data->clk);
+       if (err)
+               dev_warn(dev, "could not enable optional baudclk: %d\n", err);
+
+       if (data->clk)
+               p->uartclk = clk_get_rate(data->clk);
 
        /* If no clock rate is defined, fail. */
        if (!p->uartclk) {
@@ -493,17 +489,16 @@ static int dw8250_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       data->pclk = devm_clk_get(dev, "apb_pclk");
-       if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) {
-               err = -EPROBE_DEFER;
+       data->pclk = devm_clk_get_optional(dev, "apb_pclk");
+       if (IS_ERR(data->pclk)) {
+               err = PTR_ERR(data->pclk);
                goto err_clk;
        }
-       if (!IS_ERR(data->pclk)) {
-               err = clk_prepare_enable(data->pclk);
-               if (err) {
-                       dev_err(dev, "could not enable apb_pclk\n");
-                       goto err_clk;
-               }
+
+       err = clk_prepare_enable(data->pclk);
+       if (err) {
+               dev_err(dev, "could not enable apb_pclk\n");
+               goto err_clk;
        }
 
        data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
@@ -546,12 +541,10 @@ err_reset:
        reset_control_assert(data->rst);
 
 err_pclk:
-       if (!IS_ERR(data->pclk))
-               clk_disable_unprepare(data->pclk);
+       clk_disable_unprepare(data->pclk);
 
 err_clk:
-       if (!IS_ERR(data->clk))
-               clk_disable_unprepare(data->clk);
+       clk_disable_unprepare(data->clk);
 
        return err;
 }
@@ -567,11 +560,9 @@ static int dw8250_remove(struct platform_device *pdev)
 
        reset_control_assert(data->rst);
 
-       if (!IS_ERR(data->pclk))
-               clk_disable_unprepare(data->pclk);
+       clk_disable_unprepare(data->pclk);
 
-       if (!IS_ERR(data->clk))
-               clk_disable_unprepare(data->clk);
+       clk_disable_unprepare(data->clk);
 
        pm_runtime_disable(dev);
        pm_runtime_put_noidle(dev);
@@ -604,11 +595,9 @@ static int dw8250_runtime_suspend(struct device *dev)
 {
        struct dw8250_data *data = dev_get_drvdata(dev);
 
-       if (!IS_ERR(data->clk))
-               clk_disable_unprepare(data->clk);
+       clk_disable_unprepare(data->clk);
 
-       if (!IS_ERR(data->pclk))
-               clk_disable_unprepare(data->pclk);
+       clk_disable_unprepare(data->pclk);
 
        return 0;
 }
@@ -617,11 +606,9 @@ static int dw8250_runtime_resume(struct device *dev)
 {
        struct dw8250_data *data = dev_get_drvdata(dev);
 
-       if (!IS_ERR(data->pclk))
-               clk_prepare_enable(data->pclk);
+       clk_prepare_enable(data->pclk);
 
-       if (!IS_ERR(data->clk))
-               clk_prepare_enable(data->clk);
+       clk_prepare_enable(data->clk);
 
        return 0;
 }
index 597eb9d..108cd55 100644 (file)
@@ -166,6 +166,23 @@ static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud,
        serial_port_out(p, 0x2, quot_frac);
 }
 
+static int xr17v35x_startup(struct uart_port *port)
+{
+       /*
+        * First enable access to IER [7:5], ISR [5:4], FCR [5:4],
+        * MCR [7:5] and MSR [7:0]
+        */
+       serial_port_out(port, UART_XR_EFR, UART_EFR_ECB);
+
+       /*
+        * Make sure all interrups are masked until initialization is
+        * complete and the FIFOs are cleared
+        */
+       serial_port_out(port, UART_IER, 0);
+
+       return serial8250_do_startup(port);
+}
+
 static void exar_shutdown(struct uart_port *port)
 {
        unsigned char lsr;
@@ -212,6 +229,8 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
 
                port->port.get_divisor = xr17v35x_get_divisor;
                port->port.set_divisor = xr17v35x_set_divisor;
+
+               port->port.startup = xr17v35x_startup;
        } else {
                port->port.type = PORT_XR17D15X;
        }
index 5f72ef3..60eff32 100644 (file)
@@ -221,17 +221,6 @@ static void qrk_serial_exit_dma(struct lpss8250 *lpss) {}
 
 static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
 {
-       struct pci_dev *pdev = to_pci_dev(port->dev);
-       int ret;
-
-       pci_set_master(pdev);
-
-       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
-       if (ret < 0)
-               return ret;
-
-       port->irq = pci_irq_vector(pdev, 0);
-
        qrk_serial_setup_dma(lpss, port);
        return 0;
 }
@@ -293,16 +282,22 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ret)
                return ret;
 
+       pci_set_master(pdev);
+
        lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL);
        if (!lpss)
                return -ENOMEM;
 
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+       if (ret < 0)
+               return ret;
+
        lpss->board = (struct lpss8250_board *)id->driver_data;
 
        memset(&uart, 0, sizeof(struct uart_8250_port));
 
        uart.port.dev = &pdev->dev;
-       uart.port.irq = pdev->irq;
+       uart.port.irq = pci_irq_vector(pdev, 0);
        uart.port.private_data = &lpss->data;
        uart.port.type = PORT_16550A;
        uart.port.iotype = UPIO_MEM;
@@ -337,6 +332,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 err_exit:
        if (lpss->board->exit)
                lpss->board->exit(lpss);
+       pci_free_irq_vectors(pdev);
        return ret;
 }
 
@@ -348,6 +344,7 @@ static void lpss8250_remove(struct pci_dev *pdev)
 
        if (lpss->board->exit)
                lpss->board->exit(lpss);
+       pci_free_irq_vectors(pdev);
 }
 
 static const struct lpss8250_board byt_board = {
index b411ba4..4d067f5 100644 (file)
@@ -544,7 +544,7 @@ static int mtk8250_probe(struct platform_device *pdev)
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
-       data->rx_wakeup_irq = platform_get_irq(pdev, 1);
+       data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1);
 
        return 0;
 }
index 0826cfd..92fbf46 100644 (file)
@@ -48,6 +48,36 @@ static inline void tegra_serial_handle_break(struct uart_port *port)
 }
 #endif
 
+static int of_8250_rs485_config(struct uart_port *port,
+                                 struct serial_rs485 *rs485)
+{
+       struct uart_8250_port *up = up_to_u8250p(port);
+
+       /* Clamp the delays to [0, 100ms] */
+       rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+       rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
+
+       port->rs485 = *rs485;
+
+       /*
+        * Both serial8250_em485_init and serial8250_em485_destroy
+        * are idempotent
+        */
+       if (rs485->flags & SER_RS485_ENABLED) {
+               int ret = serial8250_em485_init(up);
+
+               if (ret) {
+                       rs485->flags &= ~SER_RS485_ENABLED;
+                       port->rs485.flags &= ~SER_RS485_ENABLED;
+               }
+               return ret;
+       }
+
+       serial8250_em485_destroy(up);
+
+       return 0;
+}
+
 /*
  * Fill a struct uart_port for a given device node
  */
@@ -178,6 +208,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                port->flags |= UPF_SKIP_TEST;
 
        port->dev = &ofdev->dev;
+       port->rs485_config = of_8250_rs485_config;
 
        switch (type) {
        case PORT_TEGRA:
index 6adbadd..022924d 100644 (file)
@@ -48,8 +48,6 @@ struct f815xxa_data {
        int idx;
 };
 
-#define PCI_NUM_BAR_RESOURCES  6
-
 struct serial_private {
        struct pci_dev          *dev;
        unsigned int            nr;
@@ -89,7 +87,7 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
 {
        struct pci_dev *dev = priv->dev;
 
-       if (bar >= PCI_NUM_BAR_RESOURCES)
+       if (bar >= PCI_STD_NUM_BARS)
                return -EINVAL;
 
        if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
@@ -745,16 +743,8 @@ static int pci_ni8430_init(struct pci_dev *dev)
 }
 
 /* UART Port Control Register */
-#define NI16550_PCR_OFFSET     0x0f
-#define NI16550_PCR_RS422      0x00
-#define NI16550_PCR_ECHO_RS485 0x01
-#define NI16550_PCR_DTR_RS485  0x02
-#define NI16550_PCR_AUTO_RS485 0x03
-#define NI16550_PCR_WIRE_MODE_MASK     0x03
-#define NI16550_PCR_TXVR_ENABLE_BIT    BIT(3)
-#define NI16550_PCR_RS485_TERMINATION_BIT      BIT(6)
-#define NI16550_ACR_DTR_AUTO_DTR       (0x2 << 3)
-#define NI16550_ACR_DTR_MANUAL_DTR     (0x0 << 3)
+#define NI8430_PORTCON 0x0f
+#define NI8430_PORTCON_TXVR_ENABLE     (1 << 3)
 
 static int
 pci_ni8430_setup(struct serial_private *priv,
@@ -776,117 +766,14 @@ pci_ni8430_setup(struct serial_private *priv,
                return -ENOMEM;
 
        /* enable the transceiver */
-       writeb(readb(p + offset + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT,
-              p + offset + NI16550_PCR_OFFSET);
+       writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
+              p + offset + NI8430_PORTCON);
 
        iounmap(p);
 
        return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
-static int pci_ni8431_config_rs485(struct uart_port *port,
-       struct serial_rs485 *rs485)
-{
-       u8 pcr, acr;
-       struct uart_8250_port *up;
-
-       up = container_of(port, struct uart_8250_port, port);
-       acr = up->acr;
-       pcr = port->serial_in(port, NI16550_PCR_OFFSET);
-       pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
-
-       if (rs485->flags & SER_RS485_ENABLED) {
-               /* RS-485 */
-               if ((rs485->flags & SER_RS485_RX_DURING_TX) &&
-                       (rs485->flags & SER_RS485_RTS_ON_SEND)) {
-                       dev_dbg(port->dev, "Invalid 2-wire mode\n");
-                       return -EINVAL;
-               }
-
-               if (rs485->flags & SER_RS485_RX_DURING_TX) {
-                       /* Echo */
-                       dev_vdbg(port->dev, "2-wire DTR with echo\n");
-                       pcr |= NI16550_PCR_ECHO_RS485;
-                       acr |= NI16550_ACR_DTR_MANUAL_DTR;
-               } else {
-                       /* Auto or DTR */
-                       if (rs485->flags & SER_RS485_RTS_ON_SEND) {
-                               /* Auto */
-                               dev_vdbg(port->dev, "2-wire Auto\n");
-                               pcr |= NI16550_PCR_AUTO_RS485;
-                               acr |= NI16550_ACR_DTR_AUTO_DTR;
-                       } else {
-                               /* DTR-controlled */
-                               /* No Echo */
-                               dev_vdbg(port->dev, "2-wire DTR no echo\n");
-                               pcr |= NI16550_PCR_DTR_RS485;
-                               acr |= NI16550_ACR_DTR_MANUAL_DTR;
-                       }
-               }
-       } else {
-               /* RS-422 */
-               dev_vdbg(port->dev, "4-wire\n");
-               pcr |= NI16550_PCR_RS422;
-               acr |= NI16550_ACR_DTR_MANUAL_DTR;
-       }
-
-       dev_dbg(port->dev, "write pcr: 0x%08x\n", pcr);
-       port->serial_out(port, NI16550_PCR_OFFSET, pcr);
-
-       up->acr = acr;
-       port->serial_out(port, UART_SCR, UART_ACR);
-       port->serial_out(port, UART_ICR, up->acr);
-
-       /* Update the cache. */
-       port->rs485 = *rs485;
-
-       return 0;
-}
-
-static int pci_ni8431_setup(struct serial_private *priv,
-                const struct pciserial_board *board,
-                struct uart_8250_port *uart, int idx)
-{
-       u8 pcr, acr;
-       struct pci_dev *dev = priv->dev;
-       void __iomem *addr;
-       unsigned int bar, offset = board->first_offset;
-
-       if (idx >= board->num_ports)
-               return 1;
-
-       bar = FL_GET_BASE(board->flags);
-       offset += idx * board->uart_offset;
-
-       addr = pci_ioremap_bar(dev, bar);
-       if (!addr)
-               return -ENOMEM;
-
-       /* enable the transceiver */
-       writeb(readb(addr + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT,
-               addr + NI16550_PCR_OFFSET);
-
-       pcr = readb(addr + NI16550_PCR_OFFSET);
-       pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
-
-       /* set wire mode to default RS-422 */
-       pcr |= NI16550_PCR_RS422;
-       acr = NI16550_ACR_DTR_MANUAL_DTR;
-
-       /* write port configuration to register */
-       writeb(pcr, addr + NI16550_PCR_OFFSET);
-
-       /* access and write to UART acr register */
-       writeb(UART_ACR, addr + UART_SCR);
-       writeb(acr, addr + UART_ICR);
-
-       uart->port.rs485_config = &pci_ni8431_config_rs485;
-
-       iounmap(addr);
-
-       return setup_port(priv, uart, bar, offset, board->reg_shift);
-}
-
 static int pci_netmos_9900_setup(struct serial_private *priv,
                                const struct pciserial_board *board,
                                struct uart_8250_port *port, int idx)
@@ -2023,15 +1910,6 @@ pci_moxa_setup(struct serial_private *priv,
 #define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM     0x10E9
 #define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM     0x11D8
 
-#define PCIE_DEVICE_ID_NI_PXIE8430_2328        0x74C2
-#define PCIE_DEVICE_ID_NI_PXIE8430_23216       0x74C1
-#define PCI_DEVICE_ID_NI_PXI8431_4852  0x7081
-#define PCI_DEVICE_ID_NI_PXI8431_4854  0x70DE
-#define PCI_DEVICE_ID_NI_PXI8431_4858  0x70E3
-#define PCI_DEVICE_ID_NI_PXI8433_4852  0x70E9
-#define PCI_DEVICE_ID_NI_PXI8433_4854  0x70ED
-#define PCIE_DEVICE_ID_NI_PXIE8431_4858        0x74C4
-#define PCIE_DEVICE_ID_NI_PXIE8431_48516       0x74C3
 
 #define        PCI_DEVICE_ID_MOXA_CP102E       0x1024
 #define        PCI_DEVICE_ID_MOXA_CP102EL      0x1025
@@ -2269,87 +2147,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .setup          = pci_ni8430_setup,
                .exit           = pci_ni8430_exit,
        },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCIE_DEVICE_ID_NI_PXIE8430_2328,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8430_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCIE_DEVICE_ID_NI_PXIE8430_23216,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8430_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8431_4852,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8431_4854,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8431_4858,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8433_4852,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8433_4854,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCIE_DEVICE_ID_NI_PXIE8431_4858,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCIE_DEVICE_ID_NI_PXIE8431_48516,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8431_setup,
-               .exit           = pci_ni8430_exit,
-       },
        /* Quatech */
        {
                .vendor         = PCI_VENDOR_ID_QUATECH,
@@ -3106,13 +2903,6 @@ enum pci_board_num_t {
        pbn_ni8430_4,
        pbn_ni8430_8,
        pbn_ni8430_16,
-       pbn_ni8430_pxie_8,
-       pbn_ni8430_pxie_16,
-       pbn_ni8431_2,
-       pbn_ni8431_4,
-       pbn_ni8431_8,
-       pbn_ni8431_pxie_8,
-       pbn_ni8431_pxie_16,
        pbn_ADDIDATA_PCIe_1_3906250,
        pbn_ADDIDATA_PCIe_2_3906250,
        pbn_ADDIDATA_PCIe_4_3906250,
@@ -3765,55 +3555,6 @@ static struct pciserial_board pci_boards[] = {
                .uart_offset    = 0x10,
                .first_offset   = 0x800,
        },
-       [pbn_ni8430_pxie_16] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 16,
-               .base_baud      = 3125000,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_pxie_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3125000,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8431_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8431_4] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8431_2] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8431_pxie_16] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 16,
-               .base_baud      = 3125000,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8431_pxie_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3125000,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
        /*
         * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
         */
@@ -4060,7 +3801,7 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
                return -ENODEV;
 
        num_iomem = num_port = 0;
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
                        num_port++;
                        if (first_port == -1)
@@ -4088,7 +3829,7 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
         */
        first_port = -1;
        num_port = 0;
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
                    pci_resource_len(dev, i) == 8 &&
                    (first_port == -1 || (first_port + num_port) == i)) {
@@ -5567,33 +5308,6 @@ static const struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_pxie_8 },
-       {       PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_pxie_16 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4852,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4854,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4858,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_8 },
-       {       PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_4858,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_pxie_8 },
-       {       PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_48516,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_pxie_16 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4852,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4854,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8431_4 },
 
        /*
         * MOXA
index 8407166..9065591 100644 (file)
@@ -2114,20 +2114,6 @@ int serial8250_do_startup(struct uart_port *port)
        enable_rsa(up);
 #endif
 
-       if (port->type == PORT_XR17V35X) {
-               /*
-                * First enable access to IER [7:5], ISR [5:4], FCR [5:4],
-                * MCR [7:5] and MSR [7:0]
-                */
-               serial_port_out(port, UART_XR_EFR, UART_EFR_ECB);
-
-               /*
-                * Make sure all interrups are masked until initialization is
-                * complete and the FIFOs are cleared
-                */
-               serial_port_out(port, UART_IER, 0);
-       }
-
        /*
         * Clear the FIFO buffers and disable them.
         * (they will be reenabled in set_termios())
index 7ef60f8..fab3d4f 100644 (file)
@@ -243,6 +243,7 @@ config SERIAL_8250_ASPEED_VUART
        tristate "Aspeed Virtual UART"
        depends on SERIAL_8250
        depends on OF
+       depends on REGMAP && MFD_SYSCON
        help
          If you want to use the virtual UART (VUART) device on Aspeed
          BMC platforms, enable this option. This enables the 16550A-
@@ -334,7 +335,7 @@ config SERIAL_8250_BCM2835AUX
 
          Features and limitations of the UART are
            Registers are similar to 16650 registers,
-              set bits in the control registers that are unsupported
+             set bits in the control registers that are unsupported
              are ignored and read back as 0
            7/8 bit operation with 1 start and 1 stop bit
            8 symbols deep fifo for rx and tx
index 540142c..99f5da3 100644 (file)
@@ -287,26 +287,26 @@ config SERIAL_SAMSUNG_CONSOLE
          boot time.)
 
 config SERIAL_SIRFSOC
-        tristate "SiRF SoC Platform Serial port support"
-        depends on ARCH_SIRF
-        select SERIAL_CORE
-        help
-          Support for the on-chip UART on the CSR SiRFprimaII series,
-          providing /dev/ttySiRF0, 1 and 2 (note, some machines may not
-          provide all of these ports, depending on how the serial port
-          pins are configured).
+       tristate "SiRF SoC Platform Serial port support"
+       depends on ARCH_SIRF
+       select SERIAL_CORE
+       help
+         Support for the on-chip UART on the CSR SiRFprimaII series,
+         providing /dev/ttySiRF0, 1 and 2 (note, some machines may not
+         provide all of these ports, depending on how the serial port
+         pins are configured).
 
 config SERIAL_SIRFSOC_CONSOLE
-        bool "Support for console on SiRF SoC serial port"
-        depends on SERIAL_SIRFSOC=y
-        select SERIAL_CORE_CONSOLE
-        help
-          Even if you say Y here, the currently visible virtual console
-          (/dev/tty0) will still be used as the system console by default, but
-          you can alter that using a kernel command line option such as
-          "console=ttySiRFx". (Try "man bootparam" or see the documentation of
-          your boot loader about how to pass options to the kernel at
-          boot time.)
+       bool "Support for console on SiRF SoC serial port"
+       depends on SERIAL_SIRFSOC=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySiRFx". (Try "man bootparam" or see the documentation of
+         your boot loader about how to pass options to the kernel at
+         boot time.)
 
 config SERIAL_TEGRA
        tristate "NVIDIA Tegra20/30 SoC serial controller"
@@ -1078,41 +1078,41 @@ config SERIAL_SCCNXP_CONSOLE
          Support for console on SCCNXP serial ports.
 
 config SERIAL_SC16IS7XX_CORE
-        tristate
+       tristate
 
 config SERIAL_SC16IS7XX
-        tristate "SC16IS7xx serial support"
-        select SERIAL_CORE
-        depends on (SPI_MASTER && !I2C) || I2C
-        help
-          This selects support for SC16IS7xx serial ports.
-          Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
-          SC16IS760 and SC16IS762. Select supported buses using options below.
+       tristate "SC16IS7xx serial support"
+       select SERIAL_CORE
+       depends on (SPI_MASTER && !I2C) || I2C
+       help
+         This selects support for SC16IS7xx serial ports.
+         Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
+         SC16IS760 and SC16IS762. Select supported buses using options below.
 
 config SERIAL_SC16IS7XX_I2C
-        bool "SC16IS7xx for I2C interface"
-        depends on SERIAL_SC16IS7XX
-        depends on I2C
-        select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
-        select REGMAP_I2C if I2C
-        default y
-        help
-          Enable SC16IS7xx driver on I2C bus,
-          If required say y, and say n to i2c if not required,
-          Enabled by default to support oldconfig.
-          You must select at least one bus for the driver to be built.
+       bool "SC16IS7xx for I2C interface"
+       depends on SERIAL_SC16IS7XX
+       depends on I2C
+       select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
+       select REGMAP_I2C if I2C
+       default y
+       help
+         Enable SC16IS7xx driver on I2C bus,
+         If required say y, and say n to i2c if not required,
+         Enabled by default to support oldconfig.
+         You must select at least one bus for the driver to be built.
 
 config SERIAL_SC16IS7XX_SPI
-        bool "SC16IS7xx for spi interface"
-        depends on SERIAL_SC16IS7XX
-        depends on SPI_MASTER
-        select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
-        select REGMAP_SPI if SPI_MASTER
-        help
-          Enable SC16IS7xx driver on SPI bus,
-          If required say y, and say n to spi if not required,
-          This is additional support to exsisting driver.
-          You must select at least one bus for the driver to be built.
+       bool "SC16IS7xx for spi interface"
+       depends on SERIAL_SC16IS7XX
+       depends on SPI_MASTER
+       select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
+       select REGMAP_SPI if SPI_MASTER
+       help
+         Enable SC16IS7xx driver on SPI bus,
+         If required say y, and say n to spi if not required,
+         This is additional support to exsisting driver.
+         You must select at least one bus for the driver to be built.
 
 config SERIAL_TIMBERDALE
        tristate "Support for timberdale UART"
@@ -1212,7 +1212,7 @@ config SERIAL_ALTERA_UART_CONSOLE
          Enable a Altera UART port to be the system console.
 
 config SERIAL_IFX6X60
-        tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
+       tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
        depends on GPIOLIB || COMPILE_TEST
        depends on SPI && HAS_DMA
        help
@@ -1392,19 +1392,19 @@ config SERIAL_FSL_LPUART_CONSOLE
          you can make it the console by answering Y to this option.
 
 config SERIAL_FSL_LINFLEXUART
-       tristate "Freescale linflexuart serial port support"
+       tristate "Freescale LINFlexD UART serial port support"
        depends on PRINTK
        select SERIAL_CORE
        help
-         Support for the on-chip linflexuart on some Freescale SOCs.
+         Support for the on-chip LINFlexD UART on some Freescale SOCs.
 
 config SERIAL_FSL_LINFLEXUART_CONSOLE
-       bool "Console on Freescale linflexuart serial port"
+       bool "Console on Freescale LINFlexD UART serial port"
        depends on SERIAL_FSL_LINFLEXUART=y
        select SERIAL_CORE_CONSOLE
        select SERIAL_EARLYCON
        help
-         If you have enabled the linflexuart serial port on the Freescale
+         If you have enabled the LINFlexD UART serial port on the Freescale
          SoCs, you can make it the console by answering Y to this option.
 
 config SERIAL_CONEXANT_DIGICOLOR
index 863f470..d056ee6 100644 (file)
@@ -30,7 +30,7 @@ obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o
 obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
 obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
 obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
-obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
+obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o
 obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
 obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
index 3a7d1a6..4b28134 100644 (file)
@@ -414,7 +414,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
        dma_cap_mask_t mask;
 
        uap->dma_probed = true;
-       chan = dma_request_slave_channel_reason(dev, "tx");
+       chan = dma_request_chan(dev, "tx");
        if (IS_ERR(chan)) {
                if (PTR_ERR(chan) == -EPROBE_DEFER) {
                        uap->dma_probed = false;
@@ -813,10 +813,8 @@ __acquires(&uap->port.lock)
        if (!uap->using_tx_dma)
                return;
 
-       /* Avoid deadlock with the DMA engine callback */
-       spin_unlock(&uap->port.lock);
-       dmaengine_terminate_all(uap->dmatx.chan);
-       spin_lock(&uap->port.lock);
+       dmaengine_terminate_async(uap->dmatx.chan);
+
        if (uap->dmatx.queued) {
                dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
                             DMA_TO_DEVICE);
@@ -1236,10 +1234,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
 
 #else
 /* Blank functions if the DMA engine is not available */
-static inline void pl011_dma_probe(struct uart_amba_port *uap)
-{
-}
-
 static inline void pl011_dma_remove(struct uart_amba_port *uap)
 {
 }
index a32f0d2..205c31a 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Freescale linflexuart serial port driver
+ * Freescale LINFlexD UART serial port driver
  *
  * Copyright 2012-2016 Freescale Semiconductor, Inc.
  * Copyright 2017-2019 NXP
@@ -940,5 +940,5 @@ static void __exit linflex_serial_exit(void)
 module_init(linflex_serial_init);
 module_exit(linflex_serial_exit);
 
-MODULE_DESCRIPTION("Freescale linflex serial port driver");
+MODULE_DESCRIPTION("Freescale LINFlexD serial port driver");
 MODULE_LICENSE("GPL v2");
index 537896c..4e128d1 100644 (file)
@@ -437,8 +437,8 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
        }
 
        sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl,
-                                       sport->dma_tx_nents,
-                                       DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+                                       ret, DMA_MEM_TO_DEV,
+                                       DMA_PREP_INTERRUPT);
        if (!sport->dma_tx_desc) {
                dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
                dev_err(dev, "Cannot prepare TX slave DMA!\n");
@@ -1280,6 +1280,57 @@ static int lpuart_config_rs485(struct uart_port *port,
        return 0;
 }
 
+static int lpuart32_config_rs485(struct uart_port *port,
+                       struct serial_rs485 *rs485)
+{
+       struct lpuart_port *sport = container_of(port,
+                       struct lpuart_port, port);
+
+       unsigned long modem = lpuart32_read(&sport->port, UARTMODIR)
+                               & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
+       lpuart32_write(&sport->port, modem, UARTMODIR);
+
+       /* clear unsupported configurations */
+       rs485->delay_rts_before_send = 0;
+       rs485->delay_rts_after_send = 0;
+       rs485->flags &= ~SER_RS485_RX_DURING_TX;
+
+       if (rs485->flags & SER_RS485_ENABLED) {
+               /* Enable auto RS-485 RTS mode */
+               modem |= UARTMODEM_TXRTSE;
+
+               /*
+                * RTS needs to be logic HIGH either during transer _or_ after
+                * transfer, other variants are not supported by the hardware.
+                */
+
+               if (!(rs485->flags & (SER_RS485_RTS_ON_SEND |
+                               SER_RS485_RTS_AFTER_SEND)))
+                       rs485->flags |= SER_RS485_RTS_ON_SEND;
+
+               if (rs485->flags & SER_RS485_RTS_ON_SEND &&
+                               rs485->flags & SER_RS485_RTS_AFTER_SEND)
+                       rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+
+               /*
+                * The hardware defaults to RTS logic HIGH while transfer.
+                * Switch polarity in case RTS shall be logic HIGH
+                * after transfer.
+                * Note: UART is assumed to be active high.
+                */
+               if (rs485->flags & SER_RS485_RTS_ON_SEND)
+                       modem &= ~UARTMODEM_TXRTSPOL;
+               else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
+                       modem |= UARTMODEM_TXRTSPOL;
+       }
+
+       /* Store the new configuration */
+       sport->port.rs485 = *rs485;
+
+       lpuart32_write(&sport->port, modem, UARTMODIR);
+       return 0;
+}
+
 static unsigned int lpuart_get_mctrl(struct uart_port *port)
 {
        unsigned int temp = 0;
@@ -1333,18 +1384,7 @@ static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       unsigned long temp;
-
-       temp = lpuart32_read(port, UARTMODIR) &
-                       ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
-
-       if (mctrl & TIOCM_RTS)
-               temp |= UARTMODIR_RXRTSE;
-
-       if (mctrl & TIOCM_CTS)
-               temp |= UARTMODIR_TXCTSE;
 
-       lpuart32_write(port, temp, UARTMODIR);
 }
 
 static void lpuart_break_ctl(struct uart_port *port, int break_state)
@@ -1889,11 +1929,18 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
                ctrl |= UARTCTRL_M;
        }
 
+       /*
+        * When auto RS-485 RTS mode is enabled,
+        * hardware flow control need to be disabled.
+        */
+       if (sport->port.rs485.flags & SER_RS485_ENABLED)
+               termios->c_cflag &= ~CRTSCTS;
+
        if (termios->c_cflag & CRTSCTS) {
-               modem |= UARTMODEM_RXRTSE | UARTMODEM_TXCTSE;
+               modem |= (UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
        } else {
                termios->c_cflag &= ~CRTSCTS;
-               modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
+               modem &= ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
        }
 
        if (termios->c_cflag & CSTOPB)
@@ -2416,7 +2463,10 @@ static int lpuart_probe(struct platform_device *pdev)
                sport->port.ops = &lpuart_pops;
        sport->port.flags = UPF_BOOT_AUTOCONF;
 
-       sport->port.rs485_config = lpuart_config_rs485;
+       if (lpuart_is_32(sport))
+               sport->port.rs485_config = lpuart32_config_rs485;
+       else
+               sport->port.rs485_config = lpuart_config_rs485;
 
        sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(sport->ipg_clk)) {
@@ -2470,7 +2520,7 @@ static int lpuart_probe(struct platform_device *pdev)
            sport->port.rs485.delay_rts_after_send)
                dev_err(&pdev->dev, "driver doesn't support RTS delays\n");
 
-       lpuart_config_rs485(&sport->port, &sport->port.rs485);
+       sport->port.rs485_config(&sport->port, &sport->port.rs485);
 
        sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
        if (!sport->dma_tx_chan)
index ffefd21..31033d5 100644 (file)
@@ -1230,6 +1230,9 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
        struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
        /* stop activity */
        tasklet_kill(&ifx_dev->io_work_tasklet);
+
+       pm_runtime_disable(&spi->dev);
+
        /* free irq */
        free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
        free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev);
index 5e08f26..a9e20e6 100644 (file)
@@ -619,7 +619,7 @@ static void imx_uart_dma_tx(struct imx_port *sport)
                dev_err(dev, "DMA mapping error for TX.\n");
                return;
        }
-       desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+       desc = dmaengine_prep_slave_sg(chan, sgl, ret,
                                        DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
        if (!desc) {
                dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
@@ -1034,8 +1034,6 @@ static void imx_uart_timeout(struct timer_list *t)
        }
 }
 
-#define RX_BUF_SIZE    (PAGE_SIZE)
-
 /*
  * There are two kinds of RX DMA interrupts(such as in the MX6Q):
  *   [1] the RX DMA buffer is full.
@@ -1118,7 +1116,8 @@ static void imx_uart_dma_rx_callback(void *data)
 }
 
 /* RX DMA buffer periods */
-#define RX_DMA_PERIODS 4
+#define RX_DMA_PERIODS 16
+#define RX_BUF_SIZE    (RX_DMA_PERIODS * PAGE_SIZE / 4)
 
 static int imx_uart_start_rx_dma(struct imx_port *sport)
 {
index 3657a24..1cbae07 100644 (file)
@@ -301,7 +301,7 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base)
        dma = &msm_port->tx_dma;
 
        /* allocate DMA resources, if available */
-       dma->chan = dma_request_slave_channel_reason(dev, "tx");
+       dma->chan = dma_request_chan(dev, "tx");
        if (IS_ERR(dma->chan))
                goto no_tx;
 
@@ -344,7 +344,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
        dma = &msm_port->rx_dma;
 
        /* allocate DMA resources, if available */
-       dma->chan = dma_request_slave_channel_reason(dev, "rx");
+       dma->chan = dma_request_chan(dev, "rx");
        if (IS_ERR(dma->chan))
                goto no_rx;
 
@@ -980,6 +980,7 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
 static void msm_reset(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int mr;
 
        /* reset everything */
        msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
@@ -987,7 +988,10 @@ static void msm_reset(struct uart_port *port)
        msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
        msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
        msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
-       msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+       mr = msm_read(port, UART_MR1);
+       mr &= ~UART_MR1_RX_RDY_CTL;
+       msm_write(port, mr, UART_MR1);
 
        /* Disable DM modes */
        if (msm_port->is_uartdm)
index 6157213..c16234b 100644 (file)
@@ -233,6 +233,7 @@ struct eg20t_port {
        struct dma_chan                 *chan_rx;
        struct scatterlist              *sg_tx_p;
        int                             nent;
+       int                             orig_nent;
        struct scatterlist              sg_rx;
        int                             tx_dma_use;
        void                            *rx_buf_virt;
@@ -787,9 +788,10 @@ static void pch_dma_tx_complete(void *arg)
        }
        xmit->tail &= UART_XMIT_SIZE - 1;
        async_tx_ack(priv->desc_tx);
-       dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE);
+       dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE);
        priv->tx_dma_use = 0;
        priv->nent = 0;
+       priv->orig_nent = 0;
        kfree(priv->sg_tx_p);
        pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
 }
@@ -1010,6 +1012,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
                dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__);
                return 0;
        }
+       priv->orig_nent = num;
        priv->nent = nent;
 
        for (i = 0; i < nent; i++, sg++) {
index 14c6306..ff63728 100644 (file)
@@ -9,10 +9,12 @@
 #include <linux/console.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/qcom-geni-se.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
@@ -115,6 +117,7 @@ struct qcom_geni_serial_port {
        bool brk;
 
        unsigned int tx_remaining;
+       int wakeup_irq;
 };
 
 static const struct uart_ops qcom_geni_console_pops;
@@ -754,6 +757,15 @@ out_write_wakeup:
                uart_write_wakeup(uport);
 }
 
+static irqreturn_t qcom_geni_serial_wakeup_isr(int isr, void *dev)
+{
+       struct uart_port *uport = dev;
+
+       pm_wakeup_event(uport->dev, 2000);
+
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
 {
        u32 m_irq_en;
@@ -830,7 +842,7 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
        if (uart_console(uport))
                console_stop(uport->cons);
 
-       free_irq(uport->irq, uport);
+       disable_irq(uport->irq);
        spin_lock_irqsave(&uport->lock, flags);
        qcom_geni_serial_stop_tx(uport);
        qcom_geni_serial_stop_rx(uport);
@@ -890,21 +902,14 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
        int ret;
        struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
 
-       scnprintf(port->name, sizeof(port->name),
-                 "qcom_serial_%s%d",
-               (uart_console(uport) ? "console" : "uart"), uport->line);
-
        if (!port->setup) {
                ret = qcom_geni_serial_port_setup(uport);
                if (ret)
                        return ret;
        }
+       enable_irq(uport->irq);
 
-       ret = request_irq(uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH,
-                                                       port->name, uport);
-       if (ret)
-               dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
-       return ret;
+       return 0;
 }
 
 static unsigned long get_clk_cfg(unsigned long clk_freq)
@@ -1297,11 +1302,44 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
        port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
        port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
 
+       scnprintf(port->name, sizeof(port->name), "qcom_geni_serial_%s%d",
+               (uart_console(uport) ? "console" : "uart"), uport->line);
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
        uport->irq = irq;
 
+       irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
+       ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
+                       IRQF_TRIGGER_HIGH, port->name, uport);
+       if (ret) {
+               dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
+               return ret;
+       }
+
+       if (!console) {
+               port->wakeup_irq = platform_get_irq(pdev, 1);
+               if (port->wakeup_irq < 0) {
+                       dev_err(&pdev->dev, "Failed to get wakeup IRQ %d\n",
+                                       port->wakeup_irq);
+               } else {
+                       irq_set_status_flags(port->wakeup_irq, IRQ_NOAUTOEN);
+                       ret = devm_request_irq(uport->dev, port->wakeup_irq,
+                               qcom_geni_serial_wakeup_isr,
+                               IRQF_TRIGGER_FALLING, "uart_wakeup", uport);
+                       if (ret) {
+                               dev_err(uport->dev, "Failed to register wakeup IRQ ret %d\n",
+                                               ret);
+                               return ret;
+                       }
+
+                       device_init_wakeup(&pdev->dev, true);
+                       ret = dev_pm_set_wake_irq(&pdev->dev, port->wakeup_irq);
+                       if (unlikely(ret))
+                               dev_err(uport->dev, "%s:Failed to set IRQ wake:%d\n",
+                                               __func__, ret);
+               }
+       }
        uport->private_data = drv;
        platform_set_drvdata(pdev, port);
        port->handle_rx = console ? handle_rx_console : handle_rx_uart;
@@ -1324,7 +1362,12 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
 
-       return uart_suspend_port(uport->private_data, uport);
+       uart_suspend_port(uport->private_data, uport);
+
+       if (port->wakeup_irq > 0)
+               enable_irq(port->wakeup_irq);
+
+       return 0;
 }
 
 static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
@@ -1332,6 +1375,9 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
 
+       if (port->wakeup_irq > 0)
+               disable_irq(port->wakeup_irq);
+
        return uart_resume_port(uport->private_data, uport);
 }
 
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
deleted file mode 100644 (file)
index 83fd516..0000000
+++ /dev/null
@@ -1,2595 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Driver core for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
-*/
-
-/* Hote on 2410 error handling
- *
- * The s3c2410 manual has a love/hate affair with the contents of the
- * UERSTAT register in the UART blocks, and keeps marking some of the
- * error bits as reserved. Having checked with the s3c2410x01,
- * it copes with BREAKs properly, so I am happy to ignore the RESERVED
- * feature from the latter versions of the manual.
- *
- * If it becomes aparrent that latter versions of the 2410 remove these
- * bits, then action will have to be taken to differentiate the versions
- * and change the policy on BREAK
- *
- * BJD, 04-Nov-2004
-*/
-
-#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/serial_s3c.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/of.h>
-
-#include <asm/irq.h>
-
-#include "samsung.h"
-
-#if    defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
-       !defined(MODULE)
-
-extern void printascii(const char *);
-
-__printf(1, 2)
-static void dbg(const char *fmt, ...)
-{
-       va_list va;
-       char buff[256];
-
-       va_start(va, fmt);
-       vscnprintf(buff, sizeof(buff), fmt, va);
-       va_end(va);
-
-       printascii(buff);
-}
-
-#else
-#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0)
-#endif
-
-/* UART name and device definitions */
-
-#define S3C24XX_SERIAL_NAME    "ttySAC"
-#define S3C24XX_SERIAL_MAJOR   204
-#define S3C24XX_SERIAL_MINOR   64
-
-#define S3C24XX_TX_PIO                 1
-#define S3C24XX_TX_DMA                 2
-#define S3C24XX_RX_PIO                 1
-#define S3C24XX_RX_DMA                 2
-/* macros to change one thing to another */
-
-#define tx_enabled(port) ((port)->unused[0])
-#define rx_enabled(port) ((port)->unused[1])
-
-/* flag to ignore all characters coming in */
-#define RXSTAT_DUMMY_READ (0x10000000)
-
-static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
-{
-       return container_of(port, struct s3c24xx_uart_port, port);
-}
-
-/* translate a port to the device name */
-
-static inline const char *s3c24xx_serial_portname(struct uart_port *port)
-{
-       return to_platform_device(port->dev)->name;
-}
-
-static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
-{
-       return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
-}
-
-/*
- * s3c64xx and later SoC's include the interrupt mask and status registers in
- * the controller itself, unlike the s3c24xx SoC's which have these registers
- * in the interrupt controller. Check if the port type is s3c64xx or higher.
- */
-static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
-{
-       return to_ourport(port)->info->type == PORT_S3C6400;
-}
-
-static void s3c24xx_serial_rx_enable(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ucon, ufcon;
-       int count = 10000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (--count && !s3c24xx_serial_txempty_nofifo(port))
-               udelay(100);
-
-       ufcon = rd_regl(port, S3C2410_UFCON);
-       ufcon |= S3C2410_UFCON_RESETRX;
-       wr_regl(port, S3C2410_UFCON, ufcon);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon |= S3C2410_UCON_RXIRQMODE;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       rx_enabled(port) = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_rx_disable(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ucon;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~S3C2410_UCON_RXIRQMODE;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       rx_enabled(port) = 0;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_stop_tx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct dma_tx_state state;
-       int count;
-
-       if (!tx_enabled(port))
-               return;
-
-       if (s3c24xx_serial_has_interrupt_mask(port))
-               s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-       else
-               disable_irq_nosync(ourport->tx_irq);
-
-       if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
-               dmaengine_pause(dma->tx_chan);
-               dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
-               dmaengine_terminate_all(dma->tx_chan);
-               dma_sync_single_for_cpu(ourport->port.dev,
-                       dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
-               async_tx_ack(dma->tx_desc);
-               count = dma->tx_bytes_requested - state.residue;
-               xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
-               port->icount.tx += count;
-       }
-
-       tx_enabled(port) = 0;
-       ourport->tx_in_progress = 0;
-
-       if (port->flags & UPF_CONS_FLOW)
-               s3c24xx_serial_rx_enable(port);
-
-       ourport->tx_mode = 0;
-}
-
-static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
-
-static void s3c24xx_serial_tx_dma_complete(void *args)
-{
-       struct s3c24xx_uart_port *ourport = args;
-       struct uart_port *port = &ourport->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-       struct dma_tx_state state;
-       unsigned long flags;
-       int count;
-
-
-       dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
-       count = dma->tx_bytes_requested - state.residue;
-       async_tx_ack(dma->tx_desc);
-
-       dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
-                               dma->tx_size, DMA_TO_DEVICE);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
-       port->icount.tx += count;
-       ourport->tx_in_progress = 0;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       s3c24xx_serial_start_next_tx(ourport);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       u32 ucon;
-
-       /* Mask Tx interrupt */
-       if (s3c24xx_serial_has_interrupt_mask(port))
-               s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-       else
-               disable_irq_nosync(ourport->tx_irq);
-
-       /* Enable tx dma mode */
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
-       ucon |= (dma_get_cache_alignment() >= 16) ?
-               S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
-       ucon |= S3C64XX_UCON_TXMODE_DMA;
-       wr_regl(port,  S3C2410_UCON, ucon);
-
-       ourport->tx_mode = S3C24XX_TX_DMA;
-}
-
-static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       u32 ucon, ufcon;
-
-       /* Set ufcon txtrig */
-       ourport->tx_in_progress = S3C24XX_TX_PIO;
-       ufcon = rd_regl(port, S3C2410_UFCON);
-       wr_regl(port,  S3C2410_UFCON, ufcon);
-
-       /* Enable tx pio mode */
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
-       ucon |= S3C64XX_UCON_TXMODE_CPU;
-       wr_regl(port,  S3C2410_UCON, ucon);
-
-       /* Unmask Tx interrupt */
-       if (s3c24xx_serial_has_interrupt_mask(port))
-               s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
-                                 S3C64XX_UINTM);
-       else
-               enable_irq(ourport->tx_irq);
-
-       ourport->tx_mode = S3C24XX_TX_PIO;
-}
-
-static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
-{
-       if (ourport->tx_mode != S3C24XX_TX_PIO)
-               enable_tx_pio(ourport);
-}
-
-static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
-                                     unsigned int count)
-{
-       struct uart_port *port = &ourport->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-
-
-       if (ourport->tx_mode != S3C24XX_TX_DMA)
-               enable_tx_dma(ourport);
-
-       dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
-       dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
-
-       dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
-                               dma->tx_size, DMA_TO_DEVICE);
-
-       dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
-                               dma->tx_transfer_addr, dma->tx_size,
-                               DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
-       if (!dma->tx_desc) {
-               dev_err(ourport->port.dev, "Unable to get desc for Tx\n");
-               return -EIO;
-       }
-
-       dma->tx_desc->callback = s3c24xx_serial_tx_dma_complete;
-       dma->tx_desc->callback_param = ourport;
-       dma->tx_bytes_requested = dma->tx_size;
-
-       ourport->tx_in_progress = S3C24XX_TX_DMA;
-       dma->tx_cookie = dmaengine_submit(dma->tx_desc);
-       dma_async_issue_pending(dma->tx_chan);
-       return 0;
-}
-
-static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned long count;
-
-       /* Get data size up to the end of buffer */
-       count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-
-       if (!count) {
-               s3c24xx_serial_stop_tx(port);
-               return;
-       }
-
-       if (!ourport->dma || !ourport->dma->tx_chan ||
-           count < ourport->min_dma_size ||
-           xmit->tail & (dma_get_cache_alignment() - 1))
-               s3c24xx_serial_start_tx_pio(ourport);
-       else
-               s3c24xx_serial_start_tx_dma(ourport, count);
-}
-
-static void s3c24xx_serial_start_tx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (!tx_enabled(port)) {
-               if (port->flags & UPF_CONS_FLOW)
-                       s3c24xx_serial_rx_disable(port);
-
-               tx_enabled(port) = 1;
-               if (!ourport->dma || !ourport->dma->tx_chan)
-                       s3c24xx_serial_start_tx_pio(ourport);
-       }
-
-       if (ourport->dma && ourport->dma->tx_chan) {
-               if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
-                       s3c24xx_serial_start_next_tx(ourport);
-       }
-}
-
-static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
-               struct tty_port *tty, int count)
-{
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-       int copied;
-
-       if (!count)
-               return;
-
-       dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
-
-       ourport->port.icount.rx += count;
-       if (!tty) {
-               dev_err(ourport->port.dev, "No tty port\n");
-               return;
-       }
-       copied = tty_insert_flip_string(tty,
-                       ((unsigned char *)(ourport->dma->rx_buf)), count);
-       if (copied != count) {
-               WARN_ON(1);
-               dev_err(ourport->port.dev, "RxData copy to tty layer failed\n");
-       }
-}
-
-static void s3c24xx_serial_stop_rx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-       struct tty_port *t = &port->state->port;
-       struct dma_tx_state state;
-       enum dma_status dma_status;
-       unsigned int received;
-
-       if (rx_enabled(port)) {
-               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
-               if (s3c24xx_serial_has_interrupt_mask(port))
-                       s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
-                                       S3C64XX_UINTM);
-               else
-                       disable_irq_nosync(ourport->rx_irq);
-               rx_enabled(port) = 0;
-       }
-       if (dma && dma->rx_chan) {
-               dmaengine_pause(dma->tx_chan);
-               dma_status = dmaengine_tx_status(dma->rx_chan,
-                               dma->rx_cookie, &state);
-               if (dma_status == DMA_IN_PROGRESS ||
-                       dma_status == DMA_PAUSED) {
-                       received = dma->rx_bytes_requested - state.residue;
-                       dmaengine_terminate_all(dma->rx_chan);
-                       s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
-               }
-       }
-}
-
-static inline struct s3c24xx_uart_info
-       *s3c24xx_port_to_info(struct uart_port *port)
-{
-       return to_ourport(port)->info;
-}
-
-static inline struct s3c2410_uartcfg
-       *s3c24xx_port_to_cfg(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport;
-
-       if (port->dev == NULL)
-               return NULL;
-
-       ourport = container_of(port, struct s3c24xx_uart_port, port);
-       return ourport->cfg;
-}
-
-static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
-                                    unsigned long ufstat)
-{
-       struct s3c24xx_uart_info *info = ourport->info;
-
-       if (ufstat & info->rx_fifofull)
-               return ourport->port.fifosize;
-
-       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
-}
-
-static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
-static void s3c24xx_serial_rx_dma_complete(void *args)
-{
-       struct s3c24xx_uart_port *ourport = args;
-       struct uart_port *port = &ourport->port;
-
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-       struct tty_port *t = &port->state->port;
-       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
-
-       struct dma_tx_state state;
-       unsigned long flags;
-       int received;
-
-       dmaengine_tx_status(dma->rx_chan,  dma->rx_cookie, &state);
-       received  = dma->rx_bytes_requested - state.residue;
-       async_tx_ack(dma->rx_desc);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (received)
-               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
-
-       if (tty) {
-               tty_flip_buffer_push(t);
-               tty_kref_put(tty);
-       }
-
-       s3c64xx_start_rx_dma(ourport);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
-{
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-
-       dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
-
-       dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
-                               dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
-                               DMA_PREP_INTERRUPT);
-       if (!dma->rx_desc) {
-               dev_err(ourport->port.dev, "Unable to get desc for Rx\n");
-               return;
-       }
-
-       dma->rx_desc->callback = s3c24xx_serial_rx_dma_complete;
-       dma->rx_desc->callback_param = ourport;
-       dma->rx_bytes_requested = dma->rx_size;
-
-       dma->rx_cookie = dmaengine_submit(dma->rx_desc);
-       dma_async_issue_pending(dma->rx_chan);
-}
-
-/* ? - where has parity gone?? */
-#define S3C2410_UERSTAT_PARITY (0x1000)
-
-static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       unsigned int ucon;
-
-       /* set Rx mode to DMA mode */
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~(S3C64XX_UCON_RXBURST_MASK |
-                       S3C64XX_UCON_TIMEOUT_MASK |
-                       S3C64XX_UCON_EMPTYINT_EN |
-                       S3C64XX_UCON_DMASUS_EN |
-                       S3C64XX_UCON_TIMEOUT_EN |
-                       S3C64XX_UCON_RXMODE_MASK);
-       ucon |= S3C64XX_UCON_RXBURST_16 |
-                       0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
-                       S3C64XX_UCON_EMPTYINT_EN |
-                       S3C64XX_UCON_TIMEOUT_EN |
-                       S3C64XX_UCON_RXMODE_DMA;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       ourport->rx_mode = S3C24XX_RX_DMA;
-}
-
-static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       unsigned int ucon;
-
-       /* set Rx mode to DMA mode */
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
-                       S3C64XX_UCON_EMPTYINT_EN |
-                       S3C64XX_UCON_DMASUS_EN |
-                       S3C64XX_UCON_TIMEOUT_EN |
-                       S3C64XX_UCON_RXMODE_MASK);
-       ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
-                       S3C64XX_UCON_TIMEOUT_EN |
-                       S3C64XX_UCON_RXMODE_CPU;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       ourport->rx_mode = S3C24XX_RX_PIO;
-}
-
-static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
-
-static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
-{
-       unsigned int utrstat, ufstat, received;
-       struct s3c24xx_uart_port *ourport = dev_id;
-       struct uart_port *port = &ourport->port;
-       struct s3c24xx_uart_dma *dma = ourport->dma;
-       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
-       struct tty_port *t = &port->state->port;
-       unsigned long flags;
-       struct dma_tx_state state;
-
-       utrstat = rd_regl(port, S3C2410_UTRSTAT);
-       ufstat = rd_regl(port, S3C2410_UFSTAT);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
-               s3c64xx_start_rx_dma(ourport);
-               if (ourport->rx_mode == S3C24XX_RX_PIO)
-                       enable_rx_dma(ourport);
-               goto finish;
-       }
-
-       if (ourport->rx_mode == S3C24XX_RX_DMA) {
-               dmaengine_pause(dma->rx_chan);
-               dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
-               dmaengine_terminate_all(dma->rx_chan);
-               received = dma->rx_bytes_requested - state.residue;
-               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
-
-               enable_rx_pio(ourport);
-       }
-
-       s3c24xx_serial_rx_drain_fifo(ourport);
-
-       if (tty) {
-               tty_flip_buffer_push(t);
-               tty_kref_put(tty);
-       }
-
-       wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
-
-finish:
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       unsigned int ufcon, ch, flag, ufstat, uerstat;
-       unsigned int fifocnt = 0;
-       int max_count = port->fifosize;
-
-       while (max_count-- > 0) {
-               /*
-                * Receive all characters known to be in FIFO
-                * before reading FIFO level again
-                */
-               if (fifocnt == 0) {
-                       ufstat = rd_regl(port, S3C2410_UFSTAT);
-                       fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
-                       if (fifocnt == 0)
-                               break;
-               }
-               fifocnt--;
-
-               uerstat = rd_regl(port, S3C2410_UERSTAT);
-               ch = rd_regb(port, S3C2410_URXH);
-
-               if (port->flags & UPF_CONS_FLOW) {
-                       int txe = s3c24xx_serial_txempty_nofifo(port);
-
-                       if (rx_enabled(port)) {
-                               if (!txe) {
-                                       rx_enabled(port) = 0;
-                                       continue;
-                               }
-                       } else {
-                               if (txe) {
-                                       ufcon = rd_regl(port, S3C2410_UFCON);
-                                       ufcon |= S3C2410_UFCON_RESETRX;
-                                       wr_regl(port, S3C2410_UFCON, ufcon);
-                                       rx_enabled(port) = 1;
-                                       return;
-                               }
-                               continue;
-                       }
-               }
-
-               /* insert the character into the buffer */
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
-                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
-                           ch, uerstat);
-
-                       /* check for break */
-                       if (uerstat & S3C2410_UERSTAT_BREAK) {
-                               dbg("break!\n");
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue; /* Ignore character */
-                       }
-
-                       if (uerstat & S3C2410_UERSTAT_FRAME)
-                               port->icount.frame++;
-                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
-                               port->icount.overrun++;
-
-                       uerstat &= port->read_status_mask;
-
-                       if (uerstat & S3C2410_UERSTAT_BREAK)
-                               flag = TTY_BREAK;
-                       else if (uerstat & S3C2410_UERSTAT_PARITY)
-                               flag = TTY_PARITY;
-                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
-                                           S3C2410_UERSTAT_OVERRUN))
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue; /* Ignore character */
-
-               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
-                                ch, flag);
-       }
-
-       tty_flip_buffer_push(&port->state->port);
-}
-
-static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
-{
-       struct s3c24xx_uart_port *ourport = dev_id;
-       struct uart_port *port = &ourport->port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       s3c24xx_serial_rx_drain_fifo(ourport);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-
-static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
-{
-       struct s3c24xx_uart_port *ourport = dev_id;
-
-       if (ourport->dma && ourport->dma->rx_chan)
-               return s3c24xx_serial_rx_chars_dma(dev_id);
-       return s3c24xx_serial_rx_chars_pio(dev_id);
-}
-
-static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
-{
-       struct s3c24xx_uart_port *ourport = id;
-       struct uart_port *port = &ourport->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned long flags;
-       int count, dma_count = 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-
-       if (ourport->dma && ourport->dma->tx_chan &&
-           count >= ourport->min_dma_size) {
-               int align = dma_get_cache_alignment() -
-                       (xmit->tail & (dma_get_cache_alignment() - 1));
-               if (count-align >= ourport->min_dma_size) {
-                       dma_count = count-align;
-                       count = align;
-               }
-       }
-
-       if (port->x_char) {
-               wr_regb(port, S3C2410_UTXH, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               goto out;
-       }
-
-       /* if there isn't anything more to transmit, or the uart is now
-        * stopped, disable the uart and exit
-       */
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               s3c24xx_serial_stop_tx(port);
-               goto out;
-       }
-
-       /* try and drain the buffer... */
-
-       if (count > port->fifosize) {
-               count = port->fifosize;
-               dma_count = 0;
-       }
-
-       while (!uart_circ_empty(xmit) && count > 0) {
-               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
-                       break;
-
-               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               count--;
-       }
-
-       if (!count && dma_count) {
-               s3c24xx_serial_start_tx_dma(ourport, dma_count);
-               goto out;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
-               spin_unlock(&port->lock);
-               uart_write_wakeup(port);
-               spin_lock(&port->lock);
-       }
-
-       if (uart_circ_empty(xmit))
-               s3c24xx_serial_stop_tx(port);
-
-out:
-       spin_unlock_irqrestore(&port->lock, flags);
-       return IRQ_HANDLED;
-}
-
-/* interrupt handler for s3c64xx and later SoC's.*/
-static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
-{
-       struct s3c24xx_uart_port *ourport = id;
-       struct uart_port *port = &ourport->port;
-       unsigned int pend = rd_regl(port, S3C64XX_UINTP);
-       irqreturn_t ret = IRQ_HANDLED;
-
-       if (pend & S3C64XX_UINTM_RXD_MSK) {
-               ret = s3c24xx_serial_rx_chars(irq, id);
-               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
-       }
-       if (pend & S3C64XX_UINTM_TXD_MSK) {
-               ret = s3c24xx_serial_tx_chars(irq, id);
-               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
-       }
-       return ret;
-}
-
-static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
-       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
-
-       if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               if ((ufstat & info->tx_fifomask) != 0 ||
-                   (ufstat & info->tx_fifofull))
-                       return 0;
-
-               return 1;
-       }
-
-       return s3c24xx_serial_txempty_nofifo(port);
-}
-
-/* no modem control lines */
-static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
-{
-       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
-
-       if (umstat & S3C2410_UMSTAT_CTS)
-               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-       else
-               return TIOCM_CAR | TIOCM_DSR;
-}
-
-static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int umcon = rd_regl(port, S3C2410_UMCON);
-
-       if (mctrl & TIOCM_RTS)
-               umcon |= S3C2410_UMCOM_RTS_LOW;
-       else
-               umcon &= ~S3C2410_UMCOM_RTS_LOW;
-
-       wr_regl(port, S3C2410_UMCON, umcon);
-}
-
-static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int ucon;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-
-       if (break_state)
-               ucon |= S3C2410_UCON_SBREAK;
-       else
-               ucon &= ~S3C2410_UCON_SBREAK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
-{
-       struct s3c24xx_uart_dma *dma = p->dma;
-       struct dma_slave_caps dma_caps;
-       const char *reason = NULL;
-       int ret;
-
-       /* Default slave configuration parameters */
-       dma->rx_conf.direction          = DMA_DEV_TO_MEM;
-       dma->rx_conf.src_addr_width     = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       dma->rx_conf.src_addr           = p->port.mapbase + S3C2410_URXH;
-       dma->rx_conf.src_maxburst       = 1;
-
-       dma->tx_conf.direction          = DMA_MEM_TO_DEV;
-       dma->tx_conf.dst_addr_width     = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       dma->tx_conf.dst_addr           = p->port.mapbase + S3C2410_UTXH;
-       dma->tx_conf.dst_maxburst       = 1;
-
-       dma->rx_chan = dma_request_chan(p->port.dev, "rx");
-
-       if (IS_ERR(dma->rx_chan)) {
-               reason = "DMA RX channel request failed";
-               ret = PTR_ERR(dma->rx_chan);
-               goto err_warn;
-       }
-
-       ret = dma_get_slave_caps(dma->rx_chan, &dma_caps);
-       if (ret < 0 ||
-           dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
-               reason = "insufficient DMA RX engine capabilities";
-               ret = -EOPNOTSUPP;
-               goto err_release_rx;
-       }
-
-       dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
-
-       dma->tx_chan = dma_request_chan(p->port.dev, "tx");
-       if (IS_ERR(dma->tx_chan)) {
-               reason = "DMA TX channel request failed";
-               ret = PTR_ERR(dma->tx_chan);
-               goto err_release_rx;
-       }
-
-       ret = dma_get_slave_caps(dma->tx_chan, &dma_caps);
-       if (ret < 0 ||
-           dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
-               reason = "insufficient DMA TX engine capabilities";
-               ret = -EOPNOTSUPP;
-               goto err_release_tx;
-       }
-
-       dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
-
-       /* RX buffer */
-       dma->rx_size = PAGE_SIZE;
-
-       dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
-       if (!dma->rx_buf) {
-               ret = -ENOMEM;
-               goto err_release_tx;
-       }
-
-       dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
-                               dma->rx_size, DMA_FROM_DEVICE);
-       if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
-               reason = "DMA mapping error for RX buffer";
-               ret = -EIO;
-               goto err_free_rx;
-       }
-
-       /* TX buffer */
-       dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
-                               UART_XMIT_SIZE, DMA_TO_DEVICE);
-       if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
-               reason = "DMA mapping error for TX buffer";
-               ret = -EIO;
-               goto err_unmap_rx;
-       }
-
-       return 0;
-
-err_unmap_rx:
-       dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size,
-                        DMA_FROM_DEVICE);
-err_free_rx:
-       kfree(dma->rx_buf);
-err_release_tx:
-       dma_release_channel(dma->tx_chan);
-err_release_rx:
-       dma_release_channel(dma->rx_chan);
-err_warn:
-       if (reason)
-               dev_warn(p->port.dev, "%s, DMA will not be used\n", reason);
-       return ret;
-}
-
-static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
-{
-       struct s3c24xx_uart_dma *dma = p->dma;
-
-       if (dma->rx_chan) {
-               dmaengine_terminate_all(dma->rx_chan);
-               dma_unmap_single(p->port.dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
-               kfree(dma->rx_buf);
-               dma_release_channel(dma->rx_chan);
-               dma->rx_chan = NULL;
-       }
-
-       if (dma->tx_chan) {
-               dmaengine_terminate_all(dma->tx_chan);
-               dma_unmap_single(p->port.dev, dma->tx_addr,
-                               UART_XMIT_SIZE, DMA_TO_DEVICE);
-               dma_release_channel(dma->tx_chan);
-               dma->tx_chan = NULL;
-       }
-}
-
-static void s3c24xx_serial_shutdown(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (ourport->tx_claimed) {
-               if (!s3c24xx_serial_has_interrupt_mask(port))
-                       free_irq(ourport->tx_irq, ourport);
-               tx_enabled(port) = 0;
-               ourport->tx_claimed = 0;
-               ourport->tx_mode = 0;
-       }
-
-       if (ourport->rx_claimed) {
-               if (!s3c24xx_serial_has_interrupt_mask(port))
-                       free_irq(ourport->rx_irq, ourport);
-               ourport->rx_claimed = 0;
-               rx_enabled(port) = 0;
-       }
-
-       /* Clear pending interrupts and mask all interrupts */
-       if (s3c24xx_serial_has_interrupt_mask(port)) {
-               free_irq(port->irq, ourport);
-
-               wr_regl(port, S3C64XX_UINTP, 0xf);
-               wr_regl(port, S3C64XX_UINTM, 0xf);
-       }
-
-       if (ourport->dma)
-               s3c24xx_serial_release_dma(ourport);
-
-       ourport->tx_in_progress = 0;
-}
-
-static int s3c24xx_serial_startup(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       int ret;
-
-       dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n",
-           port, (unsigned long long)port->mapbase, port->membase);
-
-       rx_enabled(port) = 1;
-
-       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
-                         s3c24xx_serial_portname(port), ourport);
-
-       if (ret != 0) {
-               dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq);
-               return ret;
-       }
-
-       ourport->rx_claimed = 1;
-
-       dbg("requesting tx irq...\n");
-
-       tx_enabled(port) = 1;
-
-       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
-                         s3c24xx_serial_portname(port), ourport);
-
-       if (ret) {
-               dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq);
-               goto err;
-       }
-
-       ourport->tx_claimed = 1;
-
-       dbg("s3c24xx_serial_startup ok\n");
-
-       /* the port reset code should have done the correct
-        * register setup for the port controls */
-
-       return ret;
-
-err:
-       s3c24xx_serial_shutdown(port);
-       return ret;
-}
-
-static int s3c64xx_serial_startup(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       unsigned long flags;
-       unsigned int ufcon;
-       int ret;
-
-       dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
-           port, (unsigned long long)port->mapbase, port->membase);
-
-       wr_regl(port, S3C64XX_UINTM, 0xf);
-       if (ourport->dma) {
-               ret = s3c24xx_serial_request_dma(ourport);
-               if (ret < 0) {
-                       devm_kfree(port->dev, ourport->dma);
-                       ourport->dma = NULL;
-               }
-       }
-
-       ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
-                         s3c24xx_serial_portname(port), ourport);
-       if (ret) {
-               dev_err(port->dev, "cannot get irq %d\n", port->irq);
-               return ret;
-       }
-
-       /* For compatibility with s3c24xx Soc's */
-       rx_enabled(port) = 1;
-       ourport->rx_claimed = 1;
-       tx_enabled(port) = 0;
-       ourport->tx_claimed = 1;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ufcon = rd_regl(port, S3C2410_UFCON);
-       ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
-       if (!uart_console(port))
-               ufcon |= S3C2410_UFCON_RESETTX;
-       wr_regl(port, S3C2410_UFCON, ufcon);
-
-       enable_rx_pio(ourport);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       /* Enable Rx Interrupt */
-       s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
-
-       dbg("s3c64xx_serial_startup ok\n");
-       return ret;
-}
-
-/* power power management control */
-
-static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
-                             unsigned int old)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       int timeout = 10000;
-
-       ourport->pm_level = level;
-
-       switch (level) {
-       case 3:
-               while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
-                       udelay(100);
-
-               if (!IS_ERR(ourport->baudclk))
-                       clk_disable_unprepare(ourport->baudclk);
-
-               clk_disable_unprepare(ourport->clk);
-               break;
-
-       case 0:
-               clk_prepare_enable(ourport->clk);
-
-               if (!IS_ERR(ourport->baudclk))
-                       clk_prepare_enable(ourport->baudclk);
-
-               break;
-       default:
-               dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
-       }
-}
-
-/* baud rate calculation
- *
- * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
- * of different sources, including the peripheral clock ("pclk") and an
- * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
- * with a programmable extra divisor.
- *
- * The following code goes through the clock sources, and calculates the
- * baud clocks (and the resultant actual baud rates) and then tries to
- * pick the closest one and select that.
- *
-*/
-
-#define MAX_CLK_NAME_LENGTH 15
-
-static inline int s3c24xx_serial_getsource(struct uart_port *port)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned int ucon;
-
-       if (info->num_clks == 1)
-               return 0;
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= info->clksel_mask;
-       return ucon >> info->clksel_shift;
-}
-
-static void s3c24xx_serial_setsource(struct uart_port *port,
-                       unsigned int clk_sel)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned int ucon;
-
-       if (info->num_clks == 1)
-               return;
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       if ((ucon & info->clksel_mask) >> info->clksel_shift == clk_sel)
-               return;
-
-       ucon &= ~info->clksel_mask;
-       ucon |= clk_sel << info->clksel_shift;
-       wr_regl(port, S3C2410_UCON, ucon);
-}
-
-static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
-                       unsigned int req_baud, struct clk **best_clk,
-                       unsigned int *clk_num)
-{
-       struct s3c24xx_uart_info *info = ourport->info;
-       struct clk *clk;
-       unsigned long rate;
-       unsigned int cnt, baud, quot, clk_sel, best_quot = 0;
-       char clkname[MAX_CLK_NAME_LENGTH];
-       int calc_deviation, deviation = (1 << 30) - 1;
-
-       clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
-                       ourport->info->def_clk_sel;
-       for (cnt = 0; cnt < info->num_clks; cnt++) {
-               if (!(clk_sel & (1 << cnt)))
-                       continue;
-
-               sprintf(clkname, "clk_uart_baud%d", cnt);
-               clk = clk_get(ourport->port.dev, clkname);
-               if (IS_ERR(clk))
-                       continue;
-
-               rate = clk_get_rate(clk);
-               if (!rate)
-                       continue;
-
-               if (ourport->info->has_divslot) {
-                       unsigned long div = rate / req_baud;
-
-                       /* The UDIVSLOT register on the newer UARTs allows us to
-                        * get a divisor adjustment of 1/16th on the baud clock.
-                        *
-                        * We don't keep the UDIVSLOT value (the 16ths we
-                        * calculated by not multiplying the baud by 16) as it
-                        * is easy enough to recalculate.
-                        */
-
-                       quot = div / 16;
-                       baud = rate / div;
-               } else {
-                       quot = (rate + (8 * req_baud)) / (16 * req_baud);
-                       baud = rate / (quot * 16);
-               }
-               quot--;
-
-               calc_deviation = req_baud - baud;
-               if (calc_deviation < 0)
-                       calc_deviation = -calc_deviation;
-
-               if (calc_deviation < deviation) {
-                       *best_clk = clk;
-                       best_quot = quot;
-                       *clk_num = cnt;
-                       deviation = calc_deviation;
-               }
-       }
-
-       return best_quot;
-}
-
-/* udivslot_table[]
- *
- * This table takes the fractional value of the baud divisor and gives
- * the recommended setting for the UDIVSLOT register.
- */
-static u16 udivslot_table[16] = {
-       [0] = 0x0000,
-       [1] = 0x0080,
-       [2] = 0x0808,
-       [3] = 0x0888,
-       [4] = 0x2222,
-       [5] = 0x4924,
-       [6] = 0x4A52,
-       [7] = 0x54AA,
-       [8] = 0x5555,
-       [9] = 0xD555,
-       [10] = 0xD5D5,
-       [11] = 0xDDD5,
-       [12] = 0xDDDD,
-       [13] = 0xDFDD,
-       [14] = 0xDFDF,
-       [15] = 0xFFDF,
-};
-
-static void s3c24xx_serial_set_termios(struct uart_port *port,
-                                      struct ktermios *termios,
-                                      struct ktermios *old)
-{
-       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct clk *clk = ERR_PTR(-EINVAL);
-       unsigned long flags;
-       unsigned int baud, quot, clk_sel = 0;
-       unsigned int ulcon;
-       unsigned int umcon;
-       unsigned int udivslot = 0;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 3000000);
-       quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
-       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
-               quot = port->custom_divisor;
-       if (IS_ERR(clk))
-               return;
-
-       /* check to see if we need  to change clock source */
-
-       if (ourport->baudclk != clk) {
-               clk_prepare_enable(clk);
-
-               s3c24xx_serial_setsource(port, clk_sel);
-
-               if (!IS_ERR(ourport->baudclk)) {
-                       clk_disable_unprepare(ourport->baudclk);
-                       ourport->baudclk = ERR_PTR(-EINVAL);
-               }
-
-               ourport->baudclk = clk;
-               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
-       }
-
-       if (ourport->info->has_divslot) {
-               unsigned int div = ourport->baudclk_rate / baud;
-
-               if (cfg->has_fracval) {
-                       udivslot = (div & 15);
-                       dbg("fracval = %04x\n", udivslot);
-               } else {
-                       udivslot = udivslot_table[div & 15];
-                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
-               }
-       }
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               dbg("config: 5bits/char\n");
-               ulcon = S3C2410_LCON_CS5;
-               break;
-       case CS6:
-               dbg("config: 6bits/char\n");
-               ulcon = S3C2410_LCON_CS6;
-               break;
-       case CS7:
-               dbg("config: 7bits/char\n");
-               ulcon = S3C2410_LCON_CS7;
-               break;
-       case CS8:
-       default:
-               dbg("config: 8bits/char\n");
-               ulcon = S3C2410_LCON_CS8;
-               break;
-       }
-
-       /* preserve original lcon IR settings */
-       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
-
-       if (termios->c_cflag & CSTOPB)
-               ulcon |= S3C2410_LCON_STOPB;
-
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & PARODD)
-                       ulcon |= S3C2410_LCON_PODD;
-               else
-                       ulcon |= S3C2410_LCON_PEVEN;
-       } else {
-               ulcon |= S3C2410_LCON_PNONE;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
-           ulcon, quot, udivslot);
-
-       wr_regl(port, S3C2410_ULCON, ulcon);
-       wr_regl(port, S3C2410_UBRDIV, quot);
-
-       port->status &= ~UPSTAT_AUTOCTS;
-
-       umcon = rd_regl(port, S3C2410_UMCON);
-       if (termios->c_cflag & CRTSCTS) {
-               umcon |= S3C2410_UMCOM_AFC;
-               /* Disable RTS when RX FIFO contains 63 bytes */
-               umcon &= ~S3C2412_UMCON_AFC_8;
-               port->status = UPSTAT_AUTOCTS;
-       } else {
-               umcon &= ~S3C2410_UMCOM_AFC;
-       }
-       wr_regl(port, S3C2410_UMCON, umcon);
-
-       if (ourport->info->has_divslot)
-               wr_regl(port, S3C2443_DIVSLOT, udivslot);
-
-       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
-           rd_regl(port, S3C2410_ULCON),
-           rd_regl(port, S3C2410_UCON),
-           rd_regl(port, S3C2410_UFCON));
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Which character status flags are we interested in?
-        */
-       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= S3C2410_UERSTAT_FRAME |
-                       S3C2410_UERSTAT_PARITY;
-       /*
-        * Which character status flags should we ignore?
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
-       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *s3c24xx_serial_type(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_S3C2410:
-               return "S3C2410";
-       case PORT_S3C2440:
-               return "S3C2440";
-       case PORT_S3C2412:
-               return "S3C2412";
-       case PORT_S3C6400:
-               return "S3C6400/10";
-       default:
-               return NULL;
-       }
-}
-
-#define MAP_SIZE (0x100)
-
-static void s3c24xx_serial_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, MAP_SIZE);
-}
-
-static int s3c24xx_serial_request_port(struct uart_port *port)
-{
-       const char *name = s3c24xx_serial_portname(port);
-       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
-}
-
-static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       if (flags & UART_CONFIG_TYPE &&
-           s3c24xx_serial_request_port(port) == 0)
-               port->type = info->type;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int
-s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-static struct console s3c24xx_serial_console;
-
-static int __init s3c24xx_serial_console_init(void)
-{
-       register_console(&s3c24xx_serial_console);
-       return 0;
-}
-console_initcall(s3c24xx_serial_console_init);
-
-#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
-#else
-#define S3C24XX_SERIAL_CONSOLE NULL
-#endif
-
-#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
-static int s3c24xx_serial_get_poll_char(struct uart_port *port);
-static void s3c24xx_serial_put_poll_char(struct uart_port *port,
-                        unsigned char c);
-#endif
-
-static struct uart_ops s3c24xx_serial_ops = {
-       .pm             = s3c24xx_serial_pm,
-       .tx_empty       = s3c24xx_serial_tx_empty,
-       .get_mctrl      = s3c24xx_serial_get_mctrl,
-       .set_mctrl      = s3c24xx_serial_set_mctrl,
-       .stop_tx        = s3c24xx_serial_stop_tx,
-       .start_tx       = s3c24xx_serial_start_tx,
-       .stop_rx        = s3c24xx_serial_stop_rx,
-       .break_ctl      = s3c24xx_serial_break_ctl,
-       .startup        = s3c24xx_serial_startup,
-       .shutdown       = s3c24xx_serial_shutdown,
-       .set_termios    = s3c24xx_serial_set_termios,
-       .type           = s3c24xx_serial_type,
-       .release_port   = s3c24xx_serial_release_port,
-       .request_port   = s3c24xx_serial_request_port,
-       .config_port    = s3c24xx_serial_config_port,
-       .verify_port    = s3c24xx_serial_verify_port,
-#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
-       .poll_get_char = s3c24xx_serial_get_poll_char,
-       .poll_put_char = s3c24xx_serial_put_poll_char,
-#endif
-};
-
-static struct uart_driver s3c24xx_uart_drv = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "s3c2410_serial",
-       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
-       .cons           = S3C24XX_SERIAL_CONSOLE,
-       .dev_name       = S3C24XX_SERIAL_NAME,
-       .major          = S3C24XX_SERIAL_MAJOR,
-       .minor          = S3C24XX_SERIAL_MINOR,
-};
-
-#define __PORT_LOCK_UNLOCKED(i) \
-       __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock)
-static struct s3c24xx_uart_port
-s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
-       [0] = {
-               .port = {
-                       .lock           = __PORT_LOCK_UNLOCKED(0),
-                       .iotype         = UPIO_MEM,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 0,
-               }
-       },
-       [1] = {
-               .port = {
-                       .lock           = __PORT_LOCK_UNLOCKED(1),
-                       .iotype         = UPIO_MEM,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 1,
-               }
-       },
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
-
-       [2] = {
-               .port = {
-                       .lock           = __PORT_LOCK_UNLOCKED(2),
-                       .iotype         = UPIO_MEM,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 2,
-               }
-       },
-#endif
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
-       [3] = {
-               .port = {
-                       .lock           = __PORT_LOCK_UNLOCKED(3),
-                       .iotype         = UPIO_MEM,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 3,
-               }
-       }
-#endif
-};
-#undef __PORT_LOCK_UNLOCKED
-
-/* s3c24xx_serial_resetport
- *
- * reset the fifos and other the settings.
-*/
-
-static void s3c24xx_serial_resetport(struct uart_port *port,
-                                  struct s3c2410_uartcfg *cfg)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-       unsigned int ucon_mask;
-
-       ucon_mask = info->clksel_mask;
-       if (info->type == PORT_S3C2440)
-               ucon_mask |= S3C2440_UCON0_DIVMASK;
-
-       ucon &= ucon_mask;
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-
-       /* reset both fifos */
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       /* some delay is required after fifo reset */
-       udelay(1);
-}
-
-
-#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
-
-static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
-                                            unsigned long val, void *data)
-{
-       struct s3c24xx_uart_port *port;
-       struct uart_port *uport;
-
-       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
-       uport = &port->port;
-
-       /* check to see if port is enabled */
-
-       if (port->pm_level != 0)
-               return 0;
-
-       /* try and work out if the baudrate is changing, we can detect
-        * a change in rate, but we do not have support for detecting
-        * a disturbance in the clock-rate over the change.
-        */
-
-       if (IS_ERR(port->baudclk))
-               goto exit;
-
-       if (port->baudclk_rate == clk_get_rate(port->baudclk))
-               goto exit;
-
-       if (val == CPUFREQ_PRECHANGE) {
-               /* we should really shut the port down whilst the
-                * frequency change is in progress. */
-
-       } else if (val == CPUFREQ_POSTCHANGE) {
-               struct ktermios *termios;
-               struct tty_struct *tty;
-
-               if (uport->state == NULL)
-                       goto exit;
-
-               tty = uport->state->port.tty;
-
-               if (tty == NULL)
-                       goto exit;
-
-               termios = &tty->termios;
-
-               if (termios == NULL) {
-                       dev_warn(uport->dev, "%s: no termios?\n", __func__);
-                       goto exit;
-               }
-
-               s3c24xx_serial_set_termios(uport, termios, NULL);
-       }
-
-exit:
-       return 0;
-}
-
-static inline int
-s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
-{
-       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
-
-       return cpufreq_register_notifier(&port->freq_transition,
-                                        CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void
-s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
-{
-       cpufreq_unregister_notifier(&port->freq_transition,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int
-s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
-{
-       return 0;
-}
-
-static inline void
-s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
-{
-}
-#endif
-
-static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport)
-{
-       struct device *dev = ourport->port.dev;
-       struct s3c24xx_uart_info *info = ourport->info;
-       char clk_name[MAX_CLK_NAME_LENGTH];
-       unsigned int clk_sel;
-       struct clk *clk;
-       int clk_num;
-       int ret;
-
-       clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel;
-       for (clk_num = 0; clk_num < info->num_clks; clk_num++) {
-               if (!(clk_sel & (1 << clk_num)))
-                       continue;
-
-               sprintf(clk_name, "clk_uart_baud%d", clk_num);
-               clk = clk_get(dev, clk_name);
-               if (IS_ERR(clk))
-                       continue;
-
-               ret = clk_prepare_enable(clk);
-               if (ret) {
-                       clk_put(clk);
-                       continue;
-               }
-
-               ourport->baudclk = clk;
-               ourport->baudclk_rate = clk_get_rate(clk);
-               s3c24xx_serial_setsource(&ourport->port, clk_num);
-
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-/* s3c24xx_serial_init_port
- *
- * initialise a single serial port from the platform device given
- */
-
-static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
-                                   struct platform_device *platdev)
-{
-       struct uart_port *port = &ourport->port;
-       struct s3c2410_uartcfg *cfg = ourport->cfg;
-       struct resource *res;
-       int ret;
-
-       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
-
-       if (platdev == NULL)
-               return -ENODEV;
-
-       if (port->mapbase != 0)
-               return -EINVAL;
-
-       /* setup info for port */
-       port->dev       = &platdev->dev;
-
-       /* Startup sequence is different for s3c64xx and higher SoC's */
-       if (s3c24xx_serial_has_interrupt_mask(port))
-               s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
-
-       port->uartclk = 1;
-
-       if (cfg->uart_flags & UPF_CONS_FLOW) {
-               dbg("s3c24xx_serial_init_port: enabling flow control\n");
-               port->flags |= UPF_CONS_FLOW;
-       }
-
-       /* sort our the physical and virtual addresses for each UART */
-
-       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(port->dev, "failed to find memory resource for uart\n");
-               return -EINVAL;
-       }
-
-       dbg("resource %pR)\n", res);
-
-       port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
-       if (!port->membase) {
-               dev_err(port->dev, "failed to remap controller address\n");
-               return -EBUSY;
-       }
-
-       port->mapbase = res->start;
-       ret = platform_get_irq(platdev, 0);
-       if (ret < 0)
-               port->irq = 0;
-       else {
-               port->irq = ret;
-               ourport->rx_irq = ret;
-               ourport->tx_irq = ret + 1;
-       }
-
-       ret = platform_get_irq(platdev, 1);
-       if (ret > 0)
-               ourport->tx_irq = ret;
-       /*
-        * DMA is currently supported only on DT platforms, if DMA properties
-        * are specified.
-        */
-       if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
-                                                    "dmas", NULL)) {
-               ourport->dma = devm_kzalloc(port->dev,
-                                           sizeof(*ourport->dma),
-                                           GFP_KERNEL);
-               if (!ourport->dma) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-       }
-
-       ourport->clk    = clk_get(&platdev->dev, "uart");
-       if (IS_ERR(ourport->clk)) {
-               pr_err("%s: Controller clock not found\n",
-                               dev_name(&platdev->dev));
-               ret = PTR_ERR(ourport->clk);
-               goto err;
-       }
-
-       ret = clk_prepare_enable(ourport->clk);
-       if (ret) {
-               pr_err("uart: clock failed to prepare+enable: %d\n", ret);
-               clk_put(ourport->clk);
-               goto err;
-       }
-
-       ret = s3c24xx_serial_enable_baudclk(ourport);
-       if (ret)
-               pr_warn("uart: failed to enable baudclk\n");
-
-       /* Keep all interrupts masked and cleared */
-       if (s3c24xx_serial_has_interrupt_mask(port)) {
-               wr_regl(port, S3C64XX_UINTM, 0xf);
-               wr_regl(port, S3C64XX_UINTP, 0xf);
-               wr_regl(port, S3C64XX_UINTSP, 0xf);
-       }
-
-       dbg("port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n",
-           &port->mapbase, port->membase, port->irq,
-           ourport->rx_irq, ourport->tx_irq, port->uartclk);
-
-       /* reset the fifos (and setup the uart) */
-       s3c24xx_serial_resetport(port, cfg);
-
-       return 0;
-
-err:
-       port->mapbase = 0;
-       return ret;
-}
-
-/* Device driver serial port probe */
-
-static const struct of_device_id s3c24xx_uart_dt_match[];
-static int probe_index;
-
-static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
-                       struct platform_device *pdev)
-{
-#ifdef CONFIG_OF
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(s3c24xx_uart_dt_match, pdev->dev.of_node);
-               return (struct s3c24xx_serial_drv_data *)match->data;
-       }
-#endif
-       return (struct s3c24xx_serial_drv_data *)
-                       platform_get_device_id(pdev)->driver_data;
-}
-
-static int s3c24xx_serial_probe(struct platform_device *pdev)
-{
-       struct device_node *np = pdev->dev.of_node;
-       struct s3c24xx_uart_port *ourport;
-       int index = probe_index;
-       int ret;
-
-       if (np) {
-               ret = of_alias_get_id(np, "serial");
-               if (ret >= 0)
-                       index = ret;
-       }
-
-       dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index);
-
-       if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) {
-               dev_err(&pdev->dev, "serial%d out of range\n", index);
-               return -EINVAL;
-       }
-       ourport = &s3c24xx_serial_ports[index];
-
-       ourport->drv_data = s3c24xx_get_driver_data(pdev);
-       if (!ourport->drv_data) {
-               dev_err(&pdev->dev, "could not find driver data\n");
-               return -ENODEV;
-       }
-
-       ourport->baudclk = ERR_PTR(-EINVAL);
-       ourport->info = ourport->drv_data->info;
-       ourport->cfg = (dev_get_platdata(&pdev->dev)) ?
-                       dev_get_platdata(&pdev->dev) :
-                       ourport->drv_data->def_cfg;
-
-       if (np)
-               of_property_read_u32(np,
-                       "samsung,uart-fifosize", &ourport->port.fifosize);
-
-       if (ourport->drv_data->fifosize[index])
-               ourport->port.fifosize = ourport->drv_data->fifosize[index];
-       else if (ourport->info->fifosize)
-               ourport->port.fifosize = ourport->info->fifosize;
-
-       /*
-        * DMA transfers must be aligned at least to cache line size,
-        * so find minimal transfer size suitable for DMA mode
-        */
-       ourport->min_dma_size = max_t(int, ourport->port.fifosize,
-                                   dma_get_cache_alignment());
-
-       dbg("%s: initialising port %p...\n", __func__, ourport);
-
-       ret = s3c24xx_serial_init_port(ourport, pdev);
-       if (ret < 0)
-               return ret;
-
-       if (!s3c24xx_uart_drv.state) {
-               ret = uart_register_driver(&s3c24xx_uart_drv);
-               if (ret < 0) {
-                       pr_err("Failed to register Samsung UART driver\n");
-                       return ret;
-               }
-       }
-
-       dbg("%s: adding port\n", __func__);
-       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
-       platform_set_drvdata(pdev, &ourport->port);
-
-       /*
-        * Deactivate the clock enabled in s3c24xx_serial_init_port here,
-        * so that a potential re-enablement through the pm-callback overlaps
-        * and keeps the clock enabled in this case.
-        */
-       clk_disable_unprepare(ourport->clk);
-       if (!IS_ERR(ourport->baudclk))
-               clk_disable_unprepare(ourport->baudclk);
-
-       ret = s3c24xx_serial_cpufreq_register(ourport);
-       if (ret < 0)
-               dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
-
-       probe_index++;
-
-       return 0;
-}
-
-static int s3c24xx_serial_remove(struct platform_device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-
-       if (port) {
-               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
-               uart_remove_one_port(&s3c24xx_uart_drv, port);
-       }
-
-       uart_unregister_driver(&s3c24xx_uart_drv);
-
-       return 0;
-}
-
-/* UART power management code */
-#ifdef CONFIG_PM_SLEEP
-static int s3c24xx_serial_suspend(struct device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(dev);
-
-       if (port)
-               uart_suspend_port(&s3c24xx_uart_drv, port);
-
-       return 0;
-}
-
-static int s3c24xx_serial_resume(struct device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(dev);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (port) {
-               clk_prepare_enable(ourport->clk);
-               if (!IS_ERR(ourport->baudclk))
-                       clk_prepare_enable(ourport->baudclk);
-               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
-               if (!IS_ERR(ourport->baudclk))
-                       clk_disable_unprepare(ourport->baudclk);
-               clk_disable_unprepare(ourport->clk);
-
-               uart_resume_port(&s3c24xx_uart_drv, port);
-       }
-
-       return 0;
-}
-
-static int s3c24xx_serial_resume_noirq(struct device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(dev);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (port) {
-               /* restore IRQ mask */
-               if (s3c24xx_serial_has_interrupt_mask(port)) {
-                       unsigned int uintm = 0xf;
-                       if (tx_enabled(port))
-                               uintm &= ~S3C64XX_UINTM_TXD_MSK;
-                       if (rx_enabled(port))
-                               uintm &= ~S3C64XX_UINTM_RXD_MSK;
-                       clk_prepare_enable(ourport->clk);
-                       if (!IS_ERR(ourport->baudclk))
-                               clk_prepare_enable(ourport->baudclk);
-                       wr_regl(port, S3C64XX_UINTM, uintm);
-                       if (!IS_ERR(ourport->baudclk))
-                               clk_disable_unprepare(ourport->baudclk);
-                       clk_disable_unprepare(ourport->clk);
-               }
-       }
-
-       return 0;
-}
-
-static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
-       .suspend = s3c24xx_serial_suspend,
-       .resume = s3c24xx_serial_resume,
-       .resume_noirq = s3c24xx_serial_resume_noirq,
-};
-#define SERIAL_SAMSUNG_PM_OPS  (&s3c24xx_serial_pm_ops)
-
-#else /* !CONFIG_PM_SLEEP */
-
-#define SERIAL_SAMSUNG_PM_OPS  NULL
-#endif /* CONFIG_PM_SLEEP */
-
-/* Console code */
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-static struct uart_port *cons_uart;
-
-static int
-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat, utrstat;
-
-       if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               /* fifo mode - check amount of data in fifo registers... */
-
-               ufstat = rd_regl(port, S3C2410_UFSTAT);
-               return (ufstat & info->tx_fifofull) ? 0 : 1;
-       }
-
-       /* in non-fifo mode, we go and use the tx buffer empty */
-
-       utrstat = rd_regl(port, S3C2410_UTRSTAT);
-       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
-}
-
-static bool
-s3c24xx_port_configured(unsigned int ucon)
-{
-       /* consider the serial port configured if the tx/rx mode set */
-       return (ucon & 0xf) != 0;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int s3c24xx_serial_get_poll_char(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       unsigned int ufstat;
-
-       ufstat = rd_regl(port, S3C2410_UFSTAT);
-       if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
-               return NO_POLL_CHAR;
-
-       return rd_regb(port, S3C2410_URXH);
-}
-
-static void s3c24xx_serial_put_poll_char(struct uart_port *port,
-               unsigned char c)
-{
-       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
-       unsigned int ucon = rd_regl(port, S3C2410_UCON);
-
-       /* not possible to xmit on unconfigured port */
-       if (!s3c24xx_port_configured(ucon))
-               return;
-
-       while (!s3c24xx_serial_console_txrdy(port, ufcon))
-               cpu_relax();
-       wr_regb(port, S3C2410_UTXH, c);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static void
-s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
-{
-       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
-
-       while (!s3c24xx_serial_console_txrdy(port, ufcon))
-               cpu_relax();
-       wr_regb(port, S3C2410_UTXH, ch);
-}
-
-static void
-s3c24xx_serial_console_write(struct console *co, const char *s,
-                            unsigned int count)
-{
-       unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
-
-       /* not possible to xmit on unconfigured port */
-       if (!s3c24xx_port_configured(ucon))
-               return;
-
-       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
-}
-
-static void __init
-s3c24xx_serial_get_options(struct uart_port *port, int *baud,
-                          int *parity, int *bits)
-{
-       struct clk *clk;
-       unsigned int ulcon;
-       unsigned int ucon;
-       unsigned int ubrdiv;
-       unsigned long rate;
-       unsigned int clk_sel;
-       char clk_name[MAX_CLK_NAME_LENGTH];
-
-       ulcon  = rd_regl(port, S3C2410_ULCON);
-       ucon   = rd_regl(port, S3C2410_UCON);
-       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
-
-       dbg("s3c24xx_serial_get_options: port=%p\n"
-           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
-           port, ulcon, ucon, ubrdiv);
-
-       if (s3c24xx_port_configured(ucon)) {
-               switch (ulcon & S3C2410_LCON_CSMASK) {
-               case S3C2410_LCON_CS5:
-                       *bits = 5;
-                       break;
-               case S3C2410_LCON_CS6:
-                       *bits = 6;
-                       break;
-               case S3C2410_LCON_CS7:
-                       *bits = 7;
-                       break;
-               case S3C2410_LCON_CS8:
-               default:
-                       *bits = 8;
-                       break;
-               }
-
-               switch (ulcon & S3C2410_LCON_PMASK) {
-               case S3C2410_LCON_PEVEN:
-                       *parity = 'e';
-                       break;
-
-               case S3C2410_LCON_PODD:
-                       *parity = 'o';
-                       break;
-
-               case S3C2410_LCON_PNONE:
-               default:
-                       *parity = 'n';
-               }
-
-               /* now calculate the baud rate */
-
-               clk_sel = s3c24xx_serial_getsource(port);
-               sprintf(clk_name, "clk_uart_baud%d", clk_sel);
-
-               clk = clk_get(port->dev, clk_name);
-               if (!IS_ERR(clk))
-                       rate = clk_get_rate(clk);
-               else
-                       rate = 1;
-
-               *baud = rate / (16 * (ubrdiv + 1));
-               dbg("calculated baud %d\n", *baud);
-       }
-
-}
-
-static int __init
-s3c24xx_serial_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
-           co, co->index, options);
-
-       /* is this a valid port */
-
-       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
-               co->index = 0;
-
-       port = &s3c24xx_serial_ports[co->index].port;
-
-       /* is the port configured? */
-
-       if (port->mapbase == 0x0)
-               return -ENODEV;
-
-       cons_uart = port;
-
-       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
-
-       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct console s3c24xx_serial_console = {
-       .name           = S3C24XX_SERIAL_NAME,
-       .device         = uart_console_device,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .write          = s3c24xx_serial_console_write,
-       .setup          = s3c24xx_serial_console_setup,
-       .data           = &s3c24xx_uart_drv,
-};
-#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
-
-#ifdef CONFIG_CPU_S3C2410
-static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = {
-       .info = &(struct s3c24xx_uart_info) {
-               .name           = "Samsung S3C2410 UART",
-               .type           = PORT_S3C2410,
-               .fifosize       = 16,
-               .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
-               .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
-               .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
-               .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
-               .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
-               .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
-               .def_clk_sel    = S3C2410_UCON_CLKSEL0,
-               .num_clks       = 2,
-               .clksel_mask    = S3C2410_UCON_CLKMASK,
-               .clksel_shift   = S3C2410_UCON_CLKSHIFT,
-       },
-       .def_cfg = &(struct s3c2410_uartcfg) {
-               .ucon           = S3C2410_UCON_DEFAULT,
-               .ufcon          = S3C2410_UFCON_DEFAULT,
-       },
-};
-#define S3C2410_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2410_serial_drv_data)
-#else
-#define S3C2410_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#endif
-
-#ifdef CONFIG_CPU_S3C2412
-static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
-       .info = &(struct s3c24xx_uart_info) {
-               .name           = "Samsung S3C2412 UART",
-               .type           = PORT_S3C2412,
-               .fifosize       = 64,
-               .has_divslot    = 1,
-               .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-               .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-               .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-               .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-               .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-               .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-               .def_clk_sel    = S3C2410_UCON_CLKSEL2,
-               .num_clks       = 4,
-               .clksel_mask    = S3C2412_UCON_CLKMASK,
-               .clksel_shift   = S3C2412_UCON_CLKSHIFT,
-       },
-       .def_cfg = &(struct s3c2410_uartcfg) {
-               .ucon           = S3C2410_UCON_DEFAULT,
-               .ufcon          = S3C2410_UFCON_DEFAULT,
-       },
-};
-#define S3C2412_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2412_serial_drv_data)
-#else
-#define S3C2412_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#endif
-
-#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
-       defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
-static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
-       .info = &(struct s3c24xx_uart_info) {
-               .name           = "Samsung S3C2440 UART",
-               .type           = PORT_S3C2440,
-               .fifosize       = 64,
-               .has_divslot    = 1,
-               .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-               .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-               .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-               .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-               .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-               .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-               .def_clk_sel    = S3C2410_UCON_CLKSEL2,
-               .num_clks       = 4,
-               .clksel_mask    = S3C2412_UCON_CLKMASK,
-               .clksel_shift   = S3C2412_UCON_CLKSHIFT,
-       },
-       .def_cfg = &(struct s3c2410_uartcfg) {
-               .ucon           = S3C2410_UCON_DEFAULT,
-               .ufcon          = S3C2410_UFCON_DEFAULT,
-       },
-};
-#define S3C2440_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2440_serial_drv_data)
-#else
-#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#endif
-
-#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)
-static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
-       .info = &(struct s3c24xx_uart_info) {
-               .name           = "Samsung S3C6400 UART",
-               .type           = PORT_S3C6400,
-               .fifosize       = 64,
-               .has_divslot    = 1,
-               .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-               .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-               .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-               .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-               .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-               .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-               .def_clk_sel    = S3C2410_UCON_CLKSEL2,
-               .num_clks       = 4,
-               .clksel_mask    = S3C6400_UCON_CLKMASK,
-               .clksel_shift   = S3C6400_UCON_CLKSHIFT,
-       },
-       .def_cfg = &(struct s3c2410_uartcfg) {
-               .ucon           = S3C2410_UCON_DEFAULT,
-               .ufcon          = S3C2410_UFCON_DEFAULT,
-       },
-};
-#define S3C6400_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c6400_serial_drv_data)
-#else
-#define S3C6400_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#endif
-
-#ifdef CONFIG_CPU_S5PV210
-static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
-       .info = &(struct s3c24xx_uart_info) {
-               .name           = "Samsung S5PV210 UART",
-               .type           = PORT_S3C6400,
-               .has_divslot    = 1,
-               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,
-               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,
-               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,
-               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,
-               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,
-               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,
-               .def_clk_sel    = S3C2410_UCON_CLKSEL0,
-               .num_clks       = 2,
-               .clksel_mask    = S5PV210_UCON_CLKMASK,
-               .clksel_shift   = S5PV210_UCON_CLKSHIFT,
-       },
-       .def_cfg = &(struct s3c2410_uartcfg) {
-               .ucon           = S5PV210_UCON_DEFAULT,
-               .ufcon          = S5PV210_UFCON_DEFAULT,
-       },
-       .fifosize = { 256, 64, 16, 16 },
-};
-#define S5PV210_SERIAL_DRV_DATA ((kernel_ulong_t)&s5pv210_serial_drv_data)
-#else
-#define S5PV210_SERIAL_DRV_DATA        (kernel_ulong_t)NULL
-#endif
-
-#if defined(CONFIG_ARCH_EXYNOS)
-#define EXYNOS_COMMON_SERIAL_DRV_DATA                          \
-       .info = &(struct s3c24xx_uart_info) {                   \
-               .name           = "Samsung Exynos UART",        \
-               .type           = PORT_S3C6400,                 \
-               .has_divslot    = 1,                            \
-               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
-               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
-               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
-               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
-               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
-               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
-               .def_clk_sel    = S3C2410_UCON_CLKSEL0,         \
-               .num_clks       = 1,                            \
-               .clksel_mask    = 0,                            \
-               .clksel_shift   = 0,                            \
-       },                                                      \
-       .def_cfg = &(struct s3c2410_uartcfg) {                  \
-               .ucon           = S5PV210_UCON_DEFAULT,         \
-               .ufcon          = S5PV210_UFCON_DEFAULT,        \
-               .has_fracval    = 1,                            \
-       }                                                       \
-
-static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
-       EXYNOS_COMMON_SERIAL_DRV_DATA,
-       .fifosize = { 256, 64, 16, 16 },
-};
-
-static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
-       EXYNOS_COMMON_SERIAL_DRV_DATA,
-       .fifosize = { 64, 256, 16, 256 },
-};
-
-#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
-#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data)
-#else
-#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#endif
-
-static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
-       {
-               .name           = "s3c2410-uart",
-               .driver_data    = S3C2410_SERIAL_DRV_DATA,
-       }, {
-               .name           = "s3c2412-uart",
-               .driver_data    = S3C2412_SERIAL_DRV_DATA,
-       }, {
-               .name           = "s3c2440-uart",
-               .driver_data    = S3C2440_SERIAL_DRV_DATA,
-       }, {
-               .name           = "s3c6400-uart",
-               .driver_data    = S3C6400_SERIAL_DRV_DATA,
-       }, {
-               .name           = "s5pv210-uart",
-               .driver_data    = S5PV210_SERIAL_DRV_DATA,
-       }, {
-               .name           = "exynos4210-uart",
-               .driver_data    = EXYNOS4210_SERIAL_DRV_DATA,
-       }, {
-               .name           = "exynos5433-uart",
-               .driver_data    = EXYNOS5433_SERIAL_DRV_DATA,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);
-
-#ifdef CONFIG_OF
-static const struct of_device_id s3c24xx_uart_dt_match[] = {
-       { .compatible = "samsung,s3c2410-uart",
-               .data = (void *)S3C2410_SERIAL_DRV_DATA },
-       { .compatible = "samsung,s3c2412-uart",
-               .data = (void *)S3C2412_SERIAL_DRV_DATA },
-       { .compatible = "samsung,s3c2440-uart",
-               .data = (void *)S3C2440_SERIAL_DRV_DATA },
-       { .compatible = "samsung,s3c6400-uart",
-               .data = (void *)S3C6400_SERIAL_DRV_DATA },
-       { .compatible = "samsung,s5pv210-uart",
-               .data = (void *)S5PV210_SERIAL_DRV_DATA },
-       { .compatible = "samsung,exynos4210-uart",
-               .data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
-       { .compatible = "samsung,exynos5433-uart",
-               .data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
-       {},
-};
-MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
-#endif
-
-static struct platform_driver samsung_serial_driver = {
-       .probe          = s3c24xx_serial_probe,
-       .remove         = s3c24xx_serial_remove,
-       .id_table       = s3c24xx_serial_driver_ids,
-       .driver         = {
-               .name   = "samsung-uart",
-               .pm     = SERIAL_SAMSUNG_PM_OPS,
-               .of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
-       },
-};
-
-module_platform_driver(samsung_serial_driver);
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-/*
- * Early console.
- */
-
-struct samsung_early_console_data {
-       u32 txfull_mask;
-};
-
-static void samsung_early_busyuart(struct uart_port *port)
-{
-       while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
-               ;
-}
-
-static void samsung_early_busyuart_fifo(struct uart_port *port)
-{
-       struct samsung_early_console_data *data = port->private_data;
-
-       while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
-               ;
-}
-
-static void samsung_early_putc(struct uart_port *port, int c)
-{
-       if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
-               samsung_early_busyuart_fifo(port);
-       else
-               samsung_early_busyuart(port);
-
-       writeb(c, port->membase + S3C2410_UTXH);
-}
-
-static void samsung_early_write(struct console *con, const char *s, unsigned n)
-{
-       struct earlycon_device *dev = con->data;
-
-       uart_console_write(&dev->port, s, n, samsung_early_putc);
-}
-
-static int __init samsung_early_console_setup(struct earlycon_device *device,
-                                             const char *opt)
-{
-       if (!device->port.membase)
-               return -ENODEV;
-
-       device->con->write = samsung_early_write;
-       return 0;
-}
-
-/* S3C2410 */
-static struct samsung_early_console_data s3c2410_early_console_data = {
-       .txfull_mask = S3C2410_UFSTAT_TXFULL,
-};
-
-static int __init s3c2410_early_console_setup(struct earlycon_device *device,
-                                             const char *opt)
-{
-       device->port.private_data = &s3c2410_early_console_data;
-       return samsung_early_console_setup(device, opt);
-}
-OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
-                       s3c2410_early_console_setup);
-
-/* S3C2412, S3C2440, S3C64xx */
-static struct samsung_early_console_data s3c2440_early_console_data = {
-       .txfull_mask = S3C2440_UFSTAT_TXFULL,
-};
-
-static int __init s3c2440_early_console_setup(struct earlycon_device *device,
-                                             const char *opt)
-{
-       device->port.private_data = &s3c2440_early_console_data;
-       return samsung_early_console_setup(device, opt);
-}
-OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
-                       s3c2440_early_console_setup);
-OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
-                       s3c2440_early_console_setup);
-OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
-                       s3c2440_early_console_setup);
-
-/* S5PV210, EXYNOS */
-static struct samsung_early_console_data s5pv210_early_console_data = {
-       .txfull_mask = S5PV210_UFSTAT_TXFULL,
-};
-
-static int __init s5pv210_early_console_setup(struct earlycon_device *device,
-                                             const char *opt)
-{
-       device->port.private_data = &s5pv210_early_console_data;
-       return samsung_early_console_setup(device, opt);
-}
-OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
-                       s5pv210_early_console_setup);
-OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
-                       s5pv210_early_console_setup);
-#endif
-
-MODULE_ALIAS("platform:samsung-uart");
-MODULE_DESCRIPTION("Samsung SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
new file mode 100644 (file)
index 0000000..83fd516
--- /dev/null
@@ -0,0 +1,2595 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver core for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+*/
+
+/* Hote on 2410 error handling
+ *
+ * The s3c2410 manual has a love/hate affair with the contents of the
+ * UERSTAT register in the UART blocks, and keeps marking some of the
+ * error bits as reserved. Having checked with the s3c2410x01,
+ * it copes with BREAKs properly, so I am happy to ignore the RESERVED
+ * feature from the latter versions of the manual.
+ *
+ * If it becomes aparrent that latter versions of the 2410 remove these
+ * bits, then action will have to be taken to differentiate the versions
+ * and change the policy on BREAK
+ *
+ * BJD, 04-Nov-2004
+*/
+
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/serial_s3c.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/of.h>
+
+#include <asm/irq.h>
+
+#include "samsung.h"
+
+#if    defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
+       !defined(MODULE)
+
+extern void printascii(const char *);
+
+__printf(1, 2)
+static void dbg(const char *fmt, ...)
+{
+       va_list va;
+       char buff[256];
+
+       va_start(va, fmt);
+       vscnprintf(buff, sizeof(buff), fmt, va);
+       va_end(va);
+
+       printascii(buff);
+}
+
+#else
+#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0)
+#endif
+
+/* UART name and device definitions */
+
+#define S3C24XX_SERIAL_NAME    "ttySAC"
+#define S3C24XX_SERIAL_MAJOR   204
+#define S3C24XX_SERIAL_MINOR   64
+
+#define S3C24XX_TX_PIO                 1
+#define S3C24XX_TX_DMA                 2
+#define S3C24XX_RX_PIO                 1
+#define S3C24XX_RX_DMA                 2
+/* macros to change one thing to another */
+
+#define tx_enabled(port) ((port)->unused[0])
+#define rx_enabled(port) ((port)->unused[1])
+
+/* flag to ignore all characters coming in */
+#define RXSTAT_DUMMY_READ (0x10000000)
+
+static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
+{
+       return container_of(port, struct s3c24xx_uart_port, port);
+}
+
+/* translate a port to the device name */
+
+static inline const char *s3c24xx_serial_portname(struct uart_port *port)
+{
+       return to_platform_device(port->dev)->name;
+}
+
+static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
+{
+       return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
+}
+
+/*
+ * s3c64xx and later SoC's include the interrupt mask and status registers in
+ * the controller itself, unlike the s3c24xx SoC's which have these registers
+ * in the interrupt controller. Check if the port type is s3c64xx or higher.
+ */
+static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+{
+       return to_ourport(port)->info->type == PORT_S3C6400;
+}
+
+static void s3c24xx_serial_rx_enable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon, ufcon;
+       int count = 10000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon |= S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_rx_disable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_stop_tx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct dma_tx_state state;
+       int count;
+
+       if (!tx_enabled(port))
+               return;
+
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
+       else
+               disable_irq_nosync(ourport->tx_irq);
+
+       if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
+               dmaengine_pause(dma->tx_chan);
+               dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+               dmaengine_terminate_all(dma->tx_chan);
+               dma_sync_single_for_cpu(ourport->port.dev,
+                       dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
+               async_tx_ack(dma->tx_desc);
+               count = dma->tx_bytes_requested - state.residue;
+               xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+               port->icount.tx += count;
+       }
+
+       tx_enabled(port) = 0;
+       ourport->tx_in_progress = 0;
+
+       if (port->flags & UPF_CONS_FLOW)
+               s3c24xx_serial_rx_enable(port);
+
+       ourport->tx_mode = 0;
+}
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
+static void s3c24xx_serial_tx_dma_complete(void *args)
+{
+       struct s3c24xx_uart_port *ourport = args;
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct dma_tx_state state;
+       unsigned long flags;
+       int count;
+
+
+       dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+       count = dma->tx_bytes_requested - state.residue;
+       async_tx_ack(dma->tx_desc);
+
+       dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
+                               dma->tx_size, DMA_TO_DEVICE);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+       port->icount.tx += count;
+       ourport->tx_in_progress = 0;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       s3c24xx_serial_start_next_tx(ourport);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       u32 ucon;
+
+       /* Mask Tx interrupt */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
+       else
+               disable_irq_nosync(ourport->tx_irq);
+
+       /* Enable tx dma mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
+       ucon |= (dma_get_cache_alignment() >= 16) ?
+               S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+       ucon |= S3C64XX_UCON_TXMODE_DMA;
+       wr_regl(port,  S3C2410_UCON, ucon);
+
+       ourport->tx_mode = S3C24XX_TX_DMA;
+}
+
+static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       u32 ucon, ufcon;
+
+       /* Set ufcon txtrig */
+       ourport->tx_in_progress = S3C24XX_TX_PIO;
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       wr_regl(port,  S3C2410_UFCON, ufcon);
+
+       /* Enable tx pio mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
+       ucon |= S3C64XX_UCON_TXMODE_CPU;
+       wr_regl(port,  S3C2410_UCON, ucon);
+
+       /* Unmask Tx interrupt */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
+                                 S3C64XX_UINTM);
+       else
+               enable_irq(ourport->tx_irq);
+
+       ourport->tx_mode = S3C24XX_TX_PIO;
+}
+
+static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+       if (ourport->tx_mode != S3C24XX_TX_PIO)
+               enable_tx_pio(ourport);
+}
+
+static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
+                                     unsigned int count)
+{
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+
+
+       if (ourport->tx_mode != S3C24XX_TX_DMA)
+               enable_tx_dma(ourport);
+
+       dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
+       dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
+
+       dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
+                               dma->tx_size, DMA_TO_DEVICE);
+
+       dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
+                               dma->tx_transfer_addr, dma->tx_size,
+                               DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+       if (!dma->tx_desc) {
+               dev_err(ourport->port.dev, "Unable to get desc for Tx\n");
+               return -EIO;
+       }
+
+       dma->tx_desc->callback = s3c24xx_serial_tx_dma_complete;
+       dma->tx_desc->callback_param = ourport;
+       dma->tx_bytes_requested = dma->tx_size;
+
+       ourport->tx_in_progress = S3C24XX_TX_DMA;
+       dma->tx_cookie = dmaengine_submit(dma->tx_desc);
+       dma_async_issue_pending(dma->tx_chan);
+       return 0;
+}
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long count;
+
+       /* Get data size up to the end of buffer */
+       count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+       if (!count) {
+               s3c24xx_serial_stop_tx(port);
+               return;
+       }
+
+       if (!ourport->dma || !ourport->dma->tx_chan ||
+           count < ourport->min_dma_size ||
+           xmit->tail & (dma_get_cache_alignment() - 1))
+               s3c24xx_serial_start_tx_pio(ourport);
+       else
+               s3c24xx_serial_start_tx_dma(ourport, count);
+}
+
+static void s3c24xx_serial_start_tx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (!tx_enabled(port)) {
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_disable(port);
+
+               tx_enabled(port) = 1;
+               if (!ourport->dma || !ourport->dma->tx_chan)
+                       s3c24xx_serial_start_tx_pio(ourport);
+       }
+
+       if (ourport->dma && ourport->dma->tx_chan) {
+               if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
+                       s3c24xx_serial_start_next_tx(ourport);
+       }
+}
+
+static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
+               struct tty_port *tty, int count)
+{
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       int copied;
+
+       if (!count)
+               return;
+
+       dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
+                               dma->rx_size, DMA_FROM_DEVICE);
+
+       ourport->port.icount.rx += count;
+       if (!tty) {
+               dev_err(ourport->port.dev, "No tty port\n");
+               return;
+       }
+       copied = tty_insert_flip_string(tty,
+                       ((unsigned char *)(ourport->dma->rx_buf)), count);
+       if (copied != count) {
+               WARN_ON(1);
+               dev_err(ourport->port.dev, "RxData copy to tty layer failed\n");
+       }
+}
+
+static void s3c24xx_serial_stop_rx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_port *t = &port->state->port;
+       struct dma_tx_state state;
+       enum dma_status dma_status;
+       unsigned int received;
+
+       if (rx_enabled(port)) {
+               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
+                                       S3C64XX_UINTM);
+               else
+                       disable_irq_nosync(ourport->rx_irq);
+               rx_enabled(port) = 0;
+       }
+       if (dma && dma->rx_chan) {
+               dmaengine_pause(dma->tx_chan);
+               dma_status = dmaengine_tx_status(dma->rx_chan,
+                               dma->rx_cookie, &state);
+               if (dma_status == DMA_IN_PROGRESS ||
+                       dma_status == DMA_PAUSED) {
+                       received = dma->rx_bytes_requested - state.residue;
+                       dmaengine_terminate_all(dma->rx_chan);
+                       s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+               }
+       }
+}
+
+static inline struct s3c24xx_uart_info
+       *s3c24xx_port_to_info(struct uart_port *port)
+{
+       return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg
+       *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport;
+
+       if (port->dev == NULL)
+               return NULL;
+
+       ourport = container_of(port, struct s3c24xx_uart_port, port);
+       return ourport->cfg;
+}
+
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+                                    unsigned long ufstat)
+{
+       struct s3c24xx_uart_info *info = ourport->info;
+
+       if (ufstat & info->rx_fifofull)
+               return ourport->port.fifosize;
+
+       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
+}
+
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
+static void s3c24xx_serial_rx_dma_complete(void *args)
+{
+       struct s3c24xx_uart_port *ourport = args;
+       struct uart_port *port = &ourport->port;
+
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_port *t = &port->state->port;
+       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+
+       struct dma_tx_state state;
+       unsigned long flags;
+       int received;
+
+       dmaengine_tx_status(dma->rx_chan,  dma->rx_cookie, &state);
+       received  = dma->rx_bytes_requested - state.residue;
+       async_tx_ack(dma->rx_desc);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (received)
+               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+       if (tty) {
+               tty_flip_buffer_push(t);
+               tty_kref_put(tty);
+       }
+
+       s3c64xx_start_rx_dma(ourport);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+
+       dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
+                               dma->rx_size, DMA_FROM_DEVICE);
+
+       dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
+                               dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
+                               DMA_PREP_INTERRUPT);
+       if (!dma->rx_desc) {
+               dev_err(ourport->port.dev, "Unable to get desc for Rx\n");
+               return;
+       }
+
+       dma->rx_desc->callback = s3c24xx_serial_rx_dma_complete;
+       dma->rx_desc->callback_param = ourport;
+       dma->rx_bytes_requested = dma->rx_size;
+
+       dma->rx_cookie = dmaengine_submit(dma->rx_desc);
+       dma_async_issue_pending(dma->rx_chan);
+}
+
+/* ? - where has parity gone?? */
+#define S3C2410_UERSTAT_PARITY (0x1000)
+
+static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       unsigned int ucon;
+
+       /* set Rx mode to DMA mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_RXBURST_MASK |
+                       S3C64XX_UCON_TIMEOUT_MASK |
+                       S3C64XX_UCON_EMPTYINT_EN |
+                       S3C64XX_UCON_DMASUS_EN |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_MASK);
+       ucon |= S3C64XX_UCON_RXBURST_16 |
+                       0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+                       S3C64XX_UCON_EMPTYINT_EN |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_DMA;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       ourport->rx_mode = S3C24XX_RX_DMA;
+}
+
+static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       unsigned int ucon;
+
+       /* set Rx mode to DMA mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+                       S3C64XX_UCON_EMPTYINT_EN |
+                       S3C64XX_UCON_DMASUS_EN |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_MASK);
+       ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_CPU;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       ourport->rx_mode = S3C24XX_RX_PIO;
+}
+
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
+{
+       unsigned int utrstat, ufstat, received;
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+       struct tty_port *t = &port->state->port;
+       unsigned long flags;
+       struct dma_tx_state state;
+
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       ufstat = rd_regl(port, S3C2410_UFSTAT);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
+               s3c64xx_start_rx_dma(ourport);
+               if (ourport->rx_mode == S3C24XX_RX_PIO)
+                       enable_rx_dma(ourport);
+               goto finish;
+       }
+
+       if (ourport->rx_mode == S3C24XX_RX_DMA) {
+               dmaengine_pause(dma->rx_chan);
+               dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
+               dmaengine_terminate_all(dma->rx_chan);
+               received = dma->rx_bytes_requested - state.residue;
+               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+               enable_rx_pio(ourport);
+       }
+
+       s3c24xx_serial_rx_drain_fifo(ourport);
+
+       if (tty) {
+               tty_flip_buffer_push(t);
+               tty_kref_put(tty);
+       }
+
+       wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
+
+finish:
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       unsigned int ufcon, ch, flag, ufstat, uerstat;
+       unsigned int fifocnt = 0;
+       int max_count = port->fifosize;
+
+       while (max_count-- > 0) {
+               /*
+                * Receive all characters known to be in FIFO
+                * before reading FIFO level again
+                */
+               if (fifocnt == 0) {
+                       ufstat = rd_regl(port, S3C2410_UFSTAT);
+                       fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+                       if (fifocnt == 0)
+                               break;
+               }
+               fifocnt--;
+
+               uerstat = rd_regl(port, S3C2410_UERSTAT);
+               ch = rd_regb(port, S3C2410_URXH);
+
+               if (port->flags & UPF_CONS_FLOW) {
+                       int txe = s3c24xx_serial_txempty_nofifo(port);
+
+                       if (rx_enabled(port)) {
+                               if (!txe) {
+                                       rx_enabled(port) = 0;
+                                       continue;
+                               }
+                       } else {
+                               if (txe) {
+                                       ufcon = rd_regl(port, S3C2410_UFCON);
+                                       ufcon |= S3C2410_UFCON_RESETRX;
+                                       wr_regl(port, S3C2410_UFCON, ufcon);
+                                       rx_enabled(port) = 1;
+                                       return;
+                               }
+                               continue;
+                       }
+               }
+
+               /* insert the character into the buffer */
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
+                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
+                           ch, uerstat);
+
+                       /* check for break */
+                       if (uerstat & S3C2410_UERSTAT_BREAK) {
+                               dbg("break!\n");
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue; /* Ignore character */
+                       }
+
+                       if (uerstat & S3C2410_UERSTAT_FRAME)
+                               port->icount.frame++;
+                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
+                               port->icount.overrun++;
+
+                       uerstat &= port->read_status_mask;
+
+                       if (uerstat & S3C2410_UERSTAT_BREAK)
+                               flag = TTY_BREAK;
+                       else if (uerstat & S3C2410_UERSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
+                                           S3C2410_UERSTAT_OVERRUN))
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue; /* Ignore character */
+
+               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
+                                ch, flag);
+       }
+
+       tty_flip_buffer_push(&port->state->port);
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       s3c24xx_serial_rx_drain_fifo(ourport);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+
+       if (ourport->dma && ourport->dma->rx_chan)
+               return s3c24xx_serial_rx_chars_dma(dev_id);
+       return s3c24xx_serial_rx_chars_pio(dev_id);
+}
+
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
+{
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
+       int count, dma_count = 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+       if (ourport->dma && ourport->dma->tx_chan &&
+           count >= ourport->min_dma_size) {
+               int align = dma_get_cache_alignment() -
+                       (xmit->tail & (dma_get_cache_alignment() - 1));
+               if (count-align >= ourport->min_dma_size) {
+                       dma_count = count-align;
+                       count = align;
+               }
+       }
+
+       if (port->x_char) {
+               wr_regb(port, S3C2410_UTXH, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+
+       /* if there isn't anything more to transmit, or the uart is now
+        * stopped, disable the uart and exit
+       */
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               s3c24xx_serial_stop_tx(port);
+               goto out;
+       }
+
+       /* try and drain the buffer... */
+
+       if (count > port->fifosize) {
+               count = port->fifosize;
+               dma_count = 0;
+       }
+
+       while (!uart_circ_empty(xmit) && count > 0) {
+               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+                       break;
+
+               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               count--;
+       }
+
+       if (!count && dma_count) {
+               s3c24xx_serial_start_tx_dma(ourport, dma_count);
+               goto out;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+               spin_unlock(&port->lock);
+               uart_write_wakeup(port);
+               spin_lock(&port->lock);
+       }
+
+       if (uart_circ_empty(xmit))
+               s3c24xx_serial_stop_tx(port);
+
+out:
+       spin_unlock_irqrestore(&port->lock, flags);
+       return IRQ_HANDLED;
+}
+
+/* interrupt handler for s3c64xx and later SoC's.*/
+static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
+{
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       unsigned int pend = rd_regl(port, S3C64XX_UINTP);
+       irqreturn_t ret = IRQ_HANDLED;
+
+       if (pend & S3C64XX_UINTM_RXD_MSK) {
+               ret = s3c24xx_serial_rx_chars(irq, id);
+               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
+       }
+       if (pend & S3C64XX_UINTM_TXD_MSK) {
+               ret = s3c24xx_serial_tx_chars(irq, id);
+               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
+       }
+       return ret;
+}
+
+static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
+       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               if ((ufstat & info->tx_fifomask) != 0 ||
+                   (ufstat & info->tx_fifofull))
+                       return 0;
+
+               return 1;
+       }
+
+       return s3c24xx_serial_txempty_nofifo(port);
+}
+
+/* no modem control lines */
+static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
+{
+       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
+
+       if (umstat & S3C2410_UMSTAT_CTS)
+               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+       else
+               return TIOCM_CAR | TIOCM_DSR;
+}
+
+static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int umcon = rd_regl(port, S3C2410_UMCON);
+
+       if (mctrl & TIOCM_RTS)
+               umcon |= S3C2410_UMCOM_RTS_LOW;
+       else
+               umcon &= ~S3C2410_UMCOM_RTS_LOW;
+
+       wr_regl(port, S3C2410_UMCON, umcon);
+}
+
+static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int ucon;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+
+       if (break_state)
+               ucon |= S3C2410_UCON_SBREAK;
+       else
+               ucon &= ~S3C2410_UCON_SBREAK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
+{
+       struct s3c24xx_uart_dma *dma = p->dma;
+       struct dma_slave_caps dma_caps;
+       const char *reason = NULL;
+       int ret;
+
+       /* Default slave configuration parameters */
+       dma->rx_conf.direction          = DMA_DEV_TO_MEM;
+       dma->rx_conf.src_addr_width     = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma->rx_conf.src_addr           = p->port.mapbase + S3C2410_URXH;
+       dma->rx_conf.src_maxburst       = 1;
+
+       dma->tx_conf.direction          = DMA_MEM_TO_DEV;
+       dma->tx_conf.dst_addr_width     = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma->tx_conf.dst_addr           = p->port.mapbase + S3C2410_UTXH;
+       dma->tx_conf.dst_maxburst       = 1;
+
+       dma->rx_chan = dma_request_chan(p->port.dev, "rx");
+
+       if (IS_ERR(dma->rx_chan)) {
+               reason = "DMA RX channel request failed";
+               ret = PTR_ERR(dma->rx_chan);
+               goto err_warn;
+       }
+
+       ret = dma_get_slave_caps(dma->rx_chan, &dma_caps);
+       if (ret < 0 ||
+           dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
+               reason = "insufficient DMA RX engine capabilities";
+               ret = -EOPNOTSUPP;
+               goto err_release_rx;
+       }
+
+       dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
+
+       dma->tx_chan = dma_request_chan(p->port.dev, "tx");
+       if (IS_ERR(dma->tx_chan)) {
+               reason = "DMA TX channel request failed";
+               ret = PTR_ERR(dma->tx_chan);
+               goto err_release_rx;
+       }
+
+       ret = dma_get_slave_caps(dma->tx_chan, &dma_caps);
+       if (ret < 0 ||
+           dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
+               reason = "insufficient DMA TX engine capabilities";
+               ret = -EOPNOTSUPP;
+               goto err_release_tx;
+       }
+
+       dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
+
+       /* RX buffer */
+       dma->rx_size = PAGE_SIZE;
+
+       dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
+       if (!dma->rx_buf) {
+               ret = -ENOMEM;
+               goto err_release_tx;
+       }
+
+       dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
+                               dma->rx_size, DMA_FROM_DEVICE);
+       if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
+               reason = "DMA mapping error for RX buffer";
+               ret = -EIO;
+               goto err_free_rx;
+       }
+
+       /* TX buffer */
+       dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
+                               UART_XMIT_SIZE, DMA_TO_DEVICE);
+       if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
+               reason = "DMA mapping error for TX buffer";
+               ret = -EIO;
+               goto err_unmap_rx;
+       }
+
+       return 0;
+
+err_unmap_rx:
+       dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size,
+                        DMA_FROM_DEVICE);
+err_free_rx:
+       kfree(dma->rx_buf);
+err_release_tx:
+       dma_release_channel(dma->tx_chan);
+err_release_rx:
+       dma_release_channel(dma->rx_chan);
+err_warn:
+       if (reason)
+               dev_warn(p->port.dev, "%s, DMA will not be used\n", reason);
+       return ret;
+}
+
+static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
+{
+       struct s3c24xx_uart_dma *dma = p->dma;
+
+       if (dma->rx_chan) {
+               dmaengine_terminate_all(dma->rx_chan);
+               dma_unmap_single(p->port.dev, dma->rx_addr,
+                               dma->rx_size, DMA_FROM_DEVICE);
+               kfree(dma->rx_buf);
+               dma_release_channel(dma->rx_chan);
+               dma->rx_chan = NULL;
+       }
+
+       if (dma->tx_chan) {
+               dmaengine_terminate_all(dma->tx_chan);
+               dma_unmap_single(p->port.dev, dma->tx_addr,
+                               UART_XMIT_SIZE, DMA_TO_DEVICE);
+               dma_release_channel(dma->tx_chan);
+               dma->tx_chan = NULL;
+       }
+}
+
+static void s3c24xx_serial_shutdown(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (ourport->tx_claimed) {
+               if (!s3c24xx_serial_has_interrupt_mask(port))
+                       free_irq(ourport->tx_irq, ourport);
+               tx_enabled(port) = 0;
+               ourport->tx_claimed = 0;
+               ourport->tx_mode = 0;
+       }
+
+       if (ourport->rx_claimed) {
+               if (!s3c24xx_serial_has_interrupt_mask(port))
+                       free_irq(ourport->rx_irq, ourport);
+               ourport->rx_claimed = 0;
+               rx_enabled(port) = 0;
+       }
+
+       /* Clear pending interrupts and mask all interrupts */
+       if (s3c24xx_serial_has_interrupt_mask(port)) {
+               free_irq(port->irq, ourport);
+
+               wr_regl(port, S3C64XX_UINTP, 0xf);
+               wr_regl(port, S3C64XX_UINTM, 0xf);
+       }
+
+       if (ourport->dma)
+               s3c24xx_serial_release_dma(ourport);
+
+       ourport->tx_in_progress = 0;
+}
+
+static int s3c24xx_serial_startup(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int ret;
+
+       dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n",
+           port, (unsigned long long)port->mapbase, port->membase);
+
+       rx_enabled(port) = 1;
+
+       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+
+       if (ret != 0) {
+               dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq);
+               return ret;
+       }
+
+       ourport->rx_claimed = 1;
+
+       dbg("requesting tx irq...\n");
+
+       tx_enabled(port) = 1;
+
+       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+
+       if (ret) {
+               dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq);
+               goto err;
+       }
+
+       ourport->tx_claimed = 1;
+
+       dbg("s3c24xx_serial_startup ok\n");
+
+       /* the port reset code should have done the correct
+        * register setup for the port controls */
+
+       return ret;
+
+err:
+       s3c24xx_serial_shutdown(port);
+       return ret;
+}
+
+static int s3c64xx_serial_startup(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
+       unsigned int ufcon;
+       int ret;
+
+       dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
+           port, (unsigned long long)port->mapbase, port->membase);
+
+       wr_regl(port, S3C64XX_UINTM, 0xf);
+       if (ourport->dma) {
+               ret = s3c24xx_serial_request_dma(ourport);
+               if (ret < 0) {
+                       devm_kfree(port->dev, ourport->dma);
+                       ourport->dma = NULL;
+               }
+       }
+
+       ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
+                         s3c24xx_serial_portname(port), ourport);
+       if (ret) {
+               dev_err(port->dev, "cannot get irq %d\n", port->irq);
+               return ret;
+       }
+
+       /* For compatibility with s3c24xx Soc's */
+       rx_enabled(port) = 1;
+       ourport->rx_claimed = 1;
+       tx_enabled(port) = 0;
+       ourport->tx_claimed = 1;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+       if (!uart_console(port))
+               ufcon |= S3C2410_UFCON_RESETTX;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+
+       enable_rx_pio(ourport);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       /* Enable Rx Interrupt */
+       s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
+
+       dbg("s3c64xx_serial_startup ok\n");
+       return ret;
+}
+
+/* power power management control */
+
+static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
+                             unsigned int old)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int timeout = 10000;
+
+       ourport->pm_level = level;
+
+       switch (level) {
+       case 3:
+               while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
+                       udelay(100);
+
+               if (!IS_ERR(ourport->baudclk))
+                       clk_disable_unprepare(ourport->baudclk);
+
+               clk_disable_unprepare(ourport->clk);
+               break;
+
+       case 0:
+               clk_prepare_enable(ourport->clk);
+
+               if (!IS_ERR(ourport->baudclk))
+                       clk_prepare_enable(ourport->baudclk);
+
+               break;
+       default:
+               dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
+       }
+}
+
+/* baud rate calculation
+ *
+ * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
+ * of different sources, including the peripheral clock ("pclk") and an
+ * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
+ * with a programmable extra divisor.
+ *
+ * The following code goes through the clock sources, and calculates the
+ * baud clocks (and the resultant actual baud rates) and then tries to
+ * pick the closest one and select that.
+ *
+*/
+
+#define MAX_CLK_NAME_LENGTH 15
+
+static inline int s3c24xx_serial_getsource(struct uart_port *port)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned int ucon;
+
+       if (info->num_clks == 1)
+               return 0;
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= info->clksel_mask;
+       return ucon >> info->clksel_shift;
+}
+
+static void s3c24xx_serial_setsource(struct uart_port *port,
+                       unsigned int clk_sel)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned int ucon;
+
+       if (info->num_clks == 1)
+               return;
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       if ((ucon & info->clksel_mask) >> info->clksel_shift == clk_sel)
+               return;
+
+       ucon &= ~info->clksel_mask;
+       ucon |= clk_sel << info->clksel_shift;
+       wr_regl(port, S3C2410_UCON, ucon);
+}
+
+static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
+                       unsigned int req_baud, struct clk **best_clk,
+                       unsigned int *clk_num)
+{
+       struct s3c24xx_uart_info *info = ourport->info;
+       struct clk *clk;
+       unsigned long rate;
+       unsigned int cnt, baud, quot, clk_sel, best_quot = 0;
+       char clkname[MAX_CLK_NAME_LENGTH];
+       int calc_deviation, deviation = (1 << 30) - 1;
+
+       clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
+                       ourport->info->def_clk_sel;
+       for (cnt = 0; cnt < info->num_clks; cnt++) {
+               if (!(clk_sel & (1 << cnt)))
+                       continue;
+
+               sprintf(clkname, "clk_uart_baud%d", cnt);
+               clk = clk_get(ourport->port.dev, clkname);
+               if (IS_ERR(clk))
+                       continue;
+
+               rate = clk_get_rate(clk);
+               if (!rate)
+                       continue;
+
+               if (ourport->info->has_divslot) {
+                       unsigned long div = rate / req_baud;
+
+                       /* The UDIVSLOT register on the newer UARTs allows us to
+                        * get a divisor adjustment of 1/16th on the baud clock.
+                        *
+                        * We don't keep the UDIVSLOT value (the 16ths we
+                        * calculated by not multiplying the baud by 16) as it
+                        * is easy enough to recalculate.
+                        */
+
+                       quot = div / 16;
+                       baud = rate / div;
+               } else {
+                       quot = (rate + (8 * req_baud)) / (16 * req_baud);
+                       baud = rate / (quot * 16);
+               }
+               quot--;
+
+               calc_deviation = req_baud - baud;
+               if (calc_deviation < 0)
+                       calc_deviation = -calc_deviation;
+
+               if (calc_deviation < deviation) {
+                       *best_clk = clk;
+                       best_quot = quot;
+                       *clk_num = cnt;
+                       deviation = calc_deviation;
+               }
+       }
+
+       return best_quot;
+}
+
+/* udivslot_table[]
+ *
+ * This table takes the fractional value of the baud divisor and gives
+ * the recommended setting for the UDIVSLOT register.
+ */
+static u16 udivslot_table[16] = {
+       [0] = 0x0000,
+       [1] = 0x0080,
+       [2] = 0x0808,
+       [3] = 0x0888,
+       [4] = 0x2222,
+       [5] = 0x4924,
+       [6] = 0x4A52,
+       [7] = 0x54AA,
+       [8] = 0x5555,
+       [9] = 0xD555,
+       [10] = 0xD5D5,
+       [11] = 0xDDD5,
+       [12] = 0xDDDD,
+       [13] = 0xDFDD,
+       [14] = 0xDFDF,
+       [15] = 0xFFDF,
+};
+
+static void s3c24xx_serial_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+{
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct clk *clk = ERR_PTR(-EINVAL);
+       unsigned long flags;
+       unsigned int baud, quot, clk_sel = 0;
+       unsigned int ulcon;
+       unsigned int umcon;
+       unsigned int udivslot = 0;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 3000000);
+       quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       if (IS_ERR(clk))
+               return;
+
+       /* check to see if we need  to change clock source */
+
+       if (ourport->baudclk != clk) {
+               clk_prepare_enable(clk);
+
+               s3c24xx_serial_setsource(port, clk_sel);
+
+               if (!IS_ERR(ourport->baudclk)) {
+                       clk_disable_unprepare(ourport->baudclk);
+                       ourport->baudclk = ERR_PTR(-EINVAL);
+               }
+
+               ourport->baudclk = clk;
+               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
+       }
+
+       if (ourport->info->has_divslot) {
+               unsigned int div = ourport->baudclk_rate / baud;
+
+               if (cfg->has_fracval) {
+                       udivslot = (div & 15);
+                       dbg("fracval = %04x\n", udivslot);
+               } else {
+                       udivslot = udivslot_table[div & 15];
+                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
+               }
+       }
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               dbg("config: 5bits/char\n");
+               ulcon = S3C2410_LCON_CS5;
+               break;
+       case CS6:
+               dbg("config: 6bits/char\n");
+               ulcon = S3C2410_LCON_CS6;
+               break;
+       case CS7:
+               dbg("config: 7bits/char\n");
+               ulcon = S3C2410_LCON_CS7;
+               break;
+       case CS8:
+       default:
+               dbg("config: 8bits/char\n");
+               ulcon = S3C2410_LCON_CS8;
+               break;
+       }
+
+       /* preserve original lcon IR settings */
+       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
+
+       if (termios->c_cflag & CSTOPB)
+               ulcon |= S3C2410_LCON_STOPB;
+
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & PARODD)
+                       ulcon |= S3C2410_LCON_PODD;
+               else
+                       ulcon |= S3C2410_LCON_PEVEN;
+       } else {
+               ulcon |= S3C2410_LCON_PNONE;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
+           ulcon, quot, udivslot);
+
+       wr_regl(port, S3C2410_ULCON, ulcon);
+       wr_regl(port, S3C2410_UBRDIV, quot);
+
+       port->status &= ~UPSTAT_AUTOCTS;
+
+       umcon = rd_regl(port, S3C2410_UMCON);
+       if (termios->c_cflag & CRTSCTS) {
+               umcon |= S3C2410_UMCOM_AFC;
+               /* Disable RTS when RX FIFO contains 63 bytes */
+               umcon &= ~S3C2412_UMCON_AFC_8;
+               port->status = UPSTAT_AUTOCTS;
+       } else {
+               umcon &= ~S3C2410_UMCOM_AFC;
+       }
+       wr_regl(port, S3C2410_UMCON, umcon);
+
+       if (ourport->info->has_divslot)
+               wr_regl(port, S3C2443_DIVSLOT, udivslot);
+
+       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
+           rd_regl(port, S3C2410_ULCON),
+           rd_regl(port, S3C2410_UCON),
+           rd_regl(port, S3C2410_UFCON));
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Which character status flags are we interested in?
+        */
+       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= S3C2410_UERSTAT_FRAME |
+                       S3C2410_UERSTAT_PARITY;
+       /*
+        * Which character status flags should we ignore?
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *s3c24xx_serial_type(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_S3C2410:
+               return "S3C2410";
+       case PORT_S3C2440:
+               return "S3C2440";
+       case PORT_S3C2412:
+               return "S3C2412";
+       case PORT_S3C6400:
+               return "S3C6400/10";
+       default:
+               return NULL;
+       }
+}
+
+#define MAP_SIZE (0x100)
+
+static void s3c24xx_serial_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, MAP_SIZE);
+}
+
+static int s3c24xx_serial_request_port(struct uart_port *port)
+{
+       const char *name = s3c24xx_serial_portname(port);
+       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
+}
+
+static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       if (flags & UART_CONFIG_TYPE &&
+           s3c24xx_serial_request_port(port) == 0)
+               port->type = info->type;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int
+s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+static struct console s3c24xx_serial_console;
+
+static int __init s3c24xx_serial_console_init(void)
+{
+       register_console(&s3c24xx_serial_console);
+       return 0;
+}
+console_initcall(s3c24xx_serial_console_init);
+
+#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
+#else
+#define S3C24XX_SERIAL_CONSOLE NULL
+#endif
+
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
+static int s3c24xx_serial_get_poll_char(struct uart_port *port);
+static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+                        unsigned char c);
+#endif
+
+static struct uart_ops s3c24xx_serial_ops = {
+       .pm             = s3c24xx_serial_pm,
+       .tx_empty       = s3c24xx_serial_tx_empty,
+       .get_mctrl      = s3c24xx_serial_get_mctrl,
+       .set_mctrl      = s3c24xx_serial_set_mctrl,
+       .stop_tx        = s3c24xx_serial_stop_tx,
+       .start_tx       = s3c24xx_serial_start_tx,
+       .stop_rx        = s3c24xx_serial_stop_rx,
+       .break_ctl      = s3c24xx_serial_break_ctl,
+       .startup        = s3c24xx_serial_startup,
+       .shutdown       = s3c24xx_serial_shutdown,
+       .set_termios    = s3c24xx_serial_set_termios,
+       .type           = s3c24xx_serial_type,
+       .release_port   = s3c24xx_serial_release_port,
+       .request_port   = s3c24xx_serial_request_port,
+       .config_port    = s3c24xx_serial_config_port,
+       .verify_port    = s3c24xx_serial_verify_port,
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
+       .poll_get_char = s3c24xx_serial_get_poll_char,
+       .poll_put_char = s3c24xx_serial_put_poll_char,
+#endif
+};
+
+static struct uart_driver s3c24xx_uart_drv = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "s3c2410_serial",
+       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
+       .cons           = S3C24XX_SERIAL_CONSOLE,
+       .dev_name       = S3C24XX_SERIAL_NAME,
+       .major          = S3C24XX_SERIAL_MAJOR,
+       .minor          = S3C24XX_SERIAL_MINOR,
+};
+
+#define __PORT_LOCK_UNLOCKED(i) \
+       __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock)
+static struct s3c24xx_uart_port
+s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
+       [0] = {
+               .port = {
+                       .lock           = __PORT_LOCK_UNLOCKED(0),
+                       .iotype         = UPIO_MEM,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               }
+       },
+       [1] = {
+               .port = {
+                       .lock           = __PORT_LOCK_UNLOCKED(1),
+                       .iotype         = UPIO_MEM,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               }
+       },
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+
+       [2] = {
+               .port = {
+                       .lock           = __PORT_LOCK_UNLOCKED(2),
+                       .iotype         = UPIO_MEM,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               }
+       },
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+       [3] = {
+               .port = {
+                       .lock           = __PORT_LOCK_UNLOCKED(3),
+                       .iotype         = UPIO_MEM,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 3,
+               }
+       }
+#endif
+};
+#undef __PORT_LOCK_UNLOCKED
+
+/* s3c24xx_serial_resetport
+ *
+ * reset the fifos and other the settings.
+*/
+
+static void s3c24xx_serial_resetport(struct uart_port *port,
+                                  struct s3c2410_uartcfg *cfg)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+       unsigned int ucon_mask;
+
+       ucon_mask = info->clksel_mask;
+       if (info->type == PORT_S3C2440)
+               ucon_mask |= S3C2440_UCON0_DIVMASK;
+
+       ucon &= ucon_mask;
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+
+       /* reset both fifos */
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       /* some delay is required after fifo reset */
+       udelay(1);
+}
+
+
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
+
+static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+                                            unsigned long val, void *data)
+{
+       struct s3c24xx_uart_port *port;
+       struct uart_port *uport;
+
+       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+       uport = &port->port;
+
+       /* check to see if port is enabled */
+
+       if (port->pm_level != 0)
+               return 0;
+
+       /* try and work out if the baudrate is changing, we can detect
+        * a change in rate, but we do not have support for detecting
+        * a disturbance in the clock-rate over the change.
+        */
+
+       if (IS_ERR(port->baudclk))
+               goto exit;
+
+       if (port->baudclk_rate == clk_get_rate(port->baudclk))
+               goto exit;
+
+       if (val == CPUFREQ_PRECHANGE) {
+               /* we should really shut the port down whilst the
+                * frequency change is in progress. */
+
+       } else if (val == CPUFREQ_POSTCHANGE) {
+               struct ktermios *termios;
+               struct tty_struct *tty;
+
+               if (uport->state == NULL)
+                       goto exit;
+
+               tty = uport->state->port.tty;
+
+               if (tty == NULL)
+                       goto exit;
+
+               termios = &tty->termios;
+
+               if (termios == NULL) {
+                       dev_warn(uport->dev, "%s: no termios?\n", __func__);
+                       goto exit;
+               }
+
+               s3c24xx_serial_set_termios(uport, termios, NULL);
+       }
+
+exit:
+       return 0;
+}
+
+static inline int
+s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+
+       return cpufreq_register_notifier(&port->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void
+s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+       cpufreq_unregister_notifier(&port->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int
+s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       return 0;
+}
+
+static inline void
+s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+}
+#endif
+
+static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport)
+{
+       struct device *dev = ourport->port.dev;
+       struct s3c24xx_uart_info *info = ourport->info;
+       char clk_name[MAX_CLK_NAME_LENGTH];
+       unsigned int clk_sel;
+       struct clk *clk;
+       int clk_num;
+       int ret;
+
+       clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel;
+       for (clk_num = 0; clk_num < info->num_clks; clk_num++) {
+               if (!(clk_sel & (1 << clk_num)))
+                       continue;
+
+               sprintf(clk_name, "clk_uart_baud%d", clk_num);
+               clk = clk_get(dev, clk_name);
+               if (IS_ERR(clk))
+                       continue;
+
+               ret = clk_prepare_enable(clk);
+               if (ret) {
+                       clk_put(clk);
+                       continue;
+               }
+
+               ourport->baudclk = clk;
+               ourport->baudclk_rate = clk_get_rate(clk);
+               s3c24xx_serial_setsource(&ourport->port, clk_num);
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/* s3c24xx_serial_init_port
+ *
+ * initialise a single serial port from the platform device given
+ */
+
+static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
+                                   struct platform_device *platdev)
+{
+       struct uart_port *port = &ourport->port;
+       struct s3c2410_uartcfg *cfg = ourport->cfg;
+       struct resource *res;
+       int ret;
+
+       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
+
+       if (platdev == NULL)
+               return -ENODEV;
+
+       if (port->mapbase != 0)
+               return -EINVAL;
+
+       /* setup info for port */
+       port->dev       = &platdev->dev;
+
+       /* Startup sequence is different for s3c64xx and higher SoC's */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
+
+       port->uartclk = 1;
+
+       if (cfg->uart_flags & UPF_CONS_FLOW) {
+               dbg("s3c24xx_serial_init_port: enabling flow control\n");
+               port->flags |= UPF_CONS_FLOW;
+       }
+
+       /* sort our the physical and virtual addresses for each UART */
+
+       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(port->dev, "failed to find memory resource for uart\n");
+               return -EINVAL;
+       }
+
+       dbg("resource %pR)\n", res);
+
+       port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
+       if (!port->membase) {
+               dev_err(port->dev, "failed to remap controller address\n");
+               return -EBUSY;
+       }
+
+       port->mapbase = res->start;
+       ret = platform_get_irq(platdev, 0);
+       if (ret < 0)
+               port->irq = 0;
+       else {
+               port->irq = ret;
+               ourport->rx_irq = ret;
+               ourport->tx_irq = ret + 1;
+       }
+
+       ret = platform_get_irq(platdev, 1);
+       if (ret > 0)
+               ourport->tx_irq = ret;
+       /*
+        * DMA is currently supported only on DT platforms, if DMA properties
+        * are specified.
+        */
+       if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
+                                                    "dmas", NULL)) {
+               ourport->dma = devm_kzalloc(port->dev,
+                                           sizeof(*ourport->dma),
+                                           GFP_KERNEL);
+               if (!ourport->dma) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       ourport->clk    = clk_get(&platdev->dev, "uart");
+       if (IS_ERR(ourport->clk)) {
+               pr_err("%s: Controller clock not found\n",
+                               dev_name(&platdev->dev));
+               ret = PTR_ERR(ourport->clk);
+               goto err;
+       }
+
+       ret = clk_prepare_enable(ourport->clk);
+       if (ret) {
+               pr_err("uart: clock failed to prepare+enable: %d\n", ret);
+               clk_put(ourport->clk);
+               goto err;
+       }
+
+       ret = s3c24xx_serial_enable_baudclk(ourport);
+       if (ret)
+               pr_warn("uart: failed to enable baudclk\n");
+
+       /* Keep all interrupts masked and cleared */
+       if (s3c24xx_serial_has_interrupt_mask(port)) {
+               wr_regl(port, S3C64XX_UINTM, 0xf);
+               wr_regl(port, S3C64XX_UINTP, 0xf);
+               wr_regl(port, S3C64XX_UINTSP, 0xf);
+       }
+
+       dbg("port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n",
+           &port->mapbase, port->membase, port->irq,
+           ourport->rx_irq, ourport->tx_irq, port->uartclk);
+
+       /* reset the fifos (and setup the uart) */
+       s3c24xx_serial_resetport(port, cfg);
+
+       return 0;
+
+err:
+       port->mapbase = 0;
+       return ret;
+}
+
+/* Device driver serial port probe */
+
+static const struct of_device_id s3c24xx_uart_dt_match[];
+static int probe_index;
+
+static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
+                       struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(s3c24xx_uart_dt_match, pdev->dev.of_node);
+               return (struct s3c24xx_serial_drv_data *)match->data;
+       }
+#endif
+       return (struct s3c24xx_serial_drv_data *)
+                       platform_get_device_id(pdev)->driver_data;
+}
+
+static int s3c24xx_serial_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct s3c24xx_uart_port *ourport;
+       int index = probe_index;
+       int ret;
+
+       if (np) {
+               ret = of_alias_get_id(np, "serial");
+               if (ret >= 0)
+                       index = ret;
+       }
+
+       dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index);
+
+       if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) {
+               dev_err(&pdev->dev, "serial%d out of range\n", index);
+               return -EINVAL;
+       }
+       ourport = &s3c24xx_serial_ports[index];
+
+       ourport->drv_data = s3c24xx_get_driver_data(pdev);
+       if (!ourport->drv_data) {
+               dev_err(&pdev->dev, "could not find driver data\n");
+               return -ENODEV;
+       }
+
+       ourport->baudclk = ERR_PTR(-EINVAL);
+       ourport->info = ourport->drv_data->info;
+       ourport->cfg = (dev_get_platdata(&pdev->dev)) ?
+                       dev_get_platdata(&pdev->dev) :
+                       ourport->drv_data->def_cfg;
+
+       if (np)
+               of_property_read_u32(np,
+                       "samsung,uart-fifosize", &ourport->port.fifosize);
+
+       if (ourport->drv_data->fifosize[index])
+               ourport->port.fifosize = ourport->drv_data->fifosize[index];
+       else if (ourport->info->fifosize)
+               ourport->port.fifosize = ourport->info->fifosize;
+
+       /*
+        * DMA transfers must be aligned at least to cache line size,
+        * so find minimal transfer size suitable for DMA mode
+        */
+       ourport->min_dma_size = max_t(int, ourport->port.fifosize,
+                                   dma_get_cache_alignment());
+
+       dbg("%s: initialising port %p...\n", __func__, ourport);
+
+       ret = s3c24xx_serial_init_port(ourport, pdev);
+       if (ret < 0)
+               return ret;
+
+       if (!s3c24xx_uart_drv.state) {
+               ret = uart_register_driver(&s3c24xx_uart_drv);
+               if (ret < 0) {
+                       pr_err("Failed to register Samsung UART driver\n");
+                       return ret;
+               }
+       }
+
+       dbg("%s: adding port\n", __func__);
+       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
+       platform_set_drvdata(pdev, &ourport->port);
+
+       /*
+        * Deactivate the clock enabled in s3c24xx_serial_init_port here,
+        * so that a potential re-enablement through the pm-callback overlaps
+        * and keeps the clock enabled in this case.
+        */
+       clk_disable_unprepare(ourport->clk);
+       if (!IS_ERR(ourport->baudclk))
+               clk_disable_unprepare(ourport->baudclk);
+
+       ret = s3c24xx_serial_cpufreq_register(ourport);
+       if (ret < 0)
+               dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
+
+       probe_index++;
+
+       return 0;
+}
+
+static int s3c24xx_serial_remove(struct platform_device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+
+       if (port) {
+               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
+               uart_remove_one_port(&s3c24xx_uart_drv, port);
+       }
+
+       uart_unregister_driver(&s3c24xx_uart_drv);
+
+       return 0;
+}
+
+/* UART power management code */
+#ifdef CONFIG_PM_SLEEP
+static int s3c24xx_serial_suspend(struct device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+
+       if (port)
+               uart_suspend_port(&s3c24xx_uart_drv, port);
+
+       return 0;
+}
+
+static int s3c24xx_serial_resume(struct device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (port) {
+               clk_prepare_enable(ourport->clk);
+               if (!IS_ERR(ourport->baudclk))
+                       clk_prepare_enable(ourport->baudclk);
+               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+               if (!IS_ERR(ourport->baudclk))
+                       clk_disable_unprepare(ourport->baudclk);
+               clk_disable_unprepare(ourport->clk);
+
+               uart_resume_port(&s3c24xx_uart_drv, port);
+       }
+
+       return 0;
+}
+
+static int s3c24xx_serial_resume_noirq(struct device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (port) {
+               /* restore IRQ mask */
+               if (s3c24xx_serial_has_interrupt_mask(port)) {
+                       unsigned int uintm = 0xf;
+                       if (tx_enabled(port))
+                               uintm &= ~S3C64XX_UINTM_TXD_MSK;
+                       if (rx_enabled(port))
+                               uintm &= ~S3C64XX_UINTM_RXD_MSK;
+                       clk_prepare_enable(ourport->clk);
+                       if (!IS_ERR(ourport->baudclk))
+                               clk_prepare_enable(ourport->baudclk);
+                       wr_regl(port, S3C64XX_UINTM, uintm);
+                       if (!IS_ERR(ourport->baudclk))
+                               clk_disable_unprepare(ourport->baudclk);
+                       clk_disable_unprepare(ourport->clk);
+               }
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
+       .suspend = s3c24xx_serial_suspend,
+       .resume = s3c24xx_serial_resume,
+       .resume_noirq = s3c24xx_serial_resume_noirq,
+};
+#define SERIAL_SAMSUNG_PM_OPS  (&s3c24xx_serial_pm_ops)
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define SERIAL_SAMSUNG_PM_OPS  NULL
+#endif /* CONFIG_PM_SLEEP */
+
+/* Console code */
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+static struct uart_port *cons_uart;
+
+static int
+s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat, utrstat;
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               /* fifo mode - check amount of data in fifo registers... */
+
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+               return (ufstat & info->tx_fifofull) ? 0 : 1;
+       }
+
+       /* in non-fifo mode, we go and use the tx buffer empty */
+
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
+}
+
+static bool
+s3c24xx_port_configured(unsigned int ucon)
+{
+       /* consider the serial port configured if the tx/rx mode set */
+       return (ucon & 0xf) != 0;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int s3c24xx_serial_get_poll_char(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned int ufstat;
+
+       ufstat = rd_regl(port, S3C2410_UFSTAT);
+       if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
+               return NO_POLL_CHAR;
+
+       return rd_regb(port, S3C2410_URXH);
+}
+
+static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+               unsigned char c)
+{
+       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
+       unsigned int ucon = rd_regl(port, S3C2410_UCON);
+
+       /* not possible to xmit on unconfigured port */
+       if (!s3c24xx_port_configured(ucon))
+               return;
+
+       while (!s3c24xx_serial_console_txrdy(port, ufcon))
+               cpu_relax();
+       wr_regb(port, S3C2410_UTXH, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static void
+s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
+{
+       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
+
+       while (!s3c24xx_serial_console_txrdy(port, ufcon))
+               cpu_relax();
+       wr_regb(port, S3C2410_UTXH, ch);
+}
+
+static void
+s3c24xx_serial_console_write(struct console *co, const char *s,
+                            unsigned int count)
+{
+       unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
+
+       /* not possible to xmit on unconfigured port */
+       if (!s3c24xx_port_configured(ucon))
+               return;
+
+       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
+}
+
+static void __init
+s3c24xx_serial_get_options(struct uart_port *port, int *baud,
+                          int *parity, int *bits)
+{
+       struct clk *clk;
+       unsigned int ulcon;
+       unsigned int ucon;
+       unsigned int ubrdiv;
+       unsigned long rate;
+       unsigned int clk_sel;
+       char clk_name[MAX_CLK_NAME_LENGTH];
+
+       ulcon  = rd_regl(port, S3C2410_ULCON);
+       ucon   = rd_regl(port, S3C2410_UCON);
+       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+
+       dbg("s3c24xx_serial_get_options: port=%p\n"
+           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+           port, ulcon, ucon, ubrdiv);
+
+       if (s3c24xx_port_configured(ucon)) {
+               switch (ulcon & S3C2410_LCON_CSMASK) {
+               case S3C2410_LCON_CS5:
+                       *bits = 5;
+                       break;
+               case S3C2410_LCON_CS6:
+                       *bits = 6;
+                       break;
+               case S3C2410_LCON_CS7:
+                       *bits = 7;
+                       break;
+               case S3C2410_LCON_CS8:
+               default:
+                       *bits = 8;
+                       break;
+               }
+
+               switch (ulcon & S3C2410_LCON_PMASK) {
+               case S3C2410_LCON_PEVEN:
+                       *parity = 'e';
+                       break;
+
+               case S3C2410_LCON_PODD:
+                       *parity = 'o';
+                       break;
+
+               case S3C2410_LCON_PNONE:
+               default:
+                       *parity = 'n';
+               }
+
+               /* now calculate the baud rate */
+
+               clk_sel = s3c24xx_serial_getsource(port);
+               sprintf(clk_name, "clk_uart_baud%d", clk_sel);
+
+               clk = clk_get(port->dev, clk_name);
+               if (!IS_ERR(clk))
+                       rate = clk_get_rate(clk);
+               else
+                       rate = 1;
+
+               *baud = rate / (16 * (ubrdiv + 1));
+               dbg("calculated baud %d\n", *baud);
+       }
+
+}
+
+static int __init
+s3c24xx_serial_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
+           co, co->index, options);
+
+       /* is this a valid port */
+
+       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
+               co->index = 0;
+
+       port = &s3c24xx_serial_ports[co->index].port;
+
+       /* is the port configured? */
+
+       if (port->mapbase == 0x0)
+               return -ENODEV;
+
+       cons_uart = port;
+
+       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+
+       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console s3c24xx_serial_console = {
+       .name           = S3C24XX_SERIAL_NAME,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .write          = s3c24xx_serial_console_write,
+       .setup          = s3c24xx_serial_console_setup,
+       .data           = &s3c24xx_uart_drv,
+};
+#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
+
+#ifdef CONFIG_CPU_S3C2410
+static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = {
+       .info = &(struct s3c24xx_uart_info) {
+               .name           = "Samsung S3C2410 UART",
+               .type           = PORT_S3C2410,
+               .fifosize       = 16,
+               .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
+               .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
+               .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
+               .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
+               .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
+               .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
+               .def_clk_sel    = S3C2410_UCON_CLKSEL0,
+               .num_clks       = 2,
+               .clksel_mask    = S3C2410_UCON_CLKMASK,
+               .clksel_shift   = S3C2410_UCON_CLKSHIFT,
+       },
+       .def_cfg = &(struct s3c2410_uartcfg) {
+               .ucon           = S3C2410_UCON_DEFAULT,
+               .ufcon          = S3C2410_UFCON_DEFAULT,
+       },
+};
+#define S3C2410_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2410_serial_drv_data)
+#else
+#define S3C2410_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#endif
+
+#ifdef CONFIG_CPU_S3C2412
+static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
+       .info = &(struct s3c24xx_uart_info) {
+               .name           = "Samsung S3C2412 UART",
+               .type           = PORT_S3C2412,
+               .fifosize       = 64,
+               .has_divslot    = 1,
+               .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+               .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+               .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+               .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+               .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+               .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+               .def_clk_sel    = S3C2410_UCON_CLKSEL2,
+               .num_clks       = 4,
+               .clksel_mask    = S3C2412_UCON_CLKMASK,
+               .clksel_shift   = S3C2412_UCON_CLKSHIFT,
+       },
+       .def_cfg = &(struct s3c2410_uartcfg) {
+               .ucon           = S3C2410_UCON_DEFAULT,
+               .ufcon          = S3C2410_UFCON_DEFAULT,
+       },
+};
+#define S3C2412_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2412_serial_drv_data)
+#else
+#define S3C2412_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#endif
+
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
+       defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
+static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
+       .info = &(struct s3c24xx_uart_info) {
+               .name           = "Samsung S3C2440 UART",
+               .type           = PORT_S3C2440,
+               .fifosize       = 64,
+               .has_divslot    = 1,
+               .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+               .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+               .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+               .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+               .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+               .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+               .def_clk_sel    = S3C2410_UCON_CLKSEL2,
+               .num_clks       = 4,
+               .clksel_mask    = S3C2412_UCON_CLKMASK,
+               .clksel_shift   = S3C2412_UCON_CLKSHIFT,
+       },
+       .def_cfg = &(struct s3c2410_uartcfg) {
+               .ucon           = S3C2410_UCON_DEFAULT,
+               .ufcon          = S3C2410_UFCON_DEFAULT,
+       },
+};
+#define S3C2440_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2440_serial_drv_data)
+#else
+#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#endif
+
+#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)
+static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
+       .info = &(struct s3c24xx_uart_info) {
+               .name           = "Samsung S3C6400 UART",
+               .type           = PORT_S3C6400,
+               .fifosize       = 64,
+               .has_divslot    = 1,
+               .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+               .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+               .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+               .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+               .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+               .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+               .def_clk_sel    = S3C2410_UCON_CLKSEL2,
+               .num_clks       = 4,
+               .clksel_mask    = S3C6400_UCON_CLKMASK,
+               .clksel_shift   = S3C6400_UCON_CLKSHIFT,
+       },
+       .def_cfg = &(struct s3c2410_uartcfg) {
+               .ucon           = S3C2410_UCON_DEFAULT,
+               .ufcon          = S3C2410_UFCON_DEFAULT,
+       },
+};
+#define S3C6400_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c6400_serial_drv_data)
+#else
+#define S3C6400_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#endif
+
+#ifdef CONFIG_CPU_S5PV210
+static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
+       .info = &(struct s3c24xx_uart_info) {
+               .name           = "Samsung S5PV210 UART",
+               .type           = PORT_S3C6400,
+               .has_divslot    = 1,
+               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,
+               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,
+               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,
+               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,
+               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,
+               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,
+               .def_clk_sel    = S3C2410_UCON_CLKSEL0,
+               .num_clks       = 2,
+               .clksel_mask    = S5PV210_UCON_CLKMASK,
+               .clksel_shift   = S5PV210_UCON_CLKSHIFT,
+       },
+       .def_cfg = &(struct s3c2410_uartcfg) {
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       .fifosize = { 256, 64, 16, 16 },
+};
+#define S5PV210_SERIAL_DRV_DATA ((kernel_ulong_t)&s5pv210_serial_drv_data)
+#else
+#define S5PV210_SERIAL_DRV_DATA        (kernel_ulong_t)NULL
+#endif
+
+#if defined(CONFIG_ARCH_EXYNOS)
+#define EXYNOS_COMMON_SERIAL_DRV_DATA                          \
+       .info = &(struct s3c24xx_uart_info) {                   \
+               .name           = "Samsung Exynos UART",        \
+               .type           = PORT_S3C6400,                 \
+               .has_divslot    = 1,                            \
+               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
+               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
+               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
+               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
+               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
+               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
+               .def_clk_sel    = S3C2410_UCON_CLKSEL0,         \
+               .num_clks       = 1,                            \
+               .clksel_mask    = 0,                            \
+               .clksel_shift   = 0,                            \
+       },                                                      \
+       .def_cfg = &(struct s3c2410_uartcfg) {                  \
+               .ucon           = S5PV210_UCON_DEFAULT,         \
+               .ufcon          = S5PV210_UFCON_DEFAULT,        \
+               .has_fracval    = 1,                            \
+       }                                                       \
+
+static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
+       .fifosize = { 256, 64, 16, 16 },
+};
+
+static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
+       .fifosize = { 64, 256, 16, 256 },
+};
+
+#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
+#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data)
+#else
+#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#endif
+
+static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
+       {
+               .name           = "s3c2410-uart",
+               .driver_data    = S3C2410_SERIAL_DRV_DATA,
+       }, {
+               .name           = "s3c2412-uart",
+               .driver_data    = S3C2412_SERIAL_DRV_DATA,
+       }, {
+               .name           = "s3c2440-uart",
+               .driver_data    = S3C2440_SERIAL_DRV_DATA,
+       }, {
+               .name           = "s3c6400-uart",
+               .driver_data    = S3C6400_SERIAL_DRV_DATA,
+       }, {
+               .name           = "s5pv210-uart",
+               .driver_data    = S5PV210_SERIAL_DRV_DATA,
+       }, {
+               .name           = "exynos4210-uart",
+               .driver_data    = EXYNOS4210_SERIAL_DRV_DATA,
+       }, {
+               .name           = "exynos5433-uart",
+               .driver_data    = EXYNOS5433_SERIAL_DRV_DATA,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id s3c24xx_uart_dt_match[] = {
+       { .compatible = "samsung,s3c2410-uart",
+               .data = (void *)S3C2410_SERIAL_DRV_DATA },
+       { .compatible = "samsung,s3c2412-uart",
+               .data = (void *)S3C2412_SERIAL_DRV_DATA },
+       { .compatible = "samsung,s3c2440-uart",
+               .data = (void *)S3C2440_SERIAL_DRV_DATA },
+       { .compatible = "samsung,s3c6400-uart",
+               .data = (void *)S3C6400_SERIAL_DRV_DATA },
+       { .compatible = "samsung,s5pv210-uart",
+               .data = (void *)S5PV210_SERIAL_DRV_DATA },
+       { .compatible = "samsung,exynos4210-uart",
+               .data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
+       { .compatible = "samsung,exynos5433-uart",
+               .data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
+       {},
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
+#endif
+
+static struct platform_driver samsung_serial_driver = {
+       .probe          = s3c24xx_serial_probe,
+       .remove         = s3c24xx_serial_remove,
+       .id_table       = s3c24xx_serial_driver_ids,
+       .driver         = {
+               .name   = "samsung-uart",
+               .pm     = SERIAL_SAMSUNG_PM_OPS,
+               .of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
+       },
+};
+
+module_platform_driver(samsung_serial_driver);
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+/*
+ * Early console.
+ */
+
+struct samsung_early_console_data {
+       u32 txfull_mask;
+};
+
+static void samsung_early_busyuart(struct uart_port *port)
+{
+       while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
+               ;
+}
+
+static void samsung_early_busyuart_fifo(struct uart_port *port)
+{
+       struct samsung_early_console_data *data = port->private_data;
+
+       while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
+               ;
+}
+
+static void samsung_early_putc(struct uart_port *port, int c)
+{
+       if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
+               samsung_early_busyuart_fifo(port);
+       else
+               samsung_early_busyuart(port);
+
+       writeb(c, port->membase + S3C2410_UTXH);
+}
+
+static void samsung_early_write(struct console *con, const char *s, unsigned n)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, n, samsung_early_putc);
+}
+
+static int __init samsung_early_console_setup(struct earlycon_device *device,
+                                             const char *opt)
+{
+       if (!device->port.membase)
+               return -ENODEV;
+
+       device->con->write = samsung_early_write;
+       return 0;
+}
+
+/* S3C2410 */
+static struct samsung_early_console_data s3c2410_early_console_data = {
+       .txfull_mask = S3C2410_UFSTAT_TXFULL,
+};
+
+static int __init s3c2410_early_console_setup(struct earlycon_device *device,
+                                             const char *opt)
+{
+       device->port.private_data = &s3c2410_early_console_data;
+       return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
+                       s3c2410_early_console_setup);
+
+/* S3C2412, S3C2440, S3C64xx */
+static struct samsung_early_console_data s3c2440_early_console_data = {
+       .txfull_mask = S3C2440_UFSTAT_TXFULL,
+};
+
+static int __init s3c2440_early_console_setup(struct earlycon_device *device,
+                                             const char *opt)
+{
+       device->port.private_data = &s3c2440_early_console_data;
+       return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
+                       s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
+                       s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
+                       s3c2440_early_console_setup);
+
+/* S5PV210, EXYNOS */
+static struct samsung_early_console_data s5pv210_early_console_data = {
+       .txfull_mask = S5PV210_UFSTAT_TXFULL,
+};
+
+static int __init s5pv210_early_console_setup(struct earlycon_device *device,
+                                             const char *opt)
+{
+       device->port.private_data = &s5pv210_early_console_data;
+       return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
+                       s5pv210_early_console_setup);
+OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
+                       s5pv210_early_console_setup);
+#endif
+
+MODULE_ALIAS("platform:samsung-uart");
+MODULE_DESCRIPTION("Samsung SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
index 2f59951..b6ace62 100644 (file)
@@ -1122,8 +1122,7 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
        int ret;
        struct dma_slave_config dma_sconfig;
 
-       dma_chan = dma_request_slave_channel_reason(tup->uport.dev,
-                                               dma_to_memory ? "rx" : "tx");
+       dma_chan = dma_request_chan(tup->uport.dev, dma_to_memory ? "rx" : "tx");
        if (IS_ERR(dma_chan)) {
                ret = PTR_ERR(dma_chan);
                dev_err(tup->uport.dev,
index c4a414a..b0a6eb1 100644 (file)
@@ -1111,7 +1111,7 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state)
        if (!uport)
                goto out;
 
-       if (uport->type != PORT_UNKNOWN)
+       if (uport->type != PORT_UNKNOWN && uport->ops->break_ctl)
                uport->ops->break_ctl(uport, break_state);
        ret = 0;
 out:
index 004ca68..637b09d 100644 (file)
@@ -120,7 +120,8 @@ static u32 uart_usp_ff_empty_mask(struct uart_port *port)
        empty_bit = ilog2(port->fifosize) + 1;
        return (1 << empty_bit);
 }
-struct sirfsoc_uart_register sirfsoc_usp = {
+
+static struct sirfsoc_uart_register sirfsoc_usp = {
        .uart_reg = {
                .sirfsoc_mode1          = 0x0000,
                .sirfsoc_mode2          = 0x0004,
@@ -186,7 +187,7 @@ struct sirfsoc_uart_register sirfsoc_usp = {
        },
 };
 
-struct sirfsoc_uart_register sirfsoc_uart = {
+static struct sirfsoc_uart_register sirfsoc_uart = {
        .uart_reg = {
                .sirfsoc_line_ctrl      = 0x0040,
                .sirfsoc_tx_rx_en       = 0x004c,
index 771d111..31df235 100644 (file)
@@ -919,6 +919,34 @@ static void sprd_pm(struct uart_port *port, unsigned int state,
        }
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+static int sprd_poll_init(struct uart_port *port)
+{
+       if (port->state->pm_state != UART_PM_STATE_ON) {
+               sprd_pm(port, UART_PM_STATE_ON, 0);
+               port->state->pm_state = UART_PM_STATE_ON;
+       }
+
+       return 0;
+}
+
+static int sprd_poll_get_char(struct uart_port *port)
+{
+       while (!(serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK))
+               cpu_relax();
+
+       return serial_in(port, SPRD_RXD);
+}
+
+static void sprd_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+       while (serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
+               cpu_relax();
+
+       serial_out(port, SPRD_TXD, ch);
+}
+#endif
+
 static const struct uart_ops serial_sprd_ops = {
        .tx_empty = sprd_tx_empty,
        .get_mctrl = sprd_get_mctrl,
@@ -936,6 +964,11 @@ static const struct uart_ops serial_sprd_ops = {
        .config_port = sprd_config_port,
        .verify_port = sprd_verify_port,
        .pm = sprd_pm,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_init      = sprd_poll_init,
+       .poll_get_char  = sprd_poll_get_char,
+       .poll_put_char  = sprd_poll_put_char,
+#endif
 };
 
 #ifdef CONFIG_SERIAL_SPRD_CONSOLE
index df90747..2f72514 100644 (file)
@@ -240,8 +240,8 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)
                 * cleared by the sequence [read SR - read DR].
                 */
                if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG)
-                       stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF |
-                                      USART_ICR_PECF | USART_ICR_FECF);
+                       writel_relaxed(sr & USART_SR_ERR_MASK,
+                                      port->membase + ofs->icr);
 
                c = stm32_get_char(port, &sr, &stm32_port->last_res);
                port->icount.rx++;
@@ -435,7 +435,7 @@ static void stm32_transmit_chars(struct uart_port *port)
        if (ofs->icr == UNDEF_REG)
                stm32_clr_bits(port, ofs->isr, USART_SR_TC);
        else
-               stm32_set_bits(port, ofs->icr, USART_ICR_TCCF);
+               writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr);
 
        if (stm32_port->tx_ch)
                stm32_transmit_chars_dma(port);
index 06e79c1..7dbd0c4 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
-#include <linux/pm_runtime.h>
 
 #define ULITE_NAME             "ttyUL"
 #define ULITE_MAJOR            204
@@ -55,7 +54,6 @@
 #define ULITE_CONTROL_RST_TX   0x01
 #define ULITE_CONTROL_RST_RX   0x02
 #define ULITE_CONTROL_IE       0x10
-#define UART_AUTOSUSPEND_TIMEOUT       3000
 
 /* Static pointer to console port */
 #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
@@ -65,7 +63,6 @@ static struct uart_port *console_port;
 struct uartlite_data {
        const struct uartlite_reg_ops *reg_ops;
        struct clk *clk;
-       struct uart_driver *ulite_uart_driver;
 };
 
 struct uartlite_reg_ops {
@@ -393,12 +390,12 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
 static void ulite_pm(struct uart_port *port, unsigned int state,
                     unsigned int oldstate)
 {
-       if (!state) {
-               pm_runtime_get_sync(port->dev);
-       } else {
-               pm_runtime_mark_last_busy(port->dev);
-               pm_runtime_put_autosuspend(port->dev);
-       }
+       struct uartlite_data *pdata = port->private_data;
+
+       if (!state)
+               clk_enable(pdata->clk);
+       else
+               clk_disable(pdata->clk);
 }
 
 #ifdef CONFIG_CONSOLE_POLL
@@ -697,9 +694,7 @@ static int ulite_release(struct device *dev)
        int rc = 0;
 
        if (port) {
-               struct uartlite_data *pdata = port->private_data;
-
-               rc = uart_remove_one_port(pdata->ulite_uart_driver, port);
+               rc = uart_remove_one_port(&ulite_uart_driver, port);
                dev_set_drvdata(dev, NULL);
                port->mapbase = 0;
        }
@@ -717,11 +712,8 @@ static int __maybe_unused ulite_suspend(struct device *dev)
 {
        struct uart_port *port = dev_get_drvdata(dev);
 
-       if (port) {
-               struct uartlite_data *pdata = port->private_data;
-
-               uart_suspend_port(pdata->ulite_uart_driver, port);
-       }
+       if (port)
+               uart_suspend_port(&ulite_uart_driver, port);
 
        return 0;
 }
@@ -736,41 +728,17 @@ static int __maybe_unused ulite_resume(struct device *dev)
 {
        struct uart_port *port = dev_get_drvdata(dev);
 
-       if (port) {
-               struct uartlite_data *pdata = port->private_data;
-
-               uart_resume_port(pdata->ulite_uart_driver, port);
-       }
+       if (port)
+               uart_resume_port(&ulite_uart_driver, port);
 
        return 0;
 }
 
-static int __maybe_unused ulite_runtime_suspend(struct device *dev)
-{
-       struct uart_port *port = dev_get_drvdata(dev);
-       struct uartlite_data *pdata = port->private_data;
-
-       clk_disable(pdata->clk);
-       return 0;
-};
-
-static int __maybe_unused ulite_runtime_resume(struct device *dev)
-{
-       struct uart_port *port = dev_get_drvdata(dev);
-       struct uartlite_data *pdata = port->private_data;
-
-       clk_enable(pdata->clk);
-       return 0;
-}
 /* ---------------------------------------------------------------------
  * Platform bus binding
  */
 
-static const struct dev_pm_ops ulite_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume)
-       SET_RUNTIME_PM_OPS(ulite_runtime_suspend,
-                          ulite_runtime_resume, NULL)
-};
+static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume);
 
 #if defined(CONFIG_OF)
 /* Match table for of_platform binding */
@@ -795,22 +763,6 @@ static int ulite_probe(struct platform_device *pdev)
        if (prop)
                id = be32_to_cpup(prop);
 #endif
-       if (id < 0) {
-               /* Look for a serialN alias */
-               id = of_alias_get_id(pdev->dev.of_node, "serial");
-               if (id < 0)
-                       id = 0;
-       }
-
-       if (!ulite_uart_driver.state) {
-               dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
-               ret = uart_register_driver(&ulite_uart_driver);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "Failed to register driver\n");
-                       return ret;
-               }
-       }
-
        pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
                             GFP_KERNEL);
        if (!pdata)
@@ -836,22 +788,24 @@ static int ulite_probe(struct platform_device *pdev)
                pdata->clk = NULL;
        }
 
-       pdata->ulite_uart_driver = &ulite_uart_driver;
        ret = clk_prepare_enable(pdata->clk);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare clock\n");
                return ret;
        }
 
-       pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
-       pm_runtime_set_active(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
+       if (!ulite_uart_driver.state) {
+               dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
+               ret = uart_register_driver(&ulite_uart_driver);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to register driver\n");
+                       return ret;
+               }
+       }
 
        ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
 
-       pm_runtime_mark_last_busy(&pdev->dev);
-       pm_runtime_put_autosuspend(&pdev->dev);
+       clk_disable(pdata->clk);
 
        return ret;
 }
@@ -860,14 +814,9 @@ static int ulite_remove(struct platform_device *pdev)
 {
        struct uart_port *port = dev_get_drvdata(&pdev->dev);
        struct uartlite_data *pdata = port->private_data;
-       int rc;
 
-       clk_unprepare(pdata->clk);
-       rc = ulite_release(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
-       pm_runtime_set_suspended(&pdev->dev);
-       pm_runtime_dont_use_autosuspend(&pdev->dev);
-       return rc;
+       clk_disable_unprepare(pdata->clk);
+       return ulite_release(&pdev->dev);
 }
 
 /* work with hotplug and coldplug */
index a81807b..d9f54c7 100644 (file)
@@ -1345,9 +1345,12 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
        if (!tty->port)
                tty->port = driver->ports[idx];
 
-       WARN_RATELIMIT(!tty->port,
-                       "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
-                       __func__, tty->driver->name);
+       if (WARN_RATELIMIT(!tty->port,
+                       "%s: %s driver does not set tty->port. This would crash the kernel. Fix the driver!\n",
+                       __func__, tty->driver->name)) {
+               retval = -EINVAL;
+               goto err_release_lock;
+       }
 
        retval = tty_ldisc_lock(tty, 5 * HZ);
        if (retval)
@@ -1925,7 +1928,6 @@ EXPORT_SYMBOL_GPL(tty_kopen);
 /**
  *     tty_open_by_driver      -       open a tty device
  *     @device: dev_t of device to open
- *     @inode: inode of device file
  *     @filp: file pointer to tty
  *
  *     Performs the driver lookup, checks for a reopen, or otherwise
@@ -1938,7 +1940,7 @@ EXPORT_SYMBOL_GPL(tty_kopen);
  *       - concurrent tty driver removal w/ lookup
  *       - concurrent tty removal from driver table
  */
-static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
+static struct tty_struct *tty_open_by_driver(dev_t device,
                                             struct file *filp)
 {
        struct tty_struct *tty;
@@ -2030,7 +2032,7 @@ retry_open:
 
        tty = tty_open_current_tty(device, filp);
        if (!tty)
-               tty = tty_open_by_driver(device, inode, filp);
+               tty = tty_open_by_driver(device, filp);
 
        if (IS_ERR(tty)) {
                tty_free_file(filp);
index 4c49f53..ec1f6a4 100644 (file)
@@ -156,12 +156,7 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
  *             takes tty_ldiscs_lock to guard against ldisc races
  */
 
-#if defined(CONFIG_LDISC_AUTOLOAD)
-       #define INITIAL_AUTOLOAD_STATE  1
-#else
-       #define INITIAL_AUTOLOAD_STATE  0
-#endif
-static int tty_ldisc_autoload = INITIAL_AUTOLOAD_STATE;
+static int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD);
 
 static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
 {
index 515fc09..15d33fa 100644 (file)
@@ -1491,7 +1491,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
 
        if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
                kbd_rawcode(value);
-       if (event_type == EV_KEY)
+       if (event_type == EV_KEY && event_code <= KEY_MAX)
                kbd_keycode(event_code, value, HW_RAW(handle->dev));
 
        spin_unlock(&kbd_event_lock);
index 1f04234..778f83e 100644 (file)
@@ -456,6 +456,9 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
        size_t ret;
        char *con_buf;
 
+       if (use_unicode(inode))
+               return -EOPNOTSUPP;
+
        con_buf = (char *) __get_free_page(GFP_KERNEL);
        if (!con_buf)
                return -ENOMEM;
index 9e26b01..9ae2a7a 100644 (file)
@@ -234,7 +234,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                /* UHCI */
                int     region;
 
-               for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+               for (region = 0; region < PCI_STD_NUM_BARS; region++) {
                        if (!(pci_resource_flags(dev, region) &
                                        IORESOURCE_IO))
                                continue;
index 1709895..f229ad6 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sched/mm.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/kcov.h>
 #include <linux/ioctl.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
@@ -5484,6 +5485,8 @@ static void hub_event(struct work_struct *work)
        hub_dev = hub->intfdev;
        intf = to_usb_interface(hub_dev);
 
+       kcov_remote_start_usb((u64)hdev->bus->busnum);
+
        dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
                        hdev->state, hdev->maxchild,
                        /* NOTE: expects max 15 ports... */
@@ -5590,6 +5593,8 @@ out_hdev_lock:
        /* Balance the stuff in kick_hub_wq() and allow autosuspend */
        usb_autopm_put_interface(intf);
        kref_put(&hub->kref, hub_release);
+
+       kcov_remote_stop();
 }
 
 static const struct usb_device_id hub_id_table[] = {
index f6d0449..6c7f0a8 100644 (file)
@@ -728,7 +728,7 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev)
        if (!pio_enabled(pdev))
                return;
 
-       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+       for (i = 0; i < PCI_STD_NUM_BARS; i++)
                if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
                        base = pci_resource_start(pdev, i);
                        break;
index 8b1b730..98c1aa5 100644 (file)
@@ -561,7 +561,7 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
                residue = min(residue, transfer_length);
                if (us->srb != NULL)
                        scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
-                                                               (int)residue));
+                                                               residue));
        }
 
        if (bcs->Status != US_BULK_STAT_OK)
index 96cb040..238a808 100644 (file)
@@ -1284,8 +1284,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 
                } else {
                        residue = min(residue, transfer_length);
-                       scsi_set_resid(srb, max(scsi_get_resid(srb),
-                                                              (int) residue));
+                       scsi_set_resid(srb, max(scsi_get_resid(srb), residue));
                }
        }
 
index 475b9c6..95bba3b 100644 (file)
@@ -869,7 +869,6 @@ static struct scsi_host_template uas_host_template = {
        .eh_abort_handler = uas_eh_abort_handler,
        .eh_device_reset_handler = uas_eh_device_reset_handler,
        .this_id = -1,
-       .sg_tablesize = SG_NONE,
        .skip_settle_delay = 1,
        .dma_boundary = PAGE_SIZE - 1,
 };
index 0220616..379a02c 100644 (file)
@@ -110,13 +110,15 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
 static void vfio_pci_probe_mmaps(struct vfio_pci_device *vdev)
 {
        struct resource *res;
-       int bar;
+       int i;
        struct vfio_pci_dummy_resource *dummy_res;
 
        INIT_LIST_HEAD(&vdev->dummy_resources_list);
 
-       for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
-               res = vdev->pdev->resource + bar;
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+               int bar = i + PCI_STD_RESOURCES;
+
+               res = &vdev->pdev->resource[bar];
 
                if (!IS_ENABLED(CONFIG_VFIO_PCI_MMAP))
                        goto no_mmap;
@@ -399,7 +401,8 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
 
        vfio_config_free(vdev);
 
-       for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+               bar = i + PCI_STD_RESOURCES;
                if (!vdev->barmap[bar])
                        continue;
                pci_iounmap(pdev, vdev->barmap[bar]);
index f0891bd..90c0b80 100644 (file)
@@ -450,30 +450,32 @@ static void vfio_bar_fixup(struct vfio_pci_device *vdev)
 {
        struct pci_dev *pdev = vdev->pdev;
        int i;
-       __le32 *bar;
+       __le32 *vbar;
        u64 mask;
 
-       bar = (__le32 *)&vdev->vconfig[PCI_BASE_ADDRESS_0];
+       vbar = (__le32 *)&vdev->vconfig[PCI_BASE_ADDRESS_0];
 
-       for (i = PCI_STD_RESOURCES; i <= PCI_STD_RESOURCE_END; i++, bar++) {
-               if (!pci_resource_start(pdev, i)) {
-                       *bar = 0; /* Unmapped by host = unimplemented to user */
+       for (i = 0; i < PCI_STD_NUM_BARS; i++, vbar++) {
+               int bar = i + PCI_STD_RESOURCES;
+
+               if (!pci_resource_start(pdev, bar)) {
+                       *vbar = 0; /* Unmapped by host = unimplemented to user */
                        continue;
                }
 
-               mask = ~(pci_resource_len(pdev, i) - 1);
+               mask = ~(pci_resource_len(pdev, bar) - 1);
 
-               *bar &= cpu_to_le32((u32)mask);
-               *bar |= vfio_generate_bar_flags(pdev, i);
+               *vbar &= cpu_to_le32((u32)mask);
+               *vbar |= vfio_generate_bar_flags(pdev, bar);
 
-               if (*bar & cpu_to_le32(PCI_BASE_ADDRESS_MEM_TYPE_64)) {
-                       bar++;
-                       *bar &= cpu_to_le32((u32)(mask >> 32));
+               if (*vbar & cpu_to_le32(PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+                       vbar++;
+                       *vbar &= cpu_to_le32((u32)(mask >> 32));
                        i++;
                }
        }
 
-       bar = (__le32 *)&vdev->vconfig[PCI_ROM_ADDRESS];
+       vbar = (__le32 *)&vdev->vconfig[PCI_ROM_ADDRESS];
 
        /*
         * NB. REGION_INFO will have reported zero size if we weren't able
@@ -483,14 +485,14 @@ static void vfio_bar_fixup(struct vfio_pci_device *vdev)
        if (pci_resource_start(pdev, PCI_ROM_RESOURCE)) {
                mask = ~(pci_resource_len(pdev, PCI_ROM_RESOURCE) - 1);
                mask |= PCI_ROM_ADDRESS_ENABLE;
-               *bar &= cpu_to_le32((u32)mask);
+               *vbar &= cpu_to_le32((u32)mask);
        } else if (pdev->resource[PCI_ROM_RESOURCE].flags &
                                        IORESOURCE_ROM_SHADOW) {
                mask = ~(0x20000 - 1);
                mask |= PCI_ROM_ADDRESS_ENABLE;
-               *bar &= cpu_to_le32((u32)mask);
+               *vbar &= cpu_to_le32((u32)mask);
        } else
-               *bar = 0;
+               *vbar = 0;
 
        vdev->bardirty = false;
 }
index ee6ee91..8a2c760 100644 (file)
@@ -86,8 +86,8 @@ struct vfio_pci_reflck {
 
 struct vfio_pci_device {
        struct pci_dev          *pdev;
-       void __iomem            *barmap[PCI_STD_RESOURCE_END + 1];
-       bool                    bar_mmap_supported[PCI_STD_RESOURCE_END + 1];
+       void __iomem            *barmap[PCI_STD_NUM_BARS];
+       bool                    bar_mmap_supported[PCI_STD_NUM_BARS];
        u8                      *pci_config_map;
        u8                      *vconfig;
        struct perm_bits        *msi_perm;
index 36ca2cf..f44340b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sched/signal.h>
 #include <linux/interval_tree_generic.h>
 #include <linux/nospec.h>
+#include <linux/kcov.h>
 
 #include "vhost.h"
 
@@ -357,7 +358,9 @@ static int vhost_worker(void *data)
                llist_for_each_entry_safe(work, work_next, node, node) {
                        clear_bit(VHOST_WORK_QUEUED, &work->flags);
                        __set_current_state(TASK_RUNNING);
+                       kcov_remote_start_common(dev->kcov_handle);
                        work->fn(work);
+                       kcov_remote_stop();
                        if (need_resched())
                                schedule();
                }
@@ -546,6 +549,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
 
        /* No owner, become one */
        dev->mm = get_task_mm(current);
+       dev->kcov_handle = kcov_common_handle();
        worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid);
        if (IS_ERR(worker)) {
                err = PTR_ERR(worker);
@@ -571,6 +575,7 @@ err_worker:
        if (dev->mm)
                mmput(dev->mm);
        dev->mm = NULL;
+       dev->kcov_handle = 0;
 err_mm:
        return err;
 }
@@ -682,6 +687,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
        if (dev->worker) {
                kthread_stop(dev->worker);
                dev->worker = NULL;
+               dev->kcov_handle = 0;
        }
        if (dev->mm)
                mmput(dev->mm);
index e9ed272..a123fd7 100644 (file)
@@ -173,6 +173,7 @@ struct vhost_dev {
        int iov_limit;
        int weight;
        int byte_weight;
+       u64 kcov_handle;
 };
 
 bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len);
index 2dc5703..7c4483c 100644 (file)
@@ -2593,7 +2593,7 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                 * calling pci_set_power_state()
                 */
                radeonfb_whack_power_state(rinfo, PCI_D2);
-               __pci_complete_power_transition(rinfo->pdev, PCI_D2);
+               pci_platform_power_transition(rinfo->pdev, PCI_D2);
        } else {
                printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
                       pci_name(rinfo->pdev));
index 95c3295..6f6fc78 100644 (file)
@@ -1772,7 +1772,7 @@ int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name)
        bool primary = false;
        int err, idx, bar;
 
-       for (idx = 0, bar = 0; bar < PCI_ROM_RESOURCE; bar++) {
+       for (idx = 0, bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
                        continue;
                idx++;
@@ -1782,7 +1782,7 @@ int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name)
        if (!ap)
                return -ENOMEM;
 
-       for (idx = 0, bar = 0; bar < PCI_ROM_RESOURCE; bar++) {
+       for (idx = 0, bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
                        continue;
                ap->ranges[idx].base = pci_resource_start(pdev, bar);
index 51d97ec..1caa372 100644 (file)
@@ -653,7 +653,7 @@ static void efifb_fixup_resources(struct pci_dev *dev)
        if (!base)
                return;
 
-       for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                struct resource *res = &dev->resource[i];
 
                if (!(res->flags & IORESOURCE_MEM))
index e48355f..9dda1b2 100644 (file)
@@ -5,3 +5,4 @@
 *_vga16.c
 *_clut224.c
 *_gray256.c
+pnmtologo
index 16f60c1..bcda657 100644 (file)
@@ -18,24 +18,19 @@ obj-$(CONFIG_SPU_BASE)                      += logo_spe_clut224.o
 
 # How to generate logo's
 
-pnmtologo := scripts/pnmtologo
+hostprogs-y := pnmtologo
 
 # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
 quiet_cmd_logo = LOGO    $@
-       cmd_logo = $(pnmtologo) \
-                       -t $(patsubst $*_%,%,$(notdir $(basename $<))) \
-                       -n $(notdir $(basename $<)) -o $@ $<
+      cmd_logo = $(obj)/pnmtologo -t $(lastword $(subst _, ,$*)) -n $* -o $@ $<
 
-$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE
+$(obj)/%.c: $(src)/%.pbm $(obj)/pnmtologo FORCE
        $(call if_changed,logo)
 
-$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE
+$(obj)/%.c: $(src)/%.ppm $(obj)/pnmtologo FORCE
        $(call if_changed,logo)
 
-$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE
-       $(call if_changed,logo)
-
-$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE
+$(obj)/%.c: $(src)/%.pgm $(obj)/pnmtologo FORCE
        $(call if_changed,logo)
 
 # generated C files
diff --git a/drivers/video/logo/pnmtologo.c b/drivers/video/logo/pnmtologo.c
new file mode 100644 (file)
index 0000000..4718d78
--- /dev/null
@@ -0,0 +1,514 @@
+
+/*
+ *  Convert a logo in ASCII PNM format to C source suitable for inclusion in
+ *  the Linux kernel
+ *
+ *  (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
+ *
+ *  --------------------------------------------------------------------------
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static const char *programname;
+static const char *filename;
+static const char *logoname = "linux_logo";
+static const char *outputname;
+static FILE *out;
+
+
+#define LINUX_LOGO_MONO                1       /* monochrome black/white */
+#define LINUX_LOGO_VGA16       2       /* 16 colors VGA text palette */
+#define LINUX_LOGO_CLUT224     3       /* 224 colors */
+#define LINUX_LOGO_GRAY256     4       /* 256 levels grayscale */
+
+static const char *logo_types[LINUX_LOGO_GRAY256+1] = {
+    [LINUX_LOGO_MONO] = "LINUX_LOGO_MONO",
+    [LINUX_LOGO_VGA16] = "LINUX_LOGO_VGA16",
+    [LINUX_LOGO_CLUT224] = "LINUX_LOGO_CLUT224",
+    [LINUX_LOGO_GRAY256] = "LINUX_LOGO_GRAY256"
+};
+
+#define MAX_LINUX_LOGO_COLORS  224
+
+struct color {
+    unsigned char red;
+    unsigned char green;
+    unsigned char blue;
+};
+
+static const struct color clut_vga16[16] = {
+    { 0x00, 0x00, 0x00 },
+    { 0x00, 0x00, 0xaa },
+    { 0x00, 0xaa, 0x00 },
+    { 0x00, 0xaa, 0xaa },
+    { 0xaa, 0x00, 0x00 },
+    { 0xaa, 0x00, 0xaa },
+    { 0xaa, 0x55, 0x00 },
+    { 0xaa, 0xaa, 0xaa },
+    { 0x55, 0x55, 0x55 },
+    { 0x55, 0x55, 0xff },
+    { 0x55, 0xff, 0x55 },
+    { 0x55, 0xff, 0xff },
+    { 0xff, 0x55, 0x55 },
+    { 0xff, 0x55, 0xff },
+    { 0xff, 0xff, 0x55 },
+    { 0xff, 0xff, 0xff },
+};
+
+
+static int logo_type = LINUX_LOGO_CLUT224;
+static unsigned int logo_width;
+static unsigned int logo_height;
+static struct color **logo_data;
+static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
+static unsigned int logo_clutsize;
+static int is_plain_pbm = 0;
+
+static void die(const char *fmt, ...)
+    __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
+static void usage(void) __attribute ((noreturn));
+
+
+static unsigned int get_number(FILE *fp)
+{
+    int c, val;
+
+    /* Skip leading whitespace */
+    do {
+       c = fgetc(fp);
+       if (c == EOF)
+           die("%s: end of file\n", filename);
+       if (c == '#') {
+           /* Ignore comments 'till end of line */
+           do {
+               c = fgetc(fp);
+               if (c == EOF)
+                   die("%s: end of file\n", filename);
+           } while (c != '\n');
+       }
+    } while (isspace(c));
+
+    /* Parse decimal number */
+    val = 0;
+    while (isdigit(c)) {
+       val = 10*val+c-'0';
+       /* some PBM are 'broken'; GiMP for example exports a PBM without space
+        * between the digits. This is Ok cause we know a PBM can only have a '1'
+        * or a '0' for the digit. */
+       if (is_plain_pbm)
+               break;
+       c = fgetc(fp);
+       if (c == EOF)
+           die("%s: end of file\n", filename);
+    }
+    return val;
+}
+
+static unsigned int get_number255(FILE *fp, unsigned int maxval)
+{
+    unsigned int val = get_number(fp);
+    return (255*val+maxval/2)/maxval;
+}
+
+static void read_image(void)
+{
+    FILE *fp;
+    unsigned int i, j;
+    int magic;
+    unsigned int maxval;
+
+    /* open image file */
+    fp = fopen(filename, "r");
+    if (!fp)
+       die("Cannot open file %s: %s\n", filename, strerror(errno));
+
+    /* check file type and read file header */
+    magic = fgetc(fp);
+    if (magic != 'P')
+       die("%s is not a PNM file\n", filename);
+    magic = fgetc(fp);
+    switch (magic) {
+       case '1':
+       case '2':
+       case '3':
+           /* Plain PBM/PGM/PPM */
+           break;
+
+       case '4':
+       case '5':
+       case '6':
+           /* Binary PBM/PGM/PPM */
+           die("%s: Binary PNM is not supported\n"
+               "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename);
+
+       default:
+           die("%s is not a PNM file\n", filename);
+    }
+    logo_width = get_number(fp);
+    logo_height = get_number(fp);
+
+    /* allocate image data */
+    logo_data = (struct color **)malloc(logo_height*sizeof(struct color *));
+    if (!logo_data)
+       die("%s\n", strerror(errno));
+    for (i = 0; i < logo_height; i++) {
+       logo_data[i] = malloc(logo_width*sizeof(struct color));
+       if (!logo_data[i])
+           die("%s\n", strerror(errno));
+    }
+
+    /* read image data */
+    switch (magic) {
+       case '1':
+           /* Plain PBM */
+           is_plain_pbm = 1;
+           for (i = 0; i < logo_height; i++)
+               for (j = 0; j < logo_width; j++)
+                   logo_data[i][j].red = logo_data[i][j].green =
+                       logo_data[i][j].blue = 255*(1-get_number(fp));
+           break;
+
+       case '2':
+           /* Plain PGM */
+           maxval = get_number(fp);
+           for (i = 0; i < logo_height; i++)
+               for (j = 0; j < logo_width; j++)
+                   logo_data[i][j].red = logo_data[i][j].green =
+                       logo_data[i][j].blue = get_number255(fp, maxval);
+           break;
+
+       case '3':
+           /* Plain PPM */
+           maxval = get_number(fp);
+           for (i = 0; i < logo_height; i++)
+               for (j = 0; j < logo_width; j++) {
+                   logo_data[i][j].red = get_number255(fp, maxval);
+                   logo_data[i][j].green = get_number255(fp, maxval);
+                   logo_data[i][j].blue = get_number255(fp, maxval);
+               }
+           break;
+    }
+
+    /* close file */
+    fclose(fp);
+}
+
+static inline int is_black(struct color c)
+{
+    return c.red == 0 && c.green == 0 && c.blue == 0;
+}
+
+static inline int is_white(struct color c)
+{
+    return c.red == 255 && c.green == 255 && c.blue == 255;
+}
+
+static inline int is_gray(struct color c)
+{
+    return c.red == c.green && c.red == c.blue;
+}
+
+static inline int is_equal(struct color c1, struct color c2)
+{
+    return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;
+}
+
+static void write_header(void)
+{
+    /* open logo file */
+    if (outputname) {
+       out = fopen(outputname, "w");
+       if (!out)
+           die("Cannot create file %s: %s\n", outputname, strerror(errno));
+    } else {
+       out = stdout;
+    }
+
+    fputs("/*\n", out);
+    fputs(" *  DO NOT EDIT THIS FILE!\n", out);
+    fputs(" *\n", out);
+    fprintf(out, " *  It was automatically generated from %s\n", filename);
+    fputs(" *\n", out);
+    fprintf(out, " *  Linux logo %s\n", logoname);
+    fputs(" */\n\n", out);
+    fputs("#include <linux/linux_logo.h>\n\n", out);
+    fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
+           logoname);
+}
+
+static void write_footer(void)
+{
+    fputs("\n};\n\n", out);
+    fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname);
+    fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
+    fprintf(out, "\t.width\t\t= %d,\n", logo_width);
+    fprintf(out, "\t.height\t\t= %d,\n", logo_height);
+    if (logo_type == LINUX_LOGO_CLUT224) {
+       fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
+       fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
+    }
+    fprintf(out, "\t.data\t\t= %s_data\n", logoname);
+    fputs("};\n\n", out);
+
+    /* close logo file */
+    if (outputname)
+       fclose(out);
+}
+
+static int write_hex_cnt;
+
+static void write_hex(unsigned char byte)
+{
+    if (write_hex_cnt % 12)
+       fprintf(out, ", 0x%02x", byte);
+    else if (write_hex_cnt)
+       fprintf(out, ",\n\t0x%02x", byte);
+    else
+       fprintf(out, "\t0x%02x", byte);
+    write_hex_cnt++;
+}
+
+static void write_logo_mono(void)
+{
+    unsigned int i, j;
+    unsigned char val, bit;
+
+    /* validate image */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++)
+           if (!is_black(logo_data[i][j]) && !is_white(logo_data[i][j]))
+               die("Image must be monochrome\n");
+
+    /* write file header */
+    write_header();
+
+    /* write logo data */
+    for (i = 0; i < logo_height; i++) {
+       for (j = 0; j < logo_width;) {
+           for (val = 0, bit = 0x80; bit && j < logo_width; j++, bit >>= 1)
+               if (logo_data[i][j].red)
+                   val |= bit;
+           write_hex(val);
+       }
+    }
+
+    /* write logo structure and file footer */
+    write_footer();
+}
+
+static void write_logo_vga16(void)
+{
+    unsigned int i, j, k;
+    unsigned char val;
+
+    /* validate image */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++) {
+           for (k = 0; k < 16; k++)
+               if (is_equal(logo_data[i][j], clut_vga16[k]))
+                   break;
+           if (k == 16)
+               die("Image must use the 16 console colors only\n"
+                   "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "
+                   "of colors\n");
+       }
+
+    /* write file header */
+    write_header();
+
+    /* write logo data */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++) {
+           for (k = 0; k < 16; k++)
+               if (is_equal(logo_data[i][j], clut_vga16[k]))
+                   break;
+           val = k<<4;
+           if (++j < logo_width) {
+               for (k = 0; k < 16; k++)
+                   if (is_equal(logo_data[i][j], clut_vga16[k]))
+                       break;
+               val |= k;
+           }
+           write_hex(val);
+       }
+
+    /* write logo structure and file footer */
+    write_footer();
+}
+
+static void write_logo_clut224(void)
+{
+    unsigned int i, j, k;
+
+    /* validate image */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++) {
+           for (k = 0; k < logo_clutsize; k++)
+               if (is_equal(logo_data[i][j], logo_clut[k]))
+                   break;
+           if (k == logo_clutsize) {
+               if (logo_clutsize == MAX_LINUX_LOGO_COLORS)
+                   die("Image has more than %d colors\n"
+                       "Use ppmquant(1) to reduce the number of colors\n",
+                       MAX_LINUX_LOGO_COLORS);
+               logo_clut[logo_clutsize++] = logo_data[i][j];
+           }
+       }
+
+    /* write file header */
+    write_header();
+
+    /* write logo data */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++) {
+           for (k = 0; k < logo_clutsize; k++)
+               if (is_equal(logo_data[i][j], logo_clut[k]))
+                   break;
+           write_hex(k+32);
+       }
+    fputs("\n};\n\n", out);
+
+    /* write logo clut */
+    fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
+           logoname);
+    write_hex_cnt = 0;
+    for (i = 0; i < logo_clutsize; i++) {
+       write_hex(logo_clut[i].red);
+       write_hex(logo_clut[i].green);
+       write_hex(logo_clut[i].blue);
+    }
+
+    /* write logo structure and file footer */
+    write_footer();
+}
+
+static void write_logo_gray256(void)
+{
+    unsigned int i, j;
+
+    /* validate image */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++)
+           if (!is_gray(logo_data[i][j]))
+               die("Image must be grayscale\n");
+
+    /* write file header */
+    write_header();
+
+    /* write logo data */
+    for (i = 0; i < logo_height; i++)
+       for (j = 0; j < logo_width; j++)
+           write_hex(logo_data[i][j].red);
+
+    /* write logo structure and file footer */
+    write_footer();
+}
+
+static void die(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    exit(1);
+}
+
+static void usage(void)
+{
+    die("\n"
+       "Usage: %s [options] <filename>\n"
+       "\n"
+       "Valid options:\n"
+       "    -h          : display this usage information\n"
+       "    -n <name>   : specify logo name (default: linux_logo)\n"
+       "    -o <output> : output to file <output> instead of stdout\n"
+       "    -t <type>   : specify logo type, one of\n"
+       "                      mono    : monochrome black/white\n"
+       "                      vga16   : 16 colors VGA text palette\n"
+       "                      clut224 : 224 colors (default)\n"
+       "                      gray256 : 256 levels grayscale\n"
+       "\n", programname);
+}
+
+int main(int argc, char *argv[])
+{
+    int opt;
+
+    programname = argv[0];
+
+    opterr = 0;
+    while (1) {
+       opt = getopt(argc, argv, "hn:o:t:");
+       if (opt == -1)
+           break;
+
+       switch (opt) {
+           case 'h':
+               usage();
+               break;
+
+           case 'n':
+               logoname = optarg;
+               break;
+
+           case 'o':
+               outputname = optarg;
+               break;
+
+           case 't':
+               if (!strcmp(optarg, "mono"))
+                   logo_type = LINUX_LOGO_MONO;
+               else if (!strcmp(optarg, "vga16"))
+                   logo_type = LINUX_LOGO_VGA16;
+               else if (!strcmp(optarg, "clut224"))
+                   logo_type = LINUX_LOGO_CLUT224;
+               else if (!strcmp(optarg, "gray256"))
+                   logo_type = LINUX_LOGO_GRAY256;
+               else
+                   usage();
+               break;
+
+           default:
+               usage();
+               break;
+       }
+    }
+    if (optind != argc-1)
+       usage();
+
+    filename = argv[optind];
+
+    read_image();
+    switch (logo_type) {
+       case LINUX_LOGO_MONO:
+           write_logo_mono();
+           break;
+
+       case LINUX_LOGO_VGA16:
+           write_logo_vga16();
+           break;
+
+       case LINUX_LOGO_CLUT224:
+           write_logo_clut224();
+           break;
+
+       case LINUX_LOGO_GRAY256:
+           write_logo_gray256();
+           break;
+    }
+    exit(0);
+}
index 5bae515..4f2e78a 100644 (file)
@@ -374,7 +374,6 @@ static void xen_online_page(struct page *page, unsigned int order)
        mutex_lock(&balloon_mutex);
        for (i = 0; i < size; i++) {
                p = pfn_to_page(start_pfn + i);
-               __online_page_set_limits(p);
                balloon_append(p);
        }
        mutex_unlock(&balloon_mutex);
index 5e30602..59e85e4 100644 (file)
@@ -74,7 +74,7 @@ static int xen_allocate_irq(struct pci_dev *pdev)
                        "xen-platform-pci", pdev);
 }
 
-static int platform_pci_resume(struct pci_dev *pdev)
+static int platform_pci_resume(struct device *dev)
 {
        int err;
 
@@ -83,7 +83,7 @@ static int platform_pci_resume(struct pci_dev *pdev)
 
        err = xen_set_callback_via(callback_via);
        if (err) {
-               dev_err(&pdev->dev, "platform_pci_resume failure!\n");
+               dev_err(dev, "platform_pci_resume failure!\n");
                return err;
        }
        return 0;
@@ -168,13 +168,17 @@ static const struct pci_device_id platform_pci_tbl[] = {
        {0,}
 };
 
+static struct dev_pm_ops platform_pm_ops = {
+       .resume_noirq =   platform_pci_resume,
+};
+
 static struct pci_driver platform_driver = {
        .name =           DRV_NAME,
        .probe =          platform_pci_probe,
        .id_table =       platform_pci_tbl,
-#ifdef CONFIG_PM
-       .resume_early =   platform_pci_resume,
-#endif
+       .driver = {
+               .pm =     &platform_pm_ops,
+       },
 };
 
 builtin_pci_driver(platform_driver);
index 8bcec8d..054f97b 100644 (file)
@@ -63,7 +63,7 @@ struct autofs_info {
 
        struct autofs_sb_info *sbi;
        unsigned long last_used;
-       atomic_t count;
+       int count;
 
        kuid_t uid;
        kgid_t gid;
index 91f5787..a1c7701 100644 (file)
@@ -211,7 +211,7 @@ static int autofs_tree_busy(struct vfsmount *mnt,
                        }
                } else {
                        struct autofs_info *ino = autofs_dentry_ino(p);
-                       unsigned int ino_count = atomic_read(&ino->count);
+                       unsigned int ino_count = READ_ONCE(ino->count);
 
                        /* allow for dget above and top is already dgot */
                        if (p == top)
@@ -379,7 +379,7 @@ static struct dentry *should_expire(struct dentry *dentry,
                /* Not a forced expire? */
                if (!(how & AUTOFS_EXP_FORCED)) {
                        /* ref-walk currently on this dentry? */
-                       ino_count = atomic_read(&ino->count) + 1;
+                       ino_count = READ_ONCE(ino->count) + 1;
                        if (d_count(dentry) > ino_count)
                                return NULL;
                }
@@ -396,7 +396,7 @@ static struct dentry *should_expire(struct dentry *dentry,
                /* Not a forced expire? */
                if (!(how & AUTOFS_EXP_FORCED)) {
                        /* ref-walk currently on this dentry? */
-                       ino_count = atomic_read(&ino->count) + 1;
+                       ino_count = READ_ONCE(ino->count) + 1;
                        if (d_count(dentry) > ino_count)
                                return NULL;
                }
index 29abafc..5aaa173 100644 (file)
@@ -569,10 +569,9 @@ static int autofs_dir_symlink(struct inode *dir,
        d_add(dentry, inode);
 
        dget(dentry);
-       atomic_inc(&ino->count);
+       ino->count++;
        p_ino = autofs_dentry_ino(dentry->d_parent);
-       if (p_ino && !IS_ROOT(dentry))
-               atomic_inc(&p_ino->count);
+       p_ino->count++;
 
        dir->i_mtime = current_time(dir);
 
@@ -610,11 +609,9 @@ static int autofs_dir_unlink(struct inode *dir, struct dentry *dentry)
        if (sbi->flags & AUTOFS_SBI_CATATONIC)
                return -EACCES;
 
-       if (atomic_dec_and_test(&ino->count)) {
-               p_ino = autofs_dentry_ino(dentry->d_parent);
-               if (p_ino && !IS_ROOT(dentry))
-                       atomic_dec(&p_ino->count);
-       }
+       ino->count--;
+       p_ino = autofs_dentry_ino(dentry->d_parent);
+       p_ino->count--;
        dput(ino->dentry);
 
        d_inode(dentry)->i_size = 0;
@@ -660,7 +657,6 @@ static void autofs_set_leaf_automount_flags(struct dentry *dentry)
 
 static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
 {
-       struct list_head *d_child;
        struct dentry *parent;
 
        /* flags for dentrys in the root are handled elsewhere */
@@ -673,10 +669,7 @@ static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
        /* only consider parents below dentrys in the root */
        if (IS_ROOT(parent->d_parent))
                return;
-       d_child = &dentry->d_child;
-       /* Set parent managed if it's becoming empty */
-       if (d_child->next == &parent->d_subdirs &&
-           d_child->prev == &parent->d_subdirs)
+       if (autofs_dentry_ino(parent)->count == 2)
                managed_dentry_set_managed(parent);
 }
 
@@ -698,11 +691,10 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry)
        if (sbi->flags & AUTOFS_SBI_CATATONIC)
                return -EACCES;
 
-       spin_lock(&sbi->lookup_lock);
-       if (!simple_empty(dentry)) {
-               spin_unlock(&sbi->lookup_lock);
+       if (ino->count != 1)
                return -ENOTEMPTY;
-       }
+
+       spin_lock(&sbi->lookup_lock);
        __autofs_add_expiring(dentry);
        d_drop(dentry);
        spin_unlock(&sbi->lookup_lock);
@@ -710,11 +702,9 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry)
        if (sbi->version < 5)
                autofs_clear_leaf_automount_flags(dentry);
 
-       if (atomic_dec_and_test(&ino->count)) {
-               p_ino = autofs_dentry_ino(dentry->d_parent);
-               if (p_ino && dentry->d_parent != dentry)
-                       atomic_dec(&p_ino->count);
-       }
+       ino->count--;
+       p_ino = autofs_dentry_ino(dentry->d_parent);
+       p_ino->count--;
        dput(ino->dentry);
        d_inode(dentry)->i_size = 0;
        clear_nlink(d_inode(dentry));
@@ -760,10 +750,9 @@ static int autofs_dir_mkdir(struct inode *dir,
                autofs_set_leaf_automount_flags(dentry);
 
        dget(dentry);
-       atomic_inc(&ino->count);
+       ino->count++;
        p_ino = autofs_dentry_ino(dentry->d_parent);
-       if (p_ino && !IS_ROOT(dentry))
-               atomic_inc(&p_ino->count);
+       p_ino->count++;
        inc_nlink(dir);
        dir->i_mtime = current_time(dir);
 
index 5372eab..ecd8d26 100644 (file)
@@ -404,6 +404,17 @@ static unsigned long total_mapping_size(const struct elf_phdr *cmds, int nr)
                                ELF_PAGESTART(cmds[first_idx].p_vaddr);
 }
 
+static int elf_read(struct file *file, void *buf, size_t len, loff_t pos)
+{
+       ssize_t rv;
+
+       rv = kernel_read(file, buf, len, &pos);
+       if (unlikely(rv != len)) {
+               return (rv < 0) ? rv : -EIO;
+       }
+       return 0;
+}
+
 /**
  * load_elf_phdrs() - load ELF program headers
  * @elf_ex:   ELF header of the binary whose program headers should be loaded
@@ -418,7 +429,6 @@ static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex,
 {
        struct elf_phdr *elf_phdata = NULL;
        int retval, err = -1;
-       loff_t pos = elf_ex->e_phoff;
        unsigned int size;
 
        /*
@@ -439,9 +449,9 @@ static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex,
                goto out;
 
        /* Read in the program headers */
-       retval = kernel_read(elf_file, elf_phdata, size, &pos);
-       if (retval != size) {
-               err = (retval < 0) ? retval : -EIO;
+       retval = elf_read(elf_file, elf_phdata, size, elf_ex->e_phoff);
+       if (retval < 0) {
+               err = retval;
                goto out;
        }
 
@@ -544,7 +554,7 @@ static inline int make_prot(u32 p_flags)
    an ELF header */
 
 static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
-               struct file *interpreter, unsigned long *interp_map_addr,
+               struct file *interpreter,
                unsigned long no_base, struct elf_phdr *interp_elf_phdata)
 {
        struct elf_phdr *eppnt;
@@ -590,8 +600,6 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                        map_addr = elf_map(interpreter, load_addr + vaddr,
                                        eppnt, elf_prot, elf_type, total_size);
                        total_size = 0;
-                       if (!*interp_map_addr)
-                               *interp_map_addr = map_addr;
                        error = map_addr;
                        if (BAD_ADDR(map_addr))
                                goto out;
@@ -722,7 +730,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
        elf_ppnt = elf_phdata;
        for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
                char *elf_interpreter;
-               loff_t pos;
 
                if (elf_ppnt->p_type != PT_INTERP)
                        continue;
@@ -740,14 +747,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
                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;
+               retval = elf_read(bprm->file, elf_interpreter, elf_ppnt->p_filesz,
+                                 elf_ppnt->p_offset);
+               if (retval < 0)
                        goto out_free_interp;
-               }
                /* make sure path is NULL terminated */
                retval = -ENOEXEC;
                if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
@@ -766,14 +769,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
                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;
+               retval = elf_read(interpreter, &loc->interp_elf_ex,
+                                 sizeof(loc->interp_elf_ex), 0);
+               if (retval < 0)
                        goto out_free_dentry;
-               }
 
                break;
 
@@ -1054,11 +1053,8 @@ out_free_interp:
        }
 
        if (interpreter) {
-               unsigned long interp_map_addr = 0;
-
                elf_entry = load_elf_interp(&loc->interp_elf_ex,
                                            interpreter,
-                                           &interp_map_addr,
                                            load_bias, interp_elf_phdata);
                if (!IS_ERR((void *)elf_entry)) {
                        /*
@@ -1179,11 +1175,10 @@ static int load_elf_library(struct file *file)
        unsigned long elf_bss, bss, len;
        int retval, error, i, j;
        struct elfhdr elf_ex;
-       loff_t pos = 0;
 
        error = -ENOEXEC;
-       retval = kernel_read(file, &elf_ex, sizeof(elf_ex), &pos);
-       if (retval != sizeof(elf_ex))
+       retval = elf_read(file, &elf_ex, sizeof(elf_ex), 0);
+       if (retval < 0)
                goto out;
 
        if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
@@ -1208,9 +1203,8 @@ static int load_elf_library(struct file *file)
 
        eppnt = elf_phdata;
        error = -ENOEXEC;
-       pos =  elf_ex.e_phoff;
-       retval = kernel_read(file, eppnt, j, &pos);
-       if (retval != j)
+       retval = elf_read(file, eppnt, j, elf_ex.e_phoff);
+       if (retval < 0)
                goto out_free_ph;
 
        for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
index d398380..d8c7242 100644 (file)
@@ -49,6 +49,8 @@
 #include <trace/events/block.h>
 #include <linux/fscrypt.h>
 
+#include "internal.h"
+
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
 static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
                         enum rw_hint hint, struct writeback_control *wbc);
@@ -1423,10 +1425,10 @@ static bool has_bh_in_lru(int cpu, void *dummy)
        
        for (i = 0; i < BH_LRU_SIZE; i++) {
                if (b->bhs[i])
-                       return 1;
+                       return true;
        }
 
-       return 0;
+       return false;
 }
 
 void invalidate_bh_lrus(void)
index b2ec29e..73f24f3 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/ceph/ceph_debug.h>
 
+#include <linux/fs_context.h>
 #include "super.h"
 #include "cache.h"
 
@@ -49,7 +50,7 @@ void ceph_fscache_unregister(void)
        fscache_unregister_netfs(&ceph_cache_netfs);
 }
 
-int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
+int ceph_fscache_register_fs(struct ceph_fs_client* fsc, struct fs_context *fc)
 {
        const struct ceph_fsid *fsid = &fsc->client->fsid;
        const char *fscache_uniq = fsc->mount_options->fscache_uniq;
@@ -66,8 +67,8 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
                if (uniq_len && memcmp(ent->uniquifier, fscache_uniq, uniq_len))
                        continue;
 
-               pr_err("fscache cookie already registered for fsid %pU\n", fsid);
-               pr_err("  use fsc=%%s mount option to specify a uniquifier\n");
+               errorf(fc, "ceph: fscache cookie already registered for fsid %pU, use fsc=<uniquifier> option",
+                      fsid);
                err = -EBUSY;
                goto out_unlock;
        }
@@ -95,7 +96,7 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
                list_add_tail(&ent->list, &ceph_fscache_list);
        } else {
                kfree(ent);
-               pr_err("unable to register fscache cookie for fsid %pU\n",
+               errorf(fc, "ceph: unable to register fscache cookie for fsid %pU",
                       fsid);
                /* all other fs ignore this error */
        }
index e486fac..89dbdd1 100644 (file)
@@ -16,7 +16,7 @@ extern struct fscache_netfs ceph_cache_netfs;
 int ceph_fscache_register(void);
 void ceph_fscache_unregister(void);
 
-int ceph_fscache_register_fs(struct ceph_fs_client* fsc);
+int ceph_fscache_register_fs(struct ceph_fs_client* fsc, struct fs_context *fc);
 void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc);
 
 void ceph_fscache_register_inode_cookie(struct inode *inode);
@@ -88,7 +88,8 @@ static inline void ceph_fscache_unregister(void)
 {
 }
 
-static inline int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
+static inline int ceph_fscache_register_fs(struct ceph_fs_client* fsc,
+                                          struct fs_context *fc)
 {
        return 0;
 }
index a516329..068b029 100644 (file)
@@ -2182,13 +2182,17 @@ retry:
        }
        base = ceph_ino(d_inode(temp));
        rcu_read_unlock();
-       if (pos < 0 || read_seqretry(&rename_lock, seq)) {
-               pr_err("build_path did not end path lookup where "
-                      "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) */
+
+       if (read_seqretry(&rename_lock, seq))
+               goto retry;
+
+       if (pos < 0) {
+               /*
+                * A rename didn't occur, but somehow we didn't end up where
+                * we thought we would. Throw a warning and try again.
+                */
+               pr_warn("build_path did not end path lookup where "
+                       "expected, pos is %d\n", pos);
                goto retry;
        }
 
@@ -2345,6 +2349,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
        head->op = cpu_to_le32(req->r_op);
        head->caller_uid = cpu_to_le32(from_kuid(&init_user_ns, req->r_uid));
        head->caller_gid = cpu_to_le32(from_kgid(&init_user_ns, req->r_gid));
+       head->ino = 0;
        head->args = req->r_args;
 
        ceph_encode_filepath(&p, end, ino1, path1);
index ce2d00d..aeec1d6 100644 (file)
@@ -20,7 +20,7 @@
 int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m)
 {
        int n = 0;
-       int i;
+       int i, j;
 
        /* special case for one mds */
        if (1 == m->m_num_mds && m->m_info[0].state > 0)
@@ -35,9 +35,12 @@ int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m)
 
        /* pick */
        n = prandom_u32() % n;
-       for (i = 0; n > 0; i++, n--)
-               while (m->m_info[i].state <= 0)
-                       i++;
+       for (j = 0, i = 0; i < m->m_num_mds; i++) {
+               if (m->m_info[i].state > 0)
+                       j++;
+               if (j > n)
+                       break;
+       }
 
        return i;
 }
index b47f43f..9c9a7c6 100644 (file)
@@ -9,7 +9,8 @@
 #include <linux/in6.h>
 #include <linux/module.h>
 #include <linux/mount.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
@@ -138,280 +139,308 @@ enum {
        Opt_readdir_max_entries,
        Opt_readdir_max_bytes,
        Opt_congestion_kb,
-       Opt_last_int,
        /* int args above */
        Opt_snapdirname,
        Opt_mds_namespace,
-       Opt_fscache_uniq,
        Opt_recover_session,
-       Opt_last_string,
+       Opt_source,
        /* string args above */
        Opt_dirstat,
-       Opt_nodirstat,
        Opt_rbytes,
-       Opt_norbytes,
        Opt_asyncreaddir,
-       Opt_noasyncreaddir,
        Opt_dcache,
-       Opt_nodcache,
        Opt_ino32,
-       Opt_noino32,
        Opt_fscache,
-       Opt_nofscache,
        Opt_poolperm,
-       Opt_nopoolperm,
        Opt_require_active_mds,
-       Opt_norequire_active_mds,
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
        Opt_acl,
-#endif
-       Opt_noacl,
        Opt_quotadf,
-       Opt_noquotadf,
        Opt_copyfrom,
-       Opt_nocopyfrom,
 };
 
-static match_table_t fsopt_tokens = {
-       {Opt_wsize, "wsize=%d"},
-       {Opt_rsize, "rsize=%d"},
-       {Opt_rasize, "rasize=%d"},
-       {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
-       {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
-       {Opt_caps_max, "caps_max=%d"},
-       {Opt_readdir_max_entries, "readdir_max_entries=%d"},
-       {Opt_readdir_max_bytes, "readdir_max_bytes=%d"},
-       {Opt_congestion_kb, "write_congestion_kb=%d"},
-       /* int args above */
-       {Opt_snapdirname, "snapdirname=%s"},
-       {Opt_mds_namespace, "mds_namespace=%s"},
-       {Opt_recover_session, "recover_session=%s"},
-       {Opt_fscache_uniq, "fsc=%s"},
-       /* string args above */
-       {Opt_dirstat, "dirstat"},
-       {Opt_nodirstat, "nodirstat"},
-       {Opt_rbytes, "rbytes"},
-       {Opt_norbytes, "norbytes"},
-       {Opt_asyncreaddir, "asyncreaddir"},
-       {Opt_noasyncreaddir, "noasyncreaddir"},
-       {Opt_dcache, "dcache"},
-       {Opt_nodcache, "nodcache"},
-       {Opt_ino32, "ino32"},
-       {Opt_noino32, "noino32"},
-       {Opt_fscache, "fsc"},
-       {Opt_nofscache, "nofsc"},
-       {Opt_poolperm, "poolperm"},
-       {Opt_nopoolperm, "nopoolperm"},
-       {Opt_require_active_mds, "require_active_mds"},
-       {Opt_norequire_active_mds, "norequire_active_mds"},
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
-       {Opt_acl, "acl"},
-#endif
-       {Opt_noacl, "noacl"},
-       {Opt_quotadf, "quotadf"},
-       {Opt_noquotadf, "noquotadf"},
-       {Opt_copyfrom, "copyfrom"},
-       {Opt_nocopyfrom, "nocopyfrom"},
-       {-1, NULL}
+enum ceph_recover_session_mode {
+       ceph_recover_session_no,
+       ceph_recover_session_clean
+};
+
+static const struct fs_parameter_enum ceph_mount_param_enums[] = {
+       { Opt_recover_session,  "no",           ceph_recover_session_no },
+       { Opt_recover_session,  "clean",        ceph_recover_session_clean },
+       {}
+};
+
+static const struct fs_parameter_spec ceph_mount_param_specs[] = {
+       fsparam_flag_no ("acl",                         Opt_acl),
+       fsparam_flag_no ("asyncreaddir",                Opt_asyncreaddir),
+       fsparam_u32     ("caps_max",                    Opt_caps_max),
+       fsparam_u32     ("caps_wanted_delay_max",       Opt_caps_wanted_delay_max),
+       fsparam_u32     ("caps_wanted_delay_min",       Opt_caps_wanted_delay_min),
+       fsparam_s32     ("write_congestion_kb",         Opt_congestion_kb),
+       fsparam_flag_no ("copyfrom",                    Opt_copyfrom),
+       fsparam_flag_no ("dcache",                      Opt_dcache),
+       fsparam_flag_no ("dirstat",                     Opt_dirstat),
+       __fsparam       (fs_param_is_string, "fsc",     Opt_fscache,
+                        fs_param_neg_with_no | fs_param_v_optional),
+       fsparam_flag_no ("ino32",                       Opt_ino32),
+       fsparam_string  ("mds_namespace",               Opt_mds_namespace),
+       fsparam_flag_no ("poolperm",                    Opt_poolperm),
+       fsparam_flag_no ("quotadf",                     Opt_quotadf),
+       fsparam_u32     ("rasize",                      Opt_rasize),
+       fsparam_flag_no ("rbytes",                      Opt_rbytes),
+       fsparam_s32     ("readdir_max_bytes",           Opt_readdir_max_bytes),
+       fsparam_s32     ("readdir_max_entries",         Opt_readdir_max_entries),
+       fsparam_enum    ("recover_session",             Opt_recover_session),
+       fsparam_flag_no ("require_active_mds",          Opt_require_active_mds),
+       fsparam_u32     ("rsize",                       Opt_rsize),
+       fsparam_string  ("snapdirname",                 Opt_snapdirname),
+       fsparam_string  ("source",                      Opt_source),
+       fsparam_u32     ("wsize",                       Opt_wsize),
+       {}
+};
+
+static const struct fs_parameter_description ceph_mount_parameters = {
+       .name           = "ceph",
+       .specs          = ceph_mount_param_specs,
+       .enums          = ceph_mount_param_enums,
 };
 
-static int parse_fsopt_token(char *c, void *private)
+struct ceph_parse_opts_ctx {
+       struct ceph_options             *copts;
+       struct ceph_mount_options       *opts;
+};
+
+/*
+ * Parse the source parameter.  Distinguish the server list from the path.
+ * Internally we do not include the leading '/' in the path.
+ *
+ * The source will look like:
+ *     <server_spec>[,<server_spec>...]:[<path>]
+ * where
+ *     <server_spec> is <ip>[:<port>]
+ *     <path> is optional, but if present must begin with '/'
+ */
+static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)
 {
-       struct ceph_mount_options *fsopt = private;
-       substring_t argstr[MAX_OPT_ARGS];
-       int token, intval, ret;
+       struct ceph_parse_opts_ctx *pctx = fc->fs_private;
+       struct ceph_mount_options *fsopt = pctx->opts;
+       char *dev_name = param->string, *dev_name_end;
+       int ret;
 
-       token = match_token((char *)c, fsopt_tokens, argstr);
-       if (token < 0)
-               return -EINVAL;
+       dout("%s '%s'\n", __func__, dev_name);
+       if (!dev_name || !*dev_name)
+               return invalf(fc, "ceph: Empty source");
 
-       if (token < Opt_last_int) {
-               ret = match_int(&argstr[0], &intval);
-               if (ret < 0) {
-                       pr_err("bad option arg (not int) at '%s'\n", c);
-                       return ret;
+       dev_name_end = strchr(dev_name, '/');
+       if (dev_name_end) {
+               if (strlen(dev_name_end) > 1) {
+                       kfree(fsopt->server_path);
+                       fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
+                       if (!fsopt->server_path)
+                               return -ENOMEM;
                }
-               dout("got int token %d val %d\n", token, intval);
-       } else if (token > Opt_last_int && token < Opt_last_string) {
-               dout("got string token %d val %s\n", token,
-                    argstr[0].from);
        } else {
-               dout("got token %d\n", token);
+               dev_name_end = dev_name + strlen(dev_name);
        }
 
+       dev_name_end--;         /* back up to ':' separator */
+       if (dev_name_end < dev_name || *dev_name_end != ':')
+               return invalf(fc, "ceph: No path or : separator in source");
+
+       dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
+       if (fsopt->server_path)
+               dout("server path '%s'\n", fsopt->server_path);
+
+       ret = ceph_parse_mon_ips(param->string, dev_name_end - dev_name,
+                                pctx->copts, fc);
+       if (ret)
+               return ret;
+
+       fc->source = param->string;
+       param->string = NULL;
+       return 0;
+}
+
+static int ceph_parse_mount_param(struct fs_context *fc,
+                                 struct fs_parameter *param)
+{
+       struct ceph_parse_opts_ctx *pctx = fc->fs_private;
+       struct ceph_mount_options *fsopt = pctx->opts;
+       struct fs_parse_result result;
+       unsigned int mode;
+       int token, ret;
+
+       ret = ceph_parse_param(param, pctx->copts, fc);
+       if (ret != -ENOPARAM)
+               return ret;
+
+       token = fs_parse(fc, &ceph_mount_parameters, param, &result);
+       dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
+       if (token < 0)
+               return token;
+
        switch (token) {
        case Opt_snapdirname:
                kfree(fsopt->snapdir_name);
-               fsopt->snapdir_name = kstrndup(argstr[0].from,
-                                              argstr[0].to-argstr[0].from,
-                                              GFP_KERNEL);
-               if (!fsopt->snapdir_name)
-                       return -ENOMEM;
+               fsopt->snapdir_name = param->string;
+               param->string = NULL;
                break;
        case Opt_mds_namespace:
                kfree(fsopt->mds_namespace);
-               fsopt->mds_namespace = kstrndup(argstr[0].from,
-                                               argstr[0].to-argstr[0].from,
-                                               GFP_KERNEL);
-               if (!fsopt->mds_namespace)
-                       return -ENOMEM;
+               fsopt->mds_namespace = param->string;
+               param->string = NULL;
                break;
        case Opt_recover_session:
-               if (!strncmp(argstr[0].from, "no",
-                            argstr[0].to - argstr[0].from)) {
+               mode = result.uint_32;
+               if (mode == ceph_recover_session_no)
                        fsopt->flags &= ~CEPH_MOUNT_OPT_CLEANRECOVER;
-               } else if (!strncmp(argstr[0].from, "clean",
-                                   argstr[0].to - argstr[0].from)) {
+               else if (mode == ceph_recover_session_clean)
                        fsopt->flags |= CEPH_MOUNT_OPT_CLEANRECOVER;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       case Opt_fscache_uniq:
-#ifdef CONFIG_CEPH_FSCACHE
-               kfree(fsopt->fscache_uniq);
-               fsopt->fscache_uniq = kstrndup(argstr[0].from,
-                                              argstr[0].to-argstr[0].from,
-                                              GFP_KERNEL);
-               if (!fsopt->fscache_uniq)
-                       return -ENOMEM;
-               fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
+               else
+                       BUG();
                break;
-#else
-               pr_err("fscache support is disabled\n");
-               return -EINVAL;
-#endif
+       case Opt_source:
+               if (fc->source)
+                       return invalf(fc, "ceph: Multiple sources specified");
+               return ceph_parse_source(param, fc);
        case Opt_wsize:
-               if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_WRITE_SIZE)
-                       return -EINVAL;
-               fsopt->wsize = ALIGN(intval, PAGE_SIZE);
+               if (result.uint_32 < PAGE_SIZE ||
+                   result.uint_32 > CEPH_MAX_WRITE_SIZE)
+                       goto out_of_range;
+               fsopt->wsize = ALIGN(result.uint_32, PAGE_SIZE);
                break;
        case Opt_rsize:
-               if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_READ_SIZE)
-                       return -EINVAL;
-               fsopt->rsize = ALIGN(intval, PAGE_SIZE);
+               if (result.uint_32 < PAGE_SIZE ||
+                   result.uint_32 > CEPH_MAX_READ_SIZE)
+                       goto out_of_range;
+               fsopt->rsize = ALIGN(result.uint_32, PAGE_SIZE);
                break;
        case Opt_rasize:
-               if (intval < 0)
-                       return -EINVAL;
-               fsopt->rasize = ALIGN(intval, PAGE_SIZE);
+               fsopt->rasize = ALIGN(result.uint_32, PAGE_SIZE);
                break;
        case Opt_caps_wanted_delay_min:
-               if (intval < 1)
-                       return -EINVAL;
-               fsopt->caps_wanted_delay_min = intval;
+               if (result.uint_32 < 1)
+                       goto out_of_range;
+               fsopt->caps_wanted_delay_min = result.uint_32;
                break;
        case Opt_caps_wanted_delay_max:
-               if (intval < 1)
-                       return -EINVAL;
-               fsopt->caps_wanted_delay_max = intval;
+               if (result.uint_32 < 1)
+                       goto out_of_range;
+               fsopt->caps_wanted_delay_max = result.uint_32;
                break;
        case Opt_caps_max:
-               if (intval < 0)
-                       return -EINVAL;
-               fsopt->caps_max = intval;
+               fsopt->caps_max = result.uint_32;
                break;
        case Opt_readdir_max_entries:
-               if (intval < 1)
-                       return -EINVAL;
-               fsopt->max_readdir = intval;
+               if (result.uint_32 < 1)
+                       goto out_of_range;
+               fsopt->max_readdir = result.uint_32;
                break;
        case Opt_readdir_max_bytes:
-               if (intval < (int)PAGE_SIZE && intval != 0)
-                       return -EINVAL;
-               fsopt->max_readdir_bytes = intval;
+               if (result.uint_32 < PAGE_SIZE && result.uint_32 != 0)
+                       goto out_of_range;
+               fsopt->max_readdir_bytes = result.uint_32;
                break;
        case Opt_congestion_kb:
-               if (intval < 1024) /* at least 1M */
-                       return -EINVAL;
-               fsopt->congestion_kb = intval;
+               if (result.uint_32 < 1024) /* at least 1M */
+                       goto out_of_range;
+               fsopt->congestion_kb = result.uint_32;
                break;
        case Opt_dirstat:
-               fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT;
-               break;
-       case Opt_nodirstat:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT;
+               if (!result.negated)
+                       fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT;
+               else
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT;
                break;
        case Opt_rbytes:
-               fsopt->flags |= CEPH_MOUNT_OPT_RBYTES;
-               break;
-       case Opt_norbytes:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
+               if (!result.negated)
+                       fsopt->flags |= CEPH_MOUNT_OPT_RBYTES;
+               else
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
                break;
        case Opt_asyncreaddir:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
-               break;
-       case Opt_noasyncreaddir:
-               fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
+               if (!result.negated)
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
+               else
+                       fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
                break;
        case Opt_dcache:
-               fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
-               break;
-       case Opt_nodcache:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
+               if (!result.negated)
+                       fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
+               else
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
                break;
        case Opt_ino32:
-               fsopt->flags |= CEPH_MOUNT_OPT_INO32;
-               break;
-       case Opt_noino32:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
+               if (!result.negated)
+                       fsopt->flags |= CEPH_MOUNT_OPT_INO32;
+               else
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
                break;
+
        case Opt_fscache:
 #ifdef CONFIG_CEPH_FSCACHE
-               fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
                kfree(fsopt->fscache_uniq);
                fsopt->fscache_uniq = NULL;
+               if (result.negated) {
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
+               } else {
+                       fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
+                       fsopt->fscache_uniq = param->string;
+                       param->string = NULL;
+               }
                break;
 #else
-               pr_err("fscache support is disabled\n");
-               return -EINVAL;
+               return invalf(fc, "ceph: fscache support is disabled");
 #endif
-       case Opt_nofscache:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
-               kfree(fsopt->fscache_uniq);
-               fsopt->fscache_uniq = NULL;
-               break;
        case Opt_poolperm:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_NOPOOLPERM;
-               break;
-       case Opt_nopoolperm:
-               fsopt->flags |= CEPH_MOUNT_OPT_NOPOOLPERM;
+               if (!result.negated)
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_NOPOOLPERM;
+               else
+                       fsopt->flags |= CEPH_MOUNT_OPT_NOPOOLPERM;
                break;
        case Opt_require_active_mds:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_MOUNTWAIT;
-               break;
-       case Opt_norequire_active_mds:
-               fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT;
+               if (!result.negated)
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_MOUNTWAIT;
+               else
+                       fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT;
                break;
        case Opt_quotadf:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF;
-               break;
-       case Opt_noquotadf:
-               fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF;
+               if (!result.negated)
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF;
+               else
+                       fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF;
                break;
        case Opt_copyfrom:
-               fsopt->flags &= ~CEPH_MOUNT_OPT_NOCOPYFROM;
-               break;
-       case Opt_nocopyfrom:
-               fsopt->flags |= CEPH_MOUNT_OPT_NOCOPYFROM;
+               if (!result.negated)
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_NOCOPYFROM;
+               else
+                       fsopt->flags |= CEPH_MOUNT_OPT_NOCOPYFROM;
                break;
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
        case Opt_acl:
-               fsopt->sb_flags |= SB_POSIXACL;
-               break;
+               if (!result.negated) {
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+                       fc->sb_flags |= SB_POSIXACL;
+#else
+                       return invalf(fc, "ceph: POSIX ACL support is disabled");
 #endif
-       case Opt_noacl:
-               fsopt->sb_flags &= ~SB_POSIXACL;
+               } else {
+                       fc->sb_flags &= ~SB_POSIXACL;
+               }
                break;
        default:
-               BUG_ON(token);
+               BUG();
        }
        return 0;
+
+out_of_range:
+       return invalf(fc, "ceph: %s out of range", param->key);
 }
 
 static void destroy_mount_options(struct ceph_mount_options *args)
 {
        dout("destroy_mount_options %p\n", args);
+       if (!args)
+               return;
+
        kfree(args->snapdir_name);
        kfree(args->mds_namespace);
        kfree(args->server_path);
@@ -459,91 +488,6 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt,
        return ceph_compare_options(new_opt, fsc->client);
 }
 
-static int parse_mount_options(struct ceph_mount_options **pfsopt,
-                              struct ceph_options **popt,
-                              int flags, char *options,
-                              const char *dev_name)
-{
-       struct ceph_mount_options *fsopt;
-       const char *dev_name_end;
-       int err;
-
-       if (!dev_name || !*dev_name)
-               return -EINVAL;
-
-       fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL);
-       if (!fsopt)
-               return -ENOMEM;
-
-       dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name);
-
-       fsopt->sb_flags = flags;
-       fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
-
-       fsopt->wsize = CEPH_MAX_WRITE_SIZE;
-       fsopt->rsize = CEPH_MAX_READ_SIZE;
-       fsopt->rasize = CEPH_RASIZE_DEFAULT;
-       fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
-       if (!fsopt->snapdir_name) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
-       fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
-       fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
-       fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
-       fsopt->congestion_kb = default_congestion_kb();
-
-       /*
-        * Distinguish the server list from the path in "dev_name".
-        * Internally we do not include the leading '/' in the path.
-        *
-        * "dev_name" will look like:
-        *     <server_spec>[,<server_spec>...]:[<path>]
-        * where
-        *     <server_spec> is <ip>[:<port>]
-        *     <path> is optional, but if present must begin with '/'
-        */
-       dev_name_end = strchr(dev_name, '/');
-       if (dev_name_end) {
-               if (strlen(dev_name_end) > 1) {
-                       fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
-                       if (!fsopt->server_path) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-               }
-       } else {
-               dev_name_end = dev_name + strlen(dev_name);
-       }
-       err = -EINVAL;
-       dev_name_end--;         /* back up to ':' separator */
-       if (dev_name_end < dev_name || *dev_name_end != ':') {
-               pr_err("device name is missing path (no : separator in %s)\n",
-                               dev_name);
-               goto out;
-       }
-       dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
-       if (fsopt->server_path)
-               dout("server path '%s'\n", fsopt->server_path);
-
-       *popt = ceph_parse_options(options, dev_name, dev_name_end,
-                                parse_fsopt_token, (void *)fsopt);
-       if (IS_ERR(*popt)) {
-               err = PTR_ERR(*popt);
-               goto out;
-       }
-
-       /* success */
-       *pfsopt = fsopt;
-       return 0;
-
-out:
-       destroy_mount_options(fsopt);
-       return err;
-}
-
 /**
  * ceph_show_options - Show mount options in /proc/mounts
  * @m: seq_file to write to
@@ -587,7 +531,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",noquotadf");
 
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
-       if (fsopt->sb_flags & SB_POSIXACL)
+       if (root->d_sb->s_flags & SB_POSIXACL)
                seq_puts(m, ",acl");
        else
                seq_puts(m, ",noacl");
@@ -860,12 +804,6 @@ static void ceph_umount_begin(struct super_block *sb)
        fsc->filp_gen++; // invalidate open files
 }
 
-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,
        .free_inode     = ceph_free_inode,
@@ -874,7 +812,6 @@ static const struct super_operations ceph_super_ops = {
        .evict_inode    = ceph_evict_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,
@@ -935,7 +872,8 @@ out:
 /*
  * mount: join the ceph cluster, and open root directory.
  */
-static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
+static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
+                                     struct fs_context *fc)
 {
        int err;
        unsigned long started = jiffies;  /* note the start time */
@@ -952,7 +890,7 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
 
                /* setup fscache */
                if (fsc->mount_options->flags & CEPH_MOUNT_OPT_FSCACHE) {
-                       err = ceph_fscache_register_fs(fsc);
+                       err = ceph_fscache_register_fs(fsc, fc);
                        if (err < 0)
                                goto out;
                }
@@ -987,18 +925,16 @@ out:
        return ERR_PTR(err);
 }
 
-static int ceph_set_super(struct super_block *s, void *data)
+static int ceph_set_super(struct super_block *s, struct fs_context *fc)
 {
-       struct ceph_fs_client *fsc = data;
+       struct ceph_fs_client *fsc = s->s_fs_info;
        int ret;
 
-       dout("set_super %p data %p\n", s, data);
+       dout("set_super %p\n", s);
 
-       s->s_flags = fsc->mount_options->sb_flags;
        s->s_maxbytes = MAX_LFS_FILESIZE;
 
        s->s_xattr = ceph_xattr_handlers;
-       s->s_fs_info = fsc;
        fsc->sb = s;
        fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
 
@@ -1010,24 +946,18 @@ static int ceph_set_super(struct super_block *s, void *data)
        s->s_time_min = 0;
        s->s_time_max = U32_MAX;
 
-       ret = set_anon_super(s, NULL);  /* what is that second arg for? */
+       ret = set_anon_super_fc(s, fc);
        if (ret != 0)
-               goto fail;
-
-       return ret;
-
-fail:
-       s->s_fs_info = NULL;
-       fsc->sb = NULL;
+               fsc->sb = NULL;
        return ret;
 }
 
 /*
  * share superblock if same fs AND options
  */
-static int ceph_compare_super(struct super_block *sb, void *data)
+static int ceph_compare_super(struct super_block *sb, struct fs_context *fc)
 {
-       struct ceph_fs_client *new = data;
+       struct ceph_fs_client *new = fc->s_fs_info;
        struct ceph_mount_options *fsopt = new->mount_options;
        struct ceph_options *opt = new->client->options;
        struct ceph_fs_client *other = ceph_sb_to_client(sb);
@@ -1043,7 +973,7 @@ static int ceph_compare_super(struct super_block *sb, void *data)
                dout("fsid doesn't match\n");
                return 0;
        }
-       if (fsopt->sb_flags != other->mount_options->sb_flags) {
+       if (fc->sb_flags != (sb->s_flags & ~SB_BORN)) {
                dout("flags differ\n");
                return 0;
        }
@@ -1073,46 +1003,46 @@ static int ceph_setup_bdi(struct super_block *sb, struct ceph_fs_client *fsc)
        return 0;
 }
 
-static struct dentry *ceph_mount(struct file_system_type *fs_type,
-                      int flags, const char *dev_name, void *data)
+static int ceph_get_tree(struct fs_context *fc)
 {
+       struct ceph_parse_opts_ctx *pctx = fc->fs_private;
        struct super_block *sb;
        struct ceph_fs_client *fsc;
        struct dentry *res;
+       int (*compare_super)(struct super_block *, struct fs_context *) =
+               ceph_compare_super;
        int err;
-       int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
-       struct ceph_mount_options *fsopt = NULL;
-       struct ceph_options *opt = NULL;
 
-       dout("ceph_mount\n");
+       dout("ceph_get_tree\n");
+
+       if (!fc->source)
+               return invalf(fc, "ceph: No source");
 
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
-       flags |= SB_POSIXACL;
+       fc->sb_flags |= SB_POSIXACL;
 #endif
-       err = parse_mount_options(&fsopt, &opt, flags, data, dev_name);
-       if (err < 0) {
-               res = ERR_PTR(err);
-               goto out_final;
-       }
 
        /* create client (which we may/may not use) */
-       fsc = create_fs_client(fsopt, opt);
+       fsc = create_fs_client(pctx->opts, pctx->copts);
+       pctx->opts = NULL;
+       pctx->copts = NULL;
        if (IS_ERR(fsc)) {
-               res = ERR_CAST(fsc);
+               err = PTR_ERR(fsc);
                goto out_final;
        }
 
        err = ceph_mdsc_init(fsc);
-       if (err < 0) {
-               res = ERR_PTR(err);
+       if (err < 0)
                goto out;
-       }
 
        if (ceph_test_opt(fsc->client, NOSHARE))
                compare_super = NULL;
-       sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc);
+
+       fc->s_fs_info = fsc;
+       sb = sget_fc(fc, compare_super, ceph_set_super);
+       fc->s_fs_info = NULL;
        if (IS_ERR(sb)) {
-               res = ERR_CAST(sb);
+               err = PTR_ERR(sb);
                goto out;
        }
 
@@ -1123,18 +1053,19 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
        } else {
                dout("get_sb using new client %p\n", fsc);
                err = ceph_setup_bdi(sb, fsc);
-               if (err < 0) {
-                       res = ERR_PTR(err);
+               if (err < 0)
                        goto out_splat;
-               }
        }
 
-       res = ceph_real_mount(fsc);
-       if (IS_ERR(res))
+       res = ceph_real_mount(fsc, fc);
+       if (IS_ERR(res)) {
+               err = PTR_ERR(res);
                goto out_splat;
+       }
        dout("root %p inode %p ino %llx.%llx\n", res,
             d_inode(res), ceph_vinop(d_inode(res)));
-       return res;
+       fc->root = fsc->sb->s_root;
+       return 0;
 
 out_splat:
        ceph_mdsc_close_sessions(fsc->mdsc);
@@ -1144,8 +1075,79 @@ out_splat:
 out:
        destroy_fs_client(fsc);
 out_final:
-       dout("ceph_mount fail %ld\n", PTR_ERR(res));
-       return res;
+       dout("ceph_get_tree fail %d\n", err);
+       return err;
+}
+
+static void ceph_free_fc(struct fs_context *fc)
+{
+       struct ceph_parse_opts_ctx *pctx = fc->fs_private;
+
+       if (pctx) {
+               destroy_mount_options(pctx->opts);
+               ceph_destroy_options(pctx->copts);
+               kfree(pctx);
+       }
+}
+
+static int ceph_reconfigure_fc(struct fs_context *fc)
+{
+       sync_filesystem(fc->root->d_sb);
+       return 0;
+}
+
+static const struct fs_context_operations ceph_context_ops = {
+       .free           = ceph_free_fc,
+       .parse_param    = ceph_parse_mount_param,
+       .get_tree       = ceph_get_tree,
+       .reconfigure    = ceph_reconfigure_fc,
+};
+
+/*
+ * Set up the filesystem mount context.
+ */
+static int ceph_init_fs_context(struct fs_context *fc)
+{
+       struct ceph_parse_opts_ctx *pctx;
+       struct ceph_mount_options *fsopt;
+
+       pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
+       if (!pctx)
+               return -ENOMEM;
+
+       pctx->copts = ceph_alloc_options();
+       if (!pctx->copts)
+               goto nomem;
+
+       pctx->opts = kzalloc(sizeof(*pctx->opts), GFP_KERNEL);
+       if (!pctx->opts)
+               goto nomem;
+
+       fsopt = pctx->opts;
+       fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
+
+       fsopt->wsize = CEPH_MAX_WRITE_SIZE;
+       fsopt->rsize = CEPH_MAX_READ_SIZE;
+       fsopt->rasize = CEPH_RASIZE_DEFAULT;
+       fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+       if (!fsopt->snapdir_name)
+               goto nomem;
+
+       fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
+       fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
+       fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
+       fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
+       fsopt->congestion_kb = default_congestion_kb();
+
+       fc->fs_private = pctx;
+       fc->ops = &ceph_context_ops;
+       return 0;
+
+nomem:
+       destroy_mount_options(pctx->opts);
+       ceph_destroy_options(pctx->copts);
+       kfree(pctx);
+       return -ENOMEM;
 }
 
 static void ceph_kill_sb(struct super_block *s)
@@ -1172,7 +1174,7 @@ static void ceph_kill_sb(struct super_block *s)
 static struct file_system_type ceph_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ceph",
-       .mount          = ceph_mount,
+       .init_fs_context = ceph_init_fs_context,
        .kill_sb        = ceph_kill_sb,
        .fs_flags       = FS_RENAME_DOES_D_MOVE,
 };
index f98d924..f0f9cb7 100644 (file)
@@ -74,7 +74,6 @@
 
 struct ceph_mount_options {
        int flags;
-       int sb_flags;
 
        int wsize;            /* max write size */
        int rsize;            /* max read size */
@@ -407,22 +406,26 @@ struct ceph_inode_info {
        struct inode vfs_inode; /* at end */
 };
 
-static inline struct ceph_inode_info *ceph_inode(struct inode *inode)
+static inline struct ceph_inode_info *
+ceph_inode(const struct inode *inode)
 {
        return container_of(inode, struct ceph_inode_info, vfs_inode);
 }
 
-static inline struct ceph_fs_client *ceph_inode_to_client(struct inode *inode)
+static inline struct ceph_fs_client *
+ceph_inode_to_client(const struct inode *inode)
 {
        return (struct ceph_fs_client *)inode->i_sb->s_fs_info;
 }
 
-static inline struct ceph_fs_client *ceph_sb_to_client(struct super_block *sb)
+static inline struct ceph_fs_client *
+ceph_sb_to_client(const struct super_block *sb)
 {
        return (struct ceph_fs_client *)sb->s_fs_info;
 }
 
-static inline struct ceph_vino ceph_vino(struct inode *inode)
+static inline struct ceph_vino
+ceph_vino(const struct inode *inode)
 {
        return ceph_inode(inode)->i_vino;
 }
index 5d3e63a..5492b98 100644 (file)
@@ -730,11 +730,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
                struct inode *dir = d_inode(dentry);
                struct dentry *child;
 
-               if (!dir) {
-                       dput(dentry);
-                       dentry = ERR_PTR(-ENOENT);
-                       break;
-               }
                if (!S_ISDIR(dir->i_mode)) {
                        dput(dentry);
                        dentry = ERR_PTR(-ENOTDIR);
@@ -751,7 +746,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
                while (*s && *s != sep)
                        s++;
 
-               child = lookup_one_len_unlocked(p, dentry, s - p);
+               child = lookup_positive_unlocked(p, dentry, s - p);
                dput(dentry);
                dentry = child;
        } while (!IS_ERR(dentry));
@@ -1551,7 +1546,7 @@ init_cifs(void)
        /*
         * Consider in future setting limit!=0 maybe to min(num_of_cores - 1, 3)
         * so that we don't launch too many worker threads but
-        * Documentation/workqueue.txt recommends setting it to 0
+        * Documentation/core-api/workqueue.rst recommends setting it to 0
         */
 
        /* WQ_UNBOUND allows decrypt tasks to run on any CPU */
index 9ae90d7..358ea2e 100644 (file)
@@ -185,15 +185,27 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
        /* handled by some ->ioctl(); always a pointer to int */
        case FIONREAD:
                goto found_handler;
-       /* these two get messy on amd64 due to alignment differences */
+       /* these get messy on amd64 due to alignment differences */
 #if defined(CONFIG_X86_64)
        case FS_IOC_RESVSP_32:
        case FS_IOC_RESVSP64_32:
-               error = compat_ioctl_preallocate(f.file, compat_ptr(arg));
+               error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
+               goto out_fput;
+       case FS_IOC_UNRESVSP_32:
+       case FS_IOC_UNRESVSP64_32:
+               error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
+                               compat_ptr(arg));
+               goto out_fput;
+       case FS_IOC_ZERO_RANGE_32:
+               error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
+                               compat_ptr(arg));
                goto out_fput;
 #else
        case FS_IOC_RESVSP:
        case FS_IOC_RESVSP64:
+       case FS_IOC_UNRESVSP:
+       case FS_IOC_UNRESVSP64:
+       case FS_IOC_ZERO_RANGE:
                goto found_handler;
 #endif
 
index f7931b6..a2749a7 100644 (file)
@@ -319,7 +319,7 @@ static inline void __d_set_inode_and_type(struct dentry *dentry,
        flags = READ_ONCE(dentry->d_flags);
        flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
        flags |= type_flags;
-       WRITE_ONCE(dentry->d_flags, flags);
+       smp_store_release(&dentry->d_flags, flags);
 }
 
 static inline void __d_clear_type_and_inode(struct dentry *dentry)
@@ -903,17 +903,19 @@ struct dentry *dget_parent(struct dentry *dentry)
 {
        int gotref;
        struct dentry *ret;
+       unsigned seq;
 
        /*
         * Do optimistic parent lookup without any
         * locking.
         */
        rcu_read_lock();
+       seq = raw_seqcount_begin(&dentry->d_seq);
        ret = READ_ONCE(dentry->d_parent);
        gotref = lockref_get_not_zero(&ret->d_lockref);
        rcu_read_unlock();
        if (likely(gotref)) {
-               if (likely(ret == READ_ONCE(dentry->d_parent)))
+               if (!read_seqcount_retry(&dentry->d_seq, seq))
                        return ret;
                dput(ret);
        }
index 7b975db..f4d8df5 100644 (file)
@@ -299,13 +299,9 @@ struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
        if (!parent)
                parent = debugfs_mount->mnt_root;
 
-       dentry = lookup_one_len_unlocked(name, parent, strlen(name));
+       dentry = lookup_positive_unlocked(name, parent, strlen(name));
        if (IS_ERR(dentry))
                return NULL;
-       if (!d_really_is_positive(dentry)) {
-               dput(dentry);
-               return NULL;
-       }
        return dentry;
 }
 EXPORT_SYMBOL_GPL(debugfs_lookup);
index 9329ced..0ec4f27 100644 (file)
@@ -220,27 +220,6 @@ static inline struct page *dio_get_page(struct dio *dio,
        return dio->pages[sdio->head];
 }
 
-/*
- * Warn about a page cache invalidation failure during a direct io write.
- */
-void dio_warn_stale_pagecache(struct file *filp)
-{
-       static DEFINE_RATELIMIT_STATE(_rs, 86400 * HZ, DEFAULT_RATELIMIT_BURST);
-       char pathname[128];
-       struct inode *inode = file_inode(filp);
-       char *path;
-
-       errseq_set(&inode->i_mapping->wb_err, -EIO);
-       if (__ratelimit(&_rs)) {
-               path = file_path(filp, pathname, sizeof(pathname));
-               if (IS_ERR(path))
-                       path = "(unknown)";
-               pr_crit("Page cache invalidation failure on direct I/O.  Possible data corruption due to collision with buffered I/O!\n");
-               pr_crit("File: %s PID: %d Comm: %.20s\n", path, current->pid,
-                       current->comm);
-       }
-}
-
 /*
  * dio_complete() - called when all DIO BIO I/O has been completed
  *
index c4159bc..67a3950 100644 (file)
@@ -551,28 +551,23 @@ out_unlock:
  */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
-static struct nested_calls poll_safewake_ncalls;
-
-static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests)
-{
-       unsigned long flags;
-       wait_queue_head_t *wqueue = (wait_queue_head_t *)cookie;
-
-       spin_lock_irqsave_nested(&wqueue->lock, flags, call_nests + 1);
-       wake_up_locked_poll(wqueue, EPOLLIN);
-       spin_unlock_irqrestore(&wqueue->lock, flags);
-
-       return 0;
-}
+static DEFINE_PER_CPU(int, wakeup_nest);
 
 static void ep_poll_safewake(wait_queue_head_t *wq)
 {
-       int this_cpu = get_cpu();
-
-       ep_call_nested(&poll_safewake_ncalls,
-                      ep_poll_wakeup_proc, NULL, wq, (void *) (long) this_cpu);
+       unsigned long flags;
+       int subclass;
 
-       put_cpu();
+       local_irq_save(flags);
+       preempt_disable();
+       subclass = __this_cpu_read(wakeup_nest);
+       spin_lock_nested(&wq->lock, subclass + 1);
+       __this_cpu_inc(wakeup_nest);
+       wake_up_locked_poll(wq, POLLIN);
+       __this_cpu_dec(wakeup_nest);
+       spin_unlock(&wq->lock);
+       local_irq_restore(flags);
+       preempt_enable();
 }
 
 #else
@@ -671,7 +666,6 @@ static __poll_t ep_scan_ready_list(struct eventpoll *ep,
                              void *priv, int depth, bool ep_locked)
 {
        __poll_t res;
-       int pwake = 0;
        struct epitem *epi, *nepi;
        LIST_HEAD(txlist);
 
@@ -738,26 +732,11 @@ static __poll_t ep_scan_ready_list(struct eventpoll *ep,
         */
        list_splice(&txlist, &ep->rdllist);
        __pm_relax(ep->ws);
-
-       if (!list_empty(&ep->rdllist)) {
-               /*
-                * Wake up (if active) both the eventpoll wait list and
-                * the ->poll() wait list (delayed after we release the lock).
-                */
-               if (waitqueue_active(&ep->wq))
-                       wake_up(&ep->wq);
-               if (waitqueue_active(&ep->poll_wait))
-                       pwake++;
-       }
        write_unlock_irq(&ep->lock);
 
        if (!ep_locked)
                mutex_unlock(&ep->mtx);
 
-       /* We have to call this outside the lock */
-       if (pwake)
-               ep_poll_safewake(&ep->poll_wait);
-
        return res;
 }
 
@@ -2370,11 +2349,6 @@ static int __init eventpoll_init(void)
         */
        ep_nested_calls_init(&poll_loop_ncalls);
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       /* Initialize the structure used to perform safe poll wait head wake ups */
-       ep_nested_calls_init(&poll_safewake_ncalls);
-#endif
-
        /*
         * We can have many thousands of epitems, so prevent this from
         * using an extra cache line on 64-bit (and smaller) CPUs
index a504ed6..74d88da 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1131,7 +1131,7 @@ static int de_thread(struct task_struct *tsk)
                 * also take its birthdate (always earlier than our own).
                 */
                tsk->start_time = leader->start_time;
-               tsk->real_start_time = leader->real_start_time;
+               tsk->start_boottime = leader->start_boottime;
 
                BUG_ON(!same_thread_group(leader, tsk));
                BUG_ON(has_group_leader_pid(tsk));
index 0635cba..eb2a585 100644 (file)
@@ -34,7 +34,7 @@ config VIRTIO_FS
        select VIRTIO
        help
          The Virtio Filesystem allows guests to mount file systems from the
-          host.
+         host.
 
          If you want to share files between guests or with the host, answer Y
-          or M.
+         or M.
index 54d638f..ee19011 100644 (file)
@@ -248,7 +248,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
                kfree(forget);
                if (ret == -ENOMEM)
                        goto out;
-               if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
+               if (ret || fuse_invalid_attr(&outarg.attr) ||
+                   (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
                        goto invalid;
 
                forget_all_cached_acls(inode);
@@ -319,6 +320,12 @@ int fuse_valid_type(int m)
                S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
 }
 
+bool fuse_invalid_attr(struct fuse_attr *attr)
+{
+       return !fuse_valid_type(attr->mode) ||
+               attr->size > LLONG_MAX;
+}
+
 int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
                     struct fuse_entry_out *outarg, struct inode **inode)
 {
@@ -350,7 +357,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
        err = -EIO;
        if (!outarg->nodeid)
                goto out_put_forget;
-       if (!fuse_valid_type(outarg->attr.mode))
+       if (fuse_invalid_attr(&outarg->attr))
                goto out_put_forget;
 
        *inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
@@ -475,7 +482,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
                goto out_free_ff;
 
        err = -EIO;
-       if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
+       if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
+           fuse_invalid_attr(&outentry.attr))
                goto out_free_ff;
 
        ff->fh = outopen.fh;
@@ -583,7 +591,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
                goto out_put_forget_req;
 
        err = -EIO;
-       if (invalid_nodeid(outarg.nodeid))
+       if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
                goto out_put_forget_req;
 
        if ((outarg.attr.mode ^ mode) & S_IFMT)
@@ -862,7 +870,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
 
                spin_lock(&fi->lock);
                fi->attr_version = atomic64_inc_return(&fc->attr_version);
-               inc_nlink(inode);
+               if (likely(inode->i_nlink < UINT_MAX))
+                       inc_nlink(inode);
                spin_unlock(&fi->lock);
                fuse_invalidate_attr(inode);
                fuse_update_ctime(inode);
@@ -942,7 +951,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
        args.out_args[0].value = &outarg;
        err = fuse_simple_request(fc, &args);
        if (!err) {
-               if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+               if (fuse_invalid_attr(&outarg.attr) ||
+                   (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
                        make_bad_inode(inode);
                        err = -EIO;
                } else {
@@ -1563,7 +1573,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
                goto error;
        }
 
-       if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+       if (fuse_invalid_attr(&outarg.attr) ||
+           (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
                make_bad_inode(inode);
                err = -EIO;
                goto error;
index db48a5c..a63d779 100644 (file)
@@ -713,8 +713,10 @@ static ssize_t fuse_async_req_send(struct fuse_conn *fc,
 
        ia->ap.args.end = fuse_aio_complete_req;
        err = fuse_simple_background(fc, &ia->ap.args, GFP_KERNEL);
+       if (err)
+               fuse_aio_complete_req(fc, &ia->ap.args, err);
 
-       return err ?: num_bytes;
+       return num_bytes;
 }
 
 static ssize_t fuse_send_read(struct fuse_io_args *ia, loff_t pos, size_t count,
@@ -1096,6 +1098,8 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
        ia->write.in.flags = fuse_write_flags(iocb);
 
        err = fuse_simple_request(fc, &ap->args);
+       if (!err && ia->write.out.size > count)
+               err = -EIO;
 
        offset = ap->descs[0].offset;
        count = ia->write.out.size;
index d148188..aa75e23 100644 (file)
@@ -989,6 +989,8 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc);
  */
 int fuse_valid_type(int m);
 
+bool fuse_invalid_attr(struct fuse_attr *attr);
+
 /**
  * Is current process allowed to perform filesystem operation?
  */
index 5c38b9d..6a40f75 100644 (file)
@@ -184,7 +184,7 @@ static int fuse_direntplus_link(struct file *file,
 
        if (invalid_nodeid(o->nodeid))
                return -EIO;
-       if (!fuse_valid_type(o->attr.mode))
+       if (fuse_invalid_attr(&o->attr))
                return -EIO;
 
        fc = get_fuse_conn(dir);
index a5c8604..bade747 100644 (file)
@@ -35,6 +35,7 @@ struct virtio_fs_vq {
        struct fuse_dev *fud;
        bool connected;
        long in_flight;
+       struct completion in_flight_zero; /* No inflight requests */
        char name[24];
 } ____cacheline_aligned_in_smp;
 
@@ -48,11 +49,15 @@ struct virtio_fs {
        unsigned int num_request_queues; /* number of request queues */
 };
 
-struct virtio_fs_forget {
+struct virtio_fs_forget_req {
        struct fuse_in_header ih;
        struct fuse_forget_in arg;
+};
+
+struct virtio_fs_forget {
        /* This request can be temporarily queued on virt queue */
        struct list_head list;
+       struct virtio_fs_forget_req req;
 };
 
 static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
@@ -81,6 +86,8 @@ static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq)
 {
        WARN_ON(fsvq->in_flight <= 0);
        fsvq->in_flight--;
+       if (!fsvq->in_flight)
+               complete(&fsvq->in_flight_zero);
 }
 
 static void release_virtio_fs_obj(struct kref *ref)
@@ -111,22 +118,23 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq)
        WARN_ON(fsvq->in_flight < 0);
 
        /* Wait for in flight requests to finish.*/
-       while (1) {
-               spin_lock(&fsvq->lock);
-               if (!fsvq->in_flight) {
-                       spin_unlock(&fsvq->lock);
-                       break;
-               }
+       spin_lock(&fsvq->lock);
+       if (fsvq->in_flight) {
+               /* We are holding virtio_fs_mutex. There should not be any
+                * waiters waiting for completion.
+                */
+               reinit_completion(&fsvq->in_flight_zero);
+               spin_unlock(&fsvq->lock);
+               wait_for_completion(&fsvq->in_flight_zero);
+       } else {
                spin_unlock(&fsvq->lock);
-               /* TODO use completion instead of timeout */
-               usleep_range(1000, 2000);
        }
 
        flush_work(&fsvq->done_work);
        flush_delayed_work(&fsvq->dispatch_work);
 }
 
-static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
+static void virtio_fs_drain_all_queues_locked(struct virtio_fs *fs)
 {
        struct virtio_fs_vq *fsvq;
        int i;
@@ -137,6 +145,19 @@ static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
        }
 }
 
+static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
+{
+       /* Provides mutual exclusion between ->remove and ->kill_sb
+        * paths. We don't want both of these draining queue at the
+        * same time. Current completion logic reinits completion
+        * and that means there should not be any other thread
+        * doing reinit or waiting for completion already.
+        */
+       mutex_lock(&virtio_fs_mutex);
+       virtio_fs_drain_all_queues_locked(fs);
+       mutex_unlock(&virtio_fs_mutex);
+}
+
 static void virtio_fs_start_all_queues(struct virtio_fs *fs)
 {
        struct virtio_fs_vq *fsvq;
@@ -313,17 +334,72 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work)
        }
 }
 
+/*
+ * Returns 1 if queue is full and sender should wait a bit before sending
+ * next request, 0 otherwise.
+ */
+static int send_forget_request(struct virtio_fs_vq *fsvq,
+                              struct virtio_fs_forget *forget,
+                              bool in_flight)
+{
+       struct scatterlist sg;
+       struct virtqueue *vq;
+       int ret = 0;
+       bool notify;
+       struct virtio_fs_forget_req *req = &forget->req;
+
+       spin_lock(&fsvq->lock);
+       if (!fsvq->connected) {
+               if (in_flight)
+                       dec_in_flight_req(fsvq);
+               kfree(forget);
+               goto out;
+       }
+
+       sg_init_one(&sg, req, sizeof(*req));
+       vq = fsvq->vq;
+       dev_dbg(&vq->vdev->dev, "%s\n", __func__);
+
+       ret = virtqueue_add_outbuf(vq, &sg, 1, forget, GFP_ATOMIC);
+       if (ret < 0) {
+               if (ret == -ENOMEM || ret == -ENOSPC) {
+                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n",
+                                ret);
+                       list_add_tail(&forget->list, &fsvq->queued_reqs);
+                       schedule_delayed_work(&fsvq->dispatch_work,
+                                             msecs_to_jiffies(1));
+                       if (!in_flight)
+                               inc_in_flight_req(fsvq);
+                       /* Queue is full */
+                       ret = 1;
+               } else {
+                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
+                                ret);
+                       kfree(forget);
+                       if (in_flight)
+                               dec_in_flight_req(fsvq);
+               }
+               goto out;
+       }
+
+       if (!in_flight)
+               inc_in_flight_req(fsvq);
+       notify = virtqueue_kick_prepare(vq);
+       spin_unlock(&fsvq->lock);
+
+       if (notify)
+               virtqueue_notify(vq);
+       return ret;
+out:
+       spin_unlock(&fsvq->lock);
+       return ret;
+}
+
 static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
 {
        struct virtio_fs_forget *forget;
        struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq,
                                                 dispatch_work.work);
-       struct virtqueue *vq = fsvq->vq;
-       struct scatterlist sg;
-       struct scatterlist *sgs[] = {&sg};
-       bool notify;
-       int ret;
-
        pr_debug("virtio-fs: worker %s called.\n", __func__);
        while (1) {
                spin_lock(&fsvq->lock);
@@ -335,43 +411,9 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
                }
 
                list_del(&forget->list);
-               if (!fsvq->connected) {
-                       dec_in_flight_req(fsvq);
-                       spin_unlock(&fsvq->lock);
-                       kfree(forget);
-                       continue;
-               }
-
-               sg_init_one(&sg, forget, sizeof(*forget));
-
-               /* Enqueue the request */
-               dev_dbg(&vq->vdev->dev, "%s\n", __func__);
-               ret = virtqueue_add_sgs(vq, sgs, 1, 0, forget, GFP_ATOMIC);
-               if (ret < 0) {
-                       if (ret == -ENOMEM || ret == -ENOSPC) {
-                               pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n",
-                                        ret);
-                               list_add_tail(&forget->list,
-                                               &fsvq->queued_reqs);
-                               schedule_delayed_work(&fsvq->dispatch_work,
-                                               msecs_to_jiffies(1));
-                       } else {
-                               pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
-                                        ret);
-                               dec_in_flight_req(fsvq);
-                               kfree(forget);
-                       }
-                       spin_unlock(&fsvq->lock);
-                       return;
-               }
-
-               notify = virtqueue_kick_prepare(vq);
                spin_unlock(&fsvq->lock);
-
-               if (notify)
-                       virtqueue_notify(vq);
-               pr_debug("virtio-fs: worker %s dispatched one forget request.\n",
-                        __func__);
+               if (send_forget_request(fsvq, forget, true))
+                       return;
        }
 }
 
@@ -556,6 +598,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
        INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].end_reqs);
        INIT_DELAYED_WORK(&fs->vqs[VQ_HIPRIO].dispatch_work,
                        virtio_fs_hiprio_dispatch_work);
+       init_completion(&fs->vqs[VQ_HIPRIO].in_flight_zero);
        spin_lock_init(&fs->vqs[VQ_HIPRIO].lock);
 
        /* Initialize the requests virtqueues */
@@ -566,6 +609,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
                                  virtio_fs_request_dispatch_work);
                INIT_LIST_HEAD(&fs->vqs[i].queued_reqs);
                INIT_LIST_HEAD(&fs->vqs[i].end_reqs);
+               init_completion(&fs->vqs[i].in_flight_zero);
                snprintf(fs->vqs[i].name, sizeof(fs->vqs[i].name),
                         "requests.%u", i - VQ_REQUEST);
                callbacks[i] = virtio_fs_vq_done;
@@ -659,7 +703,7 @@ static void virtio_fs_remove(struct virtio_device *vdev)
        /* This device is going away. No one should get new reference */
        list_del_init(&fs->list);
        virtio_fs_stop_all_queues(fs);
-       virtio_fs_drain_all_queues(fs);
+       virtio_fs_drain_all_queues_locked(fs);
        vdev->config->reset(vdev);
        virtio_fs_cleanup_vqs(vdev, fs);
 
@@ -684,12 +728,12 @@ static int virtio_fs_restore(struct virtio_device *vdev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-const static struct virtio_device_id id_table[] = {
+static const struct virtio_device_id id_table[] = {
        { VIRTIO_ID_FS, VIRTIO_DEV_ANY_ID },
        {},
 };
 
-const static unsigned int feature_table[] = {};
+static const unsigned int feature_table[] = {};
 
 static struct virtio_driver virtio_fs_driver = {
        .driver.name            = KBUILD_MODNAME,
@@ -710,14 +754,10 @@ __releases(fiq->lock)
 {
        struct fuse_forget_link *link;
        struct virtio_fs_forget *forget;
-       struct scatterlist sg;
-       struct scatterlist *sgs[] = {&sg};
+       struct virtio_fs_forget_req *req;
        struct virtio_fs *fs;
-       struct virtqueue *vq;
        struct virtio_fs_vq *fsvq;
-       bool notify;
        u64 unique;
-       int ret;
 
        link = fuse_dequeue_forget(fiq, 1, NULL);
        unique = fuse_get_unique(fiq);
@@ -728,57 +768,19 @@ __releases(fiq->lock)
 
        /* Allocate a buffer for the request */
        forget = kmalloc(sizeof(*forget), GFP_NOFS | __GFP_NOFAIL);
+       req = &forget->req;
 
-       forget->ih = (struct fuse_in_header){
+       req->ih = (struct fuse_in_header){
                .opcode = FUSE_FORGET,
                .nodeid = link->forget_one.nodeid,
                .unique = unique,
-               .len = sizeof(*forget),
+               .len = sizeof(*req),
        };
-       forget->arg = (struct fuse_forget_in){
+       req->arg = (struct fuse_forget_in){
                .nlookup = link->forget_one.nlookup,
        };
 
-       sg_init_one(&sg, forget, sizeof(*forget));
-
-       /* Enqueue the request */
-       spin_lock(&fsvq->lock);
-
-       if (!fsvq->connected) {
-               kfree(forget);
-               spin_unlock(&fsvq->lock);
-               goto out;
-       }
-
-       vq = fsvq->vq;
-       dev_dbg(&vq->vdev->dev, "%s\n", __func__);
-
-       ret = virtqueue_add_sgs(vq, sgs, 1, 0, forget, GFP_ATOMIC);
-       if (ret < 0) {
-               if (ret == -ENOMEM || ret == -ENOSPC) {
-                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later.\n",
-                                ret);
-                       list_add_tail(&forget->list, &fsvq->queued_reqs);
-                       schedule_delayed_work(&fsvq->dispatch_work,
-                                       msecs_to_jiffies(1));
-                       inc_in_flight_req(fsvq);
-               } else {
-                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
-                                ret);
-                       kfree(forget);
-               }
-               spin_unlock(&fsvq->lock);
-               goto out;
-       }
-
-       inc_in_flight_req(fsvq);
-       notify = virtqueue_kick_prepare(vq);
-
-       spin_unlock(&fsvq->lock);
-
-       if (notify)
-               virtqueue_notify(vq);
-out:
+       send_forget_request(fsvq, forget, false);
        kfree(link);
 }
 
@@ -1026,7 +1028,7 @@ __releases(fiq->lock)
        }
 }
 
-const static struct fuse_iqueue_ops virtio_fs_fiq_ops = {
+static const struct fuse_iqueue_ops virtio_fs_fiq_ops = {
        .wake_forget_and_unlock         = virtio_fs_wake_forget_and_unlock,
        .wake_interrupt_and_unlock      = virtio_fs_wake_interrupt_and_unlock,
        .wake_pending_and_unlock        = virtio_fs_wake_pending_and_unlock,
index b9fe975..9c6df72 100644 (file)
@@ -133,7 +133,7 @@ static int gfs2_write_full_page(struct page *page, get_block_t *get_block,
         * the  page size, the remaining memory is zeroed when mapped, and
         * writes to that region are not written out to the file."
         */
-       offset = i_size & (PAGE_SIZE-1);
+       offset = i_size & (PAGE_SIZE - 1);
        if (page->index == end_index && offset)
                zero_user_segment(page, offset, PAGE_SIZE);
 
@@ -497,7 +497,7 @@ static int __gfs2_readpage(void *file, struct page *page)
                error = mpage_readpage(page, gfs2_block_map);
        }
 
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
+       if (unlikely(gfs2_withdrawn(sdp)))
                return -EIO;
 
        return error;
@@ -614,7 +614,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
        gfs2_glock_dq(&gh);
 out_uninit:
        gfs2_holder_uninit(&gh);
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
+       if (unlikely(gfs2_withdrawn(sdp)))
                ret = -EIO;
        return ret;
 }
index 5161032..08f6fbb 100644 (file)
@@ -2441,8 +2441,16 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
        struct inode *inode = file_inode(file);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
+       unsigned int blocksize = i_blocksize(inode);
+       loff_t start, end;
        int error;
 
+       start = round_down(offset, blocksize);
+       end = round_up(offset + length, blocksize) - 1;
+       error = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (error)
+               return error;
+
        if (gfs2_is_jdata(ip))
                error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
                                         GFS2_JTRUNC_REVOKES);
@@ -2456,9 +2464,8 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
                if (error)
                        goto out;
        } else {
-               unsigned int start_off, end_len, blocksize;
+               unsigned int start_off, end_len;
 
-               blocksize = i_blocksize(inode);
                start_off = offset & (blocksize - 1);
                end_len = (offset + length) & (blocksize - 1);
                if (start_off) {
index d07a295..9d58295 100644 (file)
@@ -407,27 +407,28 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
 /**
  * gfs2_allocate_page_backing - Allocate blocks for a write fault
  * @page: The (locked) page to allocate backing for
+ * @length: Size of the allocation
  *
  * We try to allocate all the blocks required for the page in one go.  This
  * might fail for various reasons, so we keep trying until all the blocks to
  * back this page are allocated.  If some of the blocks are already allocated,
  * that is ok too.
  */
-static int gfs2_allocate_page_backing(struct page *page)
+static int gfs2_allocate_page_backing(struct page *page, unsigned int length)
 {
        u64 pos = page_offset(page);
-       u64 size = PAGE_SIZE;
 
        do {
                struct iomap iomap = { };
 
-               if (gfs2_iomap_get_alloc(page->mapping->host, pos, 1, &iomap))
+               if (gfs2_iomap_get_alloc(page->mapping->host, pos, length, &iomap))
                        return -EIO;
 
-               iomap.length = min(iomap.length, size);
-               size -= iomap.length;
+               if (length < iomap.length)
+                       iomap.length = length;
+               length -= iomap.length;
                pos += iomap.length;
-       } while (size > 0);
+       } while (length > 0);
 
        return 0;
 }
@@ -448,10 +449,10 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct gfs2_alloc_parms ap = { .aflags = 0, };
-       unsigned long last_index;
-       u64 pos = page_offset(page);
+       u64 offset = page_offset(page);
        unsigned int data_blocks, ind_blocks, rblocks;
        struct gfs2_holder gh;
+       unsigned int length;
        loff_t size;
        int ret;
 
@@ -461,20 +462,39 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
        if (ret)
                goto out;
 
-       gfs2_size_hint(vmf->vma->vm_file, pos, PAGE_SIZE);
-
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        ret = gfs2_glock_nq(&gh);
        if (ret)
                goto out_uninit;
 
+       /* Check page index against inode size */
+       size = i_size_read(inode);
+       if (offset >= size) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
        /* Update file times before taking page lock */
        file_update_time(vmf->vma->vm_file);
 
+       /* page is wholly or partially inside EOF */
+       if (offset > size - PAGE_SIZE)
+               length = offset_in_page(size);
+       else
+               length = PAGE_SIZE;
+
+       gfs2_size_hint(vmf->vma->vm_file, offset, length);
+
        set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
        set_bit(GIF_SW_PAGED, &ip->i_flags);
 
-       if (!gfs2_write_alloc_required(ip, pos, PAGE_SIZE)) {
+       /*
+        * iomap_writepage / iomap_writepages currently don't support inline
+        * files, so always unstuff here.
+        */
+
+       if (!gfs2_is_stuffed(ip) &&
+           !gfs2_write_alloc_required(ip, offset, length)) {
                lock_page(page);
                if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
                        ret = -EAGAIN;
@@ -487,7 +507,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
        if (ret)
                goto out_unlock;
 
-       gfs2_write_calc_reserv(ip, PAGE_SIZE, &data_blocks, &ind_blocks);
+       gfs2_write_calc_reserv(ip, length, &data_blocks, &ind_blocks);
        ap.target = data_blocks + ind_blocks;
        ret = gfs2_quota_lock_check(ip, &ap);
        if (ret)
@@ -508,13 +528,6 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
                goto out_trans_fail;
 
        lock_page(page);
-       ret = -EINVAL;
-       size = i_size_read(inode);
-       last_index = (size - 1) >> PAGE_SHIFT;
-       /* Check page index against inode size */
-       if (size == 0 || (page->index > last_index))
-               goto out_trans_end;
-
        ret = -EAGAIN;
        /* If truncated, we must retry the operation, we may have raced
         * with the glock demotion code.
@@ -527,7 +540,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
        if (gfs2_is_stuffed(ip))
                ret = gfs2_unstuff_dinode(ip, page);
        if (ret == 0)
-               ret = gfs2_allocate_page_backing(page);
+               ret = gfs2_allocate_page_backing(page, length);
 
 out_trans_end:
        if (ret)
@@ -961,6 +974,7 @@ out:
        brelse(dibh);
        return error;
 }
+
 /**
  * calc_max_reserv() - Reverse of write_calc_reserv. Given a number of
  *                     blocks, determine how many bytes can be written.
@@ -1208,7 +1222,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
                cmd = F_SETLK;
                fl->fl_type = F_UNLCK;
        }
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags))) {
+       if (unlikely(gfs2_withdrawn(sdp))) {
                if (fl->fl_type == F_UNLCK)
                        locks_lock_file_wait(file, fl);
                return -EIO;
index 0290a22..b7123de 100644 (file)
@@ -549,7 +549,7 @@ __acquires(&gl->gl_lockref.lock)
        unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0);
        int ret;
 
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) &&
+       if (unlikely(gfs2_withdrawn(sdp)) &&
            target != LM_ST_UNLOCKED)
                return;
        lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP |
@@ -558,7 +558,14 @@ __acquires(&gl->gl_lockref.lock)
        GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
        if ((target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) &&
            glops->go_inval) {
-               set_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
+               /*
+                * If another process is already doing the invalidate, let that
+                * finish first.  The glock state machine will get back to this
+                * holder again later.
+                */
+               if (test_and_set_bit(GLF_INVALIDATE_IN_PROGRESS,
+                                    &gl->gl_flags))
+                       return;
                do_error(gl, 0); /* Fail queued try locks */
        }
        gl->gl_req = target;
@@ -586,8 +593,7 @@ __acquires(&gl->gl_lockref.lock)
                }
                else if (ret) {
                        fs_err(sdp, "lm_lock ret %d\n", ret);
-                       GLOCK_BUG_ON(gl, !test_bit(SDF_WITHDRAWN,
-                                                  &sdp->sd_flags));
+                       GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp));
                }
        } else { /* lock_nolock */
                finish_xmote(gl, target);
@@ -1191,7 +1197,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
        int error = 0;
 
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
+       if (unlikely(gfs2_withdrawn(sdp)))
                return -EIO;
 
        if (test_bit(GLF_LRU, &gl->gl_flags))
index ff21369..4ede1f1 100644 (file)
@@ -350,7 +350,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
                ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
                                           be32_to_cpu(str->di_minor));
                break;
-       };
+       }
 
        i_uid_write(&ip->i_inode, be32_to_cpu(str->di_uid));
        i_gid_write(&ip->i_inode, be32_to_cpu(str->di_gid));
@@ -540,7 +540,7 @@ static int freeze_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
                        gfs2_consist(sdp);
 
                /*  Initialize some head of the log stuff  */
-               if (!test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
+               if (!gfs2_withdrawn(sdp)) {
                        sdp->sd_log_sequence = head.lh_sequence + 1;
                        gfs2_log_pointers_init(sdp, head.lh_blkno);
                }
index e1e18fb..dafef10 100644 (file)
@@ -656,7 +656,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        inode->i_rdev = dev;
        inode->i_size = size;
        inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
-       gfs2_set_inode_blocks(inode, 1);
        munge_mode_uid_gid(dip, inode);
        check_and_update_goal(dip);
        ip->i_goal = dip->i_goal;
@@ -712,7 +711,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 
        error = gfs2_trans_begin(sdp, blocks, 0);
        if (error)
-               goto fail_gunlock2;
+               goto fail_free_inode;
 
        if (blocks > 1) {
                ip->i_eattr = ip->i_no_addr + 1;
@@ -723,7 +722,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 
        error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
        if (error)
-               goto fail_gunlock2;
+               goto fail_free_inode;
 
        BUG_ON(test_and_set_bit(GLF_INODE_CREATING, &io_gl->gl_flags));
 
@@ -732,7 +731,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                goto fail_gunlock2;
 
        glock_set_object(ip->i_iopen_gh.gh_gl, ip);
-       gfs2_glock_put(io_gl);
        gfs2_set_iop(inode);
        insert_inode_hash(inode);
 
@@ -765,6 +763,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 
        mark_inode_dirty(inode);
        d_instantiate(dentry, inode);
+       /* After instantiate, errors should result in evict which will destroy
+        * both inode and iopen glocks properly. */
        if (file) {
                file->f_mode |= FMODE_CREATED;
                error = finish_open(file, dentry, gfs2_open_common);
@@ -772,15 +772,15 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        gfs2_glock_dq_uninit(ghs);
        gfs2_glock_dq_uninit(ghs + 1);
        clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
+       gfs2_glock_put(io_gl);
        return error;
 
 fail_gunlock3:
        glock_clear_object(io_gl, ip);
        gfs2_glock_dq_uninit(&ip->i_iopen_gh);
-       gfs2_glock_put(io_gl);
 fail_gunlock2:
-       if (io_gl)
-               clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
+       clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
+       gfs2_glock_put(io_gl);
 fail_free_inode:
        if (ip->i_gl) {
                glock_clear_object(ip->i_gl, ip);
@@ -1475,7 +1475,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                        error = -EEXIST;
                default:
                        goto out_gunlock;
-               };
+               }
 
                if (odip != ndip) {
                        if (!ndip->i_inode.i_nlink) {
index 58e237f..eb3f2e7 100644 (file)
@@ -31,6 +31,8 @@
 #include "dir.h"
 #include "trace_gfs2.h"
 
+static void gfs2_log_shutdown(struct gfs2_sbd *sdp);
+
 /**
  * gfs2_struct2blk - compute stuff
  * @sdp: the filesystem
@@ -159,7 +161,8 @@ restart:
        list_for_each_entry_reverse(tr, head, tr_list) {
                if (wbc->nr_to_write <= 0)
                        break;
-               if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw))
+               if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw) &&
+                   !gfs2_withdrawn(sdp))
                        goto restart;
        }
        spin_unlock(&sdp->sd_ail_lock);
@@ -609,6 +612,14 @@ void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
        list_add(&bd->bd_list, &sdp->sd_log_revokes);
 }
 
+void gfs2_glock_remove_revoke(struct gfs2_glock *gl)
+{
+       if (atomic_dec_return(&gl->gl_revokes) == 0) {
+               clear_bit(GLF_LFLUSH, &gl->gl_flags);
+               gfs2_glock_queue_put(gl);
+       }
+}
+
 void gfs2_write_revokes(struct gfs2_sbd *sdp)
 {
        struct gfs2_trans *tr;
@@ -682,12 +693,16 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
 {
        struct gfs2_log_header *lh;
        u32 hash, crc;
-       struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
+       struct page *page;
        struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
        struct timespec64 tv;
        struct super_block *sb = sdp->sd_vfs;
        u64 dblock;
 
+       if (gfs2_withdrawn(sdp))
+               goto out;
+
+       page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
        lh = page_address(page);
        clear_page(lh);
 
@@ -707,7 +722,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
        lh->lh_nsec = cpu_to_be32(tv.tv_nsec);
        lh->lh_sec = cpu_to_be64(tv.tv_sec);
        if (!list_empty(&jd->extent_list))
-               dblock = gfs2_log_bmap(sdp);
+               dblock = gfs2_log_bmap(jd, lblock);
        else {
                int ret = gfs2_lblk_to_dblk(jd->jd_inode, lblock, &dblock);
                if (gfs2_assert_withdraw(sdp, ret == 0))
@@ -740,6 +755,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
 
        gfs2_log_write(sdp, page, sb->s_blocksize, 0, dblock);
        gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE | op_flags);
+out:
        log_flush_wait(sdp);
 }
 
@@ -768,6 +784,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
        sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
        gfs2_write_log_header(sdp, sdp->sd_jdesc, sdp->sd_log_sequence++, tail,
                              sdp->sd_log_flush_head, flags, op_flags);
+       gfs2_log_incr_head(sdp);
 
        if (sdp->sd_log_tail != tail)
                log_pull_tail(sdp, tail);
@@ -948,7 +965,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
  *
  */
 
-void gfs2_log_shutdown(struct gfs2_sbd *sdp)
+static void gfs2_log_shutdown(struct gfs2_sbd *sdp)
 {
        gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
index 2315fca..2ff163a 100644 (file)
@@ -74,9 +74,9 @@ extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
 extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
 extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc);
 
-extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
 extern int gfs2_logd(void *data);
 extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
+extern void gfs2_glock_remove_revoke(struct gfs2_glock *gl);
 extern void gfs2_write_revokes(struct gfs2_sbd *sdp);
 
 #endif /* __LOG_DOT_H__ */
index 5b17979..55fed7d 100644 (file)
@@ -129,7 +129,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
        atomic_dec(&sdp->sd_log_pinned);
 }
 
-static void gfs2_log_incr_head(struct gfs2_sbd *sdp)
+void gfs2_log_incr_head(struct gfs2_sbd *sdp)
 {
        BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) &&
               (sdp->sd_log_flush_head != sdp->sd_log_head));
@@ -138,18 +138,13 @@ static void gfs2_log_incr_head(struct gfs2_sbd *sdp)
                sdp->sd_log_flush_head = 0;
 }
 
-u64 gfs2_log_bmap(struct gfs2_sbd *sdp)
+u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lblock)
 {
-       unsigned int lbn = sdp->sd_log_flush_head;
        struct gfs2_journal_extent *je;
-       u64 block;
 
-       list_for_each_entry(je, &sdp->sd_jdesc->extent_list, list) {
-               if ((lbn >= je->lblock) && (lbn < (je->lblock + je->blocks))) {
-                       block = je->dblock + lbn - je->lblock;
-                       gfs2_log_incr_head(sdp);
-                       return block;
-               }
+       list_for_each_entry(je, &jd->extent_list, list) {
+               if (lblock >= je->lblock && lblock < je->lblock + je->blocks)
+                       return je->dblock + lblock - je->lblock;
        }
 
        return -1;
@@ -351,8 +346,11 @@ void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
 
 static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh)
 {
-       gfs2_log_write(sdp, bh->b_page, bh->b_size, bh_offset(bh),
-                      gfs2_log_bmap(sdp));
+       u64 dblock;
+
+       dblock = gfs2_log_bmap(sdp->sd_jdesc, sdp->sd_log_flush_head);
+       gfs2_log_incr_head(sdp);
+       gfs2_log_write(sdp, bh->b_page, bh->b_size, bh_offset(bh), dblock);
 }
 
 /**
@@ -369,8 +367,11 @@ static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh)
 void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
 {
        struct super_block *sb = sdp->sd_vfs;
-       gfs2_log_write(sdp, page, sb->s_blocksize, 0,
-                      gfs2_log_bmap(sdp));
+       u64 dblock;
+
+       dblock = gfs2_log_bmap(sdp->sd_jdesc, sdp->sd_log_flush_head);
+       gfs2_log_incr_head(sdp);
+       gfs2_log_write(sdp, page, sb->s_blocksize, 0, dblock);
 }
 
 /**
@@ -882,10 +883,7 @@ static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
                bd = list_entry(head->next, struct gfs2_bufdata, bd_list);
                list_del_init(&bd->bd_list);
                gl = bd->bd_gl;
-               if (atomic_dec_return(&gl->gl_revokes) == 0) {
-                       clear_bit(GLF_LFLUSH, &gl->gl_flags);
-                       gfs2_glock_queue_put(gl);
-               }
+               gfs2_glock_remove_revoke(gl);
                kmem_cache_free(gfs2_bufdata_cachep, bd);
        }
 }
index 9c05995..9c5e4e4 100644 (file)
@@ -18,7 +18,8 @@
         ~(2 * sizeof(__be64) - 1))
 
 extern const struct gfs2_log_operations *gfs2_log_ops[];
-extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp);
+extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
+extern u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn);
 extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
                           unsigned size, unsigned offset, u64 blkno);
 extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page);
index 662ef36..0c37729 100644 (file)
@@ -251,7 +251,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
        struct buffer_head *bh, *bhs[2];
        int num = 0;
 
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags))) {
+       if (unlikely(gfs2_withdrawn(sdp))) {
                *bhp = NULL;
                return -EIO;
        }
@@ -309,7 +309,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
 
 int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
 {
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
+       if (unlikely(gfs2_withdrawn(sdp)))
                return -EIO;
 
        wait_on_buffer(bh);
@@ -320,7 +320,7 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
                        gfs2_io_error_bh_wd(sdp, bh);
                return -EIO;
        }
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
+       if (unlikely(gfs2_withdrawn(sdp)))
                return -EIO;
 
        return 0;
index 18daf49..e8b7b0c 100644 (file)
@@ -1006,8 +1006,7 @@ hostdata_error:
 void gfs2_lm_unmount(struct gfs2_sbd *sdp)
 {
        const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops;
-       if (likely(!test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) &&
-           lm->lm_unmount)
+       if (likely(!gfs2_withdrawn(sdp)) && lm->lm_unmount)
                lm->lm_unmount(sdp);
 }
 
@@ -1328,7 +1327,7 @@ static const struct fs_parameter_enum gfs2_param_enums[] = {
        {}
 };
 
-const struct fs_parameter_description gfs2_fs_parameters = {
+static const struct fs_parameter_description gfs2_fs_parameters = {
        .name = "gfs2",
        .specs = gfs2_param_specs,
        .enums = gfs2_param_enums,
index 7c016a0..e9f9304 100644 (file)
@@ -1273,7 +1273,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_quota_data **qda;
-       unsigned int max_qd = PAGE_SIZE/sizeof(struct gfs2_holder);
+       unsigned int max_qd = PAGE_SIZE / sizeof(struct gfs2_holder);
        unsigned int num_qd;
        unsigned int x;
        int error = 0;
@@ -1475,7 +1475,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error)
 {
        if (error == 0 || error == -EROFS)
                return;
-       if (!test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
+       if (!gfs2_withdrawn(sdp)) {
                fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error);
                sdp->sd_log_error = error;
                wake_up(&sdp->sd_logd_waitq);
index c529f87..85f830e 100644 (file)
@@ -263,11 +263,13 @@ static void clean_journal(struct gfs2_jdesc *jd,
        u32 lblock = head->lh_blkno;
 
        gfs2_replay_incr_blk(jd, &lblock);
-       if (jd->jd_jid == sdp->sd_lockstruct.ls_jid)
-               sdp->sd_log_flush_head = lblock;
        gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, lblock,
                              GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY,
                              REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC);
+       if (jd->jd_jid == sdp->sd_lockstruct.ls_jid) {
+               sdp->sd_log_flush_head = lblock;
+               gfs2_log_incr_head(sdp);
+       }
 }
 
 
@@ -326,7 +328,7 @@ void gfs2_recover_func(struct work_struct *work)
 
                default:
                        goto fail;
-               };
+               }
 
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
                                           LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh);
index 5fa1eec..68cc7c2 100644 (file)
@@ -399,8 +399,7 @@ struct lfcc {
  * Returns: errno
  */
 
-static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
-                                   struct gfs2_holder *freeze_gh)
+static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp)
 {
        struct gfs2_inode *ip;
        struct gfs2_jdesc *jd;
@@ -425,7 +424,9 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
        }
 
        error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
-                                  GL_NOCACHE, freeze_gh);
+                                  GL_NOCACHE, &sdp->sd_freeze_gh);
+       if (error)
+               goto out;
 
        list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
                error = gfs2_jdesc_check(jd);
@@ -441,7 +442,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
        }
 
        if (error)
-               gfs2_glock_dq_uninit(freeze_gh);
+               gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
 
 out:
        while (!list_empty(&list)) {
@@ -553,7 +554,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
 
        if (!(flags & I_DIRTY_INODE))
                return;
-       if (unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags)))
+       if (unlikely(gfs2_withdrawn(sdp)))
                return;
        if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
                ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
@@ -602,7 +603,7 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 
        error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
                                   &freeze_gh);
-       if (error && !test_bit(SDF_WITHDRAWN, &sdp->sd_flags))
+       if (error && !gfs2_withdrawn(sdp))
                return error;
 
        flush_workqueue(gfs2_delete_workqueue);
@@ -761,21 +762,25 @@ static int gfs2_freeze(struct super_block *sb)
        if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
                goto out;
 
-       if (test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
-               error = -EINVAL;
-               goto out;
-       }
-
        for (;;) {
-               error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
+               if (gfs2_withdrawn(sdp)) {
+                       error = -EINVAL;
+                       goto out;
+               }
+
+               error = gfs2_lock_fs_check_clean(sdp);
                if (!error)
                        break;
 
                if (error == -EBUSY)
                        fs_err(sdp, "waiting for recovery before freeze\n");
-               else
+               else if (error == -EIO) {
+                       fs_err(sdp, "Fatal IO error: cannot freeze gfs2 due "
+                              "to recovery error.\n");
+                       goto out;
+               } else {
                        fs_err(sdp, "error freezing FS: %d\n", error);
-
+               }
                fs_err(sdp, "retrying...\n");
                msleep(1000);
        }
index dd15b8e..8ccb68f 100644 (file)
@@ -118,7 +118,7 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 
 static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
 {
-       unsigned int b = test_bit(SDF_WITHDRAWN, &sdp->sd_flags);
+       unsigned int b = gfs2_withdrawn(sdp);
        return snprintf(buf, PAGE_SIZE, "%u\n", b);
 }
 
index 35e3059..9d42273 100644 (file)
@@ -262,6 +262,8 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
                        list_del_init(&bd->bd_list);
                        gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
                        sdp->sd_log_num_revoke--;
+                       if (bd->bd_gl)
+                               gfs2_glock_remove_revoke(bd->bd_gl);
                        kmem_cache_free(gfs2_bufdata_cachep, bd);
                        tr->tr_num_revoke--;
                        if (--n == 0)
index c451591..ec600b4 100644 (file)
@@ -258,7 +258,7 @@ void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
                        const char *function, char *file, unsigned int line,
                        bool withdraw)
 {
-       if (!test_bit(SDF_WITHDRAWN, &sdp->sd_flags))
+       if (!gfs2_withdrawn(sdp))
                fs_err(sdp,
                       "fatal: I/O error\n"
                       "  block = %llu\n"
index 4b68b2c..f2702bc 100644 (file)
@@ -164,6 +164,15 @@ static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
        return x;
 }
 
+/**
+ * gfs2_withdrawn - test whether the file system is withdrawing or withdrawn
+ * @sdp: the superblock
+ */
+static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
+{
+       return test_bit(SDF_WITHDRAWN, &sdp->sd_flags);
+}
+
 #define gfs2_tune_get(sdp, field) \
 gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
 
index a478df0..d5c2a31 100644 (file)
@@ -440,7 +440,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
                        u32 hash;
 
                        index = page->index;
-                       hash = hugetlb_fault_mutex_hash(h, mapping, index, 0);
+                       hash = hugetlb_fault_mutex_hash(mapping, index);
                        mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                        /*
@@ -644,7 +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, mapping, index, addr);
+               hash = hugetlb_fault_mutex_hash(mapping, index);
                mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                /* See if already present in mapping to avoid alloc/free */
@@ -815,8 +815,11 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
 /*
  * File creation. Allocate an inode, and we're done..
  */
-static int hugetlbfs_mknod(struct inode *dir,
-                       struct dentry *dentry, umode_t mode, dev_t dev)
+static int do_hugetlbfs_mknod(struct inode *dir,
+                       struct dentry *dentry,
+                       umode_t mode,
+                       dev_t dev,
+                       bool tmpfile)
 {
        struct inode *inode;
        int error = -ENOSPC;
@@ -824,13 +827,23 @@ static int hugetlbfs_mknod(struct inode *dir,
        inode = hugetlbfs_get_inode(dir->i_sb, dir, mode, dev);
        if (inode) {
                dir->i_ctime = dir->i_mtime = current_time(dir);
-               d_instantiate(dentry, inode);
-               dget(dentry);   /* Extra count - pin the dentry in core */
+               if (tmpfile) {
+                       d_tmpfile(dentry, inode);
+               } else {
+                       d_instantiate(dentry, inode);
+                       dget(dentry);/* Extra count - pin the dentry in core */
+               }
                error = 0;
        }
        return error;
 }
 
+static int hugetlbfs_mknod(struct inode *dir,
+                       struct dentry *dentry, umode_t mode, dev_t dev)
+{
+       return do_hugetlbfs_mknod(dir, dentry, mode, dev, false);
+}
+
 static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0);
@@ -844,6 +857,12 @@ static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, umode_t mo
        return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
 
+static int hugetlbfs_tmpfile(struct inode *dir,
+                       struct dentry *dentry, umode_t mode)
+{
+       return do_hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0, true);
+}
+
 static int hugetlbfs_symlink(struct inode *dir,
                        struct dentry *dentry, const char *symname)
 {
@@ -1102,6 +1121,7 @@ static const struct inode_operations hugetlbfs_dir_inode_operations = {
        .mknod          = hugetlbfs_mknod,
        .rename         = simple_rename,
        .setattr        = hugetlbfs_setattr,
+       .tmpfile        = hugetlbfs_tmpfile,
 };
 
 static const struct inode_operations hugetlbfs_inode_operations = {
@@ -1461,28 +1481,41 @@ static int __init init_hugetlbfs_fs(void)
                                        sizeof(struct hugetlbfs_inode_info),
                                        0, SLAB_ACCOUNT, init_once);
        if (hugetlbfs_inode_cachep == NULL)
-               goto out2;
+               goto out;
 
        error = register_filesystem(&hugetlbfs_fs_type);
        if (error)
-               goto out;
+               goto out_free;
 
+       /* default hstate mount is required */
+       mnt = mount_one_hugetlbfs(&hstates[default_hstate_idx]);
+       if (IS_ERR(mnt)) {
+               error = PTR_ERR(mnt);
+               goto out_unreg;
+       }
+       hugetlbfs_vfsmount[default_hstate_idx] = mnt;
+
+       /* other hstates are optional */
        i = 0;
        for_each_hstate(h) {
+               if (i == default_hstate_idx)
+                       continue;
+
                mnt = mount_one_hugetlbfs(h);
-               if (IS_ERR(mnt) && i == 0) {
-                       error = PTR_ERR(mnt);
-                       goto out;
-               }
-               hugetlbfs_vfsmount[i] = mnt;
+               if (IS_ERR(mnt))
+                       hugetlbfs_vfsmount[i] = NULL;
+               else
+                       hugetlbfs_vfsmount[i] = mnt;
                i++;
        }
 
        return 0;
 
- out:
+ out_unreg:
+       (void)unregister_filesystem(&hugetlbfs_fs_type);
+ out_free:
        kmem_cache_destroy(hugetlbfs_inode_cachep);
- out2:
+ out:
        return error;
 }
 fs_initcall(init_hugetlbfs_fs)
index 812061b..2f5e4e5 100644 (file)
@@ -467,7 +467,7 @@ EXPORT_SYMBOL(generic_block_fiemap);
  * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
  * are used here, rest are ignored.
  */
-int ioctl_preallocate(struct file *filp, void __user *argp)
+int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
 {
        struct inode *inode = file_inode(filp);
        struct space_resv sr;
@@ -488,13 +488,14 @@ int ioctl_preallocate(struct file *filp, void __user *argp)
                return -EINVAL;
        }
 
-       return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+       return vfs_fallocate(filp, mode | FALLOC_FL_KEEP_SIZE, sr.l_start,
+                       sr.l_len);
 }
 
 /* on ia32 l_start is on a 32-bit boundary */
 #if defined CONFIG_COMPAT && defined(CONFIG_X86_64)
 /* just account for different alignment */
-int compat_ioctl_preallocate(struct file *file,
+int compat_ioctl_preallocate(struct file *file, int mode,
                                struct space_resv_32 __user *argp)
 {
        struct inode *inode = file_inode(file);
@@ -516,7 +517,7 @@ int compat_ioctl_preallocate(struct file *file,
                return -EINVAL;
        }
 
-       return vfs_fallocate(file, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+       return vfs_fallocate(file, mode | FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
 }
 #endif
 
@@ -533,7 +534,12 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
                return put_user(i_size_read(inode) - filp->f_pos, p);
        case FS_IOC_RESVSP:
        case FS_IOC_RESVSP64:
-               return ioctl_preallocate(filp, p);
+               return ioctl_preallocate(filp, 0, p);
+       case FS_IOC_UNRESVSP:
+       case FS_IOC_UNRESVSP64:
+               return ioctl_preallocate(filp, FALLOC_FL_PUNCH_HOLE, p);
+       case FS_IOC_ZERO_RANGE:
+               return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
        }
 
        return vfs_ioctl(filp, cmd, arg);
index 420c0c8..2383792 100644 (file)
@@ -201,12 +201,12 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
        unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
        unsigned int fs_block_size = i_blocksize(inode), pad;
        unsigned int align = iov_iter_alignment(dio->submit.iter);
-       struct iov_iter iter;
        struct bio *bio;
        bool need_zeroout = false;
        bool use_fua = false;
        int nr_pages, ret = 0;
        size_t copied = 0;
+       size_t orig_count;
 
        if ((pos | length | align) & ((1 << blkbits) - 1))
                return -EINVAL;
@@ -236,15 +236,18 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
        }
 
        /*
-        * Operate on a partial iter trimmed to the extent we were called for.
-        * We'll update the iter in the dio once we're done with this extent.
+        * Save the original count and trim the iter to just the extent we
+        * are operating on right now.  The iter will be re-expanded once
+        * we are done.
         */
-       iter = *dio->submit.iter;
-       iov_iter_truncate(&iter, length);
+       orig_count = iov_iter_count(dio->submit.iter);
+       iov_iter_truncate(dio->submit.iter, length);
 
-       nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES);
-       if (nr_pages <= 0)
-               return nr_pages;
+       nr_pages = iov_iter_npages(dio->submit.iter, BIO_MAX_PAGES);
+       if (nr_pages <= 0) {
+               ret = nr_pages;
+               goto out;
+       }
 
        if (need_zeroout) {
                /* zero out from the start of the block to the write offset */
@@ -257,7 +260,8 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                size_t n;
                if (dio->error) {
                        iov_iter_revert(dio->submit.iter, copied);
-                       return 0;
+                       copied = ret = 0;
+                       goto out;
                }
 
                bio = bio_alloc(GFP_KERNEL, nr_pages);
@@ -268,7 +272,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                bio->bi_private = dio;
                bio->bi_end_io = iomap_dio_bio_end_io;
 
-               ret = bio_iov_iter_get_pages(bio, &iter);
+               ret = bio_iov_iter_get_pages(bio, dio->submit.iter);
                if (unlikely(ret)) {
                        /*
                         * We have to stop part way through an IO. We must fall
@@ -294,13 +298,11 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                                bio_set_pages_dirty(bio);
                }
 
-               iov_iter_advance(dio->submit.iter, n);
-
                dio->size += n;
                pos += n;
                copied += n;
 
-               nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES);
+               nr_pages = iov_iter_npages(dio->submit.iter, BIO_MAX_PAGES);
                iomap_dio_submit_bio(dio, iomap, bio);
        } while (nr_pages);
 
@@ -318,6 +320,9 @@ zero_tail:
                if (pad)
                        iomap_dio_zero(dio, iomap, pos, fs_block_size - pad);
        }
+out:
+       /* Undo iter limitation to current extent */
+       iov_iter_reexpand(dio->submit.iter, orig_count - copied);
        if (copied)
                return copied;
        return ret;
@@ -400,7 +405,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
        struct address_space *mapping = iocb->ki_filp->f_mapping;
        struct inode *inode = file_inode(iocb->ki_filp);
        size_t count = iov_iter_count(iter);
-       loff_t pos = iocb->ki_pos, start = pos;
+       loff_t pos = iocb->ki_pos;
        loff_t end = iocb->ki_pos + count - 1, ret = 0;
        unsigned int flags = IOMAP_DIRECT;
        struct blk_plug plug;
@@ -456,14 +461,14 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
        }
 
        if (iocb->ki_flags & IOCB_NOWAIT) {
-               if (filemap_range_has_page(mapping, start, end)) {
+               if (filemap_range_has_page(mapping, pos, end)) {
                        ret = -EAGAIN;
                        goto out_free_dio;
                }
                flags |= IOMAP_NOWAIT;
        }
 
-       ret = filemap_write_and_wait_range(mapping, start, end);
+       ret = filemap_write_and_wait_range(mapping, pos, end);
        if (ret)
                goto out_free_dio;
 
@@ -474,7 +479,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
         * pretty crazy thing to do, so we don't support it 100%.
         */
        ret = invalidate_inode_pages2_range(mapping,
-                       start >> PAGE_SHIFT, end >> PAGE_SHIFT);
+                       pos >> PAGE_SHIFT, end >> PAGE_SHIFT);
        if (ret)
                dio_warn_stale_pagecache(iocb->ki_filp);
        ret = 0;
index 021a4a2..b86c78d 100644 (file)
@@ -226,7 +226,7 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *r
                lastend = this->ofs + this->size;
        } else {
                dbg_fragtree2("lookup gave no frag\n");
-               return -EINVAL;
+               lastend = 0;
        }
 
        /* See if we ran off the end of the fragtree */
index 4d31503..9dc7e7a 100644 (file)
@@ -223,7 +223,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
                        dput(dentry);
                        return ERR_PTR(-EINVAL);
                }
-               dtmp = lookup_one_len_unlocked(kntmp->name, dentry,
+               dtmp = lookup_positive_unlocked(kntmp->name, dentry,
                                               strlen(kntmp->name));
                dput(dentry);
                if (IS_ERR(dtmp))
index 2dda552..d6c91d1 100644 (file)
@@ -1210,25 +1210,25 @@ static int follow_automount(struct path *path, struct nameidata *nd,
  * - Flagged as automount point
  *
  * This may only be called in refwalk mode.
+ * On success path->dentry is known positive.
  *
  * Serialization is taken care of in namespace.c
  */
 static int follow_managed(struct path *path, struct nameidata *nd)
 {
        struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */
-       unsigned managed;
+       unsigned flags;
        bool need_mntput = false;
        int ret = 0;
 
        /* Given that we're not holding a lock here, we retain the value in a
         * local variable for each dentry as we look at it so that we don't see
         * the components of that value change under us */
-       while (managed = READ_ONCE(path->dentry->d_flags),
-              managed &= DCACHE_MANAGED_DENTRY,
-              unlikely(managed != 0)) {
+       while (flags = smp_load_acquire(&path->dentry->d_flags),
+              unlikely(flags & DCACHE_MANAGED_DENTRY)) {
                /* Allow the filesystem to manage the transit without i_mutex
                 * being held. */
-               if (managed & DCACHE_MANAGE_TRANSIT) {
+               if (flags & DCACHE_MANAGE_TRANSIT) {
                        BUG_ON(!path->dentry->d_op);
                        BUG_ON(!path->dentry->d_op->d_manage);
                        ret = path->dentry->d_op->d_manage(path, false);
@@ -1237,7 +1237,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
                }
 
                /* Transit to a mounted filesystem. */
-               if (managed & DCACHE_MOUNTED) {
+               if (flags & DCACHE_MOUNTED) {
                        struct vfsmount *mounted = lookup_mnt(path);
                        if (mounted) {
                                dput(path->dentry);
@@ -1256,7 +1256,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
                }
 
                /* Handle an automount point */
-               if (managed & DCACHE_NEED_AUTOMOUNT) {
+               if (flags & DCACHE_NEED_AUTOMOUNT) {
                        ret = follow_automount(path, nd, &need_mntput);
                        if (ret < 0)
                                break;
@@ -1269,10 +1269,12 @@ static int follow_managed(struct path *path, struct nameidata *nd)
 
        if (need_mntput && path->mnt == mnt)
                mntput(path->mnt);
-       if (ret == -EISDIR || !ret)
-               ret = 1;
        if (need_mntput)
                nd->flags |= LOOKUP_JUMPED;
+       if (ret == -EISDIR || !ret)
+               ret = 1;
+       if (ret > 0 && unlikely(d_flags_negative(flags)))
+               ret = -ENOENT;
        if (unlikely(ret < 0))
                path_put_conditional(path, nd);
        return ret;
@@ -1621,10 +1623,6 @@ static int lookup_fast(struct nameidata *nd,
                dput(dentry);
                return status;
        }
-       if (unlikely(d_is_negative(dentry))) {
-               dput(dentry);
-               return -ENOENT;
-       }
 
        path->mnt = mnt;
        path->dentry = dentry;
@@ -1811,11 +1809,6 @@ static int walk_component(struct nameidata *nd, int flags)
                if (unlikely(err < 0))
                        return err;
 
-               if (unlikely(d_is_negative(path.dentry))) {
-                       path_to_nameidata(&path, nd);
-                       return -ENOENT;
-               }
-
                seq = 0;        /* we are already out of RCU mode */
                inode = d_backing_inode(path.dentry);
        }
@@ -2568,6 +2561,26 @@ struct dentry *lookup_one_len_unlocked(const char *name,
 }
 EXPORT_SYMBOL(lookup_one_len_unlocked);
 
+/*
+ * Like lookup_one_len_unlocked(), except that it yields ERR_PTR(-ENOENT)
+ * on negatives.  Returns known positive or ERR_PTR(); that's what
+ * most of the users want.  Note that pinned negative with unlocked parent
+ * _can_ become positive at any time, so callers of lookup_one_len_unlocked()
+ * need to be very careful; pinned positives have ->d_inode stable, so
+ * this one avoids such problems.
+ */
+struct dentry *lookup_positive_unlocked(const char *name,
+                                      struct dentry *base, int len)
+{
+       struct dentry *ret = lookup_one_len_unlocked(name, base, len);
+       if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
+               dput(ret);
+               ret = ERR_PTR(-ENOENT);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(lookup_positive_unlocked);
+
 #ifdef CONFIG_UNIX98_PTYS
 int path_pts(struct path *path)
 {
@@ -2662,7 +2675,7 @@ mountpoint_last(struct nameidata *nd)
                                return PTR_ERR(path.dentry);
                }
        }
-       if (d_is_negative(path.dentry)) {
+       if (d_flags_negative(smp_load_acquire(&path.dentry->d_flags))) {
                dput(path.dentry);
                return -ENOENT;
        }
@@ -3356,11 +3369,6 @@ static int do_last(struct nameidata *nd,
        if (unlikely(error < 0))
                return error;
 
-       if (unlikely(d_is_negative(path.dentry))) {
-               path_to_nameidata(&path, nd);
-               return -ENOENT;
-       }
-
        /*
         * create/update audit record if it already exists.
         */
index 86e5658..195ab7a 100644 (file)
@@ -863,13 +863,11 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
                } else
                        dchild = dget(dparent);
        } else
-               dchild = lookup_one_len_unlocked(name, dparent, namlen);
+               dchild = lookup_positive_unlocked(name, dparent, namlen);
        if (IS_ERR(dchild))
                return rv;
        if (d_mountpoint(dchild))
                goto out;
-       if (d_really_is_negative(dchild))
-               goto out;
        if (dchild->d_inode->i_ino != ino)
                goto out;
        rv = fh_compose(fhp, exp, dchild, &cd->fh);
index 533d0fc..b092374 100644 (file)
@@ -2991,18 +2991,9 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
        __be32 nfserr;
        int ignore_crossmnt = 0;
 
-       dentry = lookup_one_len_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
+       dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
        if (IS_ERR(dentry))
                return nfserrno(PTR_ERR(dentry));
-       if (d_really_is_negative(dentry)) {
-               /*
-                * we're not holding the i_mutex here, so there's
-                * a window where this directory entry could have gone
-                * away.
-                */
-               dput(dentry);
-               return nfserr_noent;
-       }
 
        exp_get(exp);
        /*
index 3e7da39..bb981ec 100644 (file)
@@ -327,8 +327,8 @@ int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
        down_read(&OCFS2_I(inode)->ip_xattr_sem);
        acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
        up_read(&OCFS2_I(inode)->ip_xattr_sem);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
+       if (IS_ERR_OR_NULL(acl))
+               return PTR_ERR_OR_ZERO(acl);
        ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
        if (ret)
                return ret;
index e9717c2..c269d60 100644 (file)
@@ -200,7 +200,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
        int err;
        bool last_element = !post[0];
 
-       this = lookup_one_len_unlocked(name, base, namelen);
+       this = lookup_positive_unlocked(name, base, namelen);
        if (IS_ERR(this)) {
                err = PTR_ERR(this);
                this = NULL;
@@ -208,8 +208,6 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
                        goto out;
                goto out_err;
        }
-       if (!this->d_inode)
-               goto put_and_out;
 
        if (ovl_dentry_weird(this)) {
                /* Don't support traversing automounts and other weirdness */
@@ -651,7 +649,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
        if (err)
                return ERR_PTR(err);
 
-       index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
+       index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
        kfree(name.name);
        if (IS_ERR(index)) {
                if (PTR_ERR(index) == -ENOENT)
@@ -659,9 +657,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
                return index;
        }
 
-       if (d_is_negative(index))
-               err = 0;
-       else if (ovl_is_whiteout(index))
+       if (ovl_is_whiteout(index))
                err = -ESTALE;
        else if (ovl_dentry_weird(index))
                err = -EIO;
@@ -685,7 +681,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
        if (err)
                return ERR_PTR(err);
 
-       index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
+       index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
        if (IS_ERR(index)) {
                err = PTR_ERR(index);
                if (err == -ENOENT) {
@@ -700,9 +696,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
        }
 
        inode = d_inode(index);
-       if (d_is_negative(index)) {
-               goto out_dput;
-       } else if (ovl_is_whiteout(index) && !verify) {
+       if (ovl_is_whiteout(index) && !verify) {
                /*
                 * When index lookup is called with !verify for decoding an
                 * overlay file handle, a whiteout index implies that decode
@@ -1131,7 +1125,7 @@ bool ovl_lower_positive(struct dentry *dentry)
                struct dentry *this;
                struct dentry *lowerdir = poe->lowerstack[i].dentry;
 
-               this = lookup_one_len_unlocked(name->name, lowerdir,
+               this = lookup_positive_unlocked(name->name, lowerdir,
                                               name->len);
                if (IS_ERR(this)) {
                        switch (PTR_ERR(this)) {
@@ -1148,10 +1142,8 @@ bool ovl_lower_positive(struct dentry *dentry)
                                break;
                        }
                } else {
-                       if (this->d_inode) {
-                               positive = !ovl_is_whiteout(this);
-                               done = true;
-                       }
+                       positive = !ovl_is_whiteout(this);
+                       done = true;
                        dput(this);
                }
        }
index 648ce44..b901c8e 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -389,7 +389,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *filp = iocb->ki_filp;
        struct pipe_inode_info *pipe = filp->private_data;
-       unsigned int head, max_usage, mask;
+       unsigned int head;
        ssize_t ret = 0;
        int do_wakeup = 0;
        size_t total_len = iov_iter_count(from);
@@ -408,12 +408,11 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
        }
 
        head = pipe->head;
-       max_usage = pipe->max_usage;
-       mask = pipe->ring_size - 1;
 
        /* We try to merge small writes */
        chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
        if (!pipe_empty(head, pipe->tail) && chars != 0) {
+               unsigned int mask = pipe->ring_size - 1;
                struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
                int offset = buf->offset + buf->len;
 
@@ -443,7 +442,8 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                }
 
                head = pipe->head;
-               if (!pipe_full(head, pipe->tail, max_usage)) {
+               if (!pipe_full(head, pipe->tail, pipe->max_usage)) {
+                       unsigned int mask = pipe->ring_size - 1;
                        struct pipe_buffer *buf = &pipe->bufs[head & mask];
                        struct page *page = pipe->tmp_page;
                        int copied;
@@ -465,7 +465,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                        spin_lock_irq(&pipe->wait.lock);
 
                        head = pipe->head;
-                       if (pipe_full(head, pipe->tail, max_usage)) {
+                       if (pipe_full(head, pipe->tail, pipe->max_usage)) {
                                spin_unlock_irq(&pipe->wait.lock);
                                continue;
                        }
@@ -510,7 +510,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                                break;
                }
 
-               if (!pipe_full(head, pipe->tail, max_usage))
+               if (!pipe_full(head, pipe->tail, pipe->max_usage))
                        continue;
 
                /* Wait for buffer space to become available. */
@@ -579,8 +579,6 @@ pipe_poll(struct file *filp, poll_table *wait)
 
        poll_wait(filp, &pipe->wait, wait);
 
-       BUG_ON(pipe_occupancy(head, tail) > pipe->ring_size);
-
        /* Reading only -- no need for acquiring the semaphore.  */
        mask = 0;
        if (filp->f_mode & FMODE_READ) {
@@ -1176,6 +1174,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
        pipe->max_usage = nr_slots;
        pipe->tail = tail;
        pipe->head = head;
+       wake_up_interruptible_all(&pipe->wait);
        return pipe->max_usage * PAGE_SIZE;
 
 out_revert_acct:
index cb5629b..733881a 100644 (file)
@@ -42,8 +42,8 @@ config PROC_VMCORE
        bool "/proc/vmcore support"
        depends on PROC_FS && CRASH_DUMP
        default y
-        help
-        Exports the dump image of crashed kernel in ELF format.
+       help
+         Exports the dump image of crashed kernel in ELF format.
 
 config PROC_VMCORE_DEVICE_DUMP
        bool "Device Hardware/Firmware Log Collection"
@@ -72,7 +72,7 @@ config PROC_SYSCTL
          a recompile of the kernel or reboot of the system.  The primary
          interface is through /proc/sys.  If you say Y here a tree of
          modifiable sysctl entries will be generated beneath the
-          /proc/sys directory. They are explained in the files
+         /proc/sys directory. They are explained in the files
          in <file:Documentation/admin-guide/sysctl/>.  Note that enabling this
          option will enlarge the kernel by at least 8 KB.
 
@@ -88,7 +88,7 @@ config PROC_PAGE_MONITOR
          Various /proc files exist to monitor process memory utilization:
          /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
          /proc/kpagecount, and /proc/kpageflags. Disabling these
-          interfaces will reduce the size of the kernel by approximately 4kb.
+         interfaces will reduce the size of the kernel by approximately 4kb.
 
 config PROC_CHILDREN
        bool "Include /proc/<pid>/task/<tid>/children file"
index 46dcb6f..5efaf37 100644 (file)
@@ -533,7 +533,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
        nice = task_nice(task);
 
        /* convert nsec -> ticks */
-       start_time = nsec_to_clock_t(task->real_start_time);
+       start_time = nsec_to_clock_t(task->start_boottime);
 
        seq_put_decimal_ull(m, "", pid_nr_ns(pid, ns));
        seq_puts(m, " (");
index 64e9ee1..074e958 100644 (file)
@@ -138,8 +138,12 @@ static int proc_getattr(const struct path *path, struct kstat *stat,
 {
        struct inode *inode = d_inode(path->dentry);
        struct proc_dir_entry *de = PDE(inode);
-       if (de && de->nlink)
-               set_nlink(inode, de->nlink);
+       if (de) {
+               nlink_t nlink = READ_ONCE(de->nlink);
+               if (nlink > 0) {
+                       set_nlink(inode, nlink);
+               }
+       }
 
        generic_fillattr(inode, stat);
        return 0;
@@ -159,7 +163,6 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
 {
        const char              *cp = name, *next;
        struct proc_dir_entry   *de;
-       unsigned int            len;
 
        de = *ret;
        if (!de)
@@ -170,13 +173,12 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
                if (!next)
                        break;
 
-               len = next - cp;
-               de = pde_subdir_find(de, cp, len);
+               de = pde_subdir_find(de, cp, next - cp);
                if (!de) {
                        WARN(1, "name '%s'\n", name);
                        return -ENOENT;
                }
-               cp += len + 1;
+               cp = next + 1;
        }
        *residual = cp;
        *ret = de;
@@ -362,6 +364,7 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir,
                write_unlock(&proc_subdir_lock);
                goto out_free_inum;
        }
+       dir->nlink++;
        write_unlock(&proc_subdir_lock);
 
        return dp;
@@ -472,10 +475,7 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
                ent->data = data;
                ent->proc_fops = &proc_dir_operations;
                ent->proc_iops = &proc_dir_inode_operations;
-               parent->nlink++;
                ent = proc_register(parent, ent);
-               if (!ent)
-                       parent->nlink--;
        }
        return ent;
 }
@@ -505,10 +505,7 @@ struct proc_dir_entry *proc_create_mount_point(const char *name)
                ent->data = NULL;
                ent->proc_fops = NULL;
                ent->proc_iops = NULL;
-               parent->nlink++;
                ent = proc_register(parent, ent);
-               if (!ent)
-                       parent->nlink--;
        }
        return ent;
 }
@@ -666,8 +663,12 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
        len = strlen(fn);
 
        de = pde_subdir_find(parent, fn, len);
-       if (de)
+       if (de) {
                rb_erase(&de->subdir_node, &parent->subdir);
+               if (S_ISDIR(de->mode)) {
+                       parent->nlink--;
+               }
+       }
        write_unlock(&proc_subdir_lock);
        if (!de) {
                WARN(1, "name '%s'\n", name);
@@ -676,9 +677,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
 
        proc_entry_rundown(de);
 
-       if (S_ISDIR(de->mode))
-               parent->nlink--;
-       de->nlink = 0;
        WARN(pde_subdir_first(de),
             "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n",
             __func__, de->parent->name, de->name, pde_subdir_first(de)->name);
@@ -714,13 +712,12 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
                        de = next;
                        continue;
                }
-               write_unlock(&proc_subdir_lock);
-
-               proc_entry_rundown(de);
                next = de->parent;
                if (S_ISDIR(de->mode))
                        next->nlink--;
-               de->nlink = 0;
+               write_unlock(&proc_subdir_lock);
+
+               proc_entry_rundown(de);
                if (de == root)
                        break;
                pde_put(de);
index cd0c8d5..0f3b557 100644 (file)
@@ -197,8 +197,8 @@ extern ssize_t proc_simple_write(struct file *, const char __user *, size_t, lof
  * inode.c
  */
 struct pde_opener {
-       struct file *file;
        struct list_head lh;
+       struct file *file;
        bool closing;
        struct completion *c;
 } __randomize_layout;
index 3d70246..d896457 100644 (file)
@@ -793,7 +793,7 @@ static void pstore_timefunc(struct timer_list *unused)
                          jiffies + msecs_to_jiffies(pstore_update_ms));
 }
 
-void __init pstore_choose_compression(void)
+static void __init pstore_choose_compression(void)
 {
        const struct pstore_zbackend *step;
 
index 4639d53..b0688c0 100644 (file)
@@ -2487,21 +2487,15 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
        struct dentry *dentry;
        int error;
 
-       dentry = lookup_one_len_unlocked(qf_name, sb->s_root, strlen(qf_name));
+       dentry = lookup_positive_unlocked(qf_name, sb->s_root, strlen(qf_name));
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
-       if (d_really_is_negative(dentry)) {
-               error = -ENOENT;
-               goto out;
-       }
-
        error = security_quota_on(dentry);
        if (!error)
                error = dquot_load_quota_inode(d_inode(dentry), type, format_id,
                                DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 
-out:
        dput(dentry);
        return error;
 }
index e4b5278..0f5a480 100644 (file)
@@ -2737,18 +2737,6 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u,
        struct dentry *dent = file->f_path.dentry;
        int val;
 
-       /*
-        * TODO: this is racy - the file-system might have already been
-        * unmounted and we'd oops in this case. The plan is to fix it with
-        * help of 'iterate_supers_type()' which we should have in v3.0: when
-        * a debugfs opened, we rember FS's UUID in file->private_data. Then
-        * whenever we access the FS via a debugfs file, we iterate all UBIFS
-        * superblocks and fine the one with the same UUID, and take the
-        * locking right.
-        *
-        * The other way to go suggested by Al Viro is to create a separate
-        * 'ubifs-debug' file-system instead.
-        */
        if (file->f_path.dentry == d->dfs_dump_lprops) {
                ubifs_dump_lprops(c);
                return count;
index 4fd9683..388fe8f 100644 (file)
@@ -503,7 +503,7 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
 static void set_dent_cookie(struct ubifs_info *c, struct ubifs_dent_node *dent)
 {
        if (c->double_hash)
-               dent->cookie = prandom_u32();
+               dent->cookie = (__force __le32) prandom_u32();
        else
                dent->cookie = 0;
 }
@@ -899,7 +899,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
                        fname_name(&nm) = xent->name;
                        fname_len(&nm) = le16_to_cpu(xent->nlen);
 
-                       xino = ubifs_iget(c->vfs_sb, xent->inum);
+                       xino = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum));
                        if (IS_ERR(xino)) {
                                err = PTR_ERR(xino);
                                ubifs_err(c, "dead directory entry '%s', error %d",
index 3b4b411..54d6db6 100644 (file)
@@ -631,12 +631,17 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
        ino_t inum;
        int i, n, err, first = 1;
 
+       ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
+       if (!ino)
+               return -ENOMEM;
+
        list_for_each_entry(snod, &sleb->nodes, list) {
                if (snod->type != UBIFS_ORPH_NODE) {
                        ubifs_err(c, "invalid node type %d in orphan area at %d:%d",
                                  snod->type, sleb->lnum, snod->offs);
                        ubifs_dump_node(c, snod->node);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out_free;
                }
 
                orph = snod->node;
@@ -663,20 +668,18 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                                ubifs_err(c, "out of order commit number %llu in orphan node at %d:%d",
                                          cmt_no, sleb->lnum, snod->offs);
                                ubifs_dump_node(c, snod->node);
-                               return -EINVAL;
+                               err = -EINVAL;
+                               goto out_free;
                        }
                        dbg_rcvry("out of date LEB %d", sleb->lnum);
                        *outofdate = 1;
-                       return 0;
+                       err = 0;
+                       goto out_free;
                }
 
                if (first)
                        first = 0;
 
-               ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
-               if (!ino)
-                       return -ENOMEM;
-
                n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
                for (i = 0; i < n; i++) {
                        union ubifs_key key1, key2;
index a551eb3..2b7c04b 100644 (file)
@@ -184,7 +184,7 @@ static int create_default_filesystem(struct ubifs_info *c)
                if (err)
                        goto out;
        } else {
-               sup->hash_algo = 0xffff;
+               sup->hash_algo = cpu_to_le16(0xffff);
        }
 
        sup->ch.node_type  = UBIFS_SB_NODE;
index 7d4547e..5e1e8ec 100644 (file)
@@ -2267,10 +2267,8 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
                }
        } else {
                err = ubifs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
-               if (err) {
-                       kfree(c);
+               if (err)
                        goto out_deact;
-               }
                /* We do not support atime */
                sb->s_flags |= SB_ACTIVE;
                if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
index a384a0f..234be1c 100644 (file)
@@ -212,7 +212,7 @@ static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
 /**
  * layout_leb_in_gaps - layout index nodes using in-the-gaps method.
  * @c: UBIFS file-system description object
- * @p: return LEB number here
+ * @p: return LEB number in @c->gap_lebs[p]
  *
  * This function lays out new index nodes for dirty znodes using in-the-gaps
  * method of TNC commit.
@@ -221,7 +221,7 @@ static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
  * This function returns the number of index nodes written into the gaps, or a
  * negative error code on failure.
  */
-static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
+static int layout_leb_in_gaps(struct ubifs_info *c, int p)
 {
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
@@ -236,7 +236,7 @@ static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
                 * filled, however we do not check there at present.
                 */
                return lnum; /* Error code */
-       *p = lnum;
+       c->gap_lebs[p] = lnum;
        dbg_gc("LEB %d", lnum);
        /*
         * Scan the index LEB.  We use the generic scan for this even though
@@ -355,7 +355,7 @@ static int get_leb_cnt(struct ubifs_info *c, int cnt)
  */
 static int layout_in_gaps(struct ubifs_info *c, int cnt)
 {
-       int err, leb_needed_cnt, written, *p;
+       int err, leb_needed_cnt, written, p = 0, old_idx_lebs, *gap_lebs;
 
        dbg_gc("%d znodes to write", cnt);
 
@@ -364,9 +364,9 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
        if (!c->gap_lebs)
                return -ENOMEM;
 
-       p = c->gap_lebs;
+       old_idx_lebs = c->lst.idx_lebs;
        do {
-               ubifs_assert(c, p < c->gap_lebs + c->lst.idx_lebs);
+               ubifs_assert(c, p < c->lst.idx_lebs);
                written = layout_leb_in_gaps(c, p);
                if (written < 0) {
                        err = written;
@@ -392,9 +392,29 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
                leb_needed_cnt = get_leb_cnt(c, cnt);
                dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt,
                       leb_needed_cnt, c->ileb_cnt);
+               /*
+                * Dynamically change the size of @c->gap_lebs to prevent
+                * oob, because @c->lst.idx_lebs could be increased by
+                * function @get_idx_gc_leb (called by layout_leb_in_gaps->
+                * ubifs_find_dirty_idx_leb) during loop. Only enlarge
+                * @c->gap_lebs when needed.
+                *
+                */
+               if (leb_needed_cnt > c->ileb_cnt && p >= old_idx_lebs &&
+                   old_idx_lebs < c->lst.idx_lebs) {
+                       old_idx_lebs = c->lst.idx_lebs;
+                       gap_lebs = krealloc(c->gap_lebs, sizeof(int) *
+                                              (old_idx_lebs + 1), GFP_NOFS);
+                       if (!gap_lebs) {
+                               kfree(c->gap_lebs);
+                               c->gap_lebs = NULL;
+                               return -ENOMEM;
+                       }
+                       c->gap_lebs = gap_lebs;
+               }
        } while (leb_needed_cnt > c->ileb_cnt);
 
-       *p = -1;
+       c->gap_lebs[p] = -1;
        return 0;
 }
 
index d7f54e5..37df7c9 100644 (file)
@@ -1460,7 +1460,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                        start = vma->vm_start;
                vma_end = min(end, vma->vm_end);
 
-               new_flags = (vma->vm_flags & ~vm_flags) | vm_flags;
+               new_flags = (vma->vm_flags &
+                            ~(VM_UFFD_MISSING|VM_UFFD_WP)) | vm_flags;
                prev = vma_merge(mm, prev, start, vma_end, new_flags,
                                 vma->anon_vma, vma->vm_file, vma->vm_pgoff,
                                 vma_policy(vma),
@@ -1834,13 +1835,12 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
        if (copy_from_user(&uffdio_api, buf, sizeof(uffdio_api)))
                goto out;
        features = uffdio_api.features;
-       if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES)) {
-               memset(&uffdio_api, 0, sizeof(uffdio_api));
-               if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
-                       goto out;
-               ret = -EINVAL;
-               goto out;
-       }
+       ret = -EINVAL;
+       if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES))
+               goto err_out;
+       ret = -EPERM;
+       if ((features & UFFD_FEATURE_EVENT_FORK) && !capable(CAP_SYS_PTRACE))
+               goto err_out;
        /* report all available features and ioctls to userland */
        uffdio_api.features = UFFD_API_FEATURES;
        uffdio_api.ioctls = UFFD_API_IOCTLS;
@@ -1853,6 +1853,11 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
        ret = 0;
 out:
        return ret;
+err_out:
+       memset(&uffdio_api, 0, sizeof(uffdio_api));
+       if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
+               ret = -EFAULT;
+       goto out;
 }
 
 static long userfaultfd_ioctl(struct file *file, unsigned cmd,
index 06b68b6..aceca2f 100644 (file)
@@ -27,7 +27,6 @@ xfs-y                         += $(addprefix libxfs/, \
                                   xfs_bmap_btree.o \
                                   xfs_btree.o \
                                   xfs_da_btree.o \
-                                  xfs_da_format.o \
                                   xfs_defer.o \
                                   xfs_dir2.o \
                                   xfs_dir2_block.o \
index da031b9..1da9423 100644 (file)
@@ -32,7 +32,7 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
 
 
 /*
- * __vmalloc() will allocate data pages and auxillary structures (e.g.
+ * __vmalloc() will allocate data pages and auxiliary structures (e.g.
  * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context here. Hence
  * we need to tell memory reclaim that we are in such a context via
  * PF_MEMALLOC_NOFS to prevent memory reclaim re-entering the filesystem here
index 8170d95..6143117 100644 (file)
@@ -78,39 +78,9 @@ kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
  * Zone interfaces
  */
 
-#define KM_ZONE_HWALIGN        SLAB_HWCACHE_ALIGN
-#define KM_ZONE_RECLAIM        SLAB_RECLAIM_ACCOUNT
-#define KM_ZONE_SPREAD SLAB_MEM_SPREAD
-#define KM_ZONE_ACCOUNT        SLAB_ACCOUNT
-
 #define kmem_zone      kmem_cache
 #define kmem_zone_t    struct kmem_cache
 
-static inline kmem_zone_t *
-kmem_zone_init(int size, char *zone_name)
-{
-       return kmem_cache_create(zone_name, size, 0, 0, NULL);
-}
-
-static inline kmem_zone_t *
-kmem_zone_init_flags(int size, char *zone_name, slab_flags_t flags,
-                    void (*construct)(void *))
-{
-       return kmem_cache_create(zone_name, size, 0, flags, construct);
-}
-
-static inline void
-kmem_zone_free(kmem_zone_t *zone, void *ptr)
-{
-       kmem_cache_free(zone, ptr);
-}
-
-static inline void
-kmem_zone_destroy(kmem_zone_t *zone)
-{
-       kmem_cache_destroy(zone);
-}
-
 extern void *kmem_zone_alloc(kmem_zone_t *, xfs_km_flags_t);
 
 static inline void *
index 87a9747..fdfe6dc 100644 (file)
@@ -19,6 +19,8 @@
 #include "xfs_btree.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_ialloc_btree.h"
+#include "xfs_sb.h"
+#include "xfs_ag_resv.h"
 
 /*
  * Per-AG Block Reservations
index 533b04a..c284e10 100644 (file)
@@ -146,9 +146,13 @@ xfs_alloc_lookup_eq(
        xfs_extlen_t            len,    /* length of extent */
        int                     *stat)  /* success/failure */
 {
+       int                     error;
+
        cur->bc_rec.a.ar_startblock = bno;
        cur->bc_rec.a.ar_blockcount = len;
-       return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
+       error = xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
+       cur->bc_private.a.priv.abt.active = (*stat == 1);
+       return error;
 }
 
 /*
@@ -162,9 +166,13 @@ xfs_alloc_lookup_ge(
        xfs_extlen_t            len,    /* length of extent */
        int                     *stat)  /* success/failure */
 {
+       int                     error;
+
        cur->bc_rec.a.ar_startblock = bno;
        cur->bc_rec.a.ar_blockcount = len;
-       return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
+       error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
+       cur->bc_private.a.priv.abt.active = (*stat == 1);
+       return error;
 }
 
 /*
@@ -178,9 +186,19 @@ xfs_alloc_lookup_le(
        xfs_extlen_t            len,    /* length of extent */
        int                     *stat)  /* success/failure */
 {
+       int                     error;
        cur->bc_rec.a.ar_startblock = bno;
        cur->bc_rec.a.ar_blockcount = len;
-       return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
+       error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
+       cur->bc_private.a.priv.abt.active = (*stat == 1);
+       return error;
+}
+
+static inline bool
+xfs_alloc_cur_active(
+       struct xfs_btree_cur    *cur)
+{
+       return cur && cur->bc_private.a.priv.abt.active;
 }
 
 /*
@@ -313,7 +331,7 @@ xfs_alloc_compute_diff(
        xfs_extlen_t    newlen1=0;      /* length with newbno1 */
        xfs_extlen_t    newlen2=0;      /* length with newbno2 */
        xfs_agblock_t   wantend;        /* end of target extent */
-       bool            userdata = xfs_alloc_is_userdata(datatype);
+       bool            userdata = datatype & XFS_ALLOC_USERDATA;
 
        ASSERT(freelen >= wantlen);
        freeend = freebno + freelen;
@@ -433,13 +451,17 @@ xfs_alloc_fixup_trees(
 #ifdef DEBUG
                if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp,
-                       i == 1 && nfbno1 == fbno && nflen1 == flen);
+               if (XFS_IS_CORRUPT(mp,
+                                  i != 1 ||
+                                  nfbno1 != fbno ||
+                                  nflen1 != flen))
+                       return -EFSCORRUPTED;
 #endif
        } else {
                if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
        }
        /*
         * Look up the record in the by-block tree if necessary.
@@ -448,13 +470,17 @@ xfs_alloc_fixup_trees(
 #ifdef DEBUG
                if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp,
-                       i == 1 && nfbno1 == fbno && nflen1 == flen);
+               if (XFS_IS_CORRUPT(mp,
+                                  i != 1 ||
+                                  nfbno1 != fbno ||
+                                  nflen1 != flen))
+                       return -EFSCORRUPTED;
 #endif
        } else {
                if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
        }
 
 #ifdef DEBUG
@@ -465,8 +491,10 @@ xfs_alloc_fixup_trees(
                bnoblock = XFS_BUF_TO_BLOCK(bno_cur->bc_bufs[0]);
                cntblock = XFS_BUF_TO_BLOCK(cnt_cur->bc_bufs[0]);
 
-               XFS_WANT_CORRUPTED_RETURN(mp,
-                       bnoblock->bb_numrecs == cntblock->bb_numrecs);
+               if (XFS_IS_CORRUPT(mp,
+                                  bnoblock->bb_numrecs !=
+                                  cntblock->bb_numrecs))
+                       return -EFSCORRUPTED;
        }
 #endif
 
@@ -496,25 +524,30 @@ xfs_alloc_fixup_trees(
         */
        if ((error = xfs_btree_delete(cnt_cur, &i)))
                return error;
-       XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+       if (XFS_IS_CORRUPT(mp, i != 1))
+               return -EFSCORRUPTED;
        /*
         * Add new by-size btree entry(s).
         */
        if (nfbno1 != NULLAGBLOCK) {
                if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 0);
+               if (XFS_IS_CORRUPT(mp, i != 0))
+                       return -EFSCORRUPTED;
                if ((error = xfs_btree_insert(cnt_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
        }
        if (nfbno2 != NULLAGBLOCK) {
                if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 0);
+               if (XFS_IS_CORRUPT(mp, i != 0))
+                       return -EFSCORRUPTED;
                if ((error = xfs_btree_insert(cnt_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
        }
        /*
         * Fix up the by-block btree entry(s).
@@ -525,7 +558,8 @@ xfs_alloc_fixup_trees(
                 */
                if ((error = xfs_btree_delete(bno_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
        } else {
                /*
                 * Update the by-block entry to start later|be shorter.
@@ -539,10 +573,12 @@ xfs_alloc_fixup_trees(
                 */
                if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 0);
+               if (XFS_IS_CORRUPT(mp, i != 0))
+                       return -EFSCORRUPTED;
                if ((error = xfs_btree_insert(bno_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
        }
        return 0;
 }
@@ -684,16 +720,298 @@ xfs_alloc_update_counters(
 
        xfs_trans_agblocks_delta(tp, len);
        if (unlikely(be32_to_cpu(agf->agf_freeblks) >
-                    be32_to_cpu(agf->agf_length)))
+                    be32_to_cpu(agf->agf_length))) {
+               xfs_buf_corruption_error(agbp);
                return -EFSCORRUPTED;
+       }
 
        xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);
        return 0;
 }
 
 /*
- * Allocation group level functions.
+ * Block allocation algorithm and data structures.
+ */
+struct xfs_alloc_cur {
+       struct xfs_btree_cur            *cnt;   /* btree cursors */
+       struct xfs_btree_cur            *bnolt;
+       struct xfs_btree_cur            *bnogt;
+       xfs_extlen_t                    cur_len;/* current search length */
+       xfs_agblock_t                   rec_bno;/* extent startblock */
+       xfs_extlen_t                    rec_len;/* extent length */
+       xfs_agblock_t                   bno;    /* alloc bno */
+       xfs_extlen_t                    len;    /* alloc len */
+       xfs_extlen_t                    diff;   /* diff from search bno */
+       unsigned int                    busy_gen;/* busy state */
+       bool                            busy;
+};
+
+/*
+ * Set up cursors, etc. in the extent allocation cursor. This function can be
+ * called multiple times to reset an initialized structure without having to
+ * reallocate cursors.
+ */
+static int
+xfs_alloc_cur_setup(
+       struct xfs_alloc_arg    *args,
+       struct xfs_alloc_cur    *acur)
+{
+       int                     error;
+       int                     i;
+
+       ASSERT(args->alignment == 1 || args->type != XFS_ALLOCTYPE_THIS_BNO);
+
+       acur->cur_len = args->maxlen;
+       acur->rec_bno = 0;
+       acur->rec_len = 0;
+       acur->bno = 0;
+       acur->len = 0;
+       acur->diff = -1;
+       acur->busy = false;
+       acur->busy_gen = 0;
+
+       /*
+        * Perform an initial cntbt lookup to check for availability of maxlen
+        * extents. If this fails, we'll return -ENOSPC to signal the caller to
+        * attempt a small allocation.
+        */
+       if (!acur->cnt)
+               acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
+                                       args->agbp, args->agno, XFS_BTNUM_CNT);
+       error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
+       if (error)
+               return error;
+
+       /*
+        * Allocate the bnobt left and right search cursors.
+        */
+       if (!acur->bnolt)
+               acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
+                                       args->agbp, args->agno, XFS_BTNUM_BNO);
+       if (!acur->bnogt)
+               acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
+                                       args->agbp, args->agno, XFS_BTNUM_BNO);
+       return i == 1 ? 0 : -ENOSPC;
+}
+
+static void
+xfs_alloc_cur_close(
+       struct xfs_alloc_cur    *acur,
+       bool                    error)
+{
+       int                     cur_error = XFS_BTREE_NOERROR;
+
+       if (error)
+               cur_error = XFS_BTREE_ERROR;
+
+       if (acur->cnt)
+               xfs_btree_del_cursor(acur->cnt, cur_error);
+       if (acur->bnolt)
+               xfs_btree_del_cursor(acur->bnolt, cur_error);
+       if (acur->bnogt)
+               xfs_btree_del_cursor(acur->bnogt, cur_error);
+       acur->cnt = acur->bnolt = acur->bnogt = NULL;
+}
+
+/*
+ * Check an extent for allocation and track the best available candidate in the
+ * allocation structure. The cursor is deactivated if it has entered an out of
+ * range state based on allocation arguments. Optionally return the extent
+ * extent geometry and allocation status if requested by the caller.
+ */
+static int
+xfs_alloc_cur_check(
+       struct xfs_alloc_arg    *args,
+       struct xfs_alloc_cur    *acur,
+       struct xfs_btree_cur    *cur,
+       int                     *new)
+{
+       int                     error, i;
+       xfs_agblock_t           bno, bnoa, bnew;
+       xfs_extlen_t            len, lena, diff = -1;
+       bool                    busy;
+       unsigned                busy_gen = 0;
+       bool                    deactivate = false;
+       bool                    isbnobt = cur->bc_btnum == XFS_BTNUM_BNO;
+
+       *new = 0;
+
+       error = xfs_alloc_get_rec(cur, &bno, &len, &i);
+       if (error)
+               return error;
+       if (XFS_IS_CORRUPT(args->mp, i != 1))
+               return -EFSCORRUPTED;
+
+       /*
+        * Check minlen and deactivate a cntbt cursor if out of acceptable size
+        * range (i.e., walking backwards looking for a minlen extent).
+        */
+       if (len < args->minlen) {
+               deactivate = !isbnobt;
+               goto out;
+       }
+
+       busy = xfs_alloc_compute_aligned(args, bno, len, &bnoa, &lena,
+                                        &busy_gen);
+       acur->busy |= busy;
+       if (busy)
+               acur->busy_gen = busy_gen;
+       /* deactivate a bnobt cursor outside of locality range */
+       if (bnoa < args->min_agbno || bnoa > args->max_agbno) {
+               deactivate = isbnobt;
+               goto out;
+       }
+       if (lena < args->minlen)
+               goto out;
+
+       args->len = XFS_EXTLEN_MIN(lena, args->maxlen);
+       xfs_alloc_fix_len(args);
+       ASSERT(args->len >= args->minlen);
+       if (args->len < acur->len)
+               goto out;
+
+       /*
+        * We have an aligned record that satisfies minlen and beats or matches
+        * the candidate extent size. Compare locality for near allocation mode.
+        */
+       ASSERT(args->type == XFS_ALLOCTYPE_NEAR_BNO);
+       diff = xfs_alloc_compute_diff(args->agbno, args->len,
+                                     args->alignment, args->datatype,
+                                     bnoa, lena, &bnew);
+       if (bnew == NULLAGBLOCK)
+               goto out;
+
+       /*
+        * Deactivate a bnobt cursor with worse locality than the current best.
+        */
+       if (diff > acur->diff) {
+               deactivate = isbnobt;
+               goto out;
+       }
+
+       ASSERT(args->len > acur->len ||
+              (args->len == acur->len && diff <= acur->diff));
+       acur->rec_bno = bno;
+       acur->rec_len = len;
+       acur->bno = bnew;
+       acur->len = args->len;
+       acur->diff = diff;
+       *new = 1;
+
+       /*
+        * We're done if we found a perfect allocation. This only deactivates
+        * the current cursor, but this is just an optimization to terminate a
+        * cntbt search that otherwise runs to the edge of the tree.
+        */
+       if (acur->diff == 0 && acur->len == args->maxlen)
+               deactivate = true;
+out:
+       if (deactivate)
+               cur->bc_private.a.priv.abt.active = false;
+       trace_xfs_alloc_cur_check(args->mp, cur->bc_btnum, bno, len, diff,
+                                 *new);
+       return 0;
+}
+
+/*
+ * Complete an allocation of a candidate extent. Remove the extent from both
+ * trees and update the args structure.
  */
+STATIC int
+xfs_alloc_cur_finish(
+       struct xfs_alloc_arg    *args,
+       struct xfs_alloc_cur    *acur)
+{
+       int                     error;
+
+       ASSERT(acur->cnt && acur->bnolt);
+       ASSERT(acur->bno >= acur->rec_bno);
+       ASSERT(acur->bno + acur->len <= acur->rec_bno + acur->rec_len);
+       ASSERT(acur->rec_bno + acur->rec_len <=
+              be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
+
+       error = xfs_alloc_fixup_trees(acur->cnt, acur->bnolt, acur->rec_bno,
+                                     acur->rec_len, acur->bno, acur->len, 0);
+       if (error)
+               return error;
+
+       args->agbno = acur->bno;
+       args->len = acur->len;
+       args->wasfromfl = 0;
+
+       trace_xfs_alloc_cur(args);
+       return 0;
+}
+
+/*
+ * Locality allocation lookup algorithm. This expects a cntbt cursor and uses
+ * bno optimized lookup to search for extents with ideal size and locality.
+ */
+STATIC int
+xfs_alloc_cntbt_iter(
+       struct xfs_alloc_arg            *args,
+       struct xfs_alloc_cur            *acur)
+{
+       struct xfs_btree_cur    *cur = acur->cnt;
+       xfs_agblock_t           bno;
+       xfs_extlen_t            len, cur_len;
+       int                     error;
+       int                     i;
+
+       if (!xfs_alloc_cur_active(cur))
+               return 0;
+
+       /* locality optimized lookup */
+       cur_len = acur->cur_len;
+       error = xfs_alloc_lookup_ge(cur, args->agbno, cur_len, &i);
+       if (error)
+               return error;
+       if (i == 0)
+               return 0;
+       error = xfs_alloc_get_rec(cur, &bno, &len, &i);
+       if (error)
+               return error;
+
+       /* check the current record and update search length from it */
+       error = xfs_alloc_cur_check(args, acur, cur, &i);
+       if (error)
+               return error;
+       ASSERT(len >= acur->cur_len);
+       acur->cur_len = len;
+
+       /*
+        * We looked up the first record >= [agbno, len] above. The agbno is a
+        * secondary key and so the current record may lie just before or after
+        * agbno. If it is past agbno, check the previous record too so long as
+        * the length matches as it may be closer. Don't check a smaller record
+        * because that could deactivate our cursor.
+        */
+       if (bno > args->agbno) {
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (!error && i) {
+                       error = xfs_alloc_get_rec(cur, &bno, &len, &i);
+                       if (!error && i && len == acur->cur_len)
+                               error = xfs_alloc_cur_check(args, acur, cur,
+                                                           &i);
+               }
+               if (error)
+                       return error;
+       }
+
+       /*
+        * Increment the search key until we find at least one allocation
+        * candidate or if the extent we found was larger. Otherwise, double the
+        * search key to optimize the search. Efficiency is more important here
+        * than absolute best locality.
+        */
+       cur_len <<= 1;
+       if (!acur->len || acur->cur_len >= cur_len)
+               acur->cur_len++;
+       else
+               acur->cur_len = cur_len;
+
+       return error;
+}
 
 /*
  * Deal with the case where only small freespaces remain. Either return the
@@ -727,7 +1045,10 @@ xfs_alloc_ag_vextent_small(
                error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i);
                if (error)
                        goto error;
-               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error);
+               if (XFS_IS_CORRUPT(args->mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
                goto out;
        }
 
@@ -744,13 +1065,13 @@ xfs_alloc_ag_vextent_small(
                goto out;
 
        xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
-                             xfs_alloc_allow_busy_reuse(args->datatype));
+                             (args->datatype & XFS_ALLOC_NOBUSY));
 
-       if (xfs_alloc_is_userdata(args->datatype)) {
+       if (args->datatype & XFS_ALLOC_USERDATA) {
                struct xfs_buf  *bp;
 
                bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno);
-               if (!bp) {
+               if (XFS_IS_CORRUPT(args->mp, !bp)) {
                        error = -EFSCORRUPTED;
                        goto error;
                }
@@ -758,9 +1079,12 @@ xfs_alloc_ag_vextent_small(
        }
        *fbnop = args->agbno = fbno;
        *flenp = args->len = 1;
-       XFS_WANT_CORRUPTED_GOTO(args->mp,
-               fbno < be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),
-               error);
+       if (XFS_IS_CORRUPT(args->mp,
+                          fbno >= be32_to_cpu(
+                                  XFS_BUF_TO_AGF(args->agbp)->agf_length))) {
+               error = -EFSCORRUPTED;
+               goto error;
+       }
        args->wasfromfl = 1;
        trace_xfs_alloc_small_freelist(args);
 
@@ -915,7 +1239,10 @@ xfs_alloc_ag_vextent_exact(
        error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i);
        if (error)
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
+       if (XFS_IS_CORRUPT(args->mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        ASSERT(fbno <= args->agbno);
 
        /*
@@ -984,98 +1311,243 @@ error0:
 }
 
 /*
- * Search the btree in a given direction via the search cursor and compare
- * the records found against the good extent we've already found.
+ * Search a given number of btree records in a given direction. Check each
+ * record against the good extent we've already found.
  */
 STATIC int
-xfs_alloc_find_best_extent(
-       struct xfs_alloc_arg    *args,  /* allocation argument structure */
-       struct xfs_btree_cur    **gcur, /* good cursor */
-       struct xfs_btree_cur    **scur, /* searching cursor */
-       xfs_agblock_t           gdiff,  /* difference for search comparison */
-       xfs_agblock_t           *sbno,  /* extent found by search */
-       xfs_extlen_t            *slen,  /* extent length */
-       xfs_agblock_t           *sbnoa, /* aligned extent found by search */
-       xfs_extlen_t            *slena, /* aligned extent length */
-       int                     dir)    /* 0 = search right, 1 = search left */
+xfs_alloc_walk_iter(
+       struct xfs_alloc_arg    *args,
+       struct xfs_alloc_cur    *acur,
+       struct xfs_btree_cur    *cur,
+       bool                    increment,
+       bool                    find_one, /* quit on first candidate */
+       int                     count,    /* rec count (-1 for infinite) */
+       int                     *stat)
 {
-       xfs_agblock_t           new;
-       xfs_agblock_t           sdiff;
        int                     error;
        int                     i;
-       unsigned                busy_gen;
 
-       /* The good extent is perfect, no need to  search. */
-       if (!gdiff)
-               goto out_use_good;
+       *stat = 0;
 
        /*
-        * Look until we find a better one, run out of space or run off the end.
+        * Search so long as the cursor is active or we find a better extent.
+        * The cursor is deactivated if it extends beyond the range of the
+        * current allocation candidate.
         */
-       do {
-               error = xfs_alloc_get_rec(*scur, sbno, slen, &i);
+       while (xfs_alloc_cur_active(cur) && count) {
+               error = xfs_alloc_cur_check(args, acur, cur, &i);
                if (error)
-                       goto error0;
-               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-               xfs_alloc_compute_aligned(args, *sbno, *slen,
-                               sbnoa, slena, &busy_gen);
+                       return error;
+               if (i == 1) {
+                       *stat = 1;
+                       if (find_one)
+                               break;
+               }
+               if (!xfs_alloc_cur_active(cur))
+                       break;
+
+               if (increment)
+                       error = xfs_btree_increment(cur, 0, &i);
+               else
+                       error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       return error;
+               if (i == 0)
+                       cur->bc_private.a.priv.abt.active = false;
+
+               if (count > 0)
+                       count--;
+       }
+
+       return 0;
+}
+
+/*
+ * Search the by-bno and by-size btrees in parallel in search of an extent with
+ * ideal locality based on the NEAR mode ->agbno locality hint.
+ */
+STATIC int
+xfs_alloc_ag_vextent_locality(
+       struct xfs_alloc_arg    *args,
+       struct xfs_alloc_cur    *acur,
+       int                     *stat)
+{
+       struct xfs_btree_cur    *fbcur = NULL;
+       int                     error;
+       int                     i;
+       bool                    fbinc;
+
+       ASSERT(acur->len == 0);
+       ASSERT(args->type == XFS_ALLOCTYPE_NEAR_BNO);
+
+       *stat = 0;
+
+       error = xfs_alloc_lookup_ge(acur->cnt, args->agbno, acur->cur_len, &i);
+       if (error)
+               return error;
+       error = xfs_alloc_lookup_le(acur->bnolt, args->agbno, 0, &i);
+       if (error)
+               return error;
+       error = xfs_alloc_lookup_ge(acur->bnogt, args->agbno, 0, &i);
+       if (error)
+               return error;
+
+       /*
+        * Search the bnobt and cntbt in parallel. Search the bnobt left and
+        * right and lookup the closest extent to the locality hint for each
+        * extent size key in the cntbt. The entire search terminates
+        * immediately on a bnobt hit because that means we've found best case
+        * locality. Otherwise the search continues until the cntbt cursor runs
+        * off the end of the tree. If no allocation candidate is found at this
+        * point, give up on locality, walk backwards from the end of the cntbt
+        * and take the first available extent.
+        *
+        * The parallel tree searches balance each other out to provide fairly
+        * consistent performance for various situations. The bnobt search can
+        * have pathological behavior in the worst case scenario of larger
+        * allocation requests and fragmented free space. On the other hand, the
+        * bnobt is able to satisfy most smaller allocation requests much more
+        * quickly than the cntbt. The cntbt search can sift through fragmented
+        * free space and sets of free extents for larger allocation requests
+        * more quickly than the bnobt. Since the locality hint is just a hint
+        * and we don't want to scan the entire bnobt for perfect locality, the
+        * cntbt search essentially bounds the bnobt search such that we can
+        * find good enough locality at reasonable performance in most cases.
+        */
+       while (xfs_alloc_cur_active(acur->bnolt) ||
+              xfs_alloc_cur_active(acur->bnogt) ||
+              xfs_alloc_cur_active(acur->cnt)) {
+
+               trace_xfs_alloc_cur_lookup(args);
 
                /*
-                * The good extent is closer than this one.
+                * Search the bnobt left and right. In the case of a hit, finish
+                * the search in the opposite direction and we're done.
                 */
-               if (!dir) {
-                       if (*sbnoa > args->max_agbno)
-                               goto out_use_good;
-                       if (*sbnoa >= args->agbno + gdiff)
-                               goto out_use_good;
-               } else {
-                       if (*sbnoa < args->min_agbno)
-                               goto out_use_good;
-                       if (*sbnoa <= args->agbno - gdiff)
-                               goto out_use_good;
+               error = xfs_alloc_walk_iter(args, acur, acur->bnolt, false,
+                                           true, 1, &i);
+               if (error)
+                       return error;
+               if (i == 1) {
+                       trace_xfs_alloc_cur_left(args);
+                       fbcur = acur->bnogt;
+                       fbinc = true;
+                       break;
+               }
+               error = xfs_alloc_walk_iter(args, acur, acur->bnogt, true, true,
+                                           1, &i);
+               if (error)
+                       return error;
+               if (i == 1) {
+                       trace_xfs_alloc_cur_right(args);
+                       fbcur = acur->bnolt;
+                       fbinc = false;
+                       break;
                }
 
                /*
-                * Same distance, compare length and pick the best.
+                * Check the extent with best locality based on the current
+                * extent size search key and keep track of the best candidate.
                 */
-               if (*slena >= args->minlen) {
-                       args->len = XFS_EXTLEN_MIN(*slena, args->maxlen);
-                       xfs_alloc_fix_len(args);
-
-                       sdiff = xfs_alloc_compute_diff(args->agbno, args->len,
-                                                      args->alignment,
-                                                      args->datatype, *sbnoa,
-                                                      *slena, &new);
+               error = xfs_alloc_cntbt_iter(args, acur);
+               if (error)
+                       return error;
+               if (!xfs_alloc_cur_active(acur->cnt)) {
+                       trace_xfs_alloc_cur_lookup_done(args);
+                       break;
+               }
+       }
 
-                       /*
-                        * Choose closer size and invalidate other cursor.
-                        */
-                       if (sdiff < gdiff)
-                               goto out_use_search;
-                       goto out_use_good;
+       /*
+        * If we failed to find anything due to busy extents, return empty
+        * handed so the caller can flush and retry. If no busy extents were
+        * found, walk backwards from the end of the cntbt as a last resort.
+        */
+       if (!xfs_alloc_cur_active(acur->cnt) && !acur->len && !acur->busy) {
+               error = xfs_btree_decrement(acur->cnt, 0, &i);
+               if (error)
+                       return error;
+               if (i) {
+                       acur->cnt->bc_private.a.priv.abt.active = true;
+                       fbcur = acur->cnt;
+                       fbinc = false;
                }
+       }
 
-               if (!dir)
-                       error = xfs_btree_increment(*scur, 0, &i);
-               else
-                       error = xfs_btree_decrement(*scur, 0, &i);
+       /*
+        * Search in the opposite direction for a better entry in the case of
+        * a bnobt hit or walk backwards from the end of the cntbt.
+        */
+       if (fbcur) {
+               error = xfs_alloc_walk_iter(args, acur, fbcur, fbinc, true, -1,
+                                           &i);
                if (error)
-                       goto error0;
-       } while (i);
+                       return error;
+       }
 
-out_use_good:
-       xfs_btree_del_cursor(*scur, XFS_BTREE_NOERROR);
-       *scur = NULL;
-       return 0;
+       if (acur->len)
+               *stat = 1;
 
-out_use_search:
-       xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR);
-       *gcur = NULL;
        return 0;
+}
 
-error0:
-       /* caller invalidates cursors */
-       return error;
+/* Check the last block of the cnt btree for allocations. */
+static int
+xfs_alloc_ag_vextent_lastblock(
+       struct xfs_alloc_arg    *args,
+       struct xfs_alloc_cur    *acur,
+       xfs_agblock_t           *bno,
+       xfs_extlen_t            *len,
+       bool                    *allocated)
+{
+       int                     error;
+       int                     i;
+
+#ifdef DEBUG
+       /* Randomly don't execute the first algorithm. */
+       if (prandom_u32() & 1)
+               return 0;
+#endif
+
+       /*
+        * Start from the entry that lookup found, sequence through all larger
+        * free blocks.  If we're actually pointing at a record smaller than
+        * maxlen, go to the start of this block, and skip all those smaller
+        * than minlen.
+        */
+       if (len || args->alignment > 1) {
+               acur->cnt->bc_ptrs[0] = 1;
+               do {
+                       error = xfs_alloc_get_rec(acur->cnt, bno, len, &i);
+                       if (error)
+                               return error;
+                       if (XFS_IS_CORRUPT(args->mp, i != 1))
+                               return -EFSCORRUPTED;
+                       if (*len >= args->minlen)
+                               break;
+                       error = xfs_btree_increment(acur->cnt, 0, &i);
+                       if (error)
+                               return error;
+               } while (i);
+               ASSERT(*len >= args->minlen);
+               if (!i)
+                       return 0;
+       }
+
+       error = xfs_alloc_walk_iter(args, acur, acur->cnt, true, false, -1, &i);
+       if (error)
+               return error;
+
+       /*
+        * It didn't work.  We COULD be in a case where there's a good record
+        * somewhere, so try again.
+        */
+       if (acur->len == 0)
+               return 0;
+
+       trace_xfs_alloc_near_first(args);
+       *allocated = true;
+       return 0;
 }
 
 /*
@@ -1084,41 +1556,17 @@ error0:
  * and of the form k * prod + mod unless there's nothing that large.
  * Return the starting a.g. block, or NULLAGBLOCK if we can't do it.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_alloc_ag_vextent_near(
-       xfs_alloc_arg_t *args)          /* allocation argument structure */
+       struct xfs_alloc_arg    *args)
 {
-       xfs_btree_cur_t *bno_cur_gt;    /* cursor for bno btree, right side */
-       xfs_btree_cur_t *bno_cur_lt;    /* cursor for bno btree, left side */
-       xfs_btree_cur_t *cnt_cur;       /* cursor for count btree */
-       xfs_agblock_t   gtbno;          /* start bno of right side entry */
-       xfs_agblock_t   gtbnoa;         /* aligned ... */
-       xfs_extlen_t    gtdiff;         /* difference to right side entry */
-       xfs_extlen_t    gtlen;          /* length of right side entry */
-       xfs_extlen_t    gtlena;         /* aligned ... */
-       xfs_agblock_t   gtnew;          /* useful start bno of right side */
-       int             error;          /* error code */
-       int             i;              /* result code, temporary */
-       int             j;              /* result code, temporary */
-       xfs_agblock_t   ltbno;          /* start bno of left side entry */
-       xfs_agblock_t   ltbnoa;         /* aligned ... */
-       xfs_extlen_t    ltdiff;         /* difference to left side entry */
-       xfs_extlen_t    ltlen;          /* length of left side entry */
-       xfs_extlen_t    ltlena;         /* aligned ... */
-       xfs_agblock_t   ltnew;          /* useful start bno of left side */
-       xfs_extlen_t    rlen;           /* length of returned extent */
-       bool            busy;
-       unsigned        busy_gen;
-#ifdef DEBUG
-       /*
-        * Randomly don't execute the first algorithm.
-        */
-       int             dofirst;        /* set to do first algorithm */
-
-       dofirst = prandom_u32() & 1;
-#endif
+       struct xfs_alloc_cur    acur = {};
+       int                     error;          /* error code */
+       int                     i;              /* result code, temporary */
+       xfs_agblock_t           bno;
+       xfs_extlen_t            len;
 
-       /* handle unitialized agbno range so caller doesn't have to */
+       /* handle uninitialized agbno range so caller doesn't have to */
        if (!args->min_agbno && !args->max_agbno)
                args->max_agbno = args->mp->m_sb.sb_agblocks - 1;
        ASSERT(args->min_agbno <= args->max_agbno);
@@ -1130,40 +1578,27 @@ xfs_alloc_ag_vextent_near(
                args->agbno = args->max_agbno;
 
 restart:
-       bno_cur_lt = NULL;
-       bno_cur_gt = NULL;
-       ltlen = 0;
-       gtlena = 0;
-       ltlena = 0;
-       busy = false;
-
-       /*
-        * Get a cursor for the by-size btree.
-        */
-       cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT);
+       len = 0;
 
        /*
-        * See if there are any free extents as big as maxlen.
+        * Set up cursors and see if there are any free extents as big as
+        * maxlen. If not, pick the last entry in the tree unless the tree is
+        * empty.
         */
-       if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i)))
-               goto error0;
-       /*
-        * If none, then pick up the last entry in the tree unless the
-        * tree is empty.
-        */
-       if (!i) {
-               if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &ltbno,
-                               &ltlen, &i)))
-                       goto error0;
-               if (i == 0 || ltlen == 0) {
-                       xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
+       error = xfs_alloc_cur_setup(args, &acur);
+       if (error == -ENOSPC) {
+               error = xfs_alloc_ag_vextent_small(args, acur.cnt, &bno,
+                               &len, &i);
+               if (error)
+                       goto out;
+               if (i == 0 || len == 0) {
                        trace_xfs_alloc_near_noentry(args);
-                       return 0;
+                       goto out;
                }
                ASSERT(i == 1);
+       } else if (error) {
+               goto out;
        }
-       args->wasfromfl = 0;
 
        /*
         * First algorithm.
@@ -1172,311 +1607,47 @@ restart:
         * near the right edge of the tree.  If it's in the last btree leaf
         * block, then we just examine all the entries in that block
         * that are big enough, and pick the best one.
-        * This is written as a while loop so we can break out of it,
-        * but we never loop back to the top.
         */
-       while (xfs_btree_islastblock(cnt_cur, 0)) {
-               xfs_extlen_t    bdiff;
-               int             besti=0;
-               xfs_extlen_t    blen=0;
-               xfs_agblock_t   bnew=0;
-
-#ifdef DEBUG
-               if (dofirst)
-                       break;
-#endif
-               /*
-                * Start from the entry that lookup found, sequence through
-                * all larger free blocks.  If we're actually pointing at a
-                * record smaller than maxlen, go to the start of this block,
-                * and skip all those smaller than minlen.
-                */
-               if (ltlen || args->alignment > 1) {
-                       cnt_cur->bc_ptrs[0] = 1;
-                       do {
-                               if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno,
-                                               &ltlen, &i)))
-                                       goto error0;
-                               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-                               if (ltlen >= args->minlen)
-                                       break;
-                               if ((error = xfs_btree_increment(cnt_cur, 0, &i)))
-                                       goto error0;
-                       } while (i);
-                       ASSERT(ltlen >= args->minlen);
-                       if (!i)
-                               break;
-               }
-               i = cnt_cur->bc_ptrs[0];
-               for (j = 1, blen = 0, bdiff = 0;
-                    !error && j && (blen < args->maxlen || bdiff > 0);
-                    error = xfs_btree_increment(cnt_cur, 0, &j)) {
-                       /*
-                        * For each entry, decide if it's better than
-                        * the previous best entry.
-                        */
-                       if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
-                               goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-                       busy = xfs_alloc_compute_aligned(args, ltbno, ltlen,
-                                       &ltbnoa, &ltlena, &busy_gen);
-                       if (ltlena < args->minlen)
-                               continue;
-                       if (ltbnoa < args->min_agbno || ltbnoa > args->max_agbno)
-                               continue;
-                       args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
-                       xfs_alloc_fix_len(args);
-                       ASSERT(args->len >= args->minlen);
-                       if (args->len < blen)
-                               continue;
-                       ltdiff = xfs_alloc_compute_diff(args->agbno, args->len,
-                               args->alignment, args->datatype, ltbnoa,
-                               ltlena, &ltnew);
-                       if (ltnew != NULLAGBLOCK &&
-                           (args->len > blen || ltdiff < bdiff)) {
-                               bdiff = ltdiff;
-                               bnew = ltnew;
-                               blen = args->len;
-                               besti = cnt_cur->bc_ptrs[0];
-                       }
-               }
-               /*
-                * It didn't work.  We COULD be in a case where
-                * there's a good record somewhere, so try again.
-                */
-               if (blen == 0)
-                       break;
-               /*
-                * Point at the best entry, and retrieve it again.
-                */
-               cnt_cur->bc_ptrs[0] = besti;
-               if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
-                       goto error0;
-               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-               ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
-               args->len = blen;
-
-               /*
-                * We are allocating starting at bnew for blen blocks.
-                */
-               args->agbno = bnew;
-               ASSERT(bnew >= ltbno);
-               ASSERT(bnew + blen <= ltbno + ltlen);
-               /*
-                * Set up a cursor for the by-bno tree.
-                */
-               bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp,
-                       args->agbp, args->agno, XFS_BTNUM_BNO);
-               /*
-                * Fix up the btree entries.
-                */
-               if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno,
-                               ltlen, bnew, blen, XFSA_FIXUP_CNT_OK)))
-                       goto error0;
-               xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
-               xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);
+       if (xfs_btree_islastblock(acur.cnt, 0)) {
+               bool            allocated = false;
 
-               trace_xfs_alloc_near_first(args);
-               return 0;
-       }
-       /*
-        * Second algorithm.
-        * Search in the by-bno tree to the left and to the right
-        * simultaneously, until in each case we find a space big enough,
-        * or run into the edge of the tree.  When we run into the edge,
-        * we deallocate that cursor.
-        * If both searches succeed, we compare the two spaces and pick
-        * the better one.
-        * With alignment, it's possible for both to fail; the upper
-        * level algorithm that picks allocation groups for allocations
-        * is not supposed to do this.
-        */
-       /*
-        * Allocate and initialize the cursor for the leftward search.
-        */
-       bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO);
-       /*
-        * Lookup <= bno to find the leftward search's starting point.
-        */
-       if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i)))
-               goto error0;
-       if (!i) {
-               /*
-                * Didn't find anything; use this cursor for the rightward
-                * search.
-                */
-               bno_cur_gt = bno_cur_lt;
-               bno_cur_lt = NULL;
-       }
-       /*
-        * Found something.  Duplicate the cursor for the rightward search.
-        */
-       else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt)))
-               goto error0;
-       /*
-        * Increment the cursor, so we will point at the entry just right
-        * of the leftward entry if any, or to the leftmost entry.
-        */
-       if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
-               goto error0;
-       if (!i) {
-               /*
-                * It failed, there are no rightward entries.
-                */
-               xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR);
-               bno_cur_gt = NULL;
+               error = xfs_alloc_ag_vextent_lastblock(args, &acur, &bno, &len,
+                               &allocated);
+               if (error)
+                       goto out;
+               if (allocated)
+                       goto alloc_finish;
        }
-       /*
-        * Loop going left with the leftward cursor, right with the
-        * rightward cursor, until either both directions give up or
-        * we find an entry at least as big as minlen.
-        */
-       do {
-               if (bno_cur_lt) {
-                       if ((error = xfs_alloc_get_rec(bno_cur_lt, &ltbno, &ltlen, &i)))
-                               goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-                       busy |= xfs_alloc_compute_aligned(args, ltbno, ltlen,
-                                       &ltbnoa, &ltlena, &busy_gen);
-                       if (ltlena >= args->minlen && ltbnoa >= args->min_agbno)
-                               break;
-                       if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i)))
-                               goto error0;
-                       if (!i || ltbnoa < args->min_agbno) {
-                               xfs_btree_del_cursor(bno_cur_lt,
-                                                    XFS_BTREE_NOERROR);
-                               bno_cur_lt = NULL;
-                       }
-               }
-               if (bno_cur_gt) {
-                       if ((error = xfs_alloc_get_rec(bno_cur_gt, &gtbno, &gtlen, &i)))
-                               goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-                       busy |= xfs_alloc_compute_aligned(args, gtbno, gtlen,
-                                       &gtbnoa, &gtlena, &busy_gen);
-                       if (gtlena >= args->minlen && gtbnoa <= args->max_agbno)
-                               break;
-                       if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
-                               goto error0;
-                       if (!i || gtbnoa > args->max_agbno) {
-                               xfs_btree_del_cursor(bno_cur_gt,
-                                                    XFS_BTREE_NOERROR);
-                               bno_cur_gt = NULL;
-                       }
-               }
-       } while (bno_cur_lt || bno_cur_gt);
 
        /*
-        * Got both cursors still active, need to find better entry.
+        * Second algorithm. Combined cntbt and bnobt search to find ideal
+        * locality.
         */
-       if (bno_cur_lt && bno_cur_gt) {
-               if (ltlena >= args->minlen) {
-                       /*
-                        * Left side is good, look for a right side entry.
-                        */
-                       args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
-                       xfs_alloc_fix_len(args);
-                       ltdiff = xfs_alloc_compute_diff(args->agbno, args->len,
-                               args->alignment, args->datatype, ltbnoa,
-                               ltlena, &ltnew);
-
-                       error = xfs_alloc_find_best_extent(args,
-                                               &bno_cur_lt, &bno_cur_gt,
-                                               ltdiff, &gtbno, &gtlen,
-                                               &gtbnoa, &gtlena,
-                                               0 /* search right */);
-               } else {
-                       ASSERT(gtlena >= args->minlen);
-
-                       /*
-                        * Right side is good, look for a left side entry.
-                        */
-                       args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen);
-                       xfs_alloc_fix_len(args);
-                       gtdiff = xfs_alloc_compute_diff(args->agbno, args->len,
-                               args->alignment, args->datatype, gtbnoa,
-                               gtlena, &gtnew);
-
-                       error = xfs_alloc_find_best_extent(args,
-                                               &bno_cur_gt, &bno_cur_lt,
-                                               gtdiff, &ltbno, &ltlen,
-                                               &ltbnoa, &ltlena,
-                                               1 /* search left */);
-               }
-
-               if (error)
-                       goto error0;
-       }
+       error = xfs_alloc_ag_vextent_locality(args, &acur, &i);
+       if (error)
+               goto out;
 
        /*
         * If we couldn't get anything, give up.
         */
-       if (bno_cur_lt == NULL && bno_cur_gt == NULL) {
-               xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
-
-               if (busy) {
+       if (!acur.len) {
+               if (acur.busy) {
                        trace_xfs_alloc_near_busy(args);
-                       xfs_extent_busy_flush(args->mp, args->pag, busy_gen);
+                       xfs_extent_busy_flush(args->mp, args->pag,
+                                             acur.busy_gen);
                        goto restart;
                }
                trace_xfs_alloc_size_neither(args);
                args->agbno = NULLAGBLOCK;
-               return 0;
+               goto out;
        }
 
-       /*
-        * At this point we have selected a freespace entry, either to the
-        * left or to the right.  If it's on the right, copy all the
-        * useful variables to the "left" set so we only have one
-        * copy of this code.
-        */
-       if (bno_cur_gt) {
-               bno_cur_lt = bno_cur_gt;
-               bno_cur_gt = NULL;
-               ltbno = gtbno;
-               ltbnoa = gtbnoa;
-               ltlen = gtlen;
-               ltlena = gtlena;
-               j = 1;
-       } else
-               j = 0;
-
-       /*
-        * Fix up the length and compute the useful address.
-        */
-       args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
-       xfs_alloc_fix_len(args);
-       rlen = args->len;
-       (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment,
-                                    args->datatype, ltbnoa, ltlena, &ltnew);
-       ASSERT(ltnew >= ltbno);
-       ASSERT(ltnew + rlen <= ltbnoa + ltlena);
-       ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
-       ASSERT(ltnew >= args->min_agbno && ltnew <= args->max_agbno);
-       args->agbno = ltnew;
-
-       if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen,
-                       ltnew, rlen, XFSA_FIXUP_BNO_OK)))
-               goto error0;
-
-       if (j)
-               trace_xfs_alloc_near_greater(args);
-       else
-               trace_xfs_alloc_near_lesser(args);
-
-       xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
-       xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);
-       return 0;
+alloc_finish:
+       /* fix up btrees on a successful allocation */
+       error = xfs_alloc_cur_finish(args, &acur);
 
- error0:
-       trace_xfs_alloc_near_error(args);
-       if (cnt_cur != NULL)
-               xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR);
-       if (bno_cur_lt != NULL)
-               xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR);
-       if (bno_cur_gt != NULL)
-               xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR);
+out:
+       xfs_alloc_cur_close(&acur, error);
        return error;
 }
 
@@ -1545,7 +1716,10 @@ restart:
                        error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i);
                        if (error)
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
+                       if (XFS_IS_CORRUPT(args->mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
 
                        busy = xfs_alloc_compute_aligned(args, fbno, flen,
                                        &rbno, &rlen, &busy_gen);
@@ -1579,8 +1753,13 @@ restart:
         * This can't happen in the second case above.
         */
        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
-       XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 ||
-                       (rlen <= flen && rbno + rlen <= fbno + flen), error0);
+       if (XFS_IS_CORRUPT(args->mp,
+                          rlen != 0 &&
+                          (rlen > flen ||
+                           rbno + rlen > fbno + flen))) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        if (rlen < args->maxlen) {
                xfs_agblock_t   bestfbno;
                xfs_extlen_t    bestflen;
@@ -1599,15 +1778,22 @@ restart:
                        if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen,
                                        &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
+                       if (XFS_IS_CORRUPT(args->mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
                        if (flen < bestrlen)
                                break;
                        busy = xfs_alloc_compute_aligned(args, fbno, flen,
                                        &rbno, &rlen, &busy_gen);
                        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
-                       XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 ||
-                               (rlen <= flen && rbno + rlen <= fbno + flen),
-                               error0);
+                       if (XFS_IS_CORRUPT(args->mp,
+                                          rlen != 0 &&
+                                          (rlen > flen ||
+                                           rbno + rlen > fbno + flen))) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
                        if (rlen > bestrlen) {
                                bestrlen = rlen;
                                bestrbno = rbno;
@@ -1620,7 +1806,10 @@ restart:
                if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen,
                                &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(args->mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                rlen = bestrlen;
                rbno = bestrbno;
                flen = bestflen;
@@ -1643,7 +1832,10 @@ restart:
        xfs_alloc_fix_len(args);
 
        rlen = args->len;
-       XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0);
+       if (XFS_IS_CORRUPT(args->mp, rlen > flen)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        /*
         * Allocate and initialize a cursor for the by-block tree.
         */
@@ -1657,10 +1849,13 @@ restart:
        cnt_cur = bno_cur = NULL;
        args->len = rlen;
        args->agbno = rbno;
-       XFS_WANT_CORRUPTED_GOTO(args->mp,
-               args->agbno + args->len <=
-                       be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),
-               error0);
+       if (XFS_IS_CORRUPT(args->mp,
+                          args->agbno + args->len >
+                          be32_to_cpu(
+                                  XFS_BUF_TO_AGF(args->agbp)->agf_length))) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        trace_xfs_alloc_size_done(args);
        return 0;
 
@@ -1732,7 +1927,10 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_get_rec(bno_cur, &ltbno, &ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * It's not contiguous, though.
                 */
@@ -1744,8 +1942,10 @@ xfs_free_ag_extent(
                         * space was invalid, it's (partly) already free.
                         * Very bad.
                         */
-                       XFS_WANT_CORRUPTED_GOTO(mp,
-                                               ltbno + ltlen <= bno, error0);
+                       if (XFS_IS_CORRUPT(mp, ltbno + ltlen > bno)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
                }
        }
        /*
@@ -1760,7 +1960,10 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_get_rec(bno_cur, &gtbno, &gtlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * It's not contiguous, though.
                 */
@@ -1772,7 +1975,10 @@ xfs_free_ag_extent(
                         * space was invalid, it's (partly) already free.
                         * Very bad.
                         */
-                       XFS_WANT_CORRUPTED_GOTO(mp, gtbno >= bno + len, error0);
+                       if (XFS_IS_CORRUPT(mp, bno + len > gtbno)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
                }
        }
        /*
@@ -1789,31 +1995,49 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * Delete the old by-size entry on the right.
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * Delete the old by-block entry for the right block.
                 */
                if ((error = xfs_btree_delete(bno_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * Move the by-block cursor back to the left neighbor.
                 */
                if ((error = xfs_btree_decrement(bno_cur, 0, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 #ifdef DEBUG
                /*
                 * Check that this is the right record: delete didn't
@@ -1826,9 +2050,13 @@ xfs_free_ag_extent(
                        if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen,
                                        &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(mp,
-                               i == 1 && xxbno == ltbno && xxlen == ltlen,
-                               error0);
+                       if (XFS_IS_CORRUPT(mp,
+                                          i != 1 ||
+                                          xxbno != ltbno ||
+                                          xxlen != ltlen)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
                }
 #endif
                /*
@@ -1849,17 +2077,26 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * Back up the by-block cursor to the left neighbor, and
                 * update its length.
                 */
                if ((error = xfs_btree_decrement(bno_cur, 0, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                nbno = ltbno;
                nlen = len + ltlen;
                if ((error = xfs_alloc_update(bno_cur, nbno, nlen)))
@@ -1875,10 +2112,16 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                /*
                 * Update the starting block and length of the right
                 * neighbor in the by-block tree.
@@ -1897,7 +2140,10 @@ xfs_free_ag_extent(
                nlen = len;
                if ((error = xfs_btree_insert(bno_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
        }
        xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR);
        bno_cur = NULL;
@@ -1906,10 +2152,16 @@ xfs_free_ag_extent(
         */
        if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i)))
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, error0);
+       if (XFS_IS_CORRUPT(mp, i != 0)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        if ((error = xfs_btree_insert(cnt_cur, &i)))
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
        cnt_cur = NULL;
 
@@ -1989,7 +2241,8 @@ xfs_alloc_longest_free_extent(
         * reservations and AGFL rules in place, we can return this extent.
         */
        if (pag->pagf_longest > delta)
-               return pag->pagf_longest - delta;
+               return min_t(xfs_extlen_t, pag->pag_mount->m_ag_max_usable,
+                               pag->pagf_longest - delta);
 
        /* Otherwise, let the caller try for 1 block if there's space. */
        return pag->pagf_flcount > 0 || pag->pagf_longest > 0;
@@ -2087,7 +2340,7 @@ xfs_free_agfl_block(
                return error;
 
        bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno);
-       if (!bp)
+       if (XFS_IS_CORRUPT(tp->t_mountp, !bp))
                return -EFSCORRUPTED;
        xfs_trans_binval(tp, bp);
 
@@ -2253,7 +2506,7 @@ xfs_alloc_fix_freelist(
         * somewhere else if we are not being asked to try harder at this
         * point
         */
-       if (pag->pagf_metadata && xfs_alloc_is_userdata(args->datatype) &&
+       if (pag->pagf_metadata && (args->datatype & XFS_ALLOC_USERDATA) &&
            (flags & XFS_ALLOC_FLAG_TRYLOCK)) {
                ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
                goto out_agbp_relse;
@@ -2956,13 +3209,6 @@ xfs_alloc_vextent(
                        args->len);
 #endif
 
-               /* Zero the extent if we were asked to do so */
-               if (args->datatype & XFS_ALLOC_USERDATA_ZERO) {
-                       error = xfs_zero_extent(args->ip, args->fsbno, args->len);
-                       if (error)
-                               goto error0;
-               }
-
        }
        xfs_perag_put(args->pag);
        return 0;
@@ -3038,12 +3284,18 @@ __xfs_free_extent(
        if (error)
                return error;
 
-       XFS_WANT_CORRUPTED_GOTO(mp, agbno < mp->m_sb.sb_agblocks, err);
+       if (XFS_IS_CORRUPT(mp, agbno >= mp->m_sb.sb_agblocks)) {
+               error = -EFSCORRUPTED;
+               goto err;
+       }
 
        /* validate the extent size is legal now we have the agf locked */
-       XFS_WANT_CORRUPTED_GOTO(mp,
-               agbno + len <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length),
-                               err);
+       if (XFS_IS_CORRUPT(mp,
+                          agbno + len >
+                          be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length))) {
+               error = -EFSCORRUPTED;
+               goto err;
+       }
 
        error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type);
        if (error)
index d6ed5d2..7380fbe 100644 (file)
@@ -54,7 +54,6 @@ typedef struct xfs_alloc_arg {
        struct xfs_mount *mp;           /* file system mount point */
        struct xfs_buf  *agbp;          /* buffer for a.g. freelist header */
        struct xfs_perag *pag;          /* per-ag struct for this agno */
-       struct xfs_inode *ip;           /* for userdata zeroing method */
        xfs_fsblock_t   fsbno;          /* file system block number */
        xfs_agnumber_t  agno;           /* allocation group number */
        xfs_agblock_t   agbno;          /* allocation group-relative block # */
@@ -83,20 +82,7 @@ typedef struct xfs_alloc_arg {
  */
 #define XFS_ALLOC_USERDATA             (1 << 0)/* allocation is for user data*/
 #define XFS_ALLOC_INITIAL_USER_DATA    (1 << 1)/* special case start of file */
-#define XFS_ALLOC_USERDATA_ZERO                (1 << 2)/* zero extent on allocation */
-#define XFS_ALLOC_NOBUSY               (1 << 3)/* Busy extents not allowed */
-
-static inline bool
-xfs_alloc_is_userdata(int datatype)
-{
-       return (datatype & ~XFS_ALLOC_NOBUSY) != 0;
-}
-
-static inline bool
-xfs_alloc_allow_busy_reuse(int datatype)
-{
-       return (datatype & XFS_ALLOC_NOBUSY) == 0;
-}
+#define XFS_ALLOC_NOBUSY               (1 << 2)/* Busy extents not allowed */
 
 /* freespace limit calculations */
 #define XFS_ALLOC_AGFL_RESERVE 4
index 2a94543..279694d 100644 (file)
@@ -507,6 +507,7 @@ xfs_allocbt_init_cursor(
 
        cur->bc_private.a.agbp = agbp;
        cur->bc_private.a.agno = agno;
+       cur->bc_private.a.priv.abt.active = false;
 
        if (xfs_sb_version_hascrc(&mp->m_sb))
                cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
index 510ca69..0d7fcc9 100644 (file)
@@ -589,7 +589,7 @@ xfs_attr_leaf_addname(
         */
        dp = args->dp;
        args->blkno = 0;
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
        if (error)
                return error;
 
@@ -715,7 +715,7 @@ xfs_attr_leaf_addname(
                 * remove the "old" attr from that block (neat, huh!)
                 */
                error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-                                          -1, &bp);
+                                          &bp);
                if (error)
                        return error;
 
@@ -769,7 +769,7 @@ xfs_attr_leaf_removename(
         */
        dp = args->dp;
        args->blkno = 0;
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
        if (error)
                return error;
 
@@ -813,7 +813,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
        trace_xfs_attr_leaf_get(args);
 
        args->blkno = 0;
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
        if (error)
                return error;
 
@@ -1173,7 +1173,7 @@ xfs_attr_node_removename(
                ASSERT(state->path.blk[0].bp);
                state->path.blk[0].bp = NULL;
 
-               error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
+               error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
                if (error)
                        goto out;
 
@@ -1266,10 +1266,9 @@ xfs_attr_refillstate(xfs_da_state_t *state)
        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
                if (blk->disk_blkno) {
-                       error = xfs_da3_node_read(state->args->trans,
-                                               state->args->dp,
-                                               blk->blkno, blk->disk_blkno,
-                                               &blk->bp, XFS_ATTR_FORK);
+                       error = xfs_da3_node_read_mapped(state->args->trans,
+                                       state->args->dp, blk->disk_blkno,
+                                       &blk->bp, XFS_ATTR_FORK);
                        if (error)
                                return error;
                } else {
@@ -1285,10 +1284,9 @@ xfs_attr_refillstate(xfs_da_state_t *state)
        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
                if (blk->disk_blkno) {
-                       error = xfs_da3_node_read(state->args->trans,
-                                               state->args->dp,
-                                               blk->blkno, blk->disk_blkno,
-                                               &blk->bp, XFS_ATTR_FORK);
+                       error = xfs_da3_node_read_mapped(state->args->trans,
+                                       state->args->dp, blk->disk_blkno,
+                                       &blk->bp, XFS_ATTR_FORK);
                        if (error)
                                return error;
                } else {
index f0089e8..08d4b10 100644 (file)
@@ -232,6 +232,61 @@ xfs_attr3_leaf_hdr_to_disk(
        }
 }
 
+static xfs_failaddr_t
+xfs_attr3_leaf_verify_entry(
+       struct xfs_mount                        *mp,
+       char                                    *buf_end,
+       struct xfs_attr_leafblock               *leaf,
+       struct xfs_attr3_icleaf_hdr             *leafhdr,
+       struct xfs_attr_leaf_entry              *ent,
+       int                                     idx,
+       __u32                                   *last_hashval)
+{
+       struct xfs_attr_leaf_name_local         *lentry;
+       struct xfs_attr_leaf_name_remote        *rentry;
+       char                                    *name_end;
+       unsigned int                            nameidx;
+       unsigned int                            namesize;
+       __u32                                   hashval;
+
+       /* hash order check */
+       hashval = be32_to_cpu(ent->hashval);
+       if (hashval < *last_hashval)
+               return __this_address;
+       *last_hashval = hashval;
+
+       nameidx = be16_to_cpu(ent->nameidx);
+       if (nameidx < leafhdr->firstused || nameidx >= mp->m_attr_geo->blksize)
+               return __this_address;
+
+       /*
+        * Check the name information.  The namelen fields are u8 so we can't
+        * possibly exceed the maximum name length of 255 bytes.
+        */
+       if (ent->flags & XFS_ATTR_LOCAL) {
+               lentry = xfs_attr3_leaf_name_local(leaf, idx);
+               namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
+                               be16_to_cpu(lentry->valuelen));
+               name_end = (char *)lentry + namesize;
+               if (lentry->namelen == 0)
+                       return __this_address;
+       } else {
+               rentry = xfs_attr3_leaf_name_remote(leaf, idx);
+               namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
+               name_end = (char *)rentry + namesize;
+               if (rentry->namelen == 0)
+                       return __this_address;
+               if (!(ent->flags & XFS_ATTR_INCOMPLETE) &&
+                   rentry->valueblk == 0)
+                       return __this_address;
+       }
+
+       if (name_end > buf_end)
+               return __this_address;
+
+       return NULL;
+}
+
 static xfs_failaddr_t
 xfs_attr3_leaf_verify(
        struct xfs_buf                  *bp)
@@ -240,7 +295,10 @@ xfs_attr3_leaf_verify(
        struct xfs_mount                *mp = bp->b_mount;
        struct xfs_attr_leafblock       *leaf = bp->b_addr;
        struct xfs_attr_leaf_entry      *entries;
+       struct xfs_attr_leaf_entry      *ent;
+       char                            *buf_end;
        uint32_t                        end;    /* must be 32bit - see below */
+       __u32                           last_hashval = 0;
        int                             i;
        xfs_failaddr_t                  fa;
 
@@ -273,8 +331,13 @@ xfs_attr3_leaf_verify(
            (char *)bp->b_addr + ichdr.firstused)
                return __this_address;
 
-       /* XXX: need to range check rest of attr header values */
-       /* XXX: hash order check? */
+       buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
+       for (i = 0, ent = entries; i < ichdr.count; ent++, i++) {
+               fa = xfs_attr3_leaf_verify_entry(mp, buf_end, leaf, &ichdr,
+                               ent, i, &last_hashval);
+               if (fa)
+                       return fa;
+       }
 
        /*
         * Quickly check the freemap information.  Attribute data has to be
@@ -367,13 +430,12 @@ xfs_attr3_leaf_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
-       xfs_daddr_t             mappedbno,
        struct xfs_buf          **bpp)
 {
        int                     err;
 
-       err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
-                               XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops);
+       err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK,
+                       &xfs_attr3_leaf_buf_ops);
        if (!err && tp && *bpp)
                xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
        return err;
@@ -453,13 +515,15 @@ xfs_attr_copy_value(
  * special case for dev/uuid inodes, they have fixed size data forks.
  */
 int
-xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
+xfs_attr_shortform_bytesfit(
+       struct xfs_inode        *dp,
+       int                     bytes)
 {
-       int offset;
-       int minforkoff; /* lower limit on valid forkoff locations */
-       int maxforkoff; /* upper limit on valid forkoff locations */
-       int dsize;
-       xfs_mount_t *mp = dp->i_mount;
+       struct xfs_mount        *mp = dp->i_mount;
+       int64_t                 dsize;
+       int                     minforkoff;
+       int                     maxforkoff;
+       int                     offset;
 
        /* rounded down */
        offset = (XFS_LITINO(mp, dp->i_d.di_version) - bytes) >> 3;
@@ -525,7 +589,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
         * A data fork btree root must have space for at least
         * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
         */
-       minforkoff = max(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
+       minforkoff = max_t(int64_t, dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
        minforkoff = roundup(minforkoff, 8) >> 3;
 
        /* attr fork btree root can have at least this many key/ptr pairs */
@@ -764,7 +828,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
 }
 
 /*
- * Retreive the attribute value and length.
+ * Retrieve the attribute value and length.
  *
  * If ATTR_KERNOVAL is specified, only the length needs to be returned.
  * Unlike a lookup, we only return an error if the attribute does not
@@ -924,7 +988,7 @@ xfs_attr_shortform_verify(
        char                            *endp;
        struct xfs_ifork                *ifp;
        int                             i;
-       int                             size;
+       int64_t                         size;
 
        ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL);
        ifp = XFS_IFORK_PTR(ip, XFS_ATTR_FORK);
@@ -1080,7 +1144,6 @@ xfs_attr3_leaf_to_node(
        struct xfs_attr_leafblock *leaf;
        struct xfs_attr3_icleaf_hdr icleafhdr;
        struct xfs_attr_leaf_entry *entries;
-       struct xfs_da_node_entry *btree;
        struct xfs_da3_icnode_hdr icnodehdr;
        struct xfs_da_intnode   *node;
        struct xfs_inode        *dp = args->dp;
@@ -1095,11 +1158,11 @@ xfs_attr3_leaf_to_node(
        error = xfs_da_grow_inode(args, &blkno);
        if (error)
                goto out;
-       error = xfs_attr3_leaf_read(args->trans, dp, 0, -1, &bp1);
+       error = xfs_attr3_leaf_read(args->trans, dp, 0, &bp1);
        if (error)
                goto out;
 
-       error = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp2, XFS_ATTR_FORK);
+       error = xfs_da_get_buf(args->trans, dp, blkno, &bp2, XFS_ATTR_FORK);
        if (error)
                goto out;
 
@@ -1120,18 +1183,17 @@ xfs_attr3_leaf_to_node(
        if (error)
                goto out;
        node = bp1->b_addr;
-       dp->d_ops->node_hdr_from_disk(&icnodehdr, node);
-       btree = dp->d_ops->node_tree_p(node);
+       xfs_da3_node_hdr_from_disk(mp, &icnodehdr, node);
 
        leaf = bp2->b_addr;
        xfs_attr3_leaf_hdr_from_disk(args->geo, &icleafhdr, leaf);
        entries = xfs_attr3_leaf_entryp(leaf);
 
        /* both on-disk, don't endian-flip twice */
-       btree[0].hashval = entries[icleafhdr.count - 1].hashval;
-       btree[0].before = cpu_to_be32(blkno);
+       icnodehdr.btree[0].hashval = entries[icleafhdr.count - 1].hashval;
+       icnodehdr.btree[0].before = cpu_to_be32(blkno);
        icnodehdr.count = 1;
-       dp->d_ops->node_hdr_to_disk(node, &icnodehdr);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node, &icnodehdr);
        xfs_trans_log_buf(args->trans, bp1, 0, args->geo->blksize - 1);
        error = 0;
 out:
@@ -1161,7 +1223,7 @@ xfs_attr3_leaf_create(
 
        trace_xfs_attr_leaf_create(args);
 
-       error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,
+       error = xfs_da_get_buf(args->trans, args->dp, blkno, &bp,
                                            XFS_ATTR_FORK);
        if (error)
                return error;
@@ -1447,7 +1509,9 @@ xfs_attr3_leaf_add_work(
        for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
                if (ichdr->freemap[i].base == tmp) {
                        ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t);
-                       ichdr->freemap[i].size -= sizeof(xfs_attr_leaf_entry_t);
+                       ichdr->freemap[i].size -=
+                               min_t(uint16_t, ichdr->freemap[i].size,
+                                               sizeof(xfs_attr_leaf_entry_t));
                }
        }
        ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
@@ -1931,7 +1995,7 @@ xfs_attr3_leaf_toosmall(
                if (blkno == 0)
                        continue;
                error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
-                                       blkno, -1, &bp);
+                                       blkno, &bp);
                if (error)
                        return error;
 
@@ -2281,8 +2345,10 @@ xfs_attr3_leaf_lookup_int(
        leaf = bp->b_addr;
        xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
        entries = xfs_attr3_leaf_entryp(leaf);
-       if (ichdr.count >= args->geo->blksize / 8)
+       if (ichdr.count >= args->geo->blksize / 8) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Binary search.  (note: small blocks will skip this loop)
@@ -2298,10 +2364,14 @@ xfs_attr3_leaf_lookup_int(
                else
                        break;
        }
-       if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count)))
+       if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
-       if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval))
+       }
+       if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Since we may have duplicate hashval's, find the first matching
@@ -2661,7 +2731,7 @@ xfs_attr3_leaf_clearflag(
        /*
         * Set up the operation.
         */
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
        if (error)
                return error;
 
@@ -2728,7 +2798,7 @@ xfs_attr3_leaf_setflag(
        /*
         * Set up the operation.
         */
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
        if (error)
                return error;
 
@@ -2790,7 +2860,7 @@ xfs_attr3_leaf_flipflags(
        /*
         * Read the block containing the "old" attr
         */
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp1);
        if (error)
                return error;
 
@@ -2799,7 +2869,7 @@ xfs_attr3_leaf_flipflags(
         */
        if (args->blkno2 != args->blkno) {
                error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
-                                          -1, &bp2);
+                                          &bp2);
                if (error)
                        return error;
        } else {
index 7b74e18..f4a188e 100644 (file)
@@ -16,6 +16,29 @@ struct xfs_da_state_blk;
 struct xfs_inode;
 struct xfs_trans;
 
+/*
+ * Incore version of the attribute leaf header.
+ */
+struct xfs_attr3_icleaf_hdr {
+       uint32_t        forw;
+       uint32_t        back;
+       uint16_t        magic;
+       uint16_t        count;
+       uint16_t        usedbytes;
+       /*
+        * Firstused is 32-bit here instead of 16-bit like the on-disk variant
+        * to support maximum fsb size of 64k without overflow issues throughout
+        * the attr code. Instead, the overflow condition is handled on
+        * conversion to/from disk.
+        */
+       uint32_t        firstused;
+       __u8            holes;
+       struct {
+               uint16_t        base;
+               uint16_t        size;
+       } freemap[XFS_ATTR_LEAF_MAPSIZE];
+};
+
 /*
  * Used to keep a list of "remote value" extents when unlinking an inode.
  */
@@ -67,8 +90,8 @@ int   xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
                                 struct xfs_da_args *args);
 int    xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer,
                                    struct xfs_da_args *args);
-void   xfs_attr3_leaf_list_int(struct xfs_buf *bp,
-                                     struct xfs_attr_list_context *context);
+int    xfs_attr3_leaf_list_int(struct xfs_buf *bp,
+                               struct xfs_attr_list_context *context);
 
 /*
  * Routines used for shrinking the Btree.
@@ -85,8 +108,7 @@ int  xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
                                   struct xfs_buf *leaf2_bp);
 int    xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
 int    xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
-                       xfs_dablk_t bno, xfs_daddr_t mappedbno,
-                       struct xfs_buf **bpp);
+                       xfs_dablk_t bno, struct xfs_buf **bpp);
 void   xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo,
                                     struct xfs_attr3_icleaf_hdr *to,
                                     struct xfs_attr_leafblock *from);
index 3e39b7d..a6ef5df 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_trans.h"
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
+#include "xfs_attr_remote.h"
 #include "xfs_trace.h"
 #include "xfs_error.h"
 
index 7071ff9..40ce5f3 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include "xfs.h"
 #include "xfs_log_format.h"
+#include "xfs_bit.h"
 
 /*
  * XFS bit manipulation routines, used in non-realtime code.
index ef75e22..4acc6e3 100644 (file)
@@ -384,8 +384,10 @@ xfs_bmap_check_leaf_extents(
                xfs_check_block(block, mp, 0, 0);
                pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
                bno = be64_to_cpu(*pp);
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                                       xfs_verify_fsbno(mp, bno), error0);
+               if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbno(mp, bno))) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if (bp_release) {
                        bp_release = 0;
                        xfs_trans_brelse(NULL, bp);
@@ -612,8 +614,8 @@ xfs_bmap_btree_to_extents(
        pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes);
        cbno = be64_to_cpu(*pp);
 #ifdef DEBUG
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
-                       xfs_btree_check_lptr(cur, cbno, 1));
+       if (XFS_IS_CORRUPT(cur->bc_mp, !xfs_btree_check_lptr(cur, cbno, 1)))
+               return -EFSCORRUPTED;
 #endif
        error = xfs_btree_read_bufl(mp, tp, cbno, &cbp, XFS_BMAP_BTREE_REF,
                                &xfs_bmbt_buf_ops);
@@ -729,7 +731,7 @@ xfs_bmap_extents_to_btree(
        ip->i_d.di_nblocks++;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
        abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
-       if (!abp) {
+       if (XFS_IS_CORRUPT(mp, !abp)) {
                error = -EFSCORRUPTED;
                goto out_unreserve_dquot;
        }
@@ -937,7 +939,10 @@ xfs_bmap_add_attrfork_btree(
                if (error)
                        goto error0;
                /* must be at least one entry */
-               XFS_WANT_CORRUPTED_GOTO(mp, stat == 1, error0);
+               if (XFS_IS_CORRUPT(mp, stat != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if ((error = xfs_btree_new_iroot(cur, flags, &stat)))
                        goto error0;
                if (stat == 0) {
@@ -1084,7 +1089,7 @@ xfs_bmap_add_attrfork(
                goto trans_cancel;
        if (XFS_IFORK_Q(ip))
                goto trans_cancel;
-       if (ip->i_d.di_anextents != 0) {
+       if (XFS_IS_CORRUPT(mp, ip->i_d.di_anextents != 0)) {
                error = -EFSCORRUPTED;
                goto trans_cancel;
        }
@@ -1155,6 +1160,65 @@ trans_cancel:
  * Internal and external extent tree search functions.
  */
 
+struct xfs_iread_state {
+       struct xfs_iext_cursor  icur;
+       xfs_extnum_t            loaded;
+};
+
+/* Stuff every bmbt record from this block into the incore extent map. */
+static int
+xfs_iread_bmbt_block(
+       struct xfs_btree_cur    *cur,
+       int                     level,
+       void                    *priv)
+{
+       struct xfs_iread_state  *ir = priv;
+       struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_inode        *ip = cur->bc_private.b.ip;
+       struct xfs_btree_block  *block;
+       struct xfs_buf          *bp;
+       struct xfs_bmbt_rec     *frp;
+       xfs_extnum_t            num_recs;
+       xfs_extnum_t            j;
+       int                     whichfork = cur->bc_private.b.whichfork;
+
+       block = xfs_btree_get_block(cur, level, &bp);
+
+       /* Abort if we find more records than nextents. */
+       num_recs = xfs_btree_get_numrecs(block);
+       if (unlikely(ir->loaded + num_recs >
+                    XFS_IFORK_NEXTENTS(ip, whichfork))) {
+               xfs_warn(ip->i_mount, "corrupt dinode %llu, (btree extents).",
+                               (unsigned long long)ip->i_ino);
+               xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block,
+                               sizeof(*block), __this_address);
+               return -EFSCORRUPTED;
+       }
+
+       /* Copy records into the incore cache. */
+       frp = XFS_BMBT_REC_ADDR(mp, block, 1);
+       for (j = 0; j < num_recs; j++, frp++, ir->loaded++) {
+               struct xfs_bmbt_irec    new;
+               xfs_failaddr_t          fa;
+
+               xfs_bmbt_disk_get_all(frp, &new);
+               fa = xfs_bmap_validate_extent(ip, whichfork, &new);
+               if (fa) {
+                       xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+                                       "xfs_iread_extents(2)", frp,
+                                       sizeof(*frp), fa);
+                       return -EFSCORRUPTED;
+               }
+               xfs_iext_insert(ip, &ir->icur, &new,
+                               xfs_bmap_fork_to_state(whichfork));
+               trace_xfs_read_extent(ip, &ir->icur,
+                               xfs_bmap_fork_to_state(whichfork), _THIS_IP_);
+               xfs_iext_next(XFS_IFORK_PTR(ip, whichfork), &ir->icur);
+       }
+
+       return 0;
+}
+
 /*
  * Read in extents from a btree-format inode.
  */
@@ -1164,134 +1228,39 @@ xfs_iread_extents(
        struct xfs_inode        *ip,
        int                     whichfork)
 {
-       struct xfs_mount        *mp = ip->i_mount;
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       struct xfs_iread_state  ir;
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
-       xfs_extnum_t            nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
-       struct xfs_btree_block  *block = ifp->if_broot;
-       struct xfs_iext_cursor  icur;
-       struct xfs_bmbt_irec    new;
-       xfs_fsblock_t           bno;
-       struct xfs_buf          *bp;
-       xfs_extnum_t            i, j;
-       int                     level;
-       __be64                  *pp;
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_btree_cur    *cur;
        int                     error;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-       if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
-               return -EFSCORRUPTED;
-       }
-
-       /*
-        * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
-        */
-       level = be16_to_cpu(block->bb_level);
-       if (unlikely(level == 0)) {
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
-               return -EFSCORRUPTED;
-       }
-       pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
-       bno = be64_to_cpu(*pp);
-
-       /*
-        * Go down the tree until leaf level is reached, following the first
-        * pointer (leftmost) at each level.
-        */
-       while (level-- > 0) {
-               error = xfs_btree_read_bufl(mp, tp, bno, &bp,
-                               XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
-               if (error)
-                       goto out;
-               block = XFS_BUF_TO_BLOCK(bp);
-               if (level == 0)
-                       break;
-               pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
-               bno = be64_to_cpu(*pp);
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                       xfs_verify_fsbno(mp, bno), out_brelse);
-               xfs_trans_brelse(tp, bp);
+       if (XFS_IS_CORRUPT(mp,
+                          XFS_IFORK_FORMAT(ip, whichfork) !=
+                          XFS_DINODE_FMT_BTREE)) {
+               error = -EFSCORRUPTED;
+               goto out;
        }
 
-       /*
-        * Here with bp and block set to the leftmost leaf node in the tree.
-        */
-       i = 0;
-       xfs_iext_first(ifp, &icur);
-
-       /*
-        * Loop over all leaf nodes.  Copy information to the extent records.
-        */
-       for (;;) {
-               xfs_bmbt_rec_t  *frp;
-               xfs_fsblock_t   nextbno;
-               xfs_extnum_t    num_recs;
-
-               num_recs = xfs_btree_get_numrecs(block);
-               if (unlikely(i + num_recs > nextents)) {
-                       xfs_warn(ip->i_mount,
-                               "corrupt dinode %Lu, (btree extents).",
-                               (unsigned long long) ip->i_ino);
-                       xfs_inode_verifier_error(ip, -EFSCORRUPTED,
-                                       __func__, block, sizeof(*block),
-                                       __this_address);
-                       error = -EFSCORRUPTED;
-                       goto out_brelse;
-               }
-               /*
-                * Read-ahead the next leaf block, if any.
-                */
-               nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
-               if (nextbno != NULLFSBLOCK)
-                       xfs_btree_reada_bufl(mp, nextbno, 1,
-                                            &xfs_bmbt_buf_ops);
-               /*
-                * Copy records into the extent records.
-                */
-               frp = XFS_BMBT_REC_ADDR(mp, block, 1);
-               for (j = 0; j < num_recs; j++, frp++, i++) {
-                       xfs_failaddr_t  fa;
-
-                       xfs_bmbt_disk_get_all(frp, &new);
-                       fa = xfs_bmap_validate_extent(ip, whichfork, &new);
-                       if (fa) {
-                               error = -EFSCORRUPTED;
-                               xfs_inode_verifier_error(ip, error,
-                                               "xfs_iread_extents(2)",
-                                               frp, sizeof(*frp), fa);
-                               goto out_brelse;
-                       }
-                       xfs_iext_insert(ip, &icur, &new, state);
-                       trace_xfs_read_extent(ip, &icur, state, _THIS_IP_);
-                       xfs_iext_next(ifp, &icur);
-               }
-               xfs_trans_brelse(tp, bp);
-               bno = nextbno;
-               /*
-                * If we've reached the end, stop.
-                */
-               if (bno == NULLFSBLOCK)
-                       break;
-               error = xfs_btree_read_bufl(mp, tp, bno, &bp,
-                               XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
-               if (error)
-                       goto out;
-               block = XFS_BUF_TO_BLOCK(bp);
-       }
+       ir.loaded = 0;
+       xfs_iext_first(ifp, &ir.icur);
+       cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
+       error = xfs_btree_visit_blocks(cur, xfs_iread_bmbt_block,
+                       XFS_BTREE_VISIT_RECORDS, &ir);
+       xfs_btree_del_cursor(cur, error);
+       if (error)
+               goto out;
 
-       if (i != XFS_IFORK_NEXTENTS(ip, whichfork)) {
+       if (XFS_IS_CORRUPT(mp,
+                          ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork))) {
                error = -EFSCORRUPTED;
                goto out;
        }
-       ASSERT(i == xfs_iext_count(ifp));
+       ASSERT(ir.loaded == xfs_iext_count(ifp));
 
        ifp->if_flags |= XFS_IFEXTENTS;
        return 0;
-
-out_brelse:
-       xfs_trans_brelse(tp, bp);
 out:
        xfs_iext_destroy(ifp);
        return error;
@@ -1318,8 +1287,7 @@ xfs_bmap_first_unused(
        xfs_fileoff_t           lowest, max;
        int                     error;
 
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE ||
-              XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ||
+       ASSERT(xfs_ifork_has_extents(ip, whichfork) ||
               XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
 
        if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
@@ -1375,7 +1343,8 @@ xfs_bmap_last_before(
        case XFS_DINODE_FMT_EXTENTS:
                break;
        default:
-               return -EIO;
+               ASSERT(0);
+               return -EFSCORRUPTED;
        }
 
        if (!(ifp->if_flags & XFS_IFEXTENTS)) {
@@ -1474,9 +1443,8 @@ xfs_bmap_last_offset(
        if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
                return 0;
 
-       if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
-              return -EIO;
+       if (XFS_IS_CORRUPT(ip->i_mount, !xfs_ifork_has_extents(ip, whichfork)))
+               return -EFSCORRUPTED;
 
        error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
        if (error || is_empty)
@@ -1653,15 +1621,24 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, &RIGHT, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_delete(bma->cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_decrement(bma->cur, 0, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(bma->cur, &LEFT);
                        if (error)
                                goto done;
@@ -1687,7 +1664,10 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(bma->cur, &LEFT);
                        if (error)
                                goto done;
@@ -1717,7 +1697,10 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, &RIGHT, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(bma->cur, &PREV);
                        if (error)
                                goto done;
@@ -1742,11 +1725,17 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_insert(bma->cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
                break;
 
@@ -1777,7 +1766,10 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(bma->cur, &LEFT);
                        if (error)
                                goto done;
@@ -1798,11 +1790,17 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_insert(bma->cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
 
                if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
@@ -1843,7 +1841,10 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(bma->cur, &RIGHT);
                        if (error)
                                goto done;
@@ -1875,11 +1876,17 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_insert(bma->cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
 
                if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
@@ -1955,11 +1962,17 @@ xfs_bmap_add_extent_delay_real(
                        error = xfs_bmbt_lookup_eq(bma->cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_insert(bma->cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
 
                if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
@@ -2153,19 +2166,34 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &RIGHT, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_delete(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_decrement(cur, 0, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_delete(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_decrement(cur, 0, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &LEFT);
                        if (error)
                                goto done;
@@ -2191,13 +2219,22 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &PREV, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_delete(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_decrement(cur, 0, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &LEFT);
                        if (error)
                                goto done;
@@ -2226,13 +2263,22 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &RIGHT, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_delete(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_decrement(cur, 0, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &PREV);
                        if (error)
                                goto done;
@@ -2255,7 +2301,10 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &PREV);
                        if (error)
                                goto done;
@@ -2285,7 +2334,10 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &PREV);
                        if (error)
                                goto done;
@@ -2319,14 +2371,20 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &PREV);
                        if (error)
                                goto done;
                        cur->bc_rec.b = *new;
                        if ((error = xfs_btree_insert(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
                break;
 
@@ -2353,7 +2411,10 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &PREV);
                        if (error)
                                goto done;
@@ -2387,17 +2448,26 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &PREV);
                        if (error)
                                goto done;
                        error = xfs_bmbt_lookup_eq(cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        if ((error = xfs_btree_insert(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
                break;
 
@@ -2431,7 +2501,10 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        /* new right extent - oldext */
                        error = xfs_bmbt_update(cur, &r[1]);
                        if (error)
@@ -2440,7 +2513,10 @@ xfs_bmap_add_extent_unwritten_real(
                        cur->bc_rec.b = PREV;
                        if ((error = xfs_btree_insert(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        /*
                         * Reset the cursor to the position of the new extent
                         * we are about to insert as we can't trust it after
@@ -2449,11 +2525,17 @@ xfs_bmap_add_extent_unwritten_real(
                        error = xfs_bmbt_lookup_eq(cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        /* new middle extent - newext */
                        if ((error = xfs_btree_insert(cur, &i)))
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
                break;
 
@@ -2736,15 +2818,24 @@ xfs_bmap_add_extent_hole_real(
                        error = xfs_bmbt_lookup_eq(cur, &right, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_delete(cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_decrement(cur, 0, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &left);
                        if (error)
                                goto done;
@@ -2770,7 +2861,10 @@ xfs_bmap_add_extent_hole_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &left);
                        if (error)
                                goto done;
@@ -2797,7 +2891,10 @@ xfs_bmap_add_extent_hole_real(
                        error = xfs_bmbt_lookup_eq(cur, &old, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_bmbt_update(cur, &right);
                        if (error)
                                goto done;
@@ -2820,11 +2917,17 @@ xfs_bmap_add_extent_hole_real(
                        error = xfs_bmbt_lookup_eq(cur, new, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+                       if (XFS_IS_CORRUPT(mp, i != 0)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                        error = xfs_btree_insert(cur, &i);
                        if (error)
                                goto done;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                }
                break;
        }
@@ -3059,7 +3162,7 @@ xfs_bmap_adjacent(
        mp = ap->ip->i_mount;
        nullfb = ap->tp->t_firstblock == NULLFSBLOCK;
        rt = XFS_IS_REALTIME_INODE(ap->ip) &&
-               xfs_alloc_is_userdata(ap->datatype);
+               (ap->datatype & XFS_ALLOC_USERDATA);
        fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp,
                                                        ap->tp->t_firstblock);
        /*
@@ -3412,7 +3515,7 @@ xfs_bmap_btalloc(
 
        if (ap->flags & XFS_BMAPI_COWFORK)
                align = xfs_get_cowextsz_hint(ap->ip);
-       else if (xfs_alloc_is_userdata(ap->datatype))
+       else if (ap->datatype & XFS_ALLOC_USERDATA)
                align = xfs_get_extsz_hint(ap->ip);
        if (align) {
                error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
@@ -3427,7 +3530,7 @@ xfs_bmap_btalloc(
        fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp,
                                                        ap->tp->t_firstblock);
        if (nullfb) {
-               if (xfs_alloc_is_userdata(ap->datatype) &&
+               if ((ap->datatype & XFS_ALLOC_USERDATA) &&
                    xfs_inode_is_filestream(ap->ip)) {
                        ag = xfs_filestream_lookup_ag(ap->ip);
                        ag = (ag != NULLAGNUMBER) ? ag : 0;
@@ -3467,7 +3570,7 @@ xfs_bmap_btalloc(
                 * enough for the request.  If one isn't found, then adjust
                 * the minimum allocation size to the largest space found.
                 */
-               if (xfs_alloc_is_userdata(ap->datatype) &&
+               if ((ap->datatype & XFS_ALLOC_USERDATA) &&
                    xfs_inode_is_filestream(ap->ip))
                        error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
                else
@@ -3501,13 +3604,11 @@ xfs_bmap_btalloc(
                        args.mod = args.prod - args.mod;
        }
        /*
-        * If we are not low on available data blocks, and the
-        * underlying logical volume manager is a stripe, and
-        * the file offset is zero then try to allocate data
-        * blocks on stripe unit boundary.
-        * NOTE: ap->aeof is only set if the allocation length
-        * is >= the stripe unit and the allocation offset is
-        * at the end of file.
+        * If we are not low on available data blocks, and the underlying
+        * logical volume manager is a stripe, and the file offset is zero then
+        * try to allocate data blocks on stripe unit boundary. NOTE: ap->aeof
+        * is only set if the allocation length is >= the stripe unit and the
+        * allocation offset is at the end of file.
         */
        if (!(ap->tp->t_flags & XFS_TRANS_LOWMODE) && ap->aeof) {
                if (!ap->offset) {
@@ -3515,9 +3616,11 @@ xfs_bmap_btalloc(
                        atype = args.type;
                        isaligned = 1;
                        /*
-                        * Adjust for alignment
+                        * Adjust minlen to try and preserve alignment if we
+                        * can't guarantee an aligned maxlen extent.
                         */
-                       if (blen > args.alignment && blen <= args.maxlen)
+                       if (blen > args.alignment &&
+                           blen <= args.maxlen + args.alignment)
                                args.minlen = blen - args.alignment;
                        args.minalignslop = 0;
                } else {
@@ -3555,8 +3658,6 @@ xfs_bmap_btalloc(
        args.wasdel = ap->wasdel;
        args.resv = XFS_AG_RESV_NONE;
        args.datatype = ap->datatype;
-       if (ap->datatype & XFS_ALLOC_USERDATA_ZERO)
-               args.ip = ap->ip;
 
        error = xfs_alloc_vextent(&args);
        if (error)
@@ -3641,20 +3742,6 @@ xfs_bmap_btalloc(
        return 0;
 }
 
-/*
- * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
- * It figures out where to ask the underlying allocator to put the new extent.
- */
-STATIC int
-xfs_bmap_alloc(
-       struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
-{
-       if (XFS_IS_REALTIME_INODE(ap->ip) &&
-           xfs_alloc_is_userdata(ap->datatype))
-               return xfs_bmap_rtalloc(ap);
-       return xfs_bmap_btalloc(ap);
-}
-
 /* Trim extent to fit a logical block range. */
 void
 xfs_trim_extent(
@@ -3816,11 +3903,8 @@ xfs_bmapi_read(
                           XFS_BMAPI_COWFORK)));
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED|XFS_ILOCK_EXCL));
 
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
@@ -4010,6 +4094,39 @@ out_unreserve_quota:
        return error;
 }
 
+static int
+xfs_bmap_alloc_userdata(
+       struct xfs_bmalloca     *bma)
+{
+       struct xfs_mount        *mp = bma->ip->i_mount;
+       int                     whichfork = xfs_bmapi_whichfork(bma->flags);
+       int                     error;
+
+       /*
+        * Set the data type being allocated. For the data fork, the first data
+        * in the file is treated differently to all other allocations. For the
+        * attribute fork, we only need to ensure the allocated range is not on
+        * the busy list.
+        */
+       bma->datatype = XFS_ALLOC_NOBUSY;
+       if (whichfork == XFS_DATA_FORK) {
+               bma->datatype |= XFS_ALLOC_USERDATA;
+               if (bma->offset == 0)
+                       bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
+
+               if (mp->m_dalign && bma->length >= mp->m_dalign) {
+                       error = xfs_bmap_isaeof(bma, whichfork);
+                       if (error)
+                               return error;
+               }
+
+               if (XFS_IS_REALTIME_INODE(bma->ip))
+                       return xfs_bmap_rtalloc(bma);
+       }
+
+       return xfs_bmap_btalloc(bma);
+}
+
 static int
 xfs_bmapi_allocate(
        struct xfs_bmalloca     *bma)
@@ -4029,7 +4146,8 @@ xfs_bmapi_allocate(
        if (bma->wasdel) {
                bma->length = (xfs_extlen_t)bma->got.br_blockcount;
                bma->offset = bma->got.br_startoff;
-               xfs_iext_peek_prev_extent(ifp, &bma->icur, &bma->prev);
+               if (!xfs_iext_peek_prev_extent(ifp, &bma->icur, &bma->prev))
+                       bma->prev.br_startoff = NULLFILEOFF;
        } else {
                bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN);
                if (!bma->eof)
@@ -4037,43 +4155,24 @@ xfs_bmapi_allocate(
                                        bma->got.br_startoff - bma->offset);
        }
 
-       /*
-        * Set the data type being allocated. For the data fork, the first data
-        * in the file is treated differently to all other allocations. For the
-        * attribute fork, we only need to ensure the allocated range is not on
-        * the busy list.
-        */
-       if (!(bma->flags & XFS_BMAPI_METADATA)) {
-               bma->datatype = XFS_ALLOC_NOBUSY;
-               if (whichfork == XFS_DATA_FORK) {
-                       if (bma->offset == 0)
-                               bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
-                       else
-                               bma->datatype |= XFS_ALLOC_USERDATA;
-               }
-               if (bma->flags & XFS_BMAPI_ZERO)
-                       bma->datatype |= XFS_ALLOC_USERDATA_ZERO;
-       }
+       if (bma->flags & XFS_BMAPI_CONTIG)
+               bma->minlen = bma->length;
+       else
+               bma->minlen = 1;
 
-       bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1;
+       if (bma->flags & XFS_BMAPI_METADATA)
+               error = xfs_bmap_btalloc(bma);
+       else
+               error = xfs_bmap_alloc_userdata(bma);
+       if (error || bma->blkno == NULLFSBLOCK)
+               return error;
 
-       /*
-        * Only want to do the alignment at the eof if it is userdata and
-        * allocation length is larger than a stripe unit.
-        */
-       if (mp->m_dalign && bma->length >= mp->m_dalign &&
-           !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {
-               error = xfs_bmap_isaeof(bma, whichfork);
+       if (bma->flags & XFS_BMAPI_ZERO) {
+               error = xfs_zero_extent(bma->ip, bma->blkno, bma->length);
                if (error)
                        return error;
        }
 
-       error = xfs_bmap_alloc(bma);
-       if (error)
-               return error;
-
-       if (bma->blkno == NULLFSBLOCK)
-               return 0;
        if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur)
                bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork);
        /*
@@ -4313,11 +4412,8 @@ xfs_bmapi_write(
        ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) !=
                        (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO));
 
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
@@ -4511,7 +4607,6 @@ xfs_bmapi_convert_delalloc(
        bma.wasdel = true;
        bma.offset = bma.got.br_startoff;
        bma.length = max_t(xfs_filblks_t, bma.got.br_blockcount, MAXEXTLEN);
-       bma.total = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK);
        bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork);
        if (whichfork == XFS_COW_FORK)
                bma.flags = XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC;
@@ -4584,11 +4679,8 @@ xfs_bmapi_remap(
        ASSERT((flags & (XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC)) !=
                        (XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC));
 
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT("xfs_bmapi_remap", XFS_ERRLEVEL_LOW, mp);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
@@ -5019,7 +5111,10 @@ xfs_bmap_del_extent_real(
                error = xfs_bmbt_lookup_eq(cur, &got, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
        }
 
        if (got.br_startoff == del->br_startoff)
@@ -5043,7 +5138,10 @@ xfs_bmap_del_extent_real(
                }
                if ((error = xfs_btree_delete(cur, &i)))
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                break;
        case BMAP_LEFT_FILLING:
                /*
@@ -5114,7 +5212,10 @@ xfs_bmap_del_extent_real(
                                error = xfs_bmbt_lookup_eq(cur, &got, &i);
                                if (error)
                                        goto done;
-                               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                                       error = -EFSCORRUPTED;
+                                       goto done;
+                               }
                                /*
                                 * Update the btree record back
                                 * to the original value.
@@ -5131,7 +5232,10 @@ xfs_bmap_del_extent_real(
                                error = -ENOSPC;
                                goto done;
                        }
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto done;
+                       }
                } else
                        flags |= xfs_ilog_fext(whichfork);
                XFS_IFORK_NEXT_SET(ip, whichfork,
@@ -5198,7 +5302,7 @@ __xfs_bunmapi(
        int                     isrt;           /* freeing in rt area */
        int                     logflags;       /* transaction logging flags */
        xfs_extlen_t            mod;            /* rt extent offset */
-       struct xfs_mount        *mp;            /* mount structure */
+       struct xfs_mount        *mp = ip->i_mount;
        int                     tmp_logflags;   /* partial logging flags */
        int                     wasdel;         /* was a delayed alloc extent */
        int                     whichfork;      /* data or attribute fork */
@@ -5215,14 +5319,8 @@ __xfs_bunmapi(
        whichfork = xfs_bmapi_whichfork(flags);
        ASSERT(whichfork != XFS_COW_FORK);
        ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (unlikely(
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
-               XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
-                                ip->i_mount);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)))
                return -EFSCORRUPTED;
-       }
-       mp = ip->i_mount;
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
@@ -5616,18 +5714,21 @@ xfs_bmse_merge(
        error = xfs_bmbt_lookup_eq(cur, got, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+       if (XFS_IS_CORRUPT(mp, i != 1))
+               return -EFSCORRUPTED;
 
        error = xfs_btree_delete(cur, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+       if (XFS_IS_CORRUPT(mp, i != 1))
+               return -EFSCORRUPTED;
 
        /* lookup and update size of the previous extent */
        error = xfs_bmbt_lookup_eq(cur, left, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+       if (XFS_IS_CORRUPT(mp, i != 1))
+               return -EFSCORRUPTED;
 
        error = xfs_bmbt_update(cur, &new);
        if (error)
@@ -5675,7 +5776,8 @@ xfs_bmap_shift_update_extent(
                error = xfs_bmbt_lookup_eq(cur, &prev, &i);
                if (error)
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
+               if (XFS_IS_CORRUPT(mp, i != 1))
+                       return -EFSCORRUPTED;
 
                error = xfs_bmbt_update(cur, got);
                if (error)
@@ -5711,11 +5813,8 @@ xfs_bmap_collapse_extents(
        int                     error = 0;
        int                     logflags = 0;
 
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
@@ -5739,8 +5838,10 @@ xfs_bmap_collapse_extents(
                *done = true;
                goto del_cursor;
        }
-       XFS_WANT_CORRUPTED_GOTO(mp, !isnullstartblock(got.br_startblock),
-                               del_cursor);
+       if (XFS_IS_CORRUPT(mp, isnullstartblock(got.br_startblock))) {
+               error = -EFSCORRUPTED;
+               goto del_cursor;
+       }
 
        new_startoff = got.br_startoff - offset_shift_fsb;
        if (xfs_iext_peek_prev_extent(ifp, &icur, &prev)) {
@@ -5829,11 +5930,8 @@ xfs_bmap_insert_extents(
        int                     error = 0;
        int                     logflags = 0;
 
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
@@ -5866,11 +5964,14 @@ xfs_bmap_insert_extents(
                        goto del_cursor;
                }
        }
-       XFS_WANT_CORRUPTED_GOTO(mp, !isnullstartblock(got.br_startblock),
-                               del_cursor);
+       if (XFS_IS_CORRUPT(mp, isnullstartblock(got.br_startblock))) {
+               error = -EFSCORRUPTED;
+               goto del_cursor;
+       }
 
-       if (stop_fsb >= got.br_startoff + got.br_blockcount) {
-               error = -EIO;
+       if (XFS_IS_CORRUPT(mp,
+                          stop_fsb >= got.br_startoff + got.br_blockcount)) {
+               error = -EFSCORRUPTED;
                goto del_cursor;
        }
 
@@ -5935,12 +6036,8 @@ xfs_bmap_split_extent_at(
        int                             logflags = 0;
        int                             i = 0;
 
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT("xfs_bmap_split_extent_at",
-                                XFS_ERRLEVEL_LOW, mp);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
@@ -5974,7 +6071,10 @@ xfs_bmap_split_extent_at(
                error = xfs_bmbt_lookup_eq(cur, &got, &i);
                if (error)
                        goto del_cursor;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto del_cursor;
+               }
        }
 
        got.br_blockcount = gotblkcnt;
@@ -5999,11 +6099,17 @@ xfs_bmap_split_extent_at(
                error = xfs_bmbt_lookup_eq(cur, &new, &i);
                if (error)
                        goto del_cursor;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 0, del_cursor);
+               if (XFS_IS_CORRUPT(mp, i != 0)) {
+                       error = -EFSCORRUPTED;
+                       goto del_cursor;
+               }
                error = xfs_btree_insert(cur, &i);
                if (error)
                        goto del_cursor;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto del_cursor;
+               }
        }
 
        /*
index 71de937..e2cc989 100644 (file)
@@ -105,11 +105,10 @@ xfs_btree_check_lblock(
        xfs_failaddr_t          fa;
 
        fa = __xfs_btree_check_lblock(cur, block, level, bp);
-       if (unlikely(XFS_TEST_ERROR(fa != NULL, mp,
-                       XFS_ERRTAG_BTREE_CHECK_LBLOCK))) {
+       if (XFS_IS_CORRUPT(mp, fa != NULL) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK)) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -169,11 +168,10 @@ xfs_btree_check_sblock(
        xfs_failaddr_t          fa;
 
        fa = __xfs_btree_check_sblock(cur, block, level, bp);
-       if (unlikely(XFS_TEST_ERROR(fa != NULL, mp,
-                       XFS_ERRTAG_BTREE_CHECK_SBLOCK))) {
+       if (XFS_IS_CORRUPT(mp, fa != NULL) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BTREE_CHECK_SBLOCK)) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -384,7 +382,7 @@ xfs_btree_del_cursor(
        /*
         * Free the cursor.
         */
-       kmem_zone_free(xfs_btree_cur_zone, cur);
+       kmem_cache_free(xfs_btree_cur_zone, cur);
 }
 
 /*
@@ -716,25 +714,6 @@ xfs_btree_get_bufs(
        return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0);
 }
 
-/*
- * Check for the cursor referring to the last block at the given level.
- */
-int                                    /* 1=is last block, 0=not last block */
-xfs_btree_islastblock(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       int                     level)  /* level to check */
-{
-       struct xfs_btree_block  *block; /* generic btree block pointer */
-       xfs_buf_t               *bp;    /* buffer containing block */
-
-       block = xfs_btree_get_block(cur, level, &bp);
-       xfs_btree_check_block(cur, block, level, bp);
-       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
-               return block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK);
-       else
-               return block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK);
-}
-
 /*
  * Change the cursor to point to the first record at the given level.
  * Other levels are unaffected.
@@ -1820,6 +1799,7 @@ xfs_btree_lookup_get_block(
 
 out_bad:
        *blkp = NULL;
+       xfs_buf_corruption_error(bp);
        xfs_trans_brelse(cur->bc_tp, bp);
        return -EFSCORRUPTED;
 }
@@ -1867,7 +1847,7 @@ xfs_btree_lookup(
        XFS_BTREE_STATS_INC(cur, lookup);
 
        /* No such thing as a zero-level tree. */
-       if (cur->bc_nlevels == 0)
+       if (XFS_IS_CORRUPT(cur->bc_mp, cur->bc_nlevels == 0))
                return -EFSCORRUPTED;
 
        block = NULL;
@@ -1987,7 +1967,8 @@ xfs_btree_lookup(
                        error = xfs_btree_increment(cur, 0, &i);
                        if (error)
                                goto error0;
-                       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+                       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+                               return -EFSCORRUPTED;
                        *stat = 1;
                        return 0;
                }
@@ -2442,7 +2423,10 @@ xfs_btree_lshift(
                if (error)
                        goto error0;
                i = xfs_btree_firstrec(tcur, level);
-               XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(tcur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                error = xfs_btree_decrement(tcur, level, &i);
                if (error)
@@ -2609,7 +2593,10 @@ xfs_btree_rshift(
        if (error)
                goto error0;
        i = xfs_btree_lastrec(tcur, level);
-       XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0);
+       if (XFS_IS_CORRUPT(tcur->bc_mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
 
        error = xfs_btree_increment(tcur, level, &i);
        if (error)
@@ -3463,7 +3450,10 @@ xfs_btree_insert(
                        goto error0;
                }
 
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                level++;
 
                /*
@@ -3867,15 +3857,24 @@ xfs_btree_delrec(
                 * Actually any entry but the first would suffice.
                 */
                i = xfs_btree_lastrec(tcur, level);
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                error = xfs_btree_increment(tcur, level, &i);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                i = xfs_btree_lastrec(tcur, level);
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                /* Grab a pointer to the block. */
                right = xfs_btree_get_block(tcur, level, &rbp);
@@ -3919,12 +3918,18 @@ xfs_btree_delrec(
                rrecs = xfs_btree_get_numrecs(right);
                if (!xfs_btree_ptr_is_null(cur, &lptr)) {
                        i = xfs_btree_firstrec(tcur, level);
-                       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+                       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
 
                        error = xfs_btree_decrement(tcur, level, &i);
                        if (error)
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+                       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto error0;
+                       }
                }
        }
 
@@ -3938,13 +3943,19 @@ xfs_btree_delrec(
                 * previous block.
                 */
                i = xfs_btree_firstrec(tcur, level);
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                error = xfs_btree_decrement(tcur, level, &i);
                if (error)
                        goto error0;
                i = xfs_btree_firstrec(tcur, level);
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                /* Grab a pointer to the block. */
                left = xfs_btree_get_block(tcur, level, &lbp);
@@ -4286,6 +4297,7 @@ int
 xfs_btree_visit_blocks(
        struct xfs_btree_cur            *cur,
        xfs_btree_visit_blocks_fn       fn,
+       unsigned int                    flags,
        void                            *data)
 {
        union xfs_btree_ptr             lptr;
@@ -4311,6 +4323,11 @@ xfs_btree_visit_blocks(
 
                        /* save for the next iteration of the loop */
                        xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
+
+                       if (!(flags & XFS_BTREE_VISIT_LEAVES))
+                               continue;
+               } else if (!(flags & XFS_BTREE_VISIT_RECORDS)) {
+                       continue;
                }
 
                /* for each buffer in the level */
@@ -4413,7 +4430,7 @@ xfs_btree_change_owner(
        bbcoi.buffer_list = buffer_list;
 
        return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner,
-                       &bbcoi);
+                       XFS_BTREE_VISIT_ALL, &bbcoi);
 }
 
 /* Verify the v5 fields of a long-format btree block. */
@@ -4865,7 +4882,7 @@ xfs_btree_count_blocks(
 {
        *blocks = 0;
        return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper,
-                       blocks);
+                       XFS_BTREE_VISIT_ALL, blocks);
 }
 
 /* Compare two btree pointers. */
index ced1e65..fb9b212 100644 (file)
@@ -183,6 +183,9 @@ union xfs_btree_cur_private {
                unsigned long   nr_ops;         /* # record updates */
                int             shape_changes;  /* # of extent splits */
        } refc;
+       struct {
+               bool            active;         /* allocation cursor state */
+       } abt;
 };
 
 /*
@@ -314,14 +317,6 @@ xfs_btree_get_bufs(
        xfs_agnumber_t          agno,   /* allocation group number */
        xfs_agblock_t           agbno); /* allocation group block number */
 
-/*
- * Check for the cursor referring to the last block at the given level.
- */
-int                                    /* 1=is last block, 0=not last block */
-xfs_btree_islastblock(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       int                     level); /* level to check */
-
 /*
  * Compute first and last byte offsets for the fields given.
  * Interprets the offsets table, which contains struct field offsets.
@@ -482,8 +477,15 @@ int xfs_btree_query_all(struct xfs_btree_cur *cur, xfs_btree_query_range_fn fn,
 
 typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level,
                void *data);
+/* Visit record blocks. */
+#define XFS_BTREE_VISIT_RECORDS                (1 << 0)
+/* Visit leaf blocks. */
+#define XFS_BTREE_VISIT_LEAVES         (1 << 1)
+/* Visit all blocks. */
+#define XFS_BTREE_VISIT_ALL            (XFS_BTREE_VISIT_RECORDS | \
+                                        XFS_BTREE_VISIT_LEAVES)
 int xfs_btree_visit_blocks(struct xfs_btree_cur *cur,
-               xfs_btree_visit_blocks_fn fn, void *data);
+               xfs_btree_visit_blocks_fn fn, unsigned int flags, void *data);
 
 int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks);
 
@@ -514,4 +516,21 @@ int xfs_btree_has_record(struct xfs_btree_cur *cur, union xfs_btree_irec *low,
                union xfs_btree_irec *high, bool *exists);
 bool xfs_btree_has_more_records(struct xfs_btree_cur *cur);
 
+/* Does this cursor point to the last block in the given level? */
+static inline bool
+xfs_btree_islastblock(
+       xfs_btree_cur_t         *cur,
+       int                     level)
+{
+       struct xfs_btree_block  *block;
+       struct xfs_buf          *bp;
+
+       block = xfs_btree_get_block(cur, level, &bp);
+       ASSERT(block && xfs_btree_check_block(cur, block, level, bp) == 0);
+
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+               return block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK);
+       return block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK);
+}
+
 #endif /* __XFS_BTREE_H__ */
index 4fd1223..8c3eafe 100644 (file)
@@ -12,9 +12,9 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_inode.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
-#include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_bmap.h"
 #include "xfs_attr_leaf.h"
@@ -107,7 +107,66 @@ xfs_da_state_free(xfs_da_state_t *state)
 #ifdef DEBUG
        memset((char *)state, 0, sizeof(*state));
 #endif /* DEBUG */
-       kmem_zone_free(xfs_da_state_zone, state);
+       kmem_cache_free(xfs_da_state_zone, state);
+}
+
+static inline int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork)
+{
+       if (whichfork == XFS_DATA_FORK)
+               return mp->m_dir_geo->fsbcount;
+       return mp->m_attr_geo->fsbcount;
+}
+
+void
+xfs_da3_node_hdr_from_disk(
+       struct xfs_mount                *mp,
+       struct xfs_da3_icnode_hdr       *to,
+       struct xfs_da_intnode           *from)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_da3_intnode  *from3 = (struct xfs_da3_intnode *)from;
+
+               to->forw = be32_to_cpu(from3->hdr.info.hdr.forw);
+               to->back = be32_to_cpu(from3->hdr.info.hdr.back);
+               to->magic = be16_to_cpu(from3->hdr.info.hdr.magic);
+               to->count = be16_to_cpu(from3->hdr.__count);
+               to->level = be16_to_cpu(from3->hdr.__level);
+               to->btree = from3->__btree;
+               ASSERT(to->magic == XFS_DA3_NODE_MAGIC);
+       } else {
+               to->forw = be32_to_cpu(from->hdr.info.forw);
+               to->back = be32_to_cpu(from->hdr.info.back);
+               to->magic = be16_to_cpu(from->hdr.info.magic);
+               to->count = be16_to_cpu(from->hdr.__count);
+               to->level = be16_to_cpu(from->hdr.__level);
+               to->btree = from->__btree;
+               ASSERT(to->magic == XFS_DA_NODE_MAGIC);
+       }
+}
+
+void
+xfs_da3_node_hdr_to_disk(
+       struct xfs_mount                *mp,
+       struct xfs_da_intnode           *to,
+       struct xfs_da3_icnode_hdr       *from)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_da3_intnode  *to3 = (struct xfs_da3_intnode *)to;
+
+               ASSERT(from->magic == XFS_DA3_NODE_MAGIC);
+               to3->hdr.info.hdr.forw = cpu_to_be32(from->forw);
+               to3->hdr.info.hdr.back = cpu_to_be32(from->back);
+               to3->hdr.info.hdr.magic = cpu_to_be16(from->magic);
+               to3->hdr.__count = cpu_to_be16(from->count);
+               to3->hdr.__level = cpu_to_be16(from->level);
+       } else {
+               ASSERT(from->magic == XFS_DA_NODE_MAGIC);
+               to->hdr.info.forw = cpu_to_be32(from->forw);
+               to->hdr.info.back = cpu_to_be32(from->back);
+               to->hdr.info.magic = cpu_to_be16(from->magic);
+               to->hdr.__count = cpu_to_be16(from->count);
+               to->hdr.__level = cpu_to_be16(from->level);
+       }
 }
 
 /*
@@ -145,12 +204,9 @@ xfs_da3_node_verify(
        struct xfs_mount        *mp = bp->b_mount;
        struct xfs_da_intnode   *hdr = bp->b_addr;
        struct xfs_da3_icnode_hdr ichdr;
-       const struct xfs_dir_ops *ops;
        xfs_failaddr_t          fa;
 
-       ops = xfs_dir_get_ops(mp, NULL);
-
-       ops->node_hdr_from_disk(&ichdr, hdr);
+       xfs_da3_node_hdr_from_disk(mp, &ichdr, hdr);
 
        fa = xfs_da3_blkinfo_verify(bp, bp->b_addr);
        if (fa)
@@ -275,46 +331,76 @@ const struct xfs_buf_ops xfs_da3_node_buf_ops = {
        .verify_struct = xfs_da3_node_verify_struct,
 };
 
+static int
+xfs_da3_node_set_type(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp)
+{
+       struct xfs_da_blkinfo   *info = bp->b_addr;
+
+       switch (be16_to_cpu(info->magic)) {
+       case XFS_DA_NODE_MAGIC:
+       case XFS_DA3_NODE_MAGIC:
+               xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
+               return 0;
+       case XFS_ATTR_LEAF_MAGIC:
+       case XFS_ATTR3_LEAF_MAGIC:
+               xfs_trans_buf_set_type(tp, bp, XFS_BLFT_ATTR_LEAF_BUF);
+               return 0;
+       case XFS_DIR2_LEAFN_MAGIC:
+       case XFS_DIR3_LEAFN_MAGIC:
+               xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF);
+               return 0;
+       default:
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, tp->t_mountp,
+                               info, sizeof(*info));
+               xfs_trans_brelse(tp, bp);
+               return -EFSCORRUPTED;
+       }
+}
+
 int
 xfs_da3_node_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
+       struct xfs_buf          **bpp,
+       int                     whichfork)
+{
+       int                     error;
+
+       error = xfs_da_read_buf(tp, dp, bno, 0, bpp, whichfork,
+                       &xfs_da3_node_buf_ops);
+       if (error || !*bpp || !tp)
+               return error;
+       return xfs_da3_node_set_type(tp, *bpp);
+}
+
+int
+xfs_da3_node_read_mapped(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
        xfs_daddr_t             mappedbno,
        struct xfs_buf          **bpp,
-       int                     which_fork)
+       int                     whichfork)
 {
-       int                     err;
+       struct xfs_mount        *mp = dp->i_mount;
+       int                     error;
 
-       err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
-                                       which_fork, &xfs_da3_node_buf_ops);
-       if (!err && tp && *bpp) {
-               struct xfs_da_blkinfo   *info = (*bpp)->b_addr;
-               int                     type;
+       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, mappedbno,
+                       XFS_FSB_TO_BB(mp, xfs_dabuf_nfsb(mp, whichfork)), 0,
+                       bpp, &xfs_da3_node_buf_ops);
+       if (error || !*bpp)
+               return error;
 
-               switch (be16_to_cpu(info->magic)) {
-               case XFS_DA_NODE_MAGIC:
-               case XFS_DA3_NODE_MAGIC:
-                       type = XFS_BLFT_DA_NODE_BUF;
-                       break;
-               case XFS_ATTR_LEAF_MAGIC:
-               case XFS_ATTR3_LEAF_MAGIC:
-                       type = XFS_BLFT_ATTR_LEAF_BUF;
-                       break;
-               case XFS_DIR2_LEAFN_MAGIC:
-               case XFS_DIR3_LEAFN_MAGIC:
-                       type = XFS_BLFT_DIR_LEAFN_BUF;
-                       break;
-               default:
-                       XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
-                                       tp->t_mountp, info, sizeof(*info));
-                       xfs_trans_brelse(tp, *bpp);
-                       *bpp = NULL;
-                       return -EFSCORRUPTED;
-               }
-               xfs_trans_buf_set_type(tp, *bpp, type);
-       }
-       return err;
+       if (whichfork == XFS_ATTR_FORK)
+               xfs_buf_set_ref(*bpp, XFS_ATTR_BTREE_REF);
+       else
+               xfs_buf_set_ref(*bpp, XFS_DIR_BTREE_REF);
+
+       if (!tp)
+               return 0;
+       return xfs_da3_node_set_type(tp, *bpp);
 }
 
 /*========================================================================
@@ -343,7 +429,7 @@ xfs_da3_node_create(
        trace_xfs_da_node_create(args);
        ASSERT(level <= XFS_DA_NODE_MAXDEPTH);
 
-       error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, whichfork);
+       error = xfs_da_get_buf(tp, dp, blkno, &bp, whichfork);
        if (error)
                return error;
        bp->b_ops = &xfs_da3_node_buf_ops;
@@ -363,9 +449,9 @@ xfs_da3_node_create(
        }
        ichdr.level = level;
 
-       dp->d_ops->node_hdr_to_disk(node, &ichdr);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node, &ichdr);
        xfs_trans_log_buf(tp, bp,
-               XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size));
+               XFS_DA_LOGRANGE(node, &node->hdr, args->geo->node_hdr_size));
 
        *bpp = bp;
        return 0;
@@ -504,6 +590,7 @@ xfs_da3_split(
        node = oldblk->bp->b_addr;
        if (node->hdr.info.forw) {
                if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) {
+                       xfs_buf_corruption_error(oldblk->bp);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -516,6 +603,7 @@ xfs_da3_split(
        node = oldblk->bp->b_addr;
        if (node->hdr.info.back) {
                if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) {
+                       xfs_buf_corruption_error(oldblk->bp);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -568,7 +656,7 @@ xfs_da3_root_split(
 
        dp = args->dp;
        tp = args->trans;
-       error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork);
+       error = xfs_da_get_buf(tp, dp, blkno, &bp, args->whichfork);
        if (error)
                return error;
        node = bp->b_addr;
@@ -577,8 +665,8 @@ xfs_da3_root_split(
            oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) {
                struct xfs_da3_icnode_hdr icnodehdr;
 
-               dp->d_ops->node_hdr_from_disk(&icnodehdr, oldroot);
-               btree = dp->d_ops->node_tree_p(oldroot);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &icnodehdr, oldroot);
+               btree = icnodehdr.btree;
                size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot);
                level = icnodehdr.level;
 
@@ -589,15 +677,14 @@ xfs_da3_root_split(
                xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
        } else {
                struct xfs_dir3_icleaf_hdr leafhdr;
-               struct xfs_dir2_leaf_entry *ents;
 
                leaf = (xfs_dir2_leaf_t *)oldroot;
-               dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-               ents = dp->d_ops->leaf_ents_p(leaf);
+               xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
 
                ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
                       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
-               size = (int)((char *)&ents[leafhdr.count] - (char *)leaf);
+               size = (int)((char *)&leafhdr.ents[leafhdr.count] -
+                       (char *)leaf);
                level = 0;
 
                /*
@@ -637,14 +724,14 @@ xfs_da3_root_split(
                return error;
 
        node = bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
-       btree = dp->d_ops->node_tree_p(node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
+       btree = nodehdr.btree;
        btree[0].hashval = cpu_to_be32(blk1->hashval);
        btree[0].before = cpu_to_be32(blk1->blkno);
        btree[1].hashval = cpu_to_be32(blk2->hashval);
        btree[1].before = cpu_to_be32(blk2->blkno);
        nodehdr.count = 2;
-       dp->d_ops->node_hdr_to_disk(node, &nodehdr);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
 
 #ifdef DEBUG
        if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
@@ -686,7 +773,7 @@ xfs_da3_node_split(
        trace_xfs_da_node_split(state->args);
 
        node = oldblk->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
 
        /*
         * With V2 dirs the extra block is data or freespace.
@@ -733,7 +820,7 @@ xfs_da3_node_split(
         * If we had double-split op below us, then add the extra block too.
         */
        node = oldblk->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
        if (oldblk->index <= nodehdr.count) {
                oldblk->index++;
                xfs_da3_node_add(state, oldblk, addblk);
@@ -788,10 +875,10 @@ xfs_da3_node_rebalance(
 
        node1 = blk1->bp->b_addr;
        node2 = blk2->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr1, node1);
-       dp->d_ops->node_hdr_from_disk(&nodehdr2, node2);
-       btree1 = dp->d_ops->node_tree_p(node1);
-       btree2 = dp->d_ops->node_tree_p(node2);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr1, node1);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr2, node2);
+       btree1 = nodehdr1.btree;
+       btree2 = nodehdr2.btree;
 
        /*
         * Figure out how many entries need to move, and in which direction.
@@ -804,10 +891,10 @@ xfs_da3_node_rebalance(
                tmpnode = node1;
                node1 = node2;
                node2 = tmpnode;
-               dp->d_ops->node_hdr_from_disk(&nodehdr1, node1);
-               dp->d_ops->node_hdr_from_disk(&nodehdr2, node2);
-               btree1 = dp->d_ops->node_tree_p(node1);
-               btree2 = dp->d_ops->node_tree_p(node2);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr1, node1);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr2, node2);
+               btree1 = nodehdr1.btree;
+               btree2 = nodehdr2.btree;
                swap = 1;
        }
 
@@ -869,14 +956,15 @@ xfs_da3_node_rebalance(
        /*
         * Log header of node 1 and all current bits of node 2.
         */
-       dp->d_ops->node_hdr_to_disk(node1, &nodehdr1);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node1, &nodehdr1);
        xfs_trans_log_buf(tp, blk1->bp,
-               XFS_DA_LOGRANGE(node1, &node1->hdr, dp->d_ops->node_hdr_size));
+               XFS_DA_LOGRANGE(node1, &node1->hdr,
+                               state->args->geo->node_hdr_size));
 
-       dp->d_ops->node_hdr_to_disk(node2, &nodehdr2);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node2, &nodehdr2);
        xfs_trans_log_buf(tp, blk2->bp,
                XFS_DA_LOGRANGE(node2, &node2->hdr,
-                               dp->d_ops->node_hdr_size +
+                               state->args->geo->node_hdr_size +
                                (sizeof(btree2[0]) * nodehdr2.count)));
 
        /*
@@ -886,10 +974,10 @@ xfs_da3_node_rebalance(
        if (swap) {
                node1 = blk1->bp->b_addr;
                node2 = blk2->bp->b_addr;
-               dp->d_ops->node_hdr_from_disk(&nodehdr1, node1);
-               dp->d_ops->node_hdr_from_disk(&nodehdr2, node2);
-               btree1 = dp->d_ops->node_tree_p(node1);
-               btree2 = dp->d_ops->node_tree_p(node2);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr1, node1);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr2, node2);
+               btree1 = nodehdr1.btree;
+               btree2 = nodehdr2.btree;
        }
        blk1->hashval = be32_to_cpu(btree1[nodehdr1.count - 1].hashval);
        blk2->hashval = be32_to_cpu(btree2[nodehdr2.count - 1].hashval);
@@ -921,8 +1009,8 @@ xfs_da3_node_add(
        trace_xfs_da_node_add(state->args);
 
        node = oldblk->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
-       btree = dp->d_ops->node_tree_p(node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
+       btree = nodehdr.btree;
 
        ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count);
        ASSERT(newblk->blkno != 0);
@@ -945,9 +1033,10 @@ xfs_da3_node_add(
                                tmp + sizeof(*btree)));
 
        nodehdr.count += 1;
-       dp->d_ops->node_hdr_to_disk(node, &nodehdr);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
        xfs_trans_log_buf(state->args->trans, oldblk->bp,
-               XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size));
+               XFS_DA_LOGRANGE(node, &node->hdr,
+                               state->args->geo->node_hdr_size));
 
        /*
         * Copy the last hash value from the oldblk to propagate upwards.
@@ -1082,7 +1171,6 @@ xfs_da3_root_join(
        xfs_dablk_t             child;
        struct xfs_buf          *bp;
        struct xfs_da3_icnode_hdr oldroothdr;
-       struct xfs_da_node_entry *btree;
        int                     error;
        struct xfs_inode        *dp = state->args->dp;
 
@@ -1092,7 +1180,7 @@ xfs_da3_root_join(
 
        args = state->args;
        oldroot = root_blk->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&oldroothdr, oldroot);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &oldroothdr, oldroot);
        ASSERT(oldroothdr.forw == 0);
        ASSERT(oldroothdr.back == 0);
 
@@ -1106,11 +1194,9 @@ xfs_da3_root_join(
         * Read in the (only) child block, then copy those bytes into
         * the root block's buffer and free the original child block.
         */
-       btree = dp->d_ops->node_tree_p(oldroot);
-       child = be32_to_cpu(btree[0].before);
+       child = be32_to_cpu(oldroothdr.btree[0].before);
        ASSERT(child != 0);
-       error = xfs_da3_node_read(args->trans, dp, child, -1, &bp,
-                                            args->whichfork);
+       error = xfs_da3_node_read(args->trans, dp, child, &bp, args->whichfork);
        if (error)
                return error;
        xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);
@@ -1172,7 +1258,7 @@ xfs_da3_node_toosmall(
        blk = &state->path.blk[ state->path.active-1 ];
        info = blk->bp->b_addr;
        node = (xfs_da_intnode_t *)info;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
        if (nodehdr.count > (state->args->geo->node_ents >> 1)) {
                *action = 0;    /* blk over 50%, don't try to join */
                return 0;       /* blk over 50%, don't try to join */
@@ -1224,13 +1310,13 @@ xfs_da3_node_toosmall(
                        blkno = nodehdr.back;
                if (blkno == 0)
                        continue;
-               error = xfs_da3_node_read(state->args->trans, dp,
-                                       blkno, -1, &bp, state->args->whichfork);
+               error = xfs_da3_node_read(state->args->trans, dp, blkno, &bp,
+                               state->args->whichfork);
                if (error)
                        return error;
 
                node = bp->b_addr;
-               dp->d_ops->node_hdr_from_disk(&thdr, node);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &thdr, node);
                xfs_trans_brelse(state->args->trans, bp);
 
                if (count - thdr.count >= 0)
@@ -1272,18 +1358,14 @@ xfs_da3_node_lasthash(
        struct xfs_buf          *bp,
        int                     *count)
 {
-       struct xfs_da_intnode    *node;
-       struct xfs_da_node_entry *btree;
        struct xfs_da3_icnode_hdr nodehdr;
 
-       node = bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, bp->b_addr);
        if (count)
                *count = nodehdr.count;
        if (!nodehdr.count)
                return 0;
-       btree = dp->d_ops->node_tree_p(node);
-       return be32_to_cpu(btree[nodehdr.count - 1].hashval);
+       return be32_to_cpu(nodehdr.btree[nodehdr.count - 1].hashval);
 }
 
 /*
@@ -1328,8 +1410,8 @@ xfs_da3_fixhashpath(
                struct xfs_da3_icnode_hdr nodehdr;
 
                node = blk->bp->b_addr;
-               dp->d_ops->node_hdr_from_disk(&nodehdr, node);
-               btree = dp->d_ops->node_tree_p(node);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
+               btree = nodehdr.btree;
                if (be32_to_cpu(btree[blk->index].hashval) == lasthash)
                        break;
                blk->hashval = lasthash;
@@ -1360,7 +1442,7 @@ xfs_da3_node_remove(
        trace_xfs_da_node_remove(state->args);
 
        node = drop_blk->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
        ASSERT(drop_blk->index < nodehdr.count);
        ASSERT(drop_blk->index >= 0);
 
@@ -1368,7 +1450,7 @@ xfs_da3_node_remove(
         * Copy over the offending entry, or just zero it out.
         */
        index = drop_blk->index;
-       btree = dp->d_ops->node_tree_p(node);
+       btree = nodehdr.btree;
        if (index < nodehdr.count - 1) {
                tmp  = nodehdr.count - index - 1;
                tmp *= (uint)sizeof(xfs_da_node_entry_t);
@@ -1381,9 +1463,9 @@ xfs_da3_node_remove(
        xfs_trans_log_buf(state->args->trans, drop_blk->bp,
            XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index])));
        nodehdr.count -= 1;
-       dp->d_ops->node_hdr_to_disk(node, &nodehdr);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
        xfs_trans_log_buf(state->args->trans, drop_blk->bp,
-           XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size));
+           XFS_DA_LOGRANGE(node, &node->hdr, state->args->geo->node_hdr_size));
 
        /*
         * Copy the last hash value from the block to propagate upwards.
@@ -1416,10 +1498,10 @@ xfs_da3_node_unbalance(
 
        drop_node = drop_blk->bp->b_addr;
        save_node = save_blk->bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&drop_hdr, drop_node);
-       dp->d_ops->node_hdr_from_disk(&save_hdr, save_node);
-       drop_btree = dp->d_ops->node_tree_p(drop_node);
-       save_btree = dp->d_ops->node_tree_p(save_node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &drop_hdr, drop_node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &save_hdr, save_node);
+       drop_btree = drop_hdr.btree;
+       save_btree = save_hdr.btree;
        tp = state->args->trans;
 
        /*
@@ -1453,10 +1535,10 @@ xfs_da3_node_unbalance(
        memcpy(&save_btree[sindex], &drop_btree[0], tmp);
        save_hdr.count += drop_hdr.count;
 
-       dp->d_ops->node_hdr_to_disk(save_node, &save_hdr);
+       xfs_da3_node_hdr_to_disk(dp->i_mount, save_node, &save_hdr);
        xfs_trans_log_buf(tp, save_blk->bp,
                XFS_DA_LOGRANGE(save_node, &save_node->hdr,
-                               dp->d_ops->node_hdr_size));
+                               state->args->geo->node_hdr_size));
 
        /*
         * Save the last hashval in the remaining block for upward propagation.
@@ -1517,7 +1599,7 @@ xfs_da3_node_lookup_int(
                 */
                blk->blkno = blkno;
                error = xfs_da3_node_read(args->trans, args->dp, blkno,
-                                       -1, &blk->bp, args->whichfork);
+                                       &blk->bp, args->whichfork);
                if (error) {
                        blk->blkno = 0;
                        state->path.active--;
@@ -1541,8 +1623,10 @@ xfs_da3_node_lookup_int(
                        break;
                }
 
-               if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC)
+               if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC) {
+                       xfs_buf_corruption_error(blk->bp);
                        return -EFSCORRUPTED;
+               }
 
                blk->magic = XFS_DA_NODE_MAGIC;
 
@@ -1550,19 +1634,22 @@ xfs_da3_node_lookup_int(
                 * Search an intermediate node for a match.
                 */
                node = blk->bp->b_addr;
-               dp->d_ops->node_hdr_from_disk(&nodehdr, node);
-               btree = dp->d_ops->node_tree_p(node);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
+               btree = nodehdr.btree;
 
                /* Tree taller than we can handle; bail out! */
-               if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
+               if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
+                       xfs_buf_corruption_error(blk->bp);
                        return -EFSCORRUPTED;
+               }
 
                /* Check the level from the root. */
                if (blkno == args->geo->leafblk)
                        expected_level = nodehdr.level - 1;
-               else if (expected_level != nodehdr.level)
+               else if (expected_level != nodehdr.level) {
+                       xfs_buf_corruption_error(blk->bp);
                        return -EFSCORRUPTED;
-               else
+               else
                        expected_level--;
 
                max = nodehdr.count;
@@ -1612,11 +1699,11 @@ xfs_da3_node_lookup_int(
                }
 
                /* We can't point back to the root. */
-               if (blkno == args->geo->leafblk)
+               if (XFS_IS_CORRUPT(dp->i_mount, blkno == args->geo->leafblk))
                        return -EFSCORRUPTED;
        }
 
-       if (expected_level != 0)
+       if (XFS_IS_CORRUPT(dp->i_mount, expected_level != 0))
                return -EFSCORRUPTED;
 
        /*
@@ -1678,10 +1765,10 @@ xfs_da3_node_order(
 
        node1 = node1_bp->b_addr;
        node2 = node2_bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&node1hdr, node1);
-       dp->d_ops->node_hdr_from_disk(&node2hdr, node2);
-       btree1 = dp->d_ops->node_tree_p(node1);
-       btree2 = dp->d_ops->node_tree_p(node2);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &node1hdr, node1);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &node2hdr, node2);
+       btree1 = node1hdr.btree;
+       btree2 = node2hdr.btree;
 
        if (node1hdr.count > 0 && node2hdr.count > 0 &&
            ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) ||
@@ -1746,7 +1833,7 @@ xfs_da3_blk_link(
                if (old_info->back) {
                        error = xfs_da3_node_read(args->trans, dp,
                                                be32_to_cpu(old_info->back),
-                                               -1, &bp, args->whichfork);
+                                               &bp, args->whichfork);
                        if (error)
                                return error;
                        ASSERT(bp != NULL);
@@ -1767,7 +1854,7 @@ xfs_da3_blk_link(
                if (old_info->forw) {
                        error = xfs_da3_node_read(args->trans, dp,
                                                be32_to_cpu(old_info->forw),
-                                               -1, &bp, args->whichfork);
+                                               &bp, args->whichfork);
                        if (error)
                                return error;
                        ASSERT(bp != NULL);
@@ -1826,7 +1913,7 @@ xfs_da3_blk_unlink(
                if (drop_info->back) {
                        error = xfs_da3_node_read(args->trans, args->dp,
                                                be32_to_cpu(drop_info->back),
-                                               -1, &bp, args->whichfork);
+                                               &bp, args->whichfork);
                        if (error)
                                return error;
                        ASSERT(bp != NULL);
@@ -1843,7 +1930,7 @@ xfs_da3_blk_unlink(
                if (drop_info->forw) {
                        error = xfs_da3_node_read(args->trans, args->dp,
                                                be32_to_cpu(drop_info->forw),
-                                               -1, &bp, args->whichfork);
+                                               &bp, args->whichfork);
                        if (error)
                                return error;
                        ASSERT(bp != NULL);
@@ -1878,7 +1965,6 @@ xfs_da3_path_shift(
 {
        struct xfs_da_state_blk *blk;
        struct xfs_da_blkinfo   *info;
-       struct xfs_da_intnode   *node;
        struct xfs_da_args      *args;
        struct xfs_da_node_entry *btree;
        struct xfs_da3_icnode_hdr nodehdr;
@@ -1901,17 +1987,16 @@ xfs_da3_path_shift(
        ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
        level = (path->active-1) - 1;   /* skip bottom layer in path */
        for (blk = &path->blk[level]; level >= 0; blk--, level--) {
-               node = blk->bp->b_addr;
-               dp->d_ops->node_hdr_from_disk(&nodehdr, node);
-               btree = dp->d_ops->node_tree_p(node);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
+                                          blk->bp->b_addr);
 
                if (forward && (blk->index < nodehdr.count - 1)) {
                        blk->index++;
-                       blkno = be32_to_cpu(btree[blk->index].before);
+                       blkno = be32_to_cpu(nodehdr.btree[blk->index].before);
                        break;
                } else if (!forward && (blk->index > 0)) {
                        blk->index--;
-                       blkno = be32_to_cpu(btree[blk->index].before);
+                       blkno = be32_to_cpu(nodehdr.btree[blk->index].before);
                        break;
                }
        }
@@ -1929,7 +2014,7 @@ xfs_da3_path_shift(
                /*
                 * Read the next child block into a local buffer.
                 */
-               error = xfs_da3_node_read(args->trans, dp, blkno, -1, &bp,
+               error = xfs_da3_node_read(args->trans, dp, blkno, &bp,
                                          args->whichfork);
                if (error)
                        return error;
@@ -1962,9 +2047,9 @@ xfs_da3_path_shift(
                case XFS_DA_NODE_MAGIC:
                case XFS_DA3_NODE_MAGIC:
                        blk->magic = XFS_DA_NODE_MAGIC;
-                       node = (xfs_da_intnode_t *)info;
-                       dp->d_ops->node_hdr_from_disk(&nodehdr, node);
-                       btree = dp->d_ops->node_tree_p(node);
+                       xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
+                                                  bp->b_addr);
+                       btree = nodehdr.btree;
                        blk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval);
                        if (forward)
                                blk->index = 0;
@@ -2044,18 +2129,6 @@ xfs_da_compname(
                                        XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
 }
 
-static xfs_dahash_t
-xfs_default_hashname(
-       struct xfs_name *name)
-{
-       return xfs_da_hashname(name->name, name->len);
-}
-
-const struct xfs_nameops xfs_default_nameops = {
-       .hashname       = xfs_default_hashname,
-       .compname       = xfs_da_compname
-};
-
 int
 xfs_da_grow_inode_int(
        struct xfs_da_args      *args,
@@ -2213,16 +2286,13 @@ xfs_da3_swap_lastblock(
        error = xfs_bmap_last_before(tp, dp, &lastoff, w);
        if (error)
                return error;
-       if (unlikely(lastoff == 0)) {
-               XFS_ERROR_REPORT("xfs_da_swap_lastblock(1)", XFS_ERRLEVEL_LOW,
-                                mp);
+       if (XFS_IS_CORRUPT(mp, lastoff == 0))
                return -EFSCORRUPTED;
-       }
        /*
         * Read the last block in the btree space.
         */
        last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount;
-       error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w);
+       error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w);
        if (error)
                return error;
        /*
@@ -2240,16 +2310,17 @@ xfs_da3_swap_lastblock(
                struct xfs_dir2_leaf_entry *ents;
 
                dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
-               dp->d_ops->leaf_hdr_from_disk(&leafhdr, dead_leaf2);
-               ents = dp->d_ops->leaf_ents_p(dead_leaf2);
+               xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr,
+                                           dead_leaf2);
+               ents = leafhdr.ents;
                dead_level = 0;
                dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval);
        } else {
                struct xfs_da3_icnode_hdr deadhdr;
 
                dead_node = (xfs_da_intnode_t *)dead_info;
-               dp->d_ops->node_hdr_from_disk(&deadhdr, dead_node);
-               btree = dp->d_ops->node_tree_p(dead_node);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &deadhdr, dead_node);
+               btree = deadhdr.btree;
                dead_level = deadhdr.level;
                dead_hash = be32_to_cpu(btree[deadhdr.count - 1].hashval);
        }
@@ -2258,15 +2329,13 @@ xfs_da3_swap_lastblock(
         * If the moved block has a left sibling, fix up the pointers.
         */
        if ((sib_blkno = be32_to_cpu(dead_info->back))) {
-               error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w);
+               error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
                if (error)
                        goto done;
                sib_info = sib_buf->b_addr;
-               if (unlikely(
-                   be32_to_cpu(sib_info->forw) != last_blkno ||
-                   sib_info->magic != dead_info->magic)) {
-                       XFS_ERROR_REPORT("xfs_da_swap_lastblock(2)",
-                                        XFS_ERRLEVEL_LOW, mp);
+               if (XFS_IS_CORRUPT(mp,
+                                  be32_to_cpu(sib_info->forw) != last_blkno ||
+                                  sib_info->magic != dead_info->magic)) {
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -2280,15 +2349,13 @@ xfs_da3_swap_lastblock(
         * If the moved block has a right sibling, fix up the pointers.
         */
        if ((sib_blkno = be32_to_cpu(dead_info->forw))) {
-               error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w);
+               error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
                if (error)
                        goto done;
                sib_info = sib_buf->b_addr;
-               if (unlikely(
-                      be32_to_cpu(sib_info->back) != last_blkno ||
-                      sib_info->magic != dead_info->magic)) {
-                       XFS_ERROR_REPORT("xfs_da_swap_lastblock(3)",
-                                        XFS_ERRLEVEL_LOW, mp);
+               if (XFS_IS_CORRUPT(mp,
+                                  be32_to_cpu(sib_info->back) != last_blkno ||
+                                  sib_info->magic != dead_info->magic)) {
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -2304,27 +2371,24 @@ xfs_da3_swap_lastblock(
         * Walk down the tree looking for the parent of the moved block.
         */
        for (;;) {
-               error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w);
+               error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
                if (error)
                        goto done;
                par_node = par_buf->b_addr;
-               dp->d_ops->node_hdr_from_disk(&par_hdr, par_node);
-               if (level >= 0 && level != par_hdr.level + 1) {
-                       XFS_ERROR_REPORT("xfs_da_swap_lastblock(4)",
-                                        XFS_ERRLEVEL_LOW, mp);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
+               if (XFS_IS_CORRUPT(mp,
+                                  level >= 0 && level != par_hdr.level + 1)) {
                        error = -EFSCORRUPTED;
                        goto done;
                }
                level = par_hdr.level;
-               btree = dp->d_ops->node_tree_p(par_node);
+               btree = par_hdr.btree;
                for (entno = 0;
                     entno < par_hdr.count &&
                     be32_to_cpu(btree[entno].hashval) < dead_hash;
                     entno++)
                        continue;
-               if (entno == par_hdr.count) {
-                       XFS_ERROR_REPORT("xfs_da_swap_lastblock(5)",
-                                        XFS_ERRLEVEL_LOW, mp);
+               if (XFS_IS_CORRUPT(mp, entno == par_hdr.count)) {
                        error = -EFSCORRUPTED;
                        goto done;
                }
@@ -2349,24 +2413,20 @@ xfs_da3_swap_lastblock(
                par_blkno = par_hdr.forw;
                xfs_trans_brelse(tp, par_buf);
                par_buf = NULL;
-               if (unlikely(par_blkno == 0)) {
-                       XFS_ERROR_REPORT("xfs_da_swap_lastblock(6)",
-                                        XFS_ERRLEVEL_LOW, mp);
+               if (XFS_IS_CORRUPT(mp, par_blkno == 0)) {
                        error = -EFSCORRUPTED;
                        goto done;
                }
-               error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w);
+               error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
                if (error)
                        goto done;
                par_node = par_buf->b_addr;
-               dp->d_ops->node_hdr_from_disk(&par_hdr, par_node);
-               if (par_hdr.level != level) {
-                       XFS_ERROR_REPORT("xfs_da_swap_lastblock(7)",
-                                        XFS_ERRLEVEL_LOW, mp);
+               xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
+               if (XFS_IS_CORRUPT(mp, par_hdr.level != level)) {
                        error = -EFSCORRUPTED;
                        goto done;
                }
-               btree = dp->d_ops->node_tree_p(par_node);
+               btree = par_hdr.btree;
                entno = 0;
        }
        /*
@@ -2429,159 +2489,84 @@ xfs_da_shrink_inode(
        return error;
 }
 
-/*
- * See if the mapping(s) for this btree block are valid, i.e.
- * don't contain holes, are logically contiguous, and cover the whole range.
- */
-STATIC int
-xfs_da_map_covers_blocks(
-       int             nmap,
-       xfs_bmbt_irec_t *mapp,
-       xfs_dablk_t     bno,
-       int             count)
-{
-       int             i;
-       xfs_fileoff_t   off;
-
-       for (i = 0, off = bno; i < nmap; i++) {
-               if (mapp[i].br_startblock == HOLESTARTBLOCK ||
-                   mapp[i].br_startblock == DELAYSTARTBLOCK) {
-                       return 0;
-               }
-               if (off != mapp[i].br_startoff) {
-                       return 0;
-               }
-               off += mapp[i].br_blockcount;
-       }
-       return off == bno + count;
-}
-
-/*
- * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map.
- *
- * For the single map case, it is assumed that the caller has provided a pointer
- * to a valid xfs_buf_map.  For the multiple map case, this function will
- * allocate the xfs_buf_map to hold all the maps and replace the caller's single
- * map pointer with the allocated map.
- */
 static int
-xfs_buf_map_from_irec(
-       struct xfs_mount        *mp,
+xfs_dabuf_map(
+       struct xfs_inode        *dp,
+       xfs_dablk_t             bno,
+       unsigned int            flags,
+       int                     whichfork,
        struct xfs_buf_map      **mapp,
-       int                     *nmaps,
-       struct xfs_bmbt_irec    *irecs,
-       int                     nirecs)
+       int                     *nmaps)
 {
-       struct xfs_buf_map      *map;
-       int                     i;
-
-       ASSERT(*nmaps == 1);
-       ASSERT(nirecs >= 1);
+       struct xfs_mount        *mp = dp->i_mount;
+       int                     nfsb = xfs_dabuf_nfsb(mp, whichfork);
+       struct xfs_bmbt_irec    irec, *irecs = &irec;
+       struct xfs_buf_map      *map = *mapp;
+       xfs_fileoff_t           off = bno;
+       int                     error = 0, nirecs, i;
+
+       if (nfsb > 1)
+               irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_NOFS);
+
+       nirecs = nfsb;
+       error = xfs_bmapi_read(dp, bno, nfsb, irecs, &nirecs,
+                       xfs_bmapi_aflag(whichfork));
+       if (error)
+               goto out_free_irecs;
 
+       /*
+        * Use the caller provided map for the single map case, else allocate a
+        * larger one that needs to be free by the caller.
+        */
        if (nirecs > 1) {
-               map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map),
-                                 KM_NOFS);
+               map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), KM_NOFS);
                if (!map)
-                       return -ENOMEM;
+                       goto out_free_irecs;
                *mapp = map;
        }
 
-       *nmaps = nirecs;
-       map = *mapp;
-       for (i = 0; i < *nmaps; i++) {
-               ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK &&
-                      irecs[i].br_startblock != HOLESTARTBLOCK);
+       for (i = 0; i < nirecs; i++) {
+               if (irecs[i].br_startblock == HOLESTARTBLOCK ||
+                   irecs[i].br_startblock == DELAYSTARTBLOCK)
+                       goto invalid_mapping;
+               if (off != irecs[i].br_startoff)
+                       goto invalid_mapping;
+
                map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock);
                map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount);
+               off += irecs[i].br_blockcount;
        }
-       return 0;
-}
-
-/*
- * Map the block we are given ready for reading. There are three possible return
- * values:
- *     -1 - will be returned if we land in a hole and mappedbno == -2 so the
- *          caller knows not to execute a subsequent read.
- *      0 - if we mapped the block successfully
- *     >0 - positive error number if there was an error.
- */
-static int
-xfs_dabuf_map(
-       struct xfs_inode        *dp,
-       xfs_dablk_t             bno,
-       xfs_daddr_t             mappedbno,
-       int                     whichfork,
-       struct xfs_buf_map      **map,
-       int                     *nmaps)
-{
-       struct xfs_mount        *mp = dp->i_mount;
-       int                     nfsb;
-       int                     error = 0;
-       struct xfs_bmbt_irec    irec;
-       struct xfs_bmbt_irec    *irecs = &irec;
-       int                     nirecs;
 
-       ASSERT(map && *map);
-       ASSERT(*nmaps == 1);
+       if (off != bno + nfsb)
+               goto invalid_mapping;
 
-       if (whichfork == XFS_DATA_FORK)
-               nfsb = mp->m_dir_geo->fsbcount;
-       else
-               nfsb = mp->m_attr_geo->fsbcount;
-
-       /*
-        * Caller doesn't have a mapping.  -2 means don't complain
-        * if we land in a hole.
-        */
-       if (mappedbno == -1 || mappedbno == -2) {
-               /*
-                * Optimize the one-block case.
-                */
-               if (nfsb != 1)
-                       irecs = kmem_zalloc(sizeof(irec) * nfsb,
-                                           KM_NOFS);
+       *nmaps = nirecs;
+out_free_irecs:
+       if (irecs != &irec)
+               kmem_free(irecs);
+       return error;
 
-               nirecs = nfsb;
-               error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs,
-                                      &nirecs, xfs_bmapi_aflag(whichfork));
-               if (error)
-                       goto out;
-       } else {
-               irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno);
-               irecs->br_startoff = (xfs_fileoff_t)bno;
-               irecs->br_blockcount = nfsb;
-               irecs->br_state = 0;
-               nirecs = 1;
-       }
+invalid_mapping:
+       /* Caller ok with no mapping. */
+       if (XFS_IS_CORRUPT(mp, !(flags & XFS_DABUF_MAP_HOLE_OK))) {
+               error = -EFSCORRUPTED;
+               if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
+                       xfs_alert(mp, "%s: bno %u inode %llu",
+                                       __func__, bno, dp->i_ino);
 
-       if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) {
-               error = mappedbno == -2 ? -1 : -EFSCORRUPTED;
-               if (unlikely(error == -EFSCORRUPTED)) {
-                       if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
-                               int i;
-                               xfs_alert(mp, "%s: bno %lld dir: inode %lld",
-                                       __func__, (long long)bno,
-                                       (long long)dp->i_ino);
-                               for (i = 0; i < *nmaps; i++) {
-                                       xfs_alert(mp,
+                       for (i = 0; i < nirecs; i++) {
+                               xfs_alert(mp,
 "[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d",
-                                               i,
-                                               (long long)irecs[i].br_startoff,
-                                               (long long)irecs[i].br_startblock,
-                                               (long long)irecs[i].br_blockcount,
-                                               irecs[i].br_state);
-                               }
+                                       i, irecs[i].br_startoff,
+                                       irecs[i].br_startblock,
+                                       irecs[i].br_blockcount,
+                                       irecs[i].br_state);
                        }
-                       XFS_ERROR_REPORT("xfs_da_do_buf(1)",
-                                        XFS_ERRLEVEL_LOW, mp);
                }
-               goto out;
+       } else {
+               *nmaps = 0;
        }
-       error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs);
-out:
-       if (irecs != &irec)
-               kmem_free(irecs);
-       return error;
+       goto out_free_irecs;
 }
 
 /*
@@ -2589,37 +2574,28 @@ out:
  */
 int
 xfs_da_get_buf(
-       struct xfs_trans        *trans,
+       struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
-       xfs_daddr_t             mappedbno,
        struct xfs_buf          **bpp,
        int                     whichfork)
 {
+       struct xfs_mount        *mp = dp->i_mount;
        struct xfs_buf          *bp;
-       struct xfs_buf_map      map;
-       struct xfs_buf_map      *mapp;
-       int                     nmap;
+       struct xfs_buf_map      map, *mapp = &map;
+       int                     nmap = 1;
        int                     error;
 
        *bpp = NULL;
-       mapp = &map;
-       nmap = 1;
-       error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
-                               &mapp, &nmap);
-       if (error) {
-               /* mapping a hole is not an error, but we don't continue */
-               if (error == -1)
-                       error = 0;
+       error = xfs_dabuf_map(dp, bno, 0, whichfork, &mapp, &nmap);
+       if (error || nmap == 0)
                goto out_free;
-       }
 
-       bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp,
-                                   mapp, nmap, 0);
+       bp = xfs_trans_get_buf_map(tp, mp->m_ddev_targp, mapp, nmap, 0);
        error = bp ? bp->b_error : -EIO;
        if (error) {
                if (bp)
-                       xfs_trans_brelse(trans, bp);
+                       xfs_trans_brelse(tp, bp);
                goto out_free;
        }
 
@@ -2637,35 +2613,27 @@ out_free:
  */
 int
 xfs_da_read_buf(
-       struct xfs_trans        *trans,
+       struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
-       xfs_daddr_t             mappedbno,
+       unsigned int            flags,
        struct xfs_buf          **bpp,
        int                     whichfork,
        const struct xfs_buf_ops *ops)
 {
+       struct xfs_mount        *mp = dp->i_mount;
        struct xfs_buf          *bp;
-       struct xfs_buf_map      map;
-       struct xfs_buf_map      *mapp;
-       int                     nmap;
+       struct xfs_buf_map      map, *mapp = &map;
+       int                     nmap = 1;
        int                     error;
 
        *bpp = NULL;
-       mapp = &map;
-       nmap = 1;
-       error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
-                               &mapp, &nmap);
-       if (error) {
-               /* mapping a hole is not an error, but we don't continue */
-               if (error == -1)
-                       error = 0;
+       error = xfs_dabuf_map(dp, bno, flags, whichfork, &mapp, &nmap);
+       if (error || !nmap)
                goto out_free;
-       }
 
-       error = xfs_trans_read_buf_map(dp->i_mount, trans,
-                                       dp->i_mount->m_ddev_targp,
-                                       mapp, nmap, 0, &bp, ops);
+       error = xfs_trans_read_buf_map(mp, tp, mp->m_ddev_targp, mapp, nmap, 0,
+                       &bp, ops);
        if (error)
                goto out_free;
 
@@ -2688,7 +2656,7 @@ int
 xfs_da_reada_buf(
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
-       xfs_daddr_t             mappedbno,
+       unsigned int            flags,
        int                     whichfork,
        const struct xfs_buf_ops *ops)
 {
@@ -2699,16 +2667,10 @@ xfs_da_reada_buf(
 
        mapp = &map;
        nmap = 1;
-       error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
-                               &mapp, &nmap);
-       if (error) {
-               /* mapping a hole is not an error, but we don't continue */
-               if (error == -1)
-                       error = 0;
+       error = xfs_dabuf_map(dp, bno, flags, whichfork, &mapp, &nmap);
+       if (error || !nmap)
                goto out_free;
-       }
 
-       mappedbno = mapp[0].bm_bn;
        xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, ops);
 
 out_free:
index ae0bbd2..e16610d 100644 (file)
@@ -10,7 +10,6 @@
 struct xfs_inode;
 struct xfs_trans;
 struct zone;
-struct xfs_dir_ops;
 
 /*
  * Directory/attribute geometry information. There will be one of these for each
@@ -18,15 +17,23 @@ struct xfs_dir_ops;
  * structures will be attached to the xfs_mount.
  */
 struct xfs_da_geometry {
-       int             blksize;        /* da block size in bytes */
-       int             fsbcount;       /* da block size in filesystem blocks */
+       unsigned int    blksize;        /* da block size in bytes */
+       unsigned int    fsbcount;       /* da block size in filesystem blocks */
        uint8_t         fsblog;         /* log2 of _filesystem_ block size */
        uint8_t         blklog;         /* log2 of da block size */
-       uint            node_ents;      /* # of entries in a danode */
-       int             magicpct;       /* 37% of block size in bytes */
+       unsigned int    node_hdr_size;  /* danode header size in bytes */
+       unsigned int    node_ents;      /* # of entries in a danode */
+       unsigned int    magicpct;       /* 37% of block size in bytes */
        xfs_dablk_t     datablk;        /* blockno of dir data v2 */
+       unsigned int    leaf_hdr_size;  /* dir2 leaf header size */
+       unsigned int    leaf_max_ents;  /* # of entries in dir2 leaf */
        xfs_dablk_t     leafblk;        /* blockno of leaf data v2 */
+       unsigned int    free_hdr_size;  /* dir2 free header size */
+       unsigned int    free_max_bests; /* # of bests entries in dir2 free */
        xfs_dablk_t     freeblk;        /* blockno of free data v2 */
+
+       xfs_dir2_data_aoff_t data_first_offset;
+       size_t          data_entry_offset;
 };
 
 /*========================================================================
@@ -124,6 +131,25 @@ typedef struct xfs_da_state {
                                                /* for dirv2 extrablk is data */
 } xfs_da_state_t;
 
+/*
+ * In-core version of the node header to abstract the differences in the v2 and
+ * v3 disk format of the headers. Callers need to convert to/from disk format as
+ * appropriate.
+ */
+struct xfs_da3_icnode_hdr {
+       uint32_t                forw;
+       uint32_t                back;
+       uint16_t                magic;
+       uint16_t                count;
+       uint16_t                level;
+
+       /*
+        * Pointer to the on-disk format entries, which are behind the
+        * variable size (v4 vs v5) header in the on-disk block.
+        */
+       struct xfs_da_node_entry *btree;
+};
+
 /*
  * Utility macros to aid in logging changed structure fields.
  */
@@ -132,16 +158,6 @@ typedef struct xfs_da_state {
                (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \
                (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1)
 
-/*
- * Name ops for directory and/or attr name operations
- */
-struct xfs_nameops {
-       xfs_dahash_t    (*hashname)(struct xfs_name *);
-       enum xfs_dacmp  (*compname)(struct xfs_da_args *,
-                                       const unsigned char *, int);
-};
-
-
 /*========================================================================
  * Function prototypes.
  *========================================================================*/
@@ -172,25 +188,28 @@ int       xfs_da3_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
 int    xfs_da3_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
                                       xfs_da_state_blk_t *new_blk);
 int    xfs_da3_node_read(struct xfs_trans *tp, struct xfs_inode *dp,
-                        xfs_dablk_t bno, xfs_daddr_t mappedbno,
-                        struct xfs_buf **bpp, int which_fork);
+                       xfs_dablk_t bno, struct xfs_buf **bpp, int whichfork);
+int    xfs_da3_node_read_mapped(struct xfs_trans *tp, struct xfs_inode *dp,
+                       xfs_daddr_t mappedbno, struct xfs_buf **bpp,
+                       int whichfork);
 
 /*
  * Utility routines.
  */
+
+#define XFS_DABUF_MAP_HOLE_OK  (1 << 0)
+
 int    xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno);
 int    xfs_da_grow_inode_int(struct xfs_da_args *args, xfs_fileoff_t *bno,
                              int count);
 int    xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp,
-                             xfs_dablk_t bno, xfs_daddr_t mappedbno,
-                             struct xfs_buf **bp, int whichfork);
+               xfs_dablk_t bno, struct xfs_buf **bp, int whichfork);
 int    xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp,
-                              xfs_dablk_t bno, xfs_daddr_t mappedbno,
-                              struct xfs_buf **bpp, int whichfork,
-                              const struct xfs_buf_ops *ops);
+               xfs_dablk_t bno, unsigned int flags, struct xfs_buf **bpp,
+               int whichfork, const struct xfs_buf_ops *ops);
 int    xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno,
-                               xfs_daddr_t mapped_bno, int whichfork,
-                               const struct xfs_buf_ops *ops);
+               unsigned int flags, int whichfork,
+               const struct xfs_buf_ops *ops);
 int    xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
                                          struct xfs_buf *dead_buf);
 
@@ -202,7 +221,11 @@ enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
 xfs_da_state_t *xfs_da_state_alloc(void);
 void xfs_da_state_free(xfs_da_state_t *state);
 
+void   xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
+               struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from);
+void   xfs_da3_node_hdr_to_disk(struct xfs_mount *mp,
+               struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from);
+
 extern struct kmem_zone *xfs_da_state_zone;
-extern const struct xfs_nameops xfs_default_nameops;
 
 #endif /* __XFS_DA_BTREE_H__ */
diff --git a/fs/xfs/libxfs/xfs_da_format.c b/fs/xfs/libxfs/xfs_da_format.c
deleted file mode 100644 (file)
index b1ae572..0000000
+++ /dev/null
@@ -1,888 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
- * Copyright (c) 2013 Red Hat, Inc.
- * All Rights Reserved.
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_shared.h"
-#include "xfs_format.h"
-#include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
-#include "xfs_inode.h"
-#include "xfs_dir2.h"
-
-/*
- * Shortform directory ops
- */
-static int
-xfs_dir2_sf_entsize(
-       struct xfs_dir2_sf_hdr  *hdr,
-       int                     len)
-{
-       int count = sizeof(struct xfs_dir2_sf_entry);   /* namelen + offset */
-
-       count += len;                                   /* name */
-       count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */
-       return count;
-}
-
-static int
-xfs_dir3_sf_entsize(
-       struct xfs_dir2_sf_hdr  *hdr,
-       int                     len)
-{
-       return xfs_dir2_sf_entsize(hdr, len) + sizeof(uint8_t);
-}
-
-static struct xfs_dir2_sf_entry *
-xfs_dir2_sf_nextentry(
-       struct xfs_dir2_sf_hdr  *hdr,
-       struct xfs_dir2_sf_entry *sfep)
-{
-       return (struct xfs_dir2_sf_entry *)
-               ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen));
-}
-
-static struct xfs_dir2_sf_entry *
-xfs_dir3_sf_nextentry(
-       struct xfs_dir2_sf_hdr  *hdr,
-       struct xfs_dir2_sf_entry *sfep)
-{
-       return (struct xfs_dir2_sf_entry *)
-               ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen));
-}
-
-
-/*
- * For filetype enabled shortform directories, the file type field is stored at
- * the end of the name.  Because it's only a single byte, endian conversion is
- * not necessary. For non-filetype enable directories, the type is always
- * unknown and we never store the value.
- */
-static uint8_t
-xfs_dir2_sfe_get_ftype(
-       struct xfs_dir2_sf_entry *sfep)
-{
-       return XFS_DIR3_FT_UNKNOWN;
-}
-
-static void
-xfs_dir2_sfe_put_ftype(
-       struct xfs_dir2_sf_entry *sfep,
-       uint8_t                 ftype)
-{
-       ASSERT(ftype < XFS_DIR3_FT_MAX);
-}
-
-static uint8_t
-xfs_dir3_sfe_get_ftype(
-       struct xfs_dir2_sf_entry *sfep)
-{
-       uint8_t         ftype;
-
-       ftype = sfep->name[sfep->namelen];
-       if (ftype >= XFS_DIR3_FT_MAX)
-               return XFS_DIR3_FT_UNKNOWN;
-       return ftype;
-}
-
-static void
-xfs_dir3_sfe_put_ftype(
-       struct xfs_dir2_sf_entry *sfep,
-       uint8_t                 ftype)
-{
-       ASSERT(ftype < XFS_DIR3_FT_MAX);
-
-       sfep->name[sfep->namelen] = ftype;
-}
-
-/*
- * Inode numbers in short-form directories can come in two versions,
- * either 4 bytes or 8 bytes wide.  These helpers deal with the
- * two forms transparently by looking at the headers i8count field.
- *
- * For 64-bit inode number the most significant byte must be zero.
- */
-static xfs_ino_t
-xfs_dir2_sf_get_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       uint8_t                 *from)
-{
-       if (hdr->i8count)
-               return get_unaligned_be64(from) & 0x00ffffffffffffffULL;
-       else
-               return get_unaligned_be32(from);
-}
-
-static void
-xfs_dir2_sf_put_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       uint8_t                 *to,
-       xfs_ino_t               ino)
-{
-       ASSERT((ino & 0xff00000000000000ULL) == 0);
-
-       if (hdr->i8count)
-               put_unaligned_be64(ino, to);
-       else
-               put_unaligned_be32(ino, to);
-}
-
-static xfs_ino_t
-xfs_dir2_sf_get_parent_ino(
-       struct xfs_dir2_sf_hdr  *hdr)
-{
-       return xfs_dir2_sf_get_ino(hdr, hdr->parent);
-}
-
-static void
-xfs_dir2_sf_put_parent_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       xfs_ino_t               ino)
-{
-       xfs_dir2_sf_put_ino(hdr, hdr->parent, ino);
-}
-
-/*
- * In short-form directory entries the inode numbers are stored at variable
- * offset behind the entry name. If the entry stores a filetype value, then it
- * sits between the name and the inode number. Hence the inode numbers may only
- * be accessed through the helpers below.
- */
-static xfs_ino_t
-xfs_dir2_sfe_get_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       struct xfs_dir2_sf_entry *sfep)
-{
-       return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen]);
-}
-
-static void
-xfs_dir2_sfe_put_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       struct xfs_dir2_sf_entry *sfep,
-       xfs_ino_t               ino)
-{
-       xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen], ino);
-}
-
-static xfs_ino_t
-xfs_dir3_sfe_get_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       struct xfs_dir2_sf_entry *sfep)
-{
-       return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen + 1]);
-}
-
-static void
-xfs_dir3_sfe_put_ino(
-       struct xfs_dir2_sf_hdr  *hdr,
-       struct xfs_dir2_sf_entry *sfep,
-       xfs_ino_t               ino)
-{
-       xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen + 1], ino);
-}
-
-
-/*
- * Directory data block operations
- */
-
-/*
- * For special situations, the dirent size ends up fixed because we always know
- * what the size of the entry is. That's true for the "." and "..", and
- * therefore we know that they are a fixed size and hence their offsets are
- * constant, as is the first entry.
- *
- * Hence, this calculation is written as a macro to be able to be calculated at
- * compile time and so certain offsets can be calculated directly in the
- * structure initaliser via the macro. There are two macros - one for dirents
- * with ftype and without so there are no unresolvable conditionals in the
- * calculations. We also use round_up() as XFS_DIR2_DATA_ALIGN is always a power
- * of 2 and the compiler doesn't reject it (unlike roundup()).
- */
-#define XFS_DIR2_DATA_ENTSIZE(n)                                       \
-       round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \
-                sizeof(xfs_dir2_data_off_t)), XFS_DIR2_DATA_ALIGN)
-
-#define XFS_DIR3_DATA_ENTSIZE(n)                                       \
-       round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \
-                sizeof(xfs_dir2_data_off_t) + sizeof(uint8_t)),        \
-               XFS_DIR2_DATA_ALIGN)
-
-static int
-xfs_dir2_data_entsize(
-       int                     n)
-{
-       return XFS_DIR2_DATA_ENTSIZE(n);
-}
-
-static int
-xfs_dir3_data_entsize(
-       int                     n)
-{
-       return XFS_DIR3_DATA_ENTSIZE(n);
-}
-
-static uint8_t
-xfs_dir2_data_get_ftype(
-       struct xfs_dir2_data_entry *dep)
-{
-       return XFS_DIR3_FT_UNKNOWN;
-}
-
-static void
-xfs_dir2_data_put_ftype(
-       struct xfs_dir2_data_entry *dep,
-       uint8_t                 ftype)
-{
-       ASSERT(ftype < XFS_DIR3_FT_MAX);
-}
-
-static uint8_t
-xfs_dir3_data_get_ftype(
-       struct xfs_dir2_data_entry *dep)
-{
-       uint8_t         ftype = dep->name[dep->namelen];
-
-       if (ftype >= XFS_DIR3_FT_MAX)
-               return XFS_DIR3_FT_UNKNOWN;
-       return ftype;
-}
-
-static void
-xfs_dir3_data_put_ftype(
-       struct xfs_dir2_data_entry *dep,
-       uint8_t                 type)
-{
-       ASSERT(type < XFS_DIR3_FT_MAX);
-       ASSERT(dep->namelen != 0);
-
-       dep->name[dep->namelen] = type;
-}
-
-/*
- * Pointer to an entry's tag word.
- */
-static __be16 *
-xfs_dir2_data_entry_tag_p(
-       struct xfs_dir2_data_entry *dep)
-{
-       return (__be16 *)((char *)dep +
-               xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16));
-}
-
-static __be16 *
-xfs_dir3_data_entry_tag_p(
-       struct xfs_dir2_data_entry *dep)
-{
-       return (__be16 *)((char *)dep +
-               xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16));
-}
-
-/*
- * location of . and .. in data space (always block 0)
- */
-static struct xfs_dir2_data_entry *
-xfs_dir2_data_dot_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir2_data_dotdot_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR2_DATA_ENTSIZE(1));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir2_data_first_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR2_DATA_ENTSIZE(1) +
-                               XFS_DIR2_DATA_ENTSIZE(2));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir2_ftype_data_dotdot_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir2_ftype_data_first_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1) +
-                               XFS_DIR3_DATA_ENTSIZE(2));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir3_data_dot_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir3_data_hdr));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir3_data_dotdot_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir3_data_first_entry_p(
-       struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1) +
-                               XFS_DIR3_DATA_ENTSIZE(2));
-}
-
-static struct xfs_dir2_data_free *
-xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr)
-{
-       return hdr->bestfree;
-}
-
-static struct xfs_dir2_data_free *
-xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr)
-{
-       return ((struct xfs_dir3_data_hdr *)hdr)->best_free;
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr));
-}
-
-static struct xfs_dir2_data_unused *
-xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_unused *)
-               ((char *)hdr + sizeof(struct xfs_dir2_data_hdr));
-}
-
-static struct xfs_dir2_data_entry *
-xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + sizeof(struct xfs_dir3_data_hdr));
-}
-
-static struct xfs_dir2_data_unused *
-xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr)
-{
-       return (struct xfs_dir2_data_unused *)
-               ((char *)hdr + sizeof(struct xfs_dir3_data_hdr));
-}
-
-
-/*
- * Directory Leaf block operations
- */
-static int
-xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo)
-{
-       return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) /
-               (uint)sizeof(struct xfs_dir2_leaf_entry);
-}
-
-static struct xfs_dir2_leaf_entry *
-xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp)
-{
-       return lp->__ents;
-}
-
-static int
-xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo)
-{
-       return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) /
-               (uint)sizeof(struct xfs_dir2_leaf_entry);
-}
-
-static struct xfs_dir2_leaf_entry *
-xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp)
-{
-       return ((struct xfs_dir3_leaf *)lp)->__ents;
-}
-
-static void
-xfs_dir2_leaf_hdr_from_disk(
-       struct xfs_dir3_icleaf_hdr      *to,
-       struct xfs_dir2_leaf            *from)
-{
-       to->forw = be32_to_cpu(from->hdr.info.forw);
-       to->back = be32_to_cpu(from->hdr.info.back);
-       to->magic = be16_to_cpu(from->hdr.info.magic);
-       to->count = be16_to_cpu(from->hdr.count);
-       to->stale = be16_to_cpu(from->hdr.stale);
-
-       ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC ||
-              to->magic == XFS_DIR2_LEAFN_MAGIC);
-}
-
-static void
-xfs_dir2_leaf_hdr_to_disk(
-       struct xfs_dir2_leaf            *to,
-       struct xfs_dir3_icleaf_hdr      *from)
-{
-       ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC ||
-              from->magic == XFS_DIR2_LEAFN_MAGIC);
-
-       to->hdr.info.forw = cpu_to_be32(from->forw);
-       to->hdr.info.back = cpu_to_be32(from->back);
-       to->hdr.info.magic = cpu_to_be16(from->magic);
-       to->hdr.count = cpu_to_be16(from->count);
-       to->hdr.stale = cpu_to_be16(from->stale);
-}
-
-static void
-xfs_dir3_leaf_hdr_from_disk(
-       struct xfs_dir3_icleaf_hdr      *to,
-       struct xfs_dir2_leaf            *from)
-{
-       struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from;
-
-       to->forw = be32_to_cpu(hdr3->info.hdr.forw);
-       to->back = be32_to_cpu(hdr3->info.hdr.back);
-       to->magic = be16_to_cpu(hdr3->info.hdr.magic);
-       to->count = be16_to_cpu(hdr3->count);
-       to->stale = be16_to_cpu(hdr3->stale);
-
-       ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC ||
-              to->magic == XFS_DIR3_LEAFN_MAGIC);
-}
-
-static void
-xfs_dir3_leaf_hdr_to_disk(
-       struct xfs_dir2_leaf            *to,
-       struct xfs_dir3_icleaf_hdr      *from)
-{
-       struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to;
-
-       ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC ||
-              from->magic == XFS_DIR3_LEAFN_MAGIC);
-
-       hdr3->info.hdr.forw = cpu_to_be32(from->forw);
-       hdr3->info.hdr.back = cpu_to_be32(from->back);
-       hdr3->info.hdr.magic = cpu_to_be16(from->magic);
-       hdr3->count = cpu_to_be16(from->count);
-       hdr3->stale = cpu_to_be16(from->stale);
-}
-
-
-/*
- * Directory/Attribute Node block operations
- */
-static struct xfs_da_node_entry *
-xfs_da2_node_tree_p(struct xfs_da_intnode *dap)
-{
-       return dap->__btree;
-}
-
-static struct xfs_da_node_entry *
-xfs_da3_node_tree_p(struct xfs_da_intnode *dap)
-{
-       return ((struct xfs_da3_intnode *)dap)->__btree;
-}
-
-static void
-xfs_da2_node_hdr_from_disk(
-       struct xfs_da3_icnode_hdr       *to,
-       struct xfs_da_intnode           *from)
-{
-       ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
-       to->forw = be32_to_cpu(from->hdr.info.forw);
-       to->back = be32_to_cpu(from->hdr.info.back);
-       to->magic = be16_to_cpu(from->hdr.info.magic);
-       to->count = be16_to_cpu(from->hdr.__count);
-       to->level = be16_to_cpu(from->hdr.__level);
-}
-
-static void
-xfs_da2_node_hdr_to_disk(
-       struct xfs_da_intnode           *to,
-       struct xfs_da3_icnode_hdr       *from)
-{
-       ASSERT(from->magic == XFS_DA_NODE_MAGIC);
-       to->hdr.info.forw = cpu_to_be32(from->forw);
-       to->hdr.info.back = cpu_to_be32(from->back);
-       to->hdr.info.magic = cpu_to_be16(from->magic);
-       to->hdr.__count = cpu_to_be16(from->count);
-       to->hdr.__level = cpu_to_be16(from->level);
-}
-
-static void
-xfs_da3_node_hdr_from_disk(
-       struct xfs_da3_icnode_hdr       *to,
-       struct xfs_da_intnode           *from)
-{
-       struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from;
-
-       ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC));
-       to->forw = be32_to_cpu(hdr3->info.hdr.forw);
-       to->back = be32_to_cpu(hdr3->info.hdr.back);
-       to->magic = be16_to_cpu(hdr3->info.hdr.magic);
-       to->count = be16_to_cpu(hdr3->__count);
-       to->level = be16_to_cpu(hdr3->__level);
-}
-
-static void
-xfs_da3_node_hdr_to_disk(
-       struct xfs_da_intnode           *to,
-       struct xfs_da3_icnode_hdr       *from)
-{
-       struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to;
-
-       ASSERT(from->magic == XFS_DA3_NODE_MAGIC);
-       hdr3->info.hdr.forw = cpu_to_be32(from->forw);
-       hdr3->info.hdr.back = cpu_to_be32(from->back);
-       hdr3->info.hdr.magic = cpu_to_be16(from->magic);
-       hdr3->__count = cpu_to_be16(from->count);
-       hdr3->__level = cpu_to_be16(from->level);
-}
-
-
-/*
- * Directory free space block operations
- */
-static int
-xfs_dir2_free_max_bests(struct xfs_da_geometry *geo)
-{
-       return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) /
-               sizeof(xfs_dir2_data_off_t);
-}
-
-static __be16 *
-xfs_dir2_free_bests_p(struct xfs_dir2_free *free)
-{
-       return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr));
-}
-
-/*
- * Convert data space db to the corresponding free db.
- */
-static xfs_dir2_db_t
-xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
-{
-       return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) +
-                       (db / xfs_dir2_free_max_bests(geo));
-}
-
-/*
- * Convert data space db to the corresponding index in a free db.
- */
-static int
-xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
-{
-       return db % xfs_dir2_free_max_bests(geo);
-}
-
-static int
-xfs_dir3_free_max_bests(struct xfs_da_geometry *geo)
-{
-       return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) /
-               sizeof(xfs_dir2_data_off_t);
-}
-
-static __be16 *
-xfs_dir3_free_bests_p(struct xfs_dir2_free *free)
-{
-       return (__be16 *)((char *)free + sizeof(struct xfs_dir3_free_hdr));
-}
-
-/*
- * Convert data space db to the corresponding free db.
- */
-static xfs_dir2_db_t
-xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
-{
-       return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) +
-                       (db / xfs_dir3_free_max_bests(geo));
-}
-
-/*
- * Convert data space db to the corresponding index in a free db.
- */
-static int
-xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
-{
-       return db % xfs_dir3_free_max_bests(geo);
-}
-
-static void
-xfs_dir2_free_hdr_from_disk(
-       struct xfs_dir3_icfree_hdr      *to,
-       struct xfs_dir2_free            *from)
-{
-       to->magic = be32_to_cpu(from->hdr.magic);
-       to->firstdb = be32_to_cpu(from->hdr.firstdb);
-       to->nvalid = be32_to_cpu(from->hdr.nvalid);
-       to->nused = be32_to_cpu(from->hdr.nused);
-       ASSERT(to->magic == XFS_DIR2_FREE_MAGIC);
-}
-
-static void
-xfs_dir2_free_hdr_to_disk(
-       struct xfs_dir2_free            *to,
-       struct xfs_dir3_icfree_hdr      *from)
-{
-       ASSERT(from->magic == XFS_DIR2_FREE_MAGIC);
-
-       to->hdr.magic = cpu_to_be32(from->magic);
-       to->hdr.firstdb = cpu_to_be32(from->firstdb);
-       to->hdr.nvalid = cpu_to_be32(from->nvalid);
-       to->hdr.nused = cpu_to_be32(from->nused);
-}
-
-static void
-xfs_dir3_free_hdr_from_disk(
-       struct xfs_dir3_icfree_hdr      *to,
-       struct xfs_dir2_free            *from)
-{
-       struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from;
-
-       to->magic = be32_to_cpu(hdr3->hdr.magic);
-       to->firstdb = be32_to_cpu(hdr3->firstdb);
-       to->nvalid = be32_to_cpu(hdr3->nvalid);
-       to->nused = be32_to_cpu(hdr3->nused);
-
-       ASSERT(to->magic == XFS_DIR3_FREE_MAGIC);
-}
-
-static void
-xfs_dir3_free_hdr_to_disk(
-       struct xfs_dir2_free            *to,
-       struct xfs_dir3_icfree_hdr      *from)
-{
-       struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to;
-
-       ASSERT(from->magic == XFS_DIR3_FREE_MAGIC);
-
-       hdr3->hdr.magic = cpu_to_be32(from->magic);
-       hdr3->firstdb = cpu_to_be32(from->firstdb);
-       hdr3->nvalid = cpu_to_be32(from->nvalid);
-       hdr3->nused = cpu_to_be32(from->nused);
-}
-
-static const struct xfs_dir_ops xfs_dir2_ops = {
-       .sf_entsize = xfs_dir2_sf_entsize,
-       .sf_nextentry = xfs_dir2_sf_nextentry,
-       .sf_get_ftype = xfs_dir2_sfe_get_ftype,
-       .sf_put_ftype = xfs_dir2_sfe_put_ftype,
-       .sf_get_ino = xfs_dir2_sfe_get_ino,
-       .sf_put_ino = xfs_dir2_sfe_put_ino,
-       .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino,
-       .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino,
-
-       .data_entsize = xfs_dir2_data_entsize,
-       .data_get_ftype = xfs_dir2_data_get_ftype,
-       .data_put_ftype = xfs_dir2_data_put_ftype,
-       .data_entry_tag_p = xfs_dir2_data_entry_tag_p,
-       .data_bestfree_p = xfs_dir2_data_bestfree_p,
-
-       .data_dot_offset = sizeof(struct xfs_dir2_data_hdr),
-       .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR2_DATA_ENTSIZE(1),
-       .data_first_offset =  sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR2_DATA_ENTSIZE(1) +
-                               XFS_DIR2_DATA_ENTSIZE(2),
-       .data_entry_offset = sizeof(struct xfs_dir2_data_hdr),
-
-       .data_dot_entry_p = xfs_dir2_data_dot_entry_p,
-       .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p,
-       .data_first_entry_p = xfs_dir2_data_first_entry_p,
-       .data_entry_p = xfs_dir2_data_entry_p,
-       .data_unused_p = xfs_dir2_data_unused_p,
-
-       .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr),
-       .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk,
-       .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk,
-       .leaf_max_ents = xfs_dir2_max_leaf_ents,
-       .leaf_ents_p = xfs_dir2_leaf_ents_p,
-
-       .node_hdr_size = sizeof(struct xfs_da_node_hdr),
-       .node_hdr_to_disk = xfs_da2_node_hdr_to_disk,
-       .node_hdr_from_disk = xfs_da2_node_hdr_from_disk,
-       .node_tree_p = xfs_da2_node_tree_p,
-
-       .free_hdr_size = sizeof(struct xfs_dir2_free_hdr),
-       .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk,
-       .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk,
-       .free_max_bests = xfs_dir2_free_max_bests,
-       .free_bests_p = xfs_dir2_free_bests_p,
-       .db_to_fdb = xfs_dir2_db_to_fdb,
-       .db_to_fdindex = xfs_dir2_db_to_fdindex,
-};
-
-static const struct xfs_dir_ops xfs_dir2_ftype_ops = {
-       .sf_entsize = xfs_dir3_sf_entsize,
-       .sf_nextentry = xfs_dir3_sf_nextentry,
-       .sf_get_ftype = xfs_dir3_sfe_get_ftype,
-       .sf_put_ftype = xfs_dir3_sfe_put_ftype,
-       .sf_get_ino = xfs_dir3_sfe_get_ino,
-       .sf_put_ino = xfs_dir3_sfe_put_ino,
-       .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino,
-       .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino,
-
-       .data_entsize = xfs_dir3_data_entsize,
-       .data_get_ftype = xfs_dir3_data_get_ftype,
-       .data_put_ftype = xfs_dir3_data_put_ftype,
-       .data_entry_tag_p = xfs_dir3_data_entry_tag_p,
-       .data_bestfree_p = xfs_dir2_data_bestfree_p,
-
-       .data_dot_offset = sizeof(struct xfs_dir2_data_hdr),
-       .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1),
-       .data_first_offset =  sizeof(struct xfs_dir2_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1) +
-                               XFS_DIR3_DATA_ENTSIZE(2),
-       .data_entry_offset = sizeof(struct xfs_dir2_data_hdr),
-
-       .data_dot_entry_p = xfs_dir2_data_dot_entry_p,
-       .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p,
-       .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p,
-       .data_entry_p = xfs_dir2_data_entry_p,
-       .data_unused_p = xfs_dir2_data_unused_p,
-
-       .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr),
-       .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk,
-       .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk,
-       .leaf_max_ents = xfs_dir2_max_leaf_ents,
-       .leaf_ents_p = xfs_dir2_leaf_ents_p,
-
-       .node_hdr_size = sizeof(struct xfs_da_node_hdr),
-       .node_hdr_to_disk = xfs_da2_node_hdr_to_disk,
-       .node_hdr_from_disk = xfs_da2_node_hdr_from_disk,
-       .node_tree_p = xfs_da2_node_tree_p,
-
-       .free_hdr_size = sizeof(struct xfs_dir2_free_hdr),
-       .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk,
-       .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk,
-       .free_max_bests = xfs_dir2_free_max_bests,
-       .free_bests_p = xfs_dir2_free_bests_p,
-       .db_to_fdb = xfs_dir2_db_to_fdb,
-       .db_to_fdindex = xfs_dir2_db_to_fdindex,
-};
-
-static const struct xfs_dir_ops xfs_dir3_ops = {
-       .sf_entsize = xfs_dir3_sf_entsize,
-       .sf_nextentry = xfs_dir3_sf_nextentry,
-       .sf_get_ftype = xfs_dir3_sfe_get_ftype,
-       .sf_put_ftype = xfs_dir3_sfe_put_ftype,
-       .sf_get_ino = xfs_dir3_sfe_get_ino,
-       .sf_put_ino = xfs_dir3_sfe_put_ino,
-       .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino,
-       .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino,
-
-       .data_entsize = xfs_dir3_data_entsize,
-       .data_get_ftype = xfs_dir3_data_get_ftype,
-       .data_put_ftype = xfs_dir3_data_put_ftype,
-       .data_entry_tag_p = xfs_dir3_data_entry_tag_p,
-       .data_bestfree_p = xfs_dir3_data_bestfree_p,
-
-       .data_dot_offset = sizeof(struct xfs_dir3_data_hdr),
-       .data_dotdot_offset = sizeof(struct xfs_dir3_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1),
-       .data_first_offset =  sizeof(struct xfs_dir3_data_hdr) +
-                               XFS_DIR3_DATA_ENTSIZE(1) +
-                               XFS_DIR3_DATA_ENTSIZE(2),
-       .data_entry_offset = sizeof(struct xfs_dir3_data_hdr),
-
-       .data_dot_entry_p = xfs_dir3_data_dot_entry_p,
-       .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p,
-       .data_first_entry_p = xfs_dir3_data_first_entry_p,
-       .data_entry_p = xfs_dir3_data_entry_p,
-       .data_unused_p = xfs_dir3_data_unused_p,
-
-       .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr),
-       .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk,
-       .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk,
-       .leaf_max_ents = xfs_dir3_max_leaf_ents,
-       .leaf_ents_p = xfs_dir3_leaf_ents_p,
-
-       .node_hdr_size = sizeof(struct xfs_da3_node_hdr),
-       .node_hdr_to_disk = xfs_da3_node_hdr_to_disk,
-       .node_hdr_from_disk = xfs_da3_node_hdr_from_disk,
-       .node_tree_p = xfs_da3_node_tree_p,
-
-       .free_hdr_size = sizeof(struct xfs_dir3_free_hdr),
-       .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk,
-       .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk,
-       .free_max_bests = xfs_dir3_free_max_bests,
-       .free_bests_p = xfs_dir3_free_bests_p,
-       .db_to_fdb = xfs_dir3_db_to_fdb,
-       .db_to_fdindex = xfs_dir3_db_to_fdindex,
-};
-
-static const struct xfs_dir_ops xfs_dir2_nondir_ops = {
-       .node_hdr_size = sizeof(struct xfs_da_node_hdr),
-       .node_hdr_to_disk = xfs_da2_node_hdr_to_disk,
-       .node_hdr_from_disk = xfs_da2_node_hdr_from_disk,
-       .node_tree_p = xfs_da2_node_tree_p,
-};
-
-static const struct xfs_dir_ops xfs_dir3_nondir_ops = {
-       .node_hdr_size = sizeof(struct xfs_da3_node_hdr),
-       .node_hdr_to_disk = xfs_da3_node_hdr_to_disk,
-       .node_hdr_from_disk = xfs_da3_node_hdr_from_disk,
-       .node_tree_p = xfs_da3_node_tree_p,
-};
-
-/*
- * Return the ops structure according to the current config.  If we are passed
- * an inode, then that overrides the default config we use which is based on
- * feature bits.
- */
-const struct xfs_dir_ops *
-xfs_dir_get_ops(
-       struct xfs_mount        *mp,
-       struct xfs_inode        *dp)
-{
-       if (dp)
-               return dp->d_ops;
-       if (mp->m_dir_inode_ops)
-               return mp->m_dir_inode_ops;
-       if (xfs_sb_version_hascrc(&mp->m_sb))
-               return &xfs_dir3_ops;
-       if (xfs_sb_version_hasftype(&mp->m_sb))
-               return &xfs_dir2_ftype_ops;
-       return &xfs_dir2_ops;
-}
-
-const struct xfs_dir_ops *
-xfs_nondir_get_ops(
-       struct xfs_mount        *mp,
-       struct xfs_inode        *dp)
-{
-       if (dp)
-               return dp->d_ops;
-       if (mp->m_nondir_inode_ops)
-               return mp->m_nondir_inode_ops;
-       if (xfs_sb_version_hascrc(&mp->m_sb))
-               return &xfs_dir3_nondir_ops;
-       return &xfs_dir2_nondir_ops;
-}
index ae654e0..3dee330 100644 (file)
@@ -93,19 +93,6 @@ struct xfs_da3_intnode {
        struct xfs_da_node_entry __btree[];
 };
 
-/*
- * In-core version of the node header to abstract the differences in the v2 and
- * v3 disk format of the headers. Callers need to convert to/from disk format as
- * appropriate.
- */
-struct xfs_da3_icnode_hdr {
-       uint32_t        forw;
-       uint32_t        back;
-       uint16_t        magic;
-       uint16_t        count;
-       uint16_t        level;
-};
-
 /*
  * Directory version 2.
  *
@@ -434,14 +421,6 @@ struct xfs_dir3_leaf_hdr {
        __be32                  pad;            /* 64 bit alignment */
 };
 
-struct xfs_dir3_icleaf_hdr {
-       uint32_t                forw;
-       uint32_t                back;
-       uint16_t                magic;
-       uint16_t                count;
-       uint16_t                stale;
-};
-
 /*
  * Leaf block entry.
  */
@@ -482,7 +461,7 @@ xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp)
 }
 
 /*
- * Free space block defintions for the node format.
+ * Free space block definitions for the node format.
  */
 
 /*
@@ -520,19 +499,6 @@ struct xfs_dir3_free {
 
 #define XFS_DIR3_FREE_CRC_OFF  offsetof(struct xfs_dir3_free, hdr.hdr.crc)
 
-/*
- * In core version of the free block header, abstracted away from on-disk format
- * differences. Use this in the code, and convert to/from the disk version using
- * xfs_dir3_free_hdr_from_disk/xfs_dir3_free_hdr_to_disk.
- */
-struct xfs_dir3_icfree_hdr {
-       uint32_t        magic;
-       uint32_t        firstdb;
-       uint32_t        nvalid;
-       uint32_t        nused;
-
-};
-
 /*
  * Single block format.
  *
@@ -709,29 +675,6 @@ struct xfs_attr3_leafblock {
         */
 };
 
-/*
- * incore, neutral version of the attribute leaf header
- */
-struct xfs_attr3_icleaf_hdr {
-       uint32_t        forw;
-       uint32_t        back;
-       uint16_t        magic;
-       uint16_t        count;
-       uint16_t        usedbytes;
-       /*
-        * firstused is 32-bit here instead of 16-bit like the on-disk variant
-        * to support maximum fsb size of 64k without overflow issues throughout
-        * the attr code. Instead, the overflow condition is handled on
-        * conversion to/from disk.
-        */
-       uint32_t        firstused;
-       __u8            holes;
-       struct {
-               uint16_t        base;
-               uint16_t        size;
-       } freemap[XFS_ATTR_LEAF_MAPSIZE];
-};
-
 /*
  * Special value to represent fs block size in the leaf header firstused field.
  * Only used when block size overflows the 2-bytes available on disk.
index 867c5de..0aa87cb 100644 (file)
@@ -52,7 +52,7 @@ xfs_mode_to_ftype(
  * ASCII case-insensitive (ie. A-Z) support for directories that was
  * used in IRIX.
  */
-STATIC xfs_dahash_t
+xfs_dahash_t
 xfs_ascii_ci_hashname(
        struct xfs_name *name)
 {
@@ -65,14 +65,14 @@ xfs_ascii_ci_hashname(
        return hash;
 }
 
-STATIC enum xfs_dacmp
+enum xfs_dacmp
 xfs_ascii_ci_compname(
-       struct xfs_da_args *args,
-       const unsigned char *name,
-       int             len)
+       struct xfs_da_args      *args,
+       const unsigned char     *name,
+       int                     len)
 {
-       enum xfs_dacmp  result;
-       int             i;
+       enum xfs_dacmp          result;
+       int                     i;
 
        if (args->namelen != len)
                return XFS_CMP_DIFFERENT;
@@ -89,26 +89,16 @@ xfs_ascii_ci_compname(
        return result;
 }
 
-static const struct xfs_nameops xfs_ascii_ci_nameops = {
-       .hashname       = xfs_ascii_ci_hashname,
-       .compname       = xfs_ascii_ci_compname,
-};
-
 int
 xfs_da_mount(
        struct xfs_mount        *mp)
 {
        struct xfs_da_geometry  *dageo;
-       int                     nodehdr_size;
 
 
        ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
        ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
 
-       mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL);
-       mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL);
-
-       nodehdr_size = mp->m_dir_inode_ops->node_hdr_size;
        mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
                                    KM_MAYFAIL);
        mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
@@ -125,6 +115,27 @@ xfs_da_mount(
        dageo->fsblog = mp->m_sb.sb_blocklog;
        dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
        dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);
+               dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);
+               dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);
+               dageo->data_entry_offset =
+                               sizeof(struct xfs_dir3_data_hdr);
+       } else {
+               dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);
+               dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);
+               dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);
+               dageo->data_entry_offset =
+                               sizeof(struct xfs_dir2_data_hdr);
+       }
+       dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /
+                       sizeof(struct xfs_dir2_leaf_entry);
+       dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /
+                       sizeof(xfs_dir2_data_off_t);
+
+       dageo->data_first_offset = dageo->data_entry_offset +
+                       xfs_dir2_data_entsize(mp, 1) +
+                       xfs_dir2_data_entsize(mp, 2);
 
        /*
         * Now we've set up the block conversion variables, we can calculate the
@@ -133,7 +144,7 @@ xfs_da_mount(
        dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
        dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
        dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
-       dageo->node_ents = (dageo->blksize - nodehdr_size) /
+       dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
                                (uint)sizeof(xfs_da_node_entry_t);
        dageo->magicpct = (dageo->blksize * 37) / 100;
 
@@ -143,15 +154,10 @@ xfs_da_mount(
        dageo->fsblog = mp->m_sb.sb_blocklog;
        dageo->blksize = 1 << dageo->blklog;
        dageo->fsbcount = 1;
-       dageo->node_ents = (dageo->blksize - nodehdr_size) /
+       dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
+       dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
                                (uint)sizeof(xfs_da_node_entry_t);
        dageo->magicpct = (dageo->blksize * 37) / 100;
-
-       if (xfs_sb_version_hasasciici(&mp->m_sb))
-               mp->m_dirnameops = &xfs_ascii_ci_nameops;
-       else
-               mp->m_dirnameops = &xfs_default_nameops;
-
        return 0;
 }
 
@@ -191,10 +197,10 @@ xfs_dir_ino_validate(
 {
        bool            ino_ok = xfs_verify_dir_ino(mp, ino);
 
-       if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
+       if (XFS_IS_CORRUPT(mp, !ino_ok) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {
                xfs_warn(mp, "Invalid inode number 0x%Lx",
                                (unsigned long long) ino);
-               XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -262,7 +268,7 @@ xfs_dir_createname(
        args->name = name->name;
        args->namelen = name->len;
        args->filetype = name->type;
-       args->hashval = dp->i_mount->m_dirnameops->hashname(name);
+       args->hashval = xfs_dir2_hashname(dp->i_mount, name);
        args->inumber = inum;
        args->dp = dp;
        args->total = total;
@@ -358,7 +364,7 @@ xfs_dir_lookup(
        args->name = name->name;
        args->namelen = name->len;
        args->filetype = name->type;
-       args->hashval = dp->i_mount->m_dirnameops->hashname(name);
+       args->hashval = xfs_dir2_hashname(dp->i_mount, name);
        args->dp = dp;
        args->whichfork = XFS_DATA_FORK;
        args->trans = tp;
@@ -430,7 +436,7 @@ xfs_dir_removename(
        args->name = name->name;
        args->namelen = name->len;
        args->filetype = name->type;
-       args->hashval = dp->i_mount->m_dirnameops->hashname(name);
+       args->hashval = xfs_dir2_hashname(dp->i_mount, name);
        args->inumber = ino;
        args->dp = dp;
        args->total = total;
@@ -491,7 +497,7 @@ xfs_dir_replace(
        args->name = name->name;
        args->namelen = name->len;
        args->filetype = name->type;
-       args->hashval = dp->i_mount->m_dirnameops->hashname(name);
+       args->hashval = xfs_dir2_hashname(dp->i_mount, name);
        args->inumber = inum;
        args->dp = dp;
        args->total = total;
@@ -600,7 +606,9 @@ xfs_dir2_isblock(
        if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
                return rval;
        rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
-       if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
+       if (XFS_IS_CORRUPT(args->dp->i_mount,
+                          rval != 0 &&
+                          args->dp->i_d.di_size != args->geo->blksize))
                return -EFSCORRUPTED;
        *vp = rval;
        return 0;
index f542447..033777e 100644 (file)
@@ -18,6 +18,8 @@ struct xfs_dir2_sf_entry;
 struct xfs_dir2_data_hdr;
 struct xfs_dir2_data_entry;
 struct xfs_dir2_data_unused;
+struct xfs_dir3_icfree_hdr;
+struct xfs_dir3_icleaf_hdr;
 
 extern struct xfs_name xfs_name_dotdot;
 
@@ -26,85 +28,6 @@ extern struct xfs_name       xfs_name_dotdot;
  */
 extern unsigned char xfs_mode_to_ftype(int mode);
 
-/*
- * directory operations vector for encode/decode routines
- */
-struct xfs_dir_ops {
-       int     (*sf_entsize)(struct xfs_dir2_sf_hdr *hdr, int len);
-       struct xfs_dir2_sf_entry *
-               (*sf_nextentry)(struct xfs_dir2_sf_hdr *hdr,
-                               struct xfs_dir2_sf_entry *sfep);
-       uint8_t (*sf_get_ftype)(struct xfs_dir2_sf_entry *sfep);
-       void    (*sf_put_ftype)(struct xfs_dir2_sf_entry *sfep,
-                               uint8_t ftype);
-       xfs_ino_t (*sf_get_ino)(struct xfs_dir2_sf_hdr *hdr,
-                               struct xfs_dir2_sf_entry *sfep);
-       void    (*sf_put_ino)(struct xfs_dir2_sf_hdr *hdr,
-                             struct xfs_dir2_sf_entry *sfep,
-                             xfs_ino_t ino);
-       xfs_ino_t (*sf_get_parent_ino)(struct xfs_dir2_sf_hdr *hdr);
-       void    (*sf_put_parent_ino)(struct xfs_dir2_sf_hdr *hdr,
-                                    xfs_ino_t ino);
-
-       int     (*data_entsize)(int len);
-       uint8_t (*data_get_ftype)(struct xfs_dir2_data_entry *dep);
-       void    (*data_put_ftype)(struct xfs_dir2_data_entry *dep,
-                               uint8_t ftype);
-       __be16 * (*data_entry_tag_p)(struct xfs_dir2_data_entry *dep);
-       struct xfs_dir2_data_free *
-               (*data_bestfree_p)(struct xfs_dir2_data_hdr *hdr);
-
-       xfs_dir2_data_aoff_t data_dot_offset;
-       xfs_dir2_data_aoff_t data_dotdot_offset;
-       xfs_dir2_data_aoff_t data_first_offset;
-       size_t  data_entry_offset;
-
-       struct xfs_dir2_data_entry *
-               (*data_dot_entry_p)(struct xfs_dir2_data_hdr *hdr);
-       struct xfs_dir2_data_entry *
-               (*data_dotdot_entry_p)(struct xfs_dir2_data_hdr *hdr);
-       struct xfs_dir2_data_entry *
-               (*data_first_entry_p)(struct xfs_dir2_data_hdr *hdr);
-       struct xfs_dir2_data_entry *
-               (*data_entry_p)(struct xfs_dir2_data_hdr *hdr);
-       struct xfs_dir2_data_unused *
-               (*data_unused_p)(struct xfs_dir2_data_hdr *hdr);
-
-       int     leaf_hdr_size;
-       void    (*leaf_hdr_to_disk)(struct xfs_dir2_leaf *to,
-                                   struct xfs_dir3_icleaf_hdr *from);
-       void    (*leaf_hdr_from_disk)(struct xfs_dir3_icleaf_hdr *to,
-                                     struct xfs_dir2_leaf *from);
-       int     (*leaf_max_ents)(struct xfs_da_geometry *geo);
-       struct xfs_dir2_leaf_entry *
-               (*leaf_ents_p)(struct xfs_dir2_leaf *lp);
-
-       int     node_hdr_size;
-       void    (*node_hdr_to_disk)(struct xfs_da_intnode *to,
-                                   struct xfs_da3_icnode_hdr *from);
-       void    (*node_hdr_from_disk)(struct xfs_da3_icnode_hdr *to,
-                                     struct xfs_da_intnode *from);
-       struct xfs_da_node_entry *
-               (*node_tree_p)(struct xfs_da_intnode *dap);
-
-       int     free_hdr_size;
-       void    (*free_hdr_to_disk)(struct xfs_dir2_free *to,
-                                   struct xfs_dir3_icfree_hdr *from);
-       void    (*free_hdr_from_disk)(struct xfs_dir3_icfree_hdr *to,
-                                     struct xfs_dir2_free *from);
-       int     (*free_max_bests)(struct xfs_da_geometry *geo);
-       __be16 * (*free_bests_p)(struct xfs_dir2_free *free);
-       xfs_dir2_db_t (*db_to_fdb)(struct xfs_da_geometry *geo,
-                                  xfs_dir2_db_t db);
-       int     (*db_to_fdindex)(struct xfs_da_geometry *geo,
-                                xfs_dir2_db_t db);
-};
-
-extern const struct xfs_dir_ops *
-       xfs_dir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp);
-extern const struct xfs_dir_ops *
-       xfs_nondir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp);
-
 /*
  * Generic directory interface routines
  */
@@ -124,6 +47,8 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t ino,
                                xfs_extlen_t tot);
+extern bool xfs_dir2_sf_replace_needblock(struct xfs_inode *dp,
+                               xfs_ino_t inum);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t inum,
                                xfs_extlen_t tot);
@@ -143,10 +68,7 @@ extern int xfs_dir2_isleaf(struct xfs_da_args *args, int *r);
 extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
                                struct xfs_buf *bp);
 
-extern void xfs_dir2_data_freescan_int(struct xfs_da_geometry *geo,
-               const struct xfs_dir_ops *ops,
-               struct xfs_dir2_data_hdr *hdr, int *loghead);
-extern void xfs_dir2_data_freescan(struct xfs_inode *dp,
+extern void xfs_dir2_data_freescan(struct xfs_mount *mp,
                struct xfs_dir2_data_hdr *hdr, int *loghead);
 extern void xfs_dir2_data_log_entry(struct xfs_da_args *args,
                struct xfs_buf *bp, struct xfs_dir2_data_entry *dep);
@@ -324,7 +246,7 @@ xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp)
 #define XFS_READDIR_BUFSIZE    (32768)
 
 unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp, uint8_t filetype);
-void *xfs_dir3_data_endp(struct xfs_da_geometry *geo,
+unsigned int xfs_dir3_data_end_offset(struct xfs_da_geometry *geo,
                struct xfs_dir2_data_hdr *hdr);
 bool xfs_dir2_namecheck(const void *name, size_t length);
 
index 49e4bc3..d6ced59 100644 (file)
@@ -123,7 +123,7 @@ xfs_dir3_block_read(
        struct xfs_mount        *mp = dp->i_mount;
        int                     err;
 
-       err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
+       err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, 0, bpp,
                                XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
        if (!err && tp && *bpp)
                xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
@@ -172,7 +172,7 @@ xfs_dir2_block_need_space(
        struct xfs_dir2_data_unused     *enddup = NULL;
 
        *compact = 0;
-       bf = dp->d_ops->data_bestfree_p(hdr);
+       bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
 
        /*
         * If there are stale entries we'll use one for the leaf.
@@ -311,7 +311,7 @@ xfs_dir2_block_compact(
         * This needs to happen before the next call to use_free.
         */
        if (needscan)
-               xfs_dir2_data_freescan(args->dp, hdr, needlog);
+               xfs_dir2_data_freescan(args->dp->i_mount, hdr, needlog);
 }
 
 /*
@@ -355,7 +355,7 @@ xfs_dir2_block_addname(
        if (error)
                return error;
 
-       len = dp->d_ops->data_entsize(args->namelen);
+       len = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
 
        /*
         * Set up pointers to parts of the block.
@@ -458,7 +458,7 @@ xfs_dir2_block_addname(
                 * This needs to happen before the next call to use_free.
                 */
                if (needscan) {
-                       xfs_dir2_data_freescan(dp, hdr, &needlog);
+                       xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
                        needscan = 0;
                }
                /*
@@ -541,14 +541,14 @@ xfs_dir2_block_addname(
        dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, args->namelen);
-       dp->d_ops->data_put_ftype(dep, args->filetype);
-       tagp = dp->d_ops->data_entry_tag_p(dep);
+       xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
+       tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        /*
         * Clean up the bestfree array and log the header, tail, and entry.
         */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        if (needlog)
                xfs_dir2_data_log_header(args, bp);
        xfs_dir2_block_log_tail(tp, bp);
@@ -633,7 +633,7 @@ xfs_dir2_block_lookup(
         * Fill in inode number, CI name if appropriate, release the block.
         */
        args->inumber = be64_to_cpu(dep->inumber);
-       args->filetype = dp->d_ops->data_get_ftype(dep);
+       args->filetype = xfs_dir2_data_get_ftype(dp->i_mount, dep);
        error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
        xfs_trans_brelse(args->trans, bp);
        return error;
@@ -660,13 +660,11 @@ xfs_dir2_block_lookup_int(
        int                     high;           /* binary search high index */
        int                     low;            /* binary search low index */
        int                     mid;            /* binary search current idx */
-       xfs_mount_t             *mp;            /* filesystem mount point */
        xfs_trans_t             *tp;            /* transaction pointer */
        enum xfs_dacmp          cmp;            /* comparison result */
 
        dp = args->dp;
        tp = args->trans;
-       mp = dp->i_mount;
 
        error = xfs_dir3_block_read(tp, dp, &bp);
        if (error)
@@ -718,7 +716,7 @@ xfs_dir2_block_lookup_int(
                 * and buffer. If it's the first case-insensitive match, store
                 * the index and buffer and continue looking for an exact match.
                 */
-               cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
+               cmp = xfs_dir2_compname(args, dep->name, dep->namelen);
                if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
                        args->cmpresult = cmp;
                        *bpp = bp;
@@ -791,7 +789,8 @@ xfs_dir2_block_removename(
        needlog = needscan = 0;
        xfs_dir2_data_make_free(args, bp,
                (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
-               dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
+               xfs_dir2_data_entsize(dp->i_mount, dep->namelen), &needlog,
+               &needscan);
        /*
         * Fix up the block tail.
         */
@@ -806,7 +805,7 @@ xfs_dir2_block_removename(
         * Fix up bestfree, log the header if necessary.
         */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        if (needlog)
                xfs_dir2_data_log_header(args, bp);
        xfs_dir3_data_check(dp, bp);
@@ -864,7 +863,7 @@ xfs_dir2_block_replace(
         * Change the inode number to the new value.
         */
        dep->inumber = cpu_to_be64(args->inumber);
-       dp->d_ops->data_put_ftype(dep, args->filetype);
+       xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
        xfs_dir2_data_log_entry(args, bp, dep);
        xfs_dir3_data_check(dp, bp);
        return 0;
@@ -914,7 +913,6 @@ xfs_dir2_leaf_to_block(
        __be16                  *tagp;          /* end of entry (tag) */
        int                     to;             /* block/leaf to index */
        xfs_trans_t             *tp;            /* transaction pointer */
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
        trace_xfs_dir2_leaf_to_block(args);
@@ -923,8 +921,7 @@ xfs_dir2_leaf_to_block(
        tp = args->trans;
        mp = dp->i_mount;
        leaf = lbp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
        ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
 
        ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC ||
@@ -938,7 +935,7 @@ xfs_dir2_leaf_to_block(
        while (dp->i_d.di_size > args->geo->blksize) {
                int hdrsz;
 
-               hdrsz = dp->d_ops->data_entry_offset;
+               hdrsz = args->geo->data_entry_offset;
                bestsp = xfs_dir2_leaf_bests_p(ltp);
                if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
                                            args->geo->blksize - hdrsz) {
@@ -953,7 +950,7 @@ xfs_dir2_leaf_to_block(
         * Read the data block if we don't already have it, give up if it fails.
         */
        if (!dbp) {
-               error = xfs_dir3_data_read(tp, dp, args->geo->datablk, -1, &dbp);
+               error = xfs_dir3_data_read(tp, dp, args->geo->datablk, 0, &dbp);
                if (error)
                        return error;
        }
@@ -1004,9 +1001,10 @@ xfs_dir2_leaf_to_block(
         */
        lep = xfs_dir2_block_leaf_p(btp);
        for (from = to = 0; from < leafhdr.count; from++) {
-               if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
+               if (leafhdr.ents[from].address ==
+                   cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
                        continue;
-               lep[to++] = ents[from];
+               lep[to++] = leafhdr.ents[from];
        }
        ASSERT(to == be32_to_cpu(btp->count));
        xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1);
@@ -1014,7 +1012,7 @@ xfs_dir2_leaf_to_block(
         * Scan the bestfree if we need it and log the data block header.
         */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        if (needlog)
                xfs_dir2_data_log_header(args, dbp);
        /*
@@ -1039,47 +1037,38 @@ xfs_dir2_leaf_to_block(
  */
 int                                            /* error */
 xfs_dir2_sf_to_block(
-       xfs_da_args_t           *args)          /* operation arguments */
+       struct xfs_da_args      *args)
 {
+       struct xfs_trans        *tp = args->trans;
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
+       struct xfs_da_geometry  *geo = args->geo;
        xfs_dir2_db_t           blkno;          /* dir-relative block # (0) */
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
        struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail pointer */
        xfs_dir2_data_entry_t   *dep;           /* data entry pointer */
-       xfs_inode_t             *dp;            /* incore directory inode */
        int                     dummy;          /* trash */
        xfs_dir2_data_unused_t  *dup;           /* unused entry pointer */
        int                     endoffset;      /* end of data objects */
        int                     error;          /* error return value */
        int                     i;              /* index */
-       xfs_mount_t             *mp;            /* filesystem mount point */
        int                     needlog;        /* need to log block header */
        int                     needscan;       /* need to scan block freespc */
        int                     newoffset;      /* offset from current entry */
-       int                     offset;         /* target block offset */
+       unsigned int            offset = geo->data_entry_offset;
        xfs_dir2_sf_entry_t     *sfep;          /* sf entry pointer */
        xfs_dir2_sf_hdr_t       *oldsfp;        /* old shortform header  */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform header  */
        __be16                  *tagp;          /* end of data entry */
-       xfs_trans_t             *tp;            /* transaction pointer */
        struct xfs_name         name;
-       struct xfs_ifork        *ifp;
 
        trace_xfs_dir2_sf_to_block(args);
 
-       dp = args->dp;
-       tp = args->trans;
-       mp = dp->i_mount;
-       ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
        ASSERT(ifp->if_flags & XFS_IFINLINE);
-       /*
-        * Bomb out if the shortform directory is way too short.
-        */
-       if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(mp));
-               return -EIO;
-       }
+       ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
 
        oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data;
 
@@ -1123,7 +1112,7 @@ xfs_dir2_sf_to_block(
         * The whole thing is initialized to free by the init routine.
         * Say we're using the leaf and tail area.
         */
-       dup = dp->d_ops->data_unused_p(hdr);
+       dup = bp->b_addr + offset;
        needlog = needscan = 0;
        error = xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
                        i, &needlog, &needscan);
@@ -1146,35 +1135,37 @@ xfs_dir2_sf_to_block(
                        be16_to_cpu(dup->length), &needlog, &needscan);
        if (error)
                goto out_free;
+
        /*
         * Create entry for .
         */
-       dep = dp->d_ops->data_dot_entry_p(hdr);
+       dep = bp->b_addr + offset;
        dep->inumber = cpu_to_be64(dp->i_ino);
        dep->namelen = 1;
        dep->name[0] = '.';
-       dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR);
-       tagp = dp->d_ops->data_entry_tag_p(dep);
-       *tagp = cpu_to_be16((char *)dep - (char *)hdr);
+       xfs_dir2_data_put_ftype(mp, dep, XFS_DIR3_FT_DIR);
+       tagp = xfs_dir2_data_entry_tag_p(mp, dep);
+       *tagp = cpu_to_be16(offset);
        xfs_dir2_data_log_entry(args, bp, dep);
        blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
-       blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
-                               (char *)dep - (char *)hdr));
+       blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(offset));
+       offset += xfs_dir2_data_entsize(mp, dep->namelen);
+
        /*
         * Create entry for ..
         */
-       dep = dp->d_ops->data_dotdot_entry_p(hdr);
-       dep->inumber = cpu_to_be64(dp->d_ops->sf_get_parent_ino(sfp));
+       dep = bp->b_addr + offset;
+       dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
        dep->namelen = 2;
        dep->name[0] = dep->name[1] = '.';
-       dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR);
-       tagp = dp->d_ops->data_entry_tag_p(dep);
-       *tagp = cpu_to_be16((char *)dep - (char *)hdr);
+       xfs_dir2_data_put_ftype(mp, dep, XFS_DIR3_FT_DIR);
+       tagp = xfs_dir2_data_entry_tag_p(mp, dep);
+       *tagp = cpu_to_be16(offset);
        xfs_dir2_data_log_entry(args, bp, dep);
        blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
-       blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
-                               (char *)dep - (char *)hdr));
-       offset = dp->d_ops->data_first_offset;
+       blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(offset));
+       offset += xfs_dir2_data_entsize(mp, dep->namelen);
+
        /*
         * Loop over existing entries, stuff them in.
         */
@@ -1183,6 +1174,7 @@ xfs_dir2_sf_to_block(
                sfep = NULL;
        else
                sfep = xfs_dir2_sf_firstentry(sfp);
+
        /*
         * Need to preserve the existing offset values in the sf directory.
         * Insert holes (unused entries) where necessary.
@@ -1199,40 +1191,39 @@ xfs_dir2_sf_to_block(
                 * There should be a hole here, make one.
                 */
                if (offset < newoffset) {
-                       dup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
+                       dup = bp->b_addr + offset;
                        dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
                        dup->length = cpu_to_be16(newoffset - offset);
-                       *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(
-                               ((char *)dup - (char *)hdr));
+                       *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(offset);
                        xfs_dir2_data_log_unused(args, bp, dup);
                        xfs_dir2_data_freeinsert(hdr,
-                                                dp->d_ops->data_bestfree_p(hdr),
-                                                dup, &dummy);
+                                       xfs_dir2_data_bestfree_p(mp, hdr),
+                                       dup, &dummy);
                        offset += be16_to_cpu(dup->length);
                        continue;
                }
                /*
                 * Copy a real entry.
                 */
-               dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset);
-               dep->inumber = cpu_to_be64(dp->d_ops->sf_get_ino(sfp, sfep));
+               dep = bp->b_addr + newoffset;
+               dep->inumber = cpu_to_be64(xfs_dir2_sf_get_ino(mp, sfp, sfep));
                dep->namelen = sfep->namelen;
-               dp->d_ops->data_put_ftype(dep, dp->d_ops->sf_get_ftype(sfep));
+               xfs_dir2_data_put_ftype(mp, dep,
+                               xfs_dir2_sf_get_ftype(mp, sfep));
                memcpy(dep->name, sfep->name, dep->namelen);
-               tagp = dp->d_ops->data_entry_tag_p(dep);
-               *tagp = cpu_to_be16((char *)dep - (char *)hdr);
+               tagp = xfs_dir2_data_entry_tag_p(mp, dep);
+               *tagp = cpu_to_be16(newoffset);
                xfs_dir2_data_log_entry(args, bp, dep);
                name.name = sfep->name;
                name.len = sfep->namelen;
-               blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->
-                                                       hashname(&name));
-               blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
-                                                (char *)dep - (char *)hdr));
+               blp[2 + i].hashval = cpu_to_be32(xfs_dir2_hashname(mp, &name));
+               blp[2 + i].address =
+                       cpu_to_be32(xfs_dir2_byte_to_dataptr(newoffset));
                offset = (int)((char *)(tagp + 1) - (char *)hdr);
                if (++i == sfp->count)
                        sfep = NULL;
                else
-                       sfep = dp->d_ops->sf_nextentry(sfp, sfep);
+                       sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
        }
        /* Done with the temporary buffer */
        kmem_free(sfp);
index 2c79be4..b9eba82 100644 (file)
@@ -13,6 +13,7 @@
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_dir2.h"
+#include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
@@ -23,6 +24,71 @@ static xfs_failaddr_t xfs_dir2_data_freefind_verify(
                struct xfs_dir2_data_unused *dup,
                struct xfs_dir2_data_free **bf_ent);
 
+struct xfs_dir2_data_free *
+xfs_dir2_data_bestfree_p(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_data_hdr        *hdr)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               return ((struct xfs_dir3_data_hdr *)hdr)->best_free;
+       return hdr->bestfree;
+}
+
+/*
+ * Pointer to an entry's tag word.
+ */
+__be16 *
+xfs_dir2_data_entry_tag_p(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_data_entry      *dep)
+{
+       return (__be16 *)((char *)dep +
+               xfs_dir2_data_entsize(mp, dep->namelen) - sizeof(__be16));
+}
+
+uint8_t
+xfs_dir2_data_get_ftype(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_data_entry      *dep)
+{
+       if (xfs_sb_version_hasftype(&mp->m_sb)) {
+               uint8_t                 ftype = dep->name[dep->namelen];
+
+               if (likely(ftype < XFS_DIR3_FT_MAX))
+                       return ftype;
+       }
+
+       return XFS_DIR3_FT_UNKNOWN;
+}
+
+void
+xfs_dir2_data_put_ftype(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_data_entry      *dep,
+       uint8_t                         ftype)
+{
+       ASSERT(ftype < XFS_DIR3_FT_MAX);
+       ASSERT(dep->namelen != 0);
+
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               dep->name[dep->namelen] = ftype;
+}
+
+/*
+ * The number of leaf entries is limited by the size of the block and the amount
+ * of space used by the data entries.  We don't know how much space is used by
+ * the data entries yet, so just ensure that the count falls somewhere inside
+ * the block right now.
+ */
+static inline unsigned int
+xfs_dir2_data_max_leaf_entries(
+       struct xfs_da_geometry          *geo)
+{
+       return (geo->blksize - sizeof(struct xfs_dir2_block_tail) -
+               geo->data_entry_offset) /
+                       sizeof(struct xfs_dir2_leaf_entry);
+}
+
 /*
  * Check the consistency of the data block.
  * The input can also be a block-format directory.
@@ -38,40 +104,27 @@ __xfs_dir3_data_check(
        xfs_dir2_block_tail_t   *btp=NULL;      /* block tail */
        int                     count;          /* count of entries found */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
-       xfs_dir2_data_entry_t   *dep;           /* data entry */
        xfs_dir2_data_free_t    *dfp;           /* bestfree entry */
-       xfs_dir2_data_unused_t  *dup;           /* unused entry */
-       char                    *endp;          /* end of useful data */
        int                     freeseen;       /* mask of bestfrees seen */
        xfs_dahash_t            hash;           /* hash of current name */
        int                     i;              /* leaf index */
        int                     lastfree;       /* last entry was unused */
        xfs_dir2_leaf_entry_t   *lep=NULL;      /* block leaf entries */
        struct xfs_mount        *mp = bp->b_mount;
-       char                    *p;             /* current data position */
        int                     stale;          /* count of stale leaves */
        struct xfs_name         name;
-       const struct xfs_dir_ops *ops;
-       struct xfs_da_geometry  *geo;
-
-       geo = mp->m_dir_geo;
+       unsigned int            offset;
+       unsigned int            end;
+       struct xfs_da_geometry  *geo = mp->m_dir_geo;
 
        /*
-        * We can be passed a null dp here from a verifier, so we need to go the
-        * hard way to get them.
+        * If this isn't a directory, something is seriously wrong.  Bail out.
         */
-       ops = xfs_dir_get_ops(mp, dp);
-
-       /*
-        * If this isn't a directory, or we don't get handed the dir ops,
-        * something is seriously wrong.  Bail out.
-        */
-       if ((dp && !S_ISDIR(VFS_I(dp)->i_mode)) ||
-           ops != xfs_dir_get_ops(mp, NULL))
+       if (dp && !S_ISDIR(VFS_I(dp)->i_mode))
                return __this_address;
 
        hdr = bp->b_addr;
-       p = (char *)ops->data_entry_p(hdr);
+       offset = geo->data_entry_offset;
 
        switch (hdr->magic) {
        case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
@@ -79,15 +132,8 @@ __xfs_dir3_data_check(
                btp = xfs_dir2_block_tail_p(geo, hdr);
                lep = xfs_dir2_block_leaf_p(btp);
 
-               /*
-                * The number of leaf entries is limited by the size of the
-                * block and the amount of space used by the data entries.
-                * We don't know how much space is used by the data entries yet,
-                * so just ensure that the count falls somewhere inside the
-                * block right now.
-                */
                if (be32_to_cpu(btp->count) >=
-                   ((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry))
+                   xfs_dir2_data_max_leaf_entries(geo))
                        return __this_address;
                break;
        case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
@@ -96,14 +142,14 @@ __xfs_dir3_data_check(
        default:
                return __this_address;
        }
-       endp = xfs_dir3_data_endp(geo, hdr);
-       if (!endp)
+       end = xfs_dir3_data_end_offset(geo, hdr);
+       if (!end)
                return __this_address;
 
        /*
         * Account for zero bestfree entries.
         */
-       bf = ops->data_bestfree_p(hdr);
+       bf = xfs_dir2_data_bestfree_p(mp, hdr);
        count = lastfree = freeseen = 0;
        if (!bf[0].length) {
                if (bf[0].offset)
@@ -128,8 +174,10 @@ __xfs_dir3_data_check(
        /*
         * Loop over the data/unused entries.
         */
-       while (p < endp) {
-               dup = (xfs_dir2_data_unused_t *)p;
+       while (offset < end) {
+               struct xfs_dir2_data_unused     *dup = bp->b_addr + offset;
+               struct xfs_dir2_data_entry      *dep = bp->b_addr + offset;
+
                /*
                 * If it's unused, look for the space in the bestfree table.
                 * If we find it, account for that, else make sure it
@@ -140,10 +188,10 @@ __xfs_dir3_data_check(
 
                        if (lastfree != 0)
                                return __this_address;
-                       if (endp < p + be16_to_cpu(dup->length))
+                       if (offset + be16_to_cpu(dup->length) > end)
                                return __this_address;
                        if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
-                           (char *)dup - (char *)hdr)
+                           offset)
                                return __this_address;
                        fa = xfs_dir2_data_freefind_verify(hdr, bf, dup, &dfp);
                        if (fa)
@@ -158,7 +206,7 @@ __xfs_dir3_data_check(
                                    be16_to_cpu(bf[2].length))
                                        return __this_address;
                        }
-                       p += be16_to_cpu(dup->length);
+                       offset += be16_to_cpu(dup->length);
                        lastfree = 1;
                        continue;
                }
@@ -168,17 +216,15 @@ __xfs_dir3_data_check(
                 * in the leaf section of the block.
                 * The linear search is crude but this is DEBUG code.
                 */
-               dep = (xfs_dir2_data_entry_t *)p;
                if (dep->namelen == 0)
                        return __this_address;
                if (xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)))
                        return __this_address;
-               if (endp < p + ops->data_entsize(dep->namelen))
+               if (offset + xfs_dir2_data_entsize(mp, dep->namelen) > end)
                        return __this_address;
-               if (be16_to_cpu(*ops->data_entry_tag_p(dep)) !=
-                   (char *)dep - (char *)hdr)
+               if (be16_to_cpu(*xfs_dir2_data_entry_tag_p(mp, dep)) != offset)
                        return __this_address;
-               if (ops->data_get_ftype(dep) >= XFS_DIR3_FT_MAX)
+               if (xfs_dir2_data_get_ftype(mp, dep) >= XFS_DIR3_FT_MAX)
                        return __this_address;
                count++;
                lastfree = 0;
@@ -189,7 +235,7 @@ __xfs_dir3_data_check(
                                                ((char *)dep - (char *)hdr));
                        name.name = dep->name;
                        name.len = dep->namelen;
-                       hash = mp->m_dirnameops->hashname(&name);
+                       hash = xfs_dir2_hashname(mp, &name);
                        for (i = 0; i < be32_to_cpu(btp->count); i++) {
                                if (be32_to_cpu(lep[i].address) == addr &&
                                    be32_to_cpu(lep[i].hashval) == hash)
@@ -198,7 +244,7 @@ __xfs_dir3_data_check(
                        if (i >= be32_to_cpu(btp->count))
                                return __this_address;
                }
-               p += ops->data_entsize(dep->namelen);
+               offset += xfs_dir2_data_entsize(mp, dep->namelen);
        }
        /*
         * Need to have seen all the entries and all the bestfree slots.
@@ -354,13 +400,13 @@ xfs_dir3_data_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
-       xfs_daddr_t             mapped_bno,
+       unsigned int            flags,
        struct xfs_buf          **bpp)
 {
        int                     err;
 
-       err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
-                               XFS_DATA_FORK, &xfs_dir3_data_buf_ops);
+       err = xfs_da_read_buf(tp, dp, bno, flags, bpp, XFS_DATA_FORK,
+                       &xfs_dir3_data_buf_ops);
        if (!err && tp && *bpp)
                xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF);
        return err;
@@ -370,10 +416,10 @@ int
 xfs_dir3_data_readahead(
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
-       xfs_daddr_t             mapped_bno)
+       unsigned int            flags)
 {
-       return xfs_da_reada_buf(dp, bno, mapped_bno,
-                               XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops);
+       return xfs_da_reada_buf(dp, bno, flags, XFS_DATA_FORK,
+                               &xfs_dir3_data_reada_buf_ops);
 }
 
 /*
@@ -561,17 +607,16 @@ xfs_dir2_data_freeremove(
  * Given a data block, reconstruct its bestfree map.
  */
 void
-xfs_dir2_data_freescan_int(
-       struct xfs_da_geometry  *geo,
-       const struct xfs_dir_ops *ops,
-       struct xfs_dir2_data_hdr *hdr,
-       int                     *loghead)
+xfs_dir2_data_freescan(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_data_hdr        *hdr,
+       int                             *loghead)
 {
-       xfs_dir2_data_entry_t   *dep;           /* active data entry */
-       xfs_dir2_data_unused_t  *dup;           /* unused data entry */
-       struct xfs_dir2_data_free *bf;
-       char                    *endp;          /* end of block's data */
-       char                    *p;             /* current entry pointer */
+       struct xfs_da_geometry          *geo = mp->m_dir_geo;
+       struct xfs_dir2_data_free       *bf = xfs_dir2_data_bestfree_p(mp, hdr);
+       void                            *addr = hdr;
+       unsigned int                    offset = geo->data_entry_offset;
+       unsigned int                    end;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
@@ -581,79 +626,60 @@ xfs_dir2_data_freescan_int(
        /*
         * Start by clearing the table.
         */
-       bf = ops->data_bestfree_p(hdr);
        memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT);
        *loghead = 1;
-       /*
-        * Set up pointers.
-        */
-       p = (char *)ops->data_entry_p(hdr);
-       endp = xfs_dir3_data_endp(geo, hdr);
-       /*
-        * Loop over the block's entries.
-        */
-       while (p < endp) {
-               dup = (xfs_dir2_data_unused_t *)p;
+
+       end = xfs_dir3_data_end_offset(geo, addr);
+       while (offset < end) {
+               struct xfs_dir2_data_unused     *dup = addr + offset;
+               struct xfs_dir2_data_entry      *dep = addr + offset;
+
                /*
                 * If it's a free entry, insert it.
                 */
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-                       ASSERT((char *)dup - (char *)hdr ==
+                       ASSERT(offset ==
                               be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
                        xfs_dir2_data_freeinsert(hdr, bf, dup, loghead);
-                       p += be16_to_cpu(dup->length);
+                       offset += be16_to_cpu(dup->length);
+                       continue;
                }
+
                /*
                 * For active entries, check their tags and skip them.
                 */
-               else {
-                       dep = (xfs_dir2_data_entry_t *)p;
-                       ASSERT((char *)dep - (char *)hdr ==
-                              be16_to_cpu(*ops->data_entry_tag_p(dep)));
-                       p += ops->data_entsize(dep->namelen);
-               }
+               ASSERT(offset ==
+                      be16_to_cpu(*xfs_dir2_data_entry_tag_p(mp, dep)));
+               offset += xfs_dir2_data_entsize(mp, dep->namelen);
        }
 }
 
-void
-xfs_dir2_data_freescan(
-       struct xfs_inode        *dp,
-       struct xfs_dir2_data_hdr *hdr,
-       int                     *loghead)
-{
-       return xfs_dir2_data_freescan_int(dp->i_mount->m_dir_geo, dp->d_ops,
-                       hdr, loghead);
-}
-
 /*
  * Initialize a data block at the given block number in the directory.
  * Give back the buffer for the created block.
  */
 int                                            /* error */
 xfs_dir3_data_init(
-       xfs_da_args_t           *args,          /* directory operation args */
-       xfs_dir2_db_t           blkno,          /* logical dir block number */
-       struct xfs_buf          **bpp)          /* output block buffer */
+       struct xfs_da_args              *args,  /* directory operation args */
+       xfs_dir2_db_t                   blkno,  /* logical dir block number */
+       struct xfs_buf                  **bpp)  /* output block buffer */
 {
-       struct xfs_buf          *bp;            /* block buffer */
-       xfs_dir2_data_hdr_t     *hdr;           /* data block header */
-       xfs_inode_t             *dp;            /* incore directory inode */
-       xfs_dir2_data_unused_t  *dup;           /* unused entry pointer */
-       struct xfs_dir2_data_free *bf;
-       int                     error;          /* error return value */
-       int                     i;              /* bestfree index */
-       xfs_mount_t             *mp;            /* filesystem mount point */
-       xfs_trans_t             *tp;            /* transaction pointer */
-       int                     t;              /* temp */
-
-       dp = args->dp;
-       mp = dp->i_mount;
-       tp = args->trans;
+       struct xfs_trans                *tp = args->trans;
+       struct xfs_inode                *dp = args->dp;
+       struct xfs_mount                *mp = dp->i_mount;
+       struct xfs_da_geometry          *geo = args->geo;
+       struct xfs_buf                  *bp;
+       struct xfs_dir2_data_hdr        *hdr;
+       struct xfs_dir2_data_unused     *dup;
+       struct xfs_dir2_data_free       *bf;
+       int                             error;
+       int                             i;
+
        /*
         * Get the buffer set up for the block.
         */
        error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
-                              -1, &bp, XFS_DATA_FORK);
+                              &bp, XFS_DATA_FORK);
        if (error)
                return error;
        bp->b_ops = &xfs_dir3_data_buf_ops;
@@ -675,8 +701,9 @@ xfs_dir3_data_init(
        } else
                hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
 
-       bf = dp->d_ops->data_bestfree_p(hdr);
-       bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset);
+       bf = xfs_dir2_data_bestfree_p(mp, hdr);
+       bf[0].offset = cpu_to_be16(geo->data_entry_offset);
+       bf[0].length = cpu_to_be16(geo->blksize - geo->data_entry_offset);
        for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
                bf[i].length = 0;
                bf[i].offset = 0;
@@ -685,13 +712,11 @@ xfs_dir3_data_init(
        /*
         * Set up an unused entry for the block's body.
         */
-       dup = dp->d_ops->data_unused_p(hdr);
+       dup = bp->b_addr + geo->data_entry_offset;
        dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
-
-       t = args->geo->blksize - (uint)dp->d_ops->data_entry_offset;
-       bf[0].length = cpu_to_be16(t);
-       dup->length = cpu_to_be16(t);
+       dup->length = bf[0].length;
        *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
+
        /*
         * Log it and return it.
         */
@@ -710,6 +735,7 @@ xfs_dir2_data_log_entry(
        struct xfs_buf          *bp,
        xfs_dir2_data_entry_t   *dep)           /* data entry pointer */
 {
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dir2_data_hdr *hdr = bp->b_addr;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
@@ -718,7 +744,7 @@ xfs_dir2_data_log_entry(
               hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
 
        xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr),
-               (uint)((char *)(args->dp->d_ops->data_entry_tag_p(dep) + 1) -
+               (uint)((char *)(xfs_dir2_data_entry_tag_p(mp, dep) + 1) -
                       (char *)hdr - 1));
 }
 
@@ -739,8 +765,7 @@ xfs_dir2_data_log_header(
               hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
 #endif
 
-       xfs_trans_log_buf(args->trans, bp, 0,
-                         args->dp->d_ops->data_entry_offset - 1);
+       xfs_trans_log_buf(args->trans, bp, 0, args->geo->data_entry_offset - 1);
 }
 
 /*
@@ -789,11 +814,11 @@ xfs_dir2_data_make_free(
 {
        xfs_dir2_data_hdr_t     *hdr;           /* data block pointer */
        xfs_dir2_data_free_t    *dfp;           /* bestfree pointer */
-       char                    *endptr;        /* end of data area */
        int                     needscan;       /* need to regen bestfree */
        xfs_dir2_data_unused_t  *newdup;        /* new unused entry */
        xfs_dir2_data_unused_t  *postdup;       /* unused entry after us */
        xfs_dir2_data_unused_t  *prevdup;       /* unused entry before us */
+       unsigned int            end;
        struct xfs_dir2_data_free *bf;
 
        hdr = bp->b_addr;
@@ -801,14 +826,14 @@ xfs_dir2_data_make_free(
        /*
         * Figure out where the end of the data area is.
         */
-       endptr = xfs_dir3_data_endp(args->geo, hdr);
-       ASSERT(endptr != NULL);
+       end = xfs_dir3_data_end_offset(args->geo, hdr);
+       ASSERT(end != 0);
 
        /*
         * If this isn't the start of the block, then back up to
         * the previous entry and see if it's free.
         */
-       if (offset > args->dp->d_ops->data_entry_offset) {
+       if (offset > args->geo->data_entry_offset) {
                __be16                  *tagp;  /* tag just before us */
 
                tagp = (__be16 *)((char *)hdr + offset) - 1;
@@ -821,7 +846,7 @@ xfs_dir2_data_make_free(
         * If this isn't the end of the block, see if the entry after
         * us is free.
         */
-       if ((char *)hdr + offset + len < endptr) {
+       if (offset + len < end) {
                postdup =
                        (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
                if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
@@ -834,7 +859,7 @@ xfs_dir2_data_make_free(
         * Previous and following entries are both free,
         * merge everything into a single free entry.
         */
-       bf = args->dp->d_ops->data_bestfree_p(hdr);
+       bf = xfs_dir2_data_bestfree_p(args->dp->i_mount, hdr);
        if (prevdup && postdup) {
                xfs_dir2_data_free_t    *dfp2;  /* another bestfree pointer */
 
@@ -1025,7 +1050,7 @@ xfs_dir2_data_use_free(
         * Look up the entry in the bestfree table.
         */
        oldlen = be16_to_cpu(dup->length);
-       bf = args->dp->d_ops->data_bestfree_p(hdr);
+       bf = xfs_dir2_data_bestfree_p(args->dp->i_mount, hdr);
        dfp = xfs_dir2_data_freefind(hdr, bf, dup);
        ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
        /*
@@ -1149,19 +1174,22 @@ corrupt:
 }
 
 /* Find the end of the entry data in a data/block format dir block. */
-void *
-xfs_dir3_data_endp(
+unsigned int
+xfs_dir3_data_end_offset(
        struct xfs_da_geometry          *geo,
        struct xfs_dir2_data_hdr        *hdr)
 {
+       void                            *p;
+
        switch (hdr->magic) {
        case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
        case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
-               return xfs_dir2_block_leaf_p(xfs_dir2_block_tail_p(geo, hdr));
+               p = xfs_dir2_block_leaf_p(xfs_dir2_block_tail_p(geo, hdr));
+               return p - (void *)hdr;
        case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
        case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
-               return (char *)hdr + geo->blksize;
+               return geo->blksize;
        default:
-               return NULL;
+               return 0;
        }
 }
index a53e458..a131b52 100644 (file)
  * Local function declarations.
  */
 static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp,
-                                   int *indexp, struct xfs_buf **dbpp);
+                                   int *indexp, struct xfs_buf **dbpp,
+                                   struct xfs_dir3_icleaf_hdr *leafhdr);
 static void xfs_dir3_leaf_log_bests(struct xfs_da_args *args,
                                    struct xfs_buf *bp, int first, int last);
 static void xfs_dir3_leaf_log_tail(struct xfs_da_args *args,
                                   struct xfs_buf *bp);
 
+void
+xfs_dir2_leaf_hdr_from_disk(
+       struct xfs_mount                *mp,
+       struct xfs_dir3_icleaf_hdr      *to,
+       struct xfs_dir2_leaf            *from)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_dir3_leaf *from3 = (struct xfs_dir3_leaf *)from;
+
+               to->forw = be32_to_cpu(from3->hdr.info.hdr.forw);
+               to->back = be32_to_cpu(from3->hdr.info.hdr.back);
+               to->magic = be16_to_cpu(from3->hdr.info.hdr.magic);
+               to->count = be16_to_cpu(from3->hdr.count);
+               to->stale = be16_to_cpu(from3->hdr.stale);
+               to->ents = from3->__ents;
+
+               ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC ||
+                      to->magic == XFS_DIR3_LEAFN_MAGIC);
+       } else {
+               to->forw = be32_to_cpu(from->hdr.info.forw);
+               to->back = be32_to_cpu(from->hdr.info.back);
+               to->magic = be16_to_cpu(from->hdr.info.magic);
+               to->count = be16_to_cpu(from->hdr.count);
+               to->stale = be16_to_cpu(from->hdr.stale);
+               to->ents = from->__ents;
+
+               ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC ||
+                      to->magic == XFS_DIR2_LEAFN_MAGIC);
+       }
+}
+
+void
+xfs_dir2_leaf_hdr_to_disk(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_leaf            *to,
+       struct xfs_dir3_icleaf_hdr      *from)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_dir3_leaf *to3 = (struct xfs_dir3_leaf *)to;
+
+               ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC ||
+                      from->magic == XFS_DIR3_LEAFN_MAGIC);
+
+               to3->hdr.info.hdr.forw = cpu_to_be32(from->forw);
+               to3->hdr.info.hdr.back = cpu_to_be32(from->back);
+               to3->hdr.info.hdr.magic = cpu_to_be16(from->magic);
+               to3->hdr.count = cpu_to_be16(from->count);
+               to3->hdr.stale = cpu_to_be16(from->stale);
+       } else {
+               ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC ||
+                      from->magic == XFS_DIR2_LEAFN_MAGIC);
+
+               to->hdr.info.forw = cpu_to_be32(from->forw);
+               to->hdr.info.back = cpu_to_be32(from->back);
+               to->hdr.info.magic = cpu_to_be16(from->magic);
+               to->hdr.count = cpu_to_be16(from->count);
+               to->hdr.stale = cpu_to_be16(from->stale);
+       }
+}
+
 /*
  * Check the internal consistency of a leaf1 block.
  * Pop an assert if something is wrong.
@@ -43,7 +104,7 @@ xfs_dir3_leaf1_check(
        struct xfs_dir2_leaf    *leaf = bp->b_addr;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
 
        if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) {
                struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
@@ -52,7 +113,7 @@ xfs_dir3_leaf1_check(
        } else if (leafhdr.magic != XFS_DIR2_LEAF1_MAGIC)
                return __this_address;
 
-       return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf);
+       return xfs_dir3_leaf_check_int(dp->i_mount, &leafhdr, leaf);
 }
 
 static inline void
@@ -76,31 +137,15 @@ xfs_dir3_leaf_check(
 
 xfs_failaddr_t
 xfs_dir3_leaf_check_int(
-       struct xfs_mount        *mp,
-       struct xfs_inode        *dp,
-       struct xfs_dir3_icleaf_hdr *hdr,
-       struct xfs_dir2_leaf    *leaf)
+       struct xfs_mount                *mp,
+       struct xfs_dir3_icleaf_hdr      *hdr,
+       struct xfs_dir2_leaf            *leaf)
 {
-       struct xfs_dir2_leaf_entry *ents;
-       xfs_dir2_leaf_tail_t    *ltp;
-       int                     stale;
-       int                     i;
-       const struct xfs_dir_ops *ops;
-       struct xfs_dir3_icleaf_hdr leafhdr;
-       struct xfs_da_geometry  *geo = mp->m_dir_geo;
-
-       /*
-        * we can be passed a null dp here from a verifier, so we need to go the
-        * hard way to get them.
-        */
-       ops = xfs_dir_get_ops(mp, dp);
+       struct xfs_da_geometry          *geo = mp->m_dir_geo;
+       xfs_dir2_leaf_tail_t            *ltp;
+       int                             stale;
+       int                             i;
 
-       if (!hdr) {
-               ops->leaf_hdr_from_disk(&leafhdr, leaf);
-               hdr = &leafhdr;
-       }
-
-       ents = ops->leaf_ents_p(leaf);
        ltp = xfs_dir2_leaf_tail_p(geo, leaf);
 
        /*
@@ -108,23 +153,23 @@ xfs_dir3_leaf_check_int(
         * Should factor in the size of the bests table as well.
         * We can deduce a value for that from di_size.
         */
-       if (hdr->count > ops->leaf_max_ents(geo))
+       if (hdr->count > geo->leaf_max_ents)
                return __this_address;
 
        /* Leaves and bests don't overlap in leaf format. */
        if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
             hdr->magic == XFS_DIR3_LEAF1_MAGIC) &&
-           (char *)&ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp))
+           (char *)&hdr->ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp))
                return __this_address;
 
        /* Check hash value order, count stale entries.  */
        for (i = stale = 0; i < hdr->count; i++) {
                if (i + 1 < hdr->count) {
-                       if (be32_to_cpu(ents[i].hashval) >
-                                       be32_to_cpu(ents[i + 1].hashval))
+                       if (be32_to_cpu(hdr->ents[i].hashval) >
+                                       be32_to_cpu(hdr->ents[i + 1].hashval))
                                return __this_address;
                }
-               if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
+               if (hdr->ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
                        stale++;
        }
        if (hdr->stale != stale)
@@ -139,17 +184,18 @@ xfs_dir3_leaf_check_int(
  */
 static xfs_failaddr_t
 xfs_dir3_leaf_verify(
-       struct xfs_buf          *bp)
+       struct xfs_buf                  *bp)
 {
-       struct xfs_mount        *mp = bp->b_mount;
-       struct xfs_dir2_leaf    *leaf = bp->b_addr;
-       xfs_failaddr_t          fa;
+       struct xfs_mount                *mp = bp->b_mount;
+       struct xfs_dir3_icleaf_hdr      leafhdr;
+       xfs_failaddr_t                  fa;
 
        fa = xfs_da3_blkinfo_verify(bp, bp->b_addr);
        if (fa)
                return fa;
 
-       return xfs_dir3_leaf_check_int(mp, NULL, NULL, leaf);
+       xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, bp->b_addr);
+       return xfs_dir3_leaf_check_int(mp, &leafhdr, bp->b_addr);
 }
 
 static void
@@ -216,13 +262,12 @@ xfs_dir3_leaf_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             fbno,
-       xfs_daddr_t             mappedbno,
        struct xfs_buf          **bpp)
 {
        int                     err;
 
-       err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
-                               XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops);
+       err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
+                       &xfs_dir3_leaf1_buf_ops);
        if (!err && tp && *bpp)
                xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF);
        return err;
@@ -233,13 +278,12 @@ xfs_dir3_leafn_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             fbno,
-       xfs_daddr_t             mappedbno,
        struct xfs_buf          **bpp)
 {
        int                     err;
 
-       err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
-                               XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops);
+       err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
+                       &xfs_dir3_leafn_buf_ops);
        if (!err && tp && *bpp)
                xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF);
        return err;
@@ -311,7 +355,7 @@ xfs_dir3_leaf_get_buf(
               bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
 
        error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
-                              -1, &bp, XFS_DATA_FORK);
+                              &bp, XFS_DATA_FORK);
        if (error)
                return error;
 
@@ -346,7 +390,6 @@ xfs_dir2_block_to_leaf(
        int                     needscan;       /* need to rescan bestfree */
        xfs_trans_t             *tp;            /* transaction pointer */
        struct xfs_dir2_data_free *bf;
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
        trace_xfs_dir2_block_to_leaf(args);
@@ -375,24 +418,24 @@ xfs_dir2_block_to_leaf(
        xfs_dir3_data_check(dp, dbp);
        btp = xfs_dir2_block_tail_p(args->geo, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
-       bf = dp->d_ops->data_bestfree_p(hdr);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
 
        /*
         * Set the counts in the leaf header.
         */
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
        leafhdr.count = be32_to_cpu(btp->count);
        leafhdr.stale = be32_to_cpu(btp->stale);
-       dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
        xfs_dir3_leaf_log_header(args, lbp);
 
        /*
         * Could compact these but I think we always do the conversion
         * after squeezing out stale entries.
         */
-       memcpy(ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t));
-       xfs_dir3_leaf_log_ents(args, lbp, 0, leafhdr.count - 1);
+       memcpy(leafhdr.ents, blp,
+               be32_to_cpu(btp->count) * sizeof(struct xfs_dir2_leaf_entry));
+       xfs_dir3_leaf_log_ents(args, &leafhdr, lbp, 0, leafhdr.count - 1);
        needscan = 0;
        needlog = 1;
        /*
@@ -415,7 +458,7 @@ xfs_dir2_block_to_leaf(
                hdr->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
 
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        /*
         * Set up leaf tail and bests table.
         */
@@ -594,7 +637,7 @@ xfs_dir2_leaf_addname(
 
        trace_xfs_dir2_leaf_addname(args);
 
-       error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
+       error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
        if (error)
                return error;
 
@@ -607,10 +650,10 @@ xfs_dir2_leaf_addname(
        index = xfs_dir2_leaf_search_hash(args, lbp);
        leaf = lbp->b_addr;
        ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
+       ents = leafhdr.ents;
        bestsp = xfs_dir2_leaf_bests_p(ltp);
-       length = dp->d_ops->data_entsize(args->namelen);
+       length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
 
        /*
         * See if there are any entries with the same hash value
@@ -773,7 +816,7 @@ xfs_dir2_leaf_addname(
                else
                        xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block);
                hdr = dbp->b_addr;
-               bf = dp->d_ops->data_bestfree_p(hdr);
+               bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
                bestsp[use_block] = bf[0].length;
                grown = 1;
        } else {
@@ -783,13 +826,13 @@ xfs_dir2_leaf_addname(
                 */
                error = xfs_dir3_data_read(tp, dp,
                                   xfs_dir2_db_to_da(args->geo, use_block),
-                                  -1, &dbp);
+                                  0, &dbp);
                if (error) {
                        xfs_trans_brelse(tp, lbp);
                        return error;
                }
                hdr = dbp->b_addr;
-               bf = dp->d_ops->data_bestfree_p(hdr);
+               bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
                grown = 0;
        }
        /*
@@ -815,14 +858,14 @@ xfs_dir2_leaf_addname(
        dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, dep->namelen);
-       dp->d_ops->data_put_ftype(dep, args->filetype);
-       tagp = dp->d_ops->data_entry_tag_p(dep);
+       xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
+       tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        /*
         * Need to scan fix up the bestfree table.
         */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        /*
         * Need to log the data block's header.
         */
@@ -852,9 +895,9 @@ xfs_dir2_leaf_addname(
        /*
         * Log the leaf fields and give up the buffers.
         */
-       dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
        xfs_dir3_leaf_log_header(args, lbp);
-       xfs_dir3_leaf_log_ents(args, lbp, lfloglow, lfloghigh);
+       xfs_dir3_leaf_log_ents(args, &leafhdr, lbp, lfloglow, lfloghigh);
        xfs_dir3_leaf_check(dp, lbp);
        xfs_dir3_data_check(dp, dbp);
        return 0;
@@ -874,7 +917,6 @@ xfs_dir3_leaf_compact(
        xfs_dir2_leaf_t *leaf;          /* leaf structure */
        int             loglow;         /* first leaf entry to log */
        int             to;             /* target leaf index */
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_inode *dp = args->dp;
 
        leaf = bp->b_addr;
@@ -884,9 +926,9 @@ xfs_dir3_leaf_compact(
        /*
         * Compress out the stale entries in place.
         */
-       ents = dp->d_ops->leaf_ents_p(leaf);
        for (from = to = 0, loglow = -1; from < leafhdr->count; from++) {
-               if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
+               if (leafhdr->ents[from].address ==
+                   cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
                        continue;
                /*
                 * Only actually copy the entries that are different.
@@ -894,7 +936,7 @@ xfs_dir3_leaf_compact(
                if (from > to) {
                        if (loglow == -1)
                                loglow = to;
-                       ents[to] = ents[from];
+                       leafhdr->ents[to] = leafhdr->ents[from];
                }
                to++;
        }
@@ -905,10 +947,10 @@ xfs_dir3_leaf_compact(
        leafhdr->count -= leafhdr->stale;
        leafhdr->stale = 0;
 
-       dp->d_ops->leaf_hdr_to_disk(leaf, leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, leafhdr);
        xfs_dir3_leaf_log_header(args, bp);
        if (loglow != -1)
-               xfs_dir3_leaf_log_ents(args, bp, loglow, to - 1);
+               xfs_dir3_leaf_log_ents(args, leafhdr, bp, loglow, to - 1);
 }
 
 /*
@@ -1037,6 +1079,7 @@ xfs_dir3_leaf_log_bests(
 void
 xfs_dir3_leaf_log_ents(
        struct xfs_da_args      *args,
+       struct xfs_dir3_icleaf_hdr *hdr,
        struct xfs_buf          *bp,
        int                     first,
        int                     last)
@@ -1044,16 +1087,14 @@ xfs_dir3_leaf_log_ents(
        xfs_dir2_leaf_entry_t   *firstlep;      /* pointer to first entry */
        xfs_dir2_leaf_entry_t   *lastlep;       /* pointer to last entry */
        struct xfs_dir2_leaf    *leaf = bp->b_addr;
-       struct xfs_dir2_leaf_entry *ents;
 
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
               leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
               leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
               leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
 
-       ents = args->dp->d_ops->leaf_ents_p(leaf);
-       firstlep = &ents[first];
-       lastlep = &ents[last];
+       firstlep = &hdr->ents[first];
+       lastlep = &hdr->ents[last];
        xfs_trans_log_buf(args->trans, bp,
                (uint)((char *)firstlep - (char *)leaf),
                (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1));
@@ -1076,7 +1117,7 @@ xfs_dir3_leaf_log_header(
 
        xfs_trans_log_buf(args->trans, bp,
                          (uint)((char *)&leaf->hdr - (char *)leaf),
-                         args->dp->d_ops->leaf_hdr_size - 1);
+                         args->geo->leaf_hdr_size - 1);
 }
 
 /*
@@ -1115,28 +1156,27 @@ xfs_dir2_leaf_lookup(
        int                     error;          /* error return code */
        int                     index;          /* found entry index */
        struct xfs_buf          *lbp;           /* leaf buffer */
-       xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        xfs_trans_t             *tp;            /* transaction pointer */
-       struct xfs_dir2_leaf_entry *ents;
+       struct xfs_dir3_icleaf_hdr leafhdr;
 
        trace_xfs_dir2_leaf_lookup(args);
 
        /*
         * Look up name in the leaf block, returning both buffers and index.
         */
-       if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) {
+       error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp, &leafhdr);
+       if (error)
                return error;
-       }
+
        tp = args->trans;
        dp = args->dp;
        xfs_dir3_leaf_check(dp, lbp);
-       leaf = lbp->b_addr;
-       ents = dp->d_ops->leaf_ents_p(leaf);
+
        /*
         * Get to the leaf entry and contained data entry address.
         */
-       lep = &ents[index];
+       lep = &leafhdr.ents[index];
 
        /*
         * Point to the data entry.
@@ -1148,7 +1188,7 @@ xfs_dir2_leaf_lookup(
         * Return the found inode number & CI name if appropriate
         */
        args->inumber = be64_to_cpu(dep->inumber);
-       args->filetype = dp->d_ops->data_get_ftype(dep);
+       args->filetype = xfs_dir2_data_get_ftype(dp->i_mount, dep);
        error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
        xfs_trans_brelse(tp, dbp);
        xfs_trans_brelse(tp, lbp);
@@ -1166,7 +1206,8 @@ xfs_dir2_leaf_lookup_int(
        xfs_da_args_t           *args,          /* operation arguments */
        struct xfs_buf          **lbpp,         /* out: leaf buffer */
        int                     *indexp,        /* out: index in leaf block */
-       struct xfs_buf          **dbpp)         /* out: data buffer */
+       struct xfs_buf          **dbpp,         /* out: data buffer */
+       struct xfs_dir3_icleaf_hdr *leafhdr)
 {
        xfs_dir2_db_t           curdb = -1;     /* current data block number */
        struct xfs_buf          *dbp = NULL;    /* data buffer */
@@ -1182,22 +1223,19 @@ xfs_dir2_leaf_lookup_int(
        xfs_trans_t             *tp;            /* transaction pointer */
        xfs_dir2_db_t           cidb = -1;      /* case match data block no. */
        enum xfs_dacmp          cmp;            /* name compare result */
-       struct xfs_dir2_leaf_entry *ents;
-       struct xfs_dir3_icleaf_hdr leafhdr;
 
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
 
-       error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
+       error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
        if (error)
                return error;
 
        *lbpp = lbp;
        leaf = lbp->b_addr;
        xfs_dir3_leaf_check(dp, lbp);
-       ents = dp->d_ops->leaf_ents_p(leaf);
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(mp, leafhdr, leaf);
 
        /*
         * Look for the first leaf entry with our hash value.
@@ -1207,8 +1245,9 @@ xfs_dir2_leaf_lookup_int(
         * Loop over all the entries with the right hash value
         * looking to match the name.
         */
-       for (lep = &ents[index];
-            index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
+       for (lep = &leafhdr->ents[index];
+            index < leafhdr->count &&
+                       be32_to_cpu(lep->hashval) == args->hashval;
             lep++, index++) {
                /*
                 * Skip over stale leaf entries.
@@ -1229,7 +1268,7 @@ xfs_dir2_leaf_lookup_int(
                                xfs_trans_brelse(tp, dbp);
                        error = xfs_dir3_data_read(tp, dp,
                                           xfs_dir2_db_to_da(args->geo, newdb),
-                                          -1, &dbp);
+                                          0, &dbp);
                        if (error) {
                                xfs_trans_brelse(tp, lbp);
                                return error;
@@ -1247,7 +1286,7 @@ xfs_dir2_leaf_lookup_int(
                 * and buffer. If it's the first case-insensitive match, store
                 * the index and buffer and continue looking for an exact match.
                 */
-               cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
+               cmp = xfs_dir2_compname(args, dep->name, dep->namelen);
                if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
                        args->cmpresult = cmp;
                        *indexp = index;
@@ -1271,7 +1310,7 @@ xfs_dir2_leaf_lookup_int(
                        xfs_trans_brelse(tp, dbp);
                        error = xfs_dir3_data_read(tp, dp,
                                           xfs_dir2_db_to_da(args->geo, cidb),
-                                          -1, &dbp);
+                                          0, &dbp);
                        if (error) {
                                xfs_trans_brelse(tp, lbp);
                                return error;
@@ -1297,6 +1336,7 @@ int                                               /* error */
 xfs_dir2_leaf_removename(
        xfs_da_args_t           *args)          /* operation arguments */
 {
+       struct xfs_da_geometry  *geo = args->geo;
        __be16                  *bestsp;        /* leaf block best freespace */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_db_t           db;             /* data block number */
@@ -1314,7 +1354,6 @@ xfs_dir2_leaf_removename(
        int                     needscan;       /* need to rescan data frees */
        xfs_dir2_data_off_t     oldbest;        /* old value of best free */
        struct xfs_dir2_data_free *bf;          /* bestfree table */
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
        trace_xfs_dir2_leaf_removename(args);
@@ -1322,51 +1361,54 @@ xfs_dir2_leaf_removename(
        /*
         * Lookup the leaf entry, get the leaf and data blocks read in.
         */
-       if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) {
+       error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp, &leafhdr);
+       if (error)
                return error;
-       }
+
        dp = args->dp;
        leaf = lbp->b_addr;
        hdr = dbp->b_addr;
        xfs_dir3_data_check(dp, dbp);
-       bf = dp->d_ops->data_bestfree_p(hdr);
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
+
        /*
         * Point to the leaf entry, use that to point to the data entry.
         */
-       lep = &ents[index];
-       db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
+       lep = &leafhdr.ents[index];
+       db = xfs_dir2_dataptr_to_db(geo, be32_to_cpu(lep->address));
        dep = (xfs_dir2_data_entry_t *)((char *)hdr +
-               xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
+               xfs_dir2_dataptr_to_off(geo, be32_to_cpu(lep->address)));
        needscan = needlog = 0;
        oldbest = be16_to_cpu(bf[0].length);
-       ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
+       ltp = xfs_dir2_leaf_tail_p(geo, leaf);
        bestsp = xfs_dir2_leaf_bests_p(ltp);
-       if (be16_to_cpu(bestsp[db]) != oldbest)
+       if (be16_to_cpu(bestsp[db]) != oldbest) {
+               xfs_buf_corruption_error(lbp);
                return -EFSCORRUPTED;
+       }
        /*
         * Mark the former data entry unused.
         */
        xfs_dir2_data_make_free(args, dbp,
                (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
-               dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
+               xfs_dir2_data_entsize(dp->i_mount, dep->namelen), &needlog,
+               &needscan);
        /*
         * We just mark the leaf entry stale by putting a null in it.
         */
        leafhdr.stale++;
-       dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
        xfs_dir3_leaf_log_header(args, lbp);
 
        lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
-       xfs_dir3_leaf_log_ents(args, lbp, index, index);
+       xfs_dir3_leaf_log_ents(args, &leafhdr, lbp, index, index);
 
        /*
         * Scan the freespace in the data block again if necessary,
         * log the data block header if necessary.
         */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        if (needlog)
                xfs_dir2_data_log_header(args, dbp);
        /*
@@ -1382,8 +1424,8 @@ xfs_dir2_leaf_removename(
         * If the data block is now empty then get rid of the data block.
         */
        if (be16_to_cpu(bf[0].length) ==
-                       args->geo->blksize - dp->d_ops->data_entry_offset) {
-               ASSERT(db != args->geo->datablk);
+           geo->blksize - geo->data_entry_offset) {
+               ASSERT(db != geo->datablk);
                if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {
                        /*
                         * Nope, can't get rid of it because it caused
@@ -1425,7 +1467,7 @@ xfs_dir2_leaf_removename(
        /*
         * If the data block was not the first one, drop it.
         */
-       else if (db != args->geo->datablk)
+       else if (db != geo->datablk)
                dbp = NULL;
 
        xfs_dir3_leaf_check(dp, lbp);
@@ -1448,26 +1490,24 @@ xfs_dir2_leaf_replace(
        int                     error;          /* error return code */
        int                     index;          /* index of leaf entry */
        struct xfs_buf          *lbp;           /* leaf buffer */
-       xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        xfs_trans_t             *tp;            /* transaction pointer */
-       struct xfs_dir2_leaf_entry *ents;
+       struct xfs_dir3_icleaf_hdr leafhdr;
 
        trace_xfs_dir2_leaf_replace(args);
 
        /*
         * Look up the entry.
         */
-       if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) {
+       error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp, &leafhdr);
+       if (error)
                return error;
-       }
+
        dp = args->dp;
-       leaf = lbp->b_addr;
-       ents = dp->d_ops->leaf_ents_p(leaf);
        /*
         * Point to the leaf entry, get data address from it.
         */
-       lep = &ents[index];
+       lep = &leafhdr.ents[index];
        /*
         * Point to the data entry.
         */
@@ -1479,7 +1519,7 @@ xfs_dir2_leaf_replace(
         * Put the new inode number in, log it.
         */
        dep->inumber = cpu_to_be64(args->inumber);
-       dp->d_ops->data_put_ftype(dep, args->filetype);
+       xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
        tp = args->trans;
        xfs_dir2_data_log_entry(args, dbp, dep);
        xfs_dir3_leaf_check(dp, lbp);
@@ -1501,21 +1541,17 @@ xfs_dir2_leaf_search_hash(
        xfs_dahash_t            hashwant;       /* hash value looking for */
        int                     high;           /* high leaf index */
        int                     low;            /* low leaf index */
-       xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        int                     mid=0;          /* current leaf index */
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
-       leaf = lbp->b_addr;
-       ents = args->dp->d_ops->leaf_ents_p(leaf);
-       args->dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(args->dp->i_mount, &leafhdr, lbp->b_addr);
 
        /*
         * Note, the table cannot be empty, so we have to go through the loop.
         * Binary search the leaf entries looking for our hash value.
         */
-       for (lep = ents, low = 0, high = leafhdr.count - 1,
+       for (lep = leafhdr.ents, low = 0, high = leafhdr.count - 1,
                hashwant = args->hashval;
             low <= high; ) {
                mid = (low + high) >> 1;
@@ -1552,6 +1588,7 @@ xfs_dir2_leaf_trim_data(
        struct xfs_buf          *lbp,           /* leaf buffer */
        xfs_dir2_db_t           db)             /* data block number */
 {
+       struct xfs_da_geometry  *geo = args->geo;
        __be16                  *bestsp;        /* leaf bests table */
        struct xfs_buf          *dbp;           /* data block buffer */
        xfs_inode_t             *dp;            /* incore directory inode */
@@ -1565,23 +1602,23 @@ xfs_dir2_leaf_trim_data(
        /*
         * Read the offending data block.  We need its buffer.
         */
-       error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, db),
-                                  -1, &dbp);
+       error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(geo, db), 0, &dbp);
        if (error)
                return error;
 
        leaf = lbp->b_addr;
-       ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
+       ltp = xfs_dir2_leaf_tail_p(geo, leaf);
 
 #ifdef DEBUG
 {
        struct xfs_dir2_data_hdr *hdr = dbp->b_addr;
-       struct xfs_dir2_data_free *bf = dp->d_ops->data_bestfree_p(hdr);
+       struct xfs_dir2_data_free *bf =
+               xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
        ASSERT(be16_to_cpu(bf[0].length) ==
-              args->geo->blksize - dp->d_ops->data_entry_offset);
+              geo->blksize - geo->data_entry_offset);
        ASSERT(db == be32_to_cpu(ltp->bestcount) - 1);
 }
 #endif
@@ -1639,7 +1676,6 @@ xfs_dir2_node_to_leaf(
        int                     error;          /* error return code */
        struct xfs_buf          *fbp;           /* buffer for freespace block */
        xfs_fileoff_t           fo;             /* freespace file offset */
-       xfs_dir2_free_t         *free;          /* freespace structure */
        struct xfs_buf          *lbp;           /* buffer for leaf block */
        xfs_dir2_leaf_tail_t    *ltp;           /* tail of leaf structure */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
@@ -1697,7 +1733,7 @@ xfs_dir2_node_to_leaf(
                return 0;
        lbp = state->path.blk[0].bp;
        leaf = lbp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
 
        ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
               leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
@@ -1708,8 +1744,7 @@ xfs_dir2_node_to_leaf(
        error = xfs_dir2_free_read(tp, dp,  args->geo->freeblk, &fbp);
        if (error)
                return error;
-       free = fbp->b_addr;
-       dp->d_ops->free_hdr_from_disk(&freehdr, free);
+       xfs_dir2_free_hdr_from_disk(mp, &freehdr, fbp->b_addr);
 
        ASSERT(!freehdr.firstdb);
 
@@ -1743,10 +1778,10 @@ xfs_dir2_node_to_leaf(
        /*
         * Set up the leaf bests table.
         */
-       memcpy(xfs_dir2_leaf_bests_p(ltp), dp->d_ops->free_bests_p(free),
+       memcpy(xfs_dir2_leaf_bests_p(ltp), freehdr.bests,
                freehdr.nvalid * sizeof(xfs_dir2_data_off_t));
 
-       dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(mp, leaf, &leafhdr);
        xfs_dir3_leaf_log_header(args, lbp);
        xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
        xfs_dir3_leaf_log_tail(args, lbp);
index 705c4f5..a0cc5e2 100644 (file)
@@ -33,6 +33,25 @@ static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp,
                                 int index, xfs_da_state_blk_t *dblk,
                                 int *rval);
 
+/*
+ * Convert data space db to the corresponding free db.
+ */
+static xfs_dir2_db_t
+xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
+{
+       return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) +
+                       (db / geo->free_max_bests);
+}
+
+/*
+ * Convert data space db to the corresponding index in a free db.
+ */
+static int
+xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
+{
+       return db % geo->free_max_bests;
+}
+
 /*
  * Check internal consistency of a leafn block.
  */
@@ -45,7 +64,7 @@ xfs_dir3_leafn_check(
        struct xfs_dir2_leaf    *leaf = bp->b_addr;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
 
        if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) {
                struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
@@ -54,7 +73,7 @@ xfs_dir3_leafn_check(
        } else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC)
                return __this_address;
 
-       return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf);
+       return xfs_dir3_leaf_check_int(dp->i_mount, &leafhdr, leaf);
 }
 
 static inline void
@@ -160,10 +179,9 @@ xfs_dir3_free_header_check(
        struct xfs_buf          *bp)
 {
        struct xfs_mount        *mp = dp->i_mount;
+       int                     maxbests = mp->m_dir_geo->free_max_bests;
        unsigned int            firstdb;
-       int                     maxbests;
 
-       maxbests = dp->d_ops->free_max_bests(mp->m_dir_geo);
        firstdb = (xfs_dir2_da_to_db(mp->m_dir_geo, fbno) -
                   xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) *
                        maxbests;
@@ -194,14 +212,14 @@ __xfs_dir3_free_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             fbno,
-       xfs_daddr_t             mappedbno,
+       unsigned int            flags,
        struct xfs_buf          **bpp)
 {
        xfs_failaddr_t          fa;
        int                     err;
 
-       err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
-                               XFS_DATA_FORK, &xfs_dir3_free_buf_ops);
+       err = xfs_da_read_buf(tp, dp, fbno, flags, bpp, XFS_DATA_FORK,
+                       &xfs_dir3_free_buf_ops);
        if (err || !*bpp)
                return err;
 
@@ -220,6 +238,58 @@ __xfs_dir3_free_read(
        return 0;
 }
 
+void
+xfs_dir2_free_hdr_from_disk(
+       struct xfs_mount                *mp,
+       struct xfs_dir3_icfree_hdr      *to,
+       struct xfs_dir2_free            *from)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_dir3_free    *from3 = (struct xfs_dir3_free *)from;
+
+               to->magic = be32_to_cpu(from3->hdr.hdr.magic);
+               to->firstdb = be32_to_cpu(from3->hdr.firstdb);
+               to->nvalid = be32_to_cpu(from3->hdr.nvalid);
+               to->nused = be32_to_cpu(from3->hdr.nused);
+               to->bests = from3->bests;
+
+               ASSERT(to->magic == XFS_DIR3_FREE_MAGIC);
+       } else {
+               to->magic = be32_to_cpu(from->hdr.magic);
+               to->firstdb = be32_to_cpu(from->hdr.firstdb);
+               to->nvalid = be32_to_cpu(from->hdr.nvalid);
+               to->nused = be32_to_cpu(from->hdr.nused);
+               to->bests = from->bests;
+
+               ASSERT(to->magic == XFS_DIR2_FREE_MAGIC);
+       }
+}
+
+static void
+xfs_dir2_free_hdr_to_disk(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_free            *to,
+       struct xfs_dir3_icfree_hdr      *from)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_dir3_free    *to3 = (struct xfs_dir3_free *)to;
+
+               ASSERT(from->magic == XFS_DIR3_FREE_MAGIC);
+
+               to3->hdr.hdr.magic = cpu_to_be32(from->magic);
+               to3->hdr.firstdb = cpu_to_be32(from->firstdb);
+               to3->hdr.nvalid = cpu_to_be32(from->nvalid);
+               to3->hdr.nused = cpu_to_be32(from->nused);
+       } else {
+               ASSERT(from->magic == XFS_DIR2_FREE_MAGIC);
+
+               to->hdr.magic = cpu_to_be32(from->magic);
+               to->hdr.firstdb = cpu_to_be32(from->firstdb);
+               to->hdr.nvalid = cpu_to_be32(from->nvalid);
+               to->hdr.nused = cpu_to_be32(from->nused);
+       }
+}
+
 int
 xfs_dir2_free_read(
        struct xfs_trans        *tp,
@@ -227,7 +297,7 @@ xfs_dir2_free_read(
        xfs_dablk_t             fbno,
        struct xfs_buf          **bpp)
 {
-       return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);
+       return __xfs_dir3_free_read(tp, dp, fbno, 0, bpp);
 }
 
 static int
@@ -237,7 +307,7 @@ xfs_dir2_free_try_read(
        xfs_dablk_t             fbno,
        struct xfs_buf          **bpp)
 {
-       return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp);
+       return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
 }
 
 static int
@@ -254,7 +324,7 @@ xfs_dir3_free_get_buf(
        struct xfs_dir3_icfree_hdr hdr;
 
        error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
-                                  -1, &bp, XFS_DATA_FORK);
+                       &bp, XFS_DATA_FORK);
        if (error)
                return error;
 
@@ -278,7 +348,7 @@ xfs_dir3_free_get_buf(
                uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
        } else
                hdr.magic = XFS_DIR2_FREE_MAGIC;
-       dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
+       xfs_dir2_free_hdr_to_disk(mp, bp->b_addr, &hdr);
        *bpp = bp;
        return 0;
 }
@@ -289,21 +359,19 @@ xfs_dir3_free_get_buf(
 STATIC void
 xfs_dir2_free_log_bests(
        struct xfs_da_args      *args,
+       struct xfs_dir3_icfree_hdr *hdr,
        struct xfs_buf          *bp,
        int                     first,          /* first entry to log */
        int                     last)           /* last entry to log */
 {
-       xfs_dir2_free_t         *free;          /* freespace structure */
-       __be16                  *bests;
+       struct xfs_dir2_free    *free = bp->b_addr;
 
-       free = bp->b_addr;
-       bests = args->dp->d_ops->free_bests_p(free);
        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
               free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
        xfs_trans_log_buf(args->trans, bp,
-               (uint)((char *)&bests[first] - (char *)free),
-               (uint)((char *)&bests[last] - (char *)free +
-                      sizeof(bests[0]) - 1));
+                         (char *)&hdr->bests[first] - (char *)free,
+                         (char *)&hdr->bests[last] - (char *)free +
+                          sizeof(hdr->bests[0]) - 1);
 }
 
 /*
@@ -322,7 +390,7 @@ xfs_dir2_free_log_header(
               free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
 #endif
        xfs_trans_log_buf(args->trans, bp, 0,
-                         args->dp->d_ops->free_hdr_size - 1);
+                         args->geo->free_hdr_size - 1);
 }
 
 /*
@@ -339,14 +407,12 @@ xfs_dir2_leaf_to_node(
        int                     error;          /* error return value */
        struct xfs_buf          *fbp;           /* freespace buffer */
        xfs_dir2_db_t           fdb;            /* freespace block number */
-       xfs_dir2_free_t         *free;          /* freespace structure */
        __be16                  *from;          /* pointer to freespace entry */
        int                     i;              /* leaf freespace index */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_tail_t    *ltp;           /* leaf tail structure */
        int                     n;              /* count of live freespc ents */
        xfs_dir2_data_off_t     off;            /* freespace entry value */
-       __be16                  *to;            /* pointer to freespace entry */
        xfs_trans_t             *tp;            /* transaction pointer */
        struct xfs_dir3_icfree_hdr freehdr;
 
@@ -368,24 +434,25 @@ xfs_dir2_leaf_to_node(
        if (error)
                return error;
 
-       free = fbp->b_addr;
-       dp->d_ops->free_hdr_from_disk(&freehdr, free);
+       xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, fbp->b_addr);
        leaf = lbp->b_addr;
        ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
        if (be32_to_cpu(ltp->bestcount) >
-                               (uint)dp->i_d.di_size / args->geo->blksize)
+                               (uint)dp->i_d.di_size / args->geo->blksize) {
+               xfs_buf_corruption_error(lbp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Copy freespace entries from the leaf block to the new block.
         * Count active entries.
         */
        from = xfs_dir2_leaf_bests_p(ltp);
-       to = dp->d_ops->free_bests_p(free);
-       for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) {
-               if ((off = be16_to_cpu(*from)) != NULLDATAOFF)
+       for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++) {
+               off = be16_to_cpu(*from);
+               if (off != NULLDATAOFF)
                        n++;
-               *to = cpu_to_be16(off);
+               freehdr.bests[i] = cpu_to_be16(off);
        }
 
        /*
@@ -394,8 +461,8 @@ xfs_dir2_leaf_to_node(
        freehdr.nused = n;
        freehdr.nvalid = be32_to_cpu(ltp->bestcount);
 
-       dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr);
-       xfs_dir2_free_log_bests(args, fbp, 0, freehdr.nvalid - 1);
+       xfs_dir2_free_hdr_to_disk(dp->i_mount, fbp->b_addr, &freehdr);
+       xfs_dir2_free_log_bests(args, &freehdr, fbp, 0, freehdr.nvalid - 1);
        xfs_dir2_free_log_header(args, fbp);
 
        /*
@@ -438,15 +505,17 @@ xfs_dir2_leafn_add(
 
        trace_xfs_dir2_leafn_add(args, index);
 
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
+       ents = leafhdr.ents;
 
        /*
         * Quick check just to make sure we are not going to index
         * into other peoples memory
         */
-       if (index < 0)
+       if (index < 0) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * If there are already the maximum number of leaf entries in
@@ -455,7 +524,7 @@ xfs_dir2_leafn_add(
         * a compact.
         */
 
-       if (leafhdr.count == dp->d_ops->leaf_max_ents(args->geo)) {
+       if (leafhdr.count == args->geo->leaf_max_ents) {
                if (!leafhdr.stale)
                        return -ENOSPC;
                compact = leafhdr.stale > 1;
@@ -493,9 +562,9 @@ xfs_dir2_leafn_add(
        lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(args->geo,
                                args->blkno, args->index));
 
-       dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
        xfs_dir3_leaf_log_header(args, bp);
-       xfs_dir3_leaf_log_ents(args, bp, lfloglow, lfloghigh);
+       xfs_dir3_leaf_log_ents(args, &leafhdr, bp, lfloglow, lfloghigh);
        xfs_dir3_leaf_check(dp, bp);
        return 0;
 }
@@ -509,10 +578,9 @@ xfs_dir2_free_hdr_check(
 {
        struct xfs_dir3_icfree_hdr hdr;
 
-       dp->d_ops->free_hdr_from_disk(&hdr, bp->b_addr);
+       xfs_dir2_free_hdr_from_disk(dp->i_mount, &hdr, bp->b_addr);
 
-       ASSERT((hdr.firstdb %
-               dp->d_ops->free_max_bests(dp->i_mount->m_dir_geo)) == 0);
+       ASSERT((hdr.firstdb % dp->i_mount->m_dir_geo->free_max_bests) == 0);
        ASSERT(hdr.firstdb <= db);
        ASSERT(db < hdr.firstdb + hdr.nvalid);
 }
@@ -530,11 +598,9 @@ xfs_dir2_leaf_lasthash(
        struct xfs_buf  *bp,                    /* leaf buffer */
        int             *count)                 /* count of entries in leaf */
 {
-       struct xfs_dir2_leaf    *leaf = bp->b_addr;
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, bp->b_addr);
 
        ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
               leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
@@ -545,9 +611,7 @@ xfs_dir2_leaf_lasthash(
                *count = leafhdr.count;
        if (!leafhdr.count)
                return 0;
-
-       ents = dp->d_ops->leaf_ents_p(leaf);
-       return be32_to_cpu(ents[leafhdr.count - 1].hashval);
+       return be32_to_cpu(leafhdr.ents[leafhdr.count - 1].hashval);
 }
 
 /*
@@ -576,15 +640,13 @@ xfs_dir2_leafn_lookup_for_addname(
        xfs_dir2_db_t           newdb;          /* new data block number */
        xfs_dir2_db_t           newfdb;         /* new free block number */
        xfs_trans_t             *tp;            /* transaction pointer */
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
        leaf = bp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
 
        xfs_dir3_leaf_check(dp, bp);
        ASSERT(leafhdr.count > 0);
@@ -604,11 +666,11 @@ xfs_dir2_leafn_lookup_for_addname(
                ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
                       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
        }
-       length = dp->d_ops->data_entsize(args->namelen);
+       length = xfs_dir2_data_entsize(mp, args->namelen);
        /*
         * Loop over leaf entries with the right hash value.
         */
-       for (lep = &ents[index];
+       for (lep = &leafhdr.ents[index];
             index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
             lep++, index++) {
                /*
@@ -630,14 +692,14 @@ xfs_dir2_leafn_lookup_for_addname(
                 * in hand, take a look at it.
                 */
                if (newdb != curdb) {
-                       __be16 *bests;
+                       struct xfs_dir3_icfree_hdr freehdr;
 
                        curdb = newdb;
                        /*
                         * Convert the data block to the free block
                         * holding its freespace information.
                         */
-                       newfdb = dp->d_ops->db_to_fdb(args->geo, newdb);
+                       newfdb = xfs_dir2_db_to_fdb(args->geo, newdb);
                        /*
                         * If it's not the one we have in hand, read it in.
                         */
@@ -661,20 +723,20 @@ xfs_dir2_leafn_lookup_for_addname(
                        /*
                         * Get the index for our entry.
                         */
-                       fi = dp->d_ops->db_to_fdindex(args->geo, curdb);
+                       fi = xfs_dir2_db_to_fdindex(args->geo, curdb);
                        /*
                         * If it has room, return it.
                         */
-                       bests = dp->d_ops->free_bests_p(free);
-                       if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) {
-                               XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",
-                                                       XFS_ERRLEVEL_LOW, mp);
+                       xfs_dir2_free_hdr_from_disk(mp, &freehdr, free);
+                       if (XFS_IS_CORRUPT(mp,
+                                          freehdr.bests[fi] ==
+                                          cpu_to_be16(NULLDATAOFF))) {
                                if (curfdb != newfdb)
                                        xfs_trans_brelse(tp, curbp);
                                return -EFSCORRUPTED;
                        }
                        curfdb = newfdb;
-                       if (be16_to_cpu(bests[fi]) >= length)
+                       if (be16_to_cpu(freehdr.bests[fi]) >= length)
                                goto out;
                }
        }
@@ -728,19 +790,19 @@ xfs_dir2_leafn_lookup_for_entry(
        xfs_dir2_db_t           newdb;          /* new data block number */
        xfs_trans_t             *tp;            /* transaction pointer */
        enum xfs_dacmp          cmp;            /* comparison result */
-       struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
 
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
        leaf = bp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
 
        xfs_dir3_leaf_check(dp, bp);
-       if (leafhdr.count <= 0)
+       if (leafhdr.count <= 0) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Look up the hash value in the leaf entries.
@@ -756,7 +818,7 @@ xfs_dir2_leafn_lookup_for_entry(
        /*
         * Loop over leaf entries with the right hash value.
         */
-       for (lep = &ents[index];
+       for (lep = &leafhdr.ents[index];
             index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
             lep++, index++) {
                /*
@@ -795,7 +857,7 @@ xfs_dir2_leafn_lookup_for_entry(
                                error = xfs_dir3_data_read(tp, dp,
                                                xfs_dir2_db_to_da(args->geo,
                                                                  newdb),
-                                               -1, &curbp);
+                                               0, &curbp);
                                if (error)
                                        return error;
                        }
@@ -813,7 +875,7 @@ xfs_dir2_leafn_lookup_for_entry(
                 * EEXIST immediately. If it's the first case-insensitive
                 * match, store the block & inode number and continue looking.
                 */
-               cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
+               cmp = xfs_dir2_compname(args, dep->name, dep->namelen);
                if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
                        /* If there is a CI match block, drop it */
                        if (args->cmpresult != XFS_CMP_DIFFERENT &&
@@ -821,7 +883,7 @@ xfs_dir2_leafn_lookup_for_entry(
                                xfs_trans_brelse(tp, state->extrablk.bp);
                        args->cmpresult = cmp;
                        args->inumber = be64_to_cpu(dep->inumber);
-                       args->filetype = dp->d_ops->data_get_ftype(dep);
+                       args->filetype = xfs_dir2_data_get_ftype(mp, dep);
                        *indexp = index;
                        state->extravalid = 1;
                        state->extrablk.bp = curbp;
@@ -911,7 +973,7 @@ xfs_dir3_leafn_moveents(
        if (start_d < dhdr->count) {
                memmove(&dents[start_d + count], &dents[start_d],
                        (dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t));
-               xfs_dir3_leaf_log_ents(args, bp_d, start_d + count,
+               xfs_dir3_leaf_log_ents(args, dhdr, bp_d, start_d + count,
                                       count + dhdr->count - 1);
        }
        /*
@@ -933,7 +995,7 @@ xfs_dir3_leafn_moveents(
         */
        memcpy(&dents[start_d], &sents[start_s],
                count * sizeof(xfs_dir2_leaf_entry_t));
-       xfs_dir3_leaf_log_ents(args, bp_d, start_d, start_d + count - 1);
+       xfs_dir3_leaf_log_ents(args, dhdr, bp_d, start_d, start_d + count - 1);
 
        /*
         * If there are source entries after the ones we copied,
@@ -942,7 +1004,8 @@ xfs_dir3_leafn_moveents(
        if (start_s + count < shdr->count) {
                memmove(&sents[start_s], &sents[start_s + count],
                        count * sizeof(xfs_dir2_leaf_entry_t));
-               xfs_dir3_leaf_log_ents(args, bp_s, start_s, start_s + count - 1);
+               xfs_dir3_leaf_log_ents(args, shdr, bp_s, start_s,
+                                      start_s + count - 1);
        }
 
        /*
@@ -971,10 +1034,10 @@ xfs_dir2_leafn_order(
        struct xfs_dir3_icleaf_hdr hdr1;
        struct xfs_dir3_icleaf_hdr hdr2;
 
-       dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1);
-       dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2);
-       ents1 = dp->d_ops->leaf_ents_p(leaf1);
-       ents2 = dp->d_ops->leaf_ents_p(leaf2);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr1, leaf1);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr2, leaf2);
+       ents1 = hdr1.ents;
+       ents2 = hdr2.ents;
 
        if (hdr1.count > 0 && hdr2.count > 0 &&
            (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) ||
@@ -1024,10 +1087,10 @@ xfs_dir2_leafn_rebalance(
 
        leaf1 = blk1->bp->b_addr;
        leaf2 = blk2->bp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1);
-       dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2);
-       ents1 = dp->d_ops->leaf_ents_p(leaf1);
-       ents2 = dp->d_ops->leaf_ents_p(leaf2);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr1, leaf1);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr2, leaf2);
+       ents1 = hdr1.ents;
+       ents2 = hdr2.ents;
 
        oldsum = hdr1.count + hdr2.count;
 #if defined(DEBUG) || defined(XFS_WARN)
@@ -1073,8 +1136,8 @@ xfs_dir2_leafn_rebalance(
        ASSERT(hdr1.stale + hdr2.stale == oldstale);
 
        /* log the changes made when moving the entries */
-       dp->d_ops->leaf_hdr_to_disk(leaf1, &hdr1);
-       dp->d_ops->leaf_hdr_to_disk(leaf2, &hdr2);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf1, &hdr1);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf2, &hdr2);
        xfs_dir3_leaf_log_header(args, blk1->bp);
        xfs_dir3_leaf_log_header(args, blk2->bp);
 
@@ -1120,19 +1183,17 @@ xfs_dir3_data_block_free(
        int                     longest)
 {
        int                     logfree = 0;
-       __be16                  *bests;
        struct xfs_dir3_icfree_hdr freehdr;
        struct xfs_inode        *dp = args->dp;
 
-       dp->d_ops->free_hdr_from_disk(&freehdr, free);
-       bests = dp->d_ops->free_bests_p(free);
+       xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, free);
        if (hdr) {
                /*
                 * Data block is not empty, just set the free entry to the new
                 * value.
                 */
-               bests[findex] = cpu_to_be16(longest);
-               xfs_dir2_free_log_bests(args, fbp, findex, findex);
+               freehdr.bests[findex] = cpu_to_be16(longest);
+               xfs_dir2_free_log_bests(args, &freehdr, fbp, findex, findex);
                return 0;
        }
 
@@ -1148,18 +1209,18 @@ xfs_dir3_data_block_free(
                int     i;              /* free entry index */
 
                for (i = findex - 1; i >= 0; i--) {
-                       if (bests[i] != cpu_to_be16(NULLDATAOFF))
+                       if (freehdr.bests[i] != cpu_to_be16(NULLDATAOFF))
                                break;
                }
                freehdr.nvalid = i + 1;
                logfree = 0;
        } else {
                /* Not the last entry, just punch it out.  */
-               bests[findex] = cpu_to_be16(NULLDATAOFF);
+               freehdr.bests[findex] = cpu_to_be16(NULLDATAOFF);
                logfree = 1;
        }
 
-       dp->d_ops->free_hdr_to_disk(free, &freehdr);
+       xfs_dir2_free_hdr_to_disk(dp->i_mount, free, &freehdr);
        xfs_dir2_free_log_header(args, fbp);
 
        /*
@@ -1184,7 +1245,7 @@ xfs_dir3_data_block_free(
 
        /* Log the free entry that changed, unless we got rid of it.  */
        if (logfree)
-               xfs_dir2_free_log_bests(args, fbp, findex, findex);
+               xfs_dir2_free_log_bests(args, &freehdr, fbp, findex, findex);
        return 0;
 }
 
@@ -1201,6 +1262,7 @@ xfs_dir2_leafn_remove(
        xfs_da_state_blk_t      *dblk,          /* data block */
        int                     *rval)          /* resulting block needs join */
 {
+       struct xfs_da_geometry  *geo = args->geo;
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_db_t           db;             /* data block number */
        struct xfs_buf          *dbp;           /* data block buffer */
@@ -1215,27 +1277,25 @@ xfs_dir2_leafn_remove(
        xfs_trans_t             *tp;            /* transaction pointer */
        struct xfs_dir2_data_free *bf;          /* bestfree table */
        struct xfs_dir3_icleaf_hdr leafhdr;
-       struct xfs_dir2_leaf_entry *ents;
 
        trace_xfs_dir2_leafn_remove(args, index);
 
        dp = args->dp;
        tp = args->trans;
        leaf = bp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
 
        /*
         * Point to the entry we're removing.
         */
-       lep = &ents[index];
+       lep = &leafhdr.ents[index];
 
        /*
         * Extract the data block and offset from the entry.
         */
-       db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
+       db = xfs_dir2_dataptr_to_db(geo, be32_to_cpu(lep->address));
        ASSERT(dblk->blkno == db);
-       off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address));
+       off = xfs_dir2_dataptr_to_off(geo, be32_to_cpu(lep->address));
        ASSERT(dblk->index == off);
 
        /*
@@ -1243,11 +1303,11 @@ xfs_dir2_leafn_remove(
         * Log the leaf block changes.
         */
        leafhdr.stale++;
-       dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
        xfs_dir3_leaf_log_header(args, bp);
 
        lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
-       xfs_dir3_leaf_log_ents(args, bp, index, index);
+       xfs_dir3_leaf_log_ents(args, &leafhdr, bp, index, index);
 
        /*
         * Make the data entry free.  Keep track of the longest freespace
@@ -1256,17 +1316,18 @@ xfs_dir2_leafn_remove(
        dbp = dblk->bp;
        hdr = dbp->b_addr;
        dep = (xfs_dir2_data_entry_t *)((char *)hdr + off);
-       bf = dp->d_ops->data_bestfree_p(hdr);
+       bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
        longest = be16_to_cpu(bf[0].length);
        needlog = needscan = 0;
        xfs_dir2_data_make_free(args, dbp, off,
-               dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
+               xfs_dir2_data_entsize(dp->i_mount, dep->namelen), &needlog,
+               &needscan);
        /*
         * Rescan the data block freespaces for bestfree.
         * Log the data block header if needed.
         */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        if (needlog)
                xfs_dir2_data_log_header(args, dbp);
        xfs_dir3_data_check(dp, dbp);
@@ -1285,9 +1346,8 @@ xfs_dir2_leafn_remove(
                 * Convert the data block number to a free block,
                 * read in the free block.
                 */
-               fdb = dp->d_ops->db_to_fdb(args->geo, db);
-               error = xfs_dir2_free_read(tp, dp,
-                                          xfs_dir2_db_to_da(args->geo, fdb),
+               fdb = xfs_dir2_db_to_fdb(geo, db);
+               error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(geo, fdb),
                                           &fbp);
                if (error)
                        return error;
@@ -1295,23 +1355,22 @@ xfs_dir2_leafn_remove(
 #ifdef DEBUG
        {
                struct xfs_dir3_icfree_hdr freehdr;
-               dp->d_ops->free_hdr_from_disk(&freehdr, free);
-               ASSERT(freehdr.firstdb == dp->d_ops->free_max_bests(args->geo) *
-                       (fdb - xfs_dir2_byte_to_db(args->geo,
-                                                  XFS_DIR2_FREE_OFFSET)));
+
+               xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, free);
+               ASSERT(freehdr.firstdb == geo->free_max_bests *
+                       (fdb - xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET)));
        }
 #endif
                /*
                 * Calculate which entry we need to fix.
                 */
-               findex = dp->d_ops->db_to_fdindex(args->geo, db);
+               findex = xfs_dir2_db_to_fdindex(geo, db);
                longest = be16_to_cpu(bf[0].length);
                /*
                 * If the data block is now empty we can get rid of it
                 * (usually).
                 */
-               if (longest == args->geo->blksize -
-                              dp->d_ops->data_entry_offset) {
+               if (longest == geo->blksize - geo->data_entry_offset) {
                        /*
                         * Try to punch out the data block.
                         */
@@ -1343,9 +1402,9 @@ xfs_dir2_leafn_remove(
         * Return indication of whether this leaf block is empty enough
         * to justify trying to join it with a neighbor.
         */
-       *rval = (dp->d_ops->leaf_hdr_size +
-                (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) <
-               args->geo->magicpct;
+       *rval = (geo->leaf_hdr_size +
+                (uint)sizeof(leafhdr.ents) * (leafhdr.count - leafhdr.stale)) <
+               geo->magicpct;
        return 0;
 }
 
@@ -1444,12 +1503,12 @@ xfs_dir2_leafn_toosmall(
         */
        blk = &state->path.blk[state->path.active - 1];
        leaf = blk->bp->b_addr;
-       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = dp->d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
+       ents = leafhdr.ents;
        xfs_dir3_leaf_check(dp, blk->bp);
 
        count = leafhdr.count - leafhdr.stale;
-       bytes = dp->d_ops->leaf_hdr_size + count * sizeof(ents[0]);
+       bytes = state->args->geo->leaf_hdr_size + count * sizeof(ents[0]);
        if (bytes > (state->args->geo->blksize >> 1)) {
                /*
                 * Blk over 50%, don't try to join.
@@ -1494,8 +1553,7 @@ xfs_dir2_leafn_toosmall(
                /*
                 * Read the sibling leaf block.
                 */
-               error = xfs_dir3_leafn_read(state->args->trans, dp,
-                                           blkno, -1, &bp);
+               error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, &bp);
                if (error)
                        return error;
 
@@ -1507,8 +1565,8 @@ xfs_dir2_leafn_toosmall(
                        (state->args->geo->blksize >> 2);
 
                leaf = bp->b_addr;
-               dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf);
-               ents = dp->d_ops->leaf_ents_p(leaf);
+               xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr2, leaf);
+               ents = hdr2.ents;
                count += hdr2.count - hdr2.stale;
                bytes -= count * sizeof(ents[0]);
 
@@ -1570,10 +1628,10 @@ xfs_dir2_leafn_unbalance(
        drop_leaf = drop_blk->bp->b_addr;
        save_leaf = save_blk->bp->b_addr;
 
-       dp->d_ops->leaf_hdr_from_disk(&savehdr, save_leaf);
-       dp->d_ops->leaf_hdr_from_disk(&drophdr, drop_leaf);
-       sents = dp->d_ops->leaf_ents_p(save_leaf);
-       dents = dp->d_ops->leaf_ents_p(drop_leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &savehdr, save_leaf);
+       xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &drophdr, drop_leaf);
+       sents = savehdr.ents;
+       dents = drophdr.ents;
 
        /*
         * If there are any stale leaf entries, take this opportunity
@@ -1599,8 +1657,8 @@ xfs_dir2_leafn_unbalance(
        save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval);
 
        /* log the changes made when moving the entries */
-       dp->d_ops->leaf_hdr_to_disk(save_leaf, &savehdr);
-       dp->d_ops->leaf_hdr_to_disk(drop_leaf, &drophdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, save_leaf, &savehdr);
+       xfs_dir2_leaf_hdr_to_disk(dp->i_mount, drop_leaf, &drophdr);
        xfs_dir3_leaf_log_header(args, save_blk->bp);
        xfs_dir3_leaf_log_header(args, drop_blk->bp);
 
@@ -1619,19 +1677,16 @@ xfs_dir2_node_add_datablk(
        xfs_dir2_db_t           *dbno,
        struct xfs_buf          **dbpp,
        struct xfs_buf          **fbpp,
+       struct xfs_dir3_icfree_hdr *hdr,
        int                     *findex)
 {
        struct xfs_inode        *dp = args->dp;
        struct xfs_trans        *tp = args->trans;
        struct xfs_mount        *mp = dp->i_mount;
-       struct xfs_dir3_icfree_hdr freehdr;
        struct xfs_dir2_data_free *bf;
-       struct xfs_dir2_data_hdr *hdr;
-       struct xfs_dir2_free    *free = NULL;
        xfs_dir2_db_t           fbno;
        struct xfs_buf          *fbp;
        struct xfs_buf          *dbp;
-       __be16                  *bests = NULL;
        int                     error;
 
        /* Not allowed to allocate, return failure. */
@@ -1650,7 +1705,7 @@ xfs_dir2_node_add_datablk(
         * Get the freespace block corresponding to the data block
         * that was just allocated.
         */
-       fbno = dp->d_ops->db_to_fdb(args->geo, *dbno);
+       fbno = xfs_dir2_db_to_fdb(args->geo, *dbno);
        error = xfs_dir2_free_try_read(tp, dp,
                               xfs_dir2_db_to_da(args->geo, fbno), &fbp);
        if (error)
@@ -1665,11 +1720,13 @@ xfs_dir2_node_add_datablk(
                if (error)
                        return error;
 
-               if (dp->d_ops->db_to_fdb(args->geo, *dbno) != fbno) {
+               if (XFS_IS_CORRUPT(mp,
+                                  xfs_dir2_db_to_fdb(args->geo, *dbno) !=
+                                  fbno)) {
                        xfs_alert(mp,
 "%s: dir ino %llu needed freesp block %lld for data block %lld, got %lld",
                                __func__, (unsigned long long)dp->i_ino,
-                               (long long)dp->d_ops->db_to_fdb(args->geo, *dbno),
+                               (long long)xfs_dir2_db_to_fdb(args->geo, *dbno),
                                (long long)*dbno, (long long)fbno);
                        if (fblk) {
                                xfs_alert(mp,
@@ -1679,7 +1736,6 @@ xfs_dir2_node_add_datablk(
                        } else {
                                xfs_alert(mp, " ... fblk is NULL");
                        }
-                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                        return -EFSCORRUPTED;
                }
 
@@ -1687,44 +1743,39 @@ xfs_dir2_node_add_datablk(
                error = xfs_dir3_free_get_buf(args, fbno, &fbp);
                if (error)
                        return error;
-               free = fbp->b_addr;
-               bests = dp->d_ops->free_bests_p(free);
-               dp->d_ops->free_hdr_from_disk(&freehdr, free);
+               xfs_dir2_free_hdr_from_disk(mp, hdr, fbp->b_addr);
 
                /* Remember the first slot as our empty slot. */
-               freehdr.firstdb = (fbno - xfs_dir2_byte_to_db(args->geo,
+               hdr->firstdb = (fbno - xfs_dir2_byte_to_db(args->geo,
                                                        XFS_DIR2_FREE_OFFSET)) *
-                               dp->d_ops->free_max_bests(args->geo);
+                               args->geo->free_max_bests;
        } else {
-               free = fbp->b_addr;
-               bests = dp->d_ops->free_bests_p(free);
-               dp->d_ops->free_hdr_from_disk(&freehdr, free);
+               xfs_dir2_free_hdr_from_disk(mp, hdr, fbp->b_addr);
        }
 
        /* Set the freespace block index from the data block number. */
-       *findex = dp->d_ops->db_to_fdindex(args->geo, *dbno);
+       *findex = xfs_dir2_db_to_fdindex(args->geo, *dbno);
 
        /* Extend the freespace table if the new data block is off the end. */
-       if (*findex >= freehdr.nvalid) {
-               ASSERT(*findex < dp->d_ops->free_max_bests(args->geo));
-               freehdr.nvalid = *findex + 1;
-               bests[*findex] = cpu_to_be16(NULLDATAOFF);
+       if (*findex >= hdr->nvalid) {
+               ASSERT(*findex < args->geo->free_max_bests);
+               hdr->nvalid = *findex + 1;
+               hdr->bests[*findex] = cpu_to_be16(NULLDATAOFF);
        }
 
        /*
         * If this entry was for an empty data block (this should always be
         * true) then update the header.
         */
-       if (bests[*findex] == cpu_to_be16(NULLDATAOFF)) {
-               freehdr.nused++;
-               dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr);
+       if (hdr->bests[*findex] == cpu_to_be16(NULLDATAOFF)) {
+               hdr->nused++;
+               xfs_dir2_free_hdr_to_disk(mp, fbp->b_addr, hdr);
                xfs_dir2_free_log_header(args, fbp);
        }
 
        /* Update the freespace value for the new block in the table. */
-       hdr = dbp->b_addr;
-       bf = dp->d_ops->data_bestfree_p(hdr);
-       bests[*findex] = bf[0].length;
+       bf = xfs_dir2_data_bestfree_p(mp, dbp->b_addr);
+       hdr->bests[*findex] = bf[0].length;
 
        *dbpp = dbp;
        *fbpp = fbp;
@@ -1737,11 +1788,10 @@ xfs_dir2_node_find_freeblk(
        struct xfs_da_state_blk *fblk,
        xfs_dir2_db_t           *dbnop,
        struct xfs_buf          **fbpp,
+       struct xfs_dir3_icfree_hdr *hdr,
        int                     *findexp,
        int                     length)
 {
-       struct xfs_dir3_icfree_hdr freehdr;
-       struct xfs_dir2_free    *free = NULL;
        struct xfs_inode        *dp = args->dp;
        struct xfs_trans        *tp = args->trans;
        struct xfs_buf          *fbp = NULL;
@@ -1751,7 +1801,6 @@ xfs_dir2_node_find_freeblk(
        xfs_dir2_db_t           dbno = -1;
        xfs_dir2_db_t           fbno;
        xfs_fileoff_t           fo;
-       __be16                  *bests = NULL;
        int                     findex = 0;
        int                     error;
 
@@ -1762,17 +1811,14 @@ xfs_dir2_node_find_freeblk(
         */
        if (fblk) {
                fbp = fblk->bp;
-               free = fbp->b_addr;
                findex = fblk->index;
+               xfs_dir2_free_hdr_from_disk(dp->i_mount, hdr, fbp->b_addr);
                if (findex >= 0) {
                        /* caller already found the freespace for us. */
-                       bests = dp->d_ops->free_bests_p(free);
-                       dp->d_ops->free_hdr_from_disk(&freehdr, free);
-
-                       ASSERT(findex < freehdr.nvalid);
-                       ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF);
-                       ASSERT(be16_to_cpu(bests[findex]) >= length);
-                       dbno = freehdr.firstdb + findex;
+                       ASSERT(findex < hdr->nvalid);
+                       ASSERT(be16_to_cpu(hdr->bests[findex]) != NULLDATAOFF);
+                       ASSERT(be16_to_cpu(hdr->bests[findex]) >= length);
+                       dbno = hdr->firstdb + findex;
                        goto found_block;
                }
 
@@ -1814,15 +1860,13 @@ xfs_dir2_node_find_freeblk(
                if (!fbp)
                        continue;
 
-               free = fbp->b_addr;
-               bests = dp->d_ops->free_bests_p(free);
-               dp->d_ops->free_hdr_from_disk(&freehdr, free);
+               xfs_dir2_free_hdr_from_disk(dp->i_mount, hdr, fbp->b_addr);
 
                /* Scan the free entry array for a large enough free space. */
-               for (findex = freehdr.nvalid - 1; findex >= 0; findex--) {
-                       if (be16_to_cpu(bests[findex]) != NULLDATAOFF &&
-                           be16_to_cpu(bests[findex]) >= length) {
-                               dbno = freehdr.firstdb + findex;
+               for (findex = hdr->nvalid - 1; findex >= 0; findex--) {
+                       if (be16_to_cpu(hdr->bests[findex]) != NULLDATAOFF &&
+                           be16_to_cpu(hdr->bests[findex]) >= length) {
+                               dbno = hdr->firstdb + findex;
                                goto found_block;
                        }
                }
@@ -1838,7 +1882,6 @@ found_block:
        return 0;
 }
 
-
 /*
  * Add the data entry for a node-format directory name addition.
  * The leaf entry is added in xfs_dir2_leafn_add.
@@ -1853,9 +1896,9 @@ xfs_dir2_node_addname_int(
        struct xfs_dir2_data_entry *dep;        /* data entry pointer */
        struct xfs_dir2_data_hdr *hdr;          /* data block header */
        struct xfs_dir2_data_free *bf;
-       struct xfs_dir2_free    *free = NULL;   /* freespace block structure */
        struct xfs_trans        *tp = args->trans;
        struct xfs_inode        *dp = args->dp;
+       struct xfs_dir3_icfree_hdr freehdr;
        struct xfs_buf          *dbp;           /* data block buffer */
        struct xfs_buf          *fbp;           /* freespace buffer */
        xfs_dir2_data_aoff_t    aoff;
@@ -1867,11 +1910,10 @@ xfs_dir2_node_addname_int(
        int                     needlog = 0;    /* need to log data header */
        int                     needscan = 0;   /* need to rescan data frees */
        __be16                  *tagp;          /* data entry tag pointer */
-       __be16                  *bests;
 
-       length = dp->d_ops->data_entsize(args->namelen);
-       error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &findex,
-                                          length);
+       length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
+       error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &freehdr,
+                                          &findex, length);
        if (error)
                return error;
 
@@ -1893,19 +1935,19 @@ xfs_dir2_node_addname_int(
                /* we're going to have to log the free block index later */
                logfree = 1;
                error = xfs_dir2_node_add_datablk(args, fblk, &dbno, &dbp, &fbp,
-                                                 &findex);
+                                                 &freehdr, &findex);
        } else {
                /* Read the data block in. */
                error = xfs_dir3_data_read(tp, dp,
                                           xfs_dir2_db_to_da(args->geo, dbno),
-                                          -1, &dbp);
+                                          0, &dbp);
        }
        if (error)
                return error;
 
        /* setup for data block up now */
        hdr = dbp->b_addr;
-       bf = dp->d_ops->data_bestfree_p(hdr);
+       bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
        ASSERT(be16_to_cpu(bf[0].length) >= length);
 
        /* Point to the existing unused space. */
@@ -1926,28 +1968,26 @@ xfs_dir2_node_addname_int(
        dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, dep->namelen);
-       dp->d_ops->data_put_ftype(dep, args->filetype);
-       tagp = dp->d_ops->data_entry_tag_p(dep);
+       xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
+       tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        xfs_dir2_data_log_entry(args, dbp, dep);
 
        /* Rescan the freespace and log the data block if needed. */
        if (needscan)
-               xfs_dir2_data_freescan(dp, hdr, &needlog);
+               xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
        if (needlog)
                xfs_dir2_data_log_header(args, dbp);
 
        /* If the freespace block entry is now wrong, update it. */
-       free = fbp->b_addr;
-       bests = dp->d_ops->free_bests_p(free);
-       if (bests[findex] != bf[0].length) {
-               bests[findex] = bf[0].length;
+       if (freehdr.bests[findex] != bf[0].length) {
+               freehdr.bests[findex] = bf[0].length;
                logfree = 1;
        }
 
        /* Log the freespace entry if needed. */
        if (logfree)
-               xfs_dir2_free_log_bests(args, fbp, findex, findex);
+               xfs_dir2_free_log_bests(args, &freehdr, fbp, findex, findex);
 
        /* Return the data block and offset in args. */
        args->blkno = (xfs_dablk_t)dbno;
@@ -2155,8 +2195,6 @@ xfs_dir2_node_replace(
        int                     i;              /* btree level */
        xfs_ino_t               inum;           /* new inode number */
        int                     ftype;          /* new file type */
-       xfs_dir2_leaf_t         *leaf;          /* leaf structure */
-       xfs_dir2_leaf_entry_t   *lep;           /* leaf entry being changed */
        int                     rval;           /* internal return value */
        xfs_da_state_t          *state;         /* btree cursor */
 
@@ -2188,16 +2226,17 @@ xfs_dir2_node_replace(
         * and locked it.  But paranoia is good.
         */
        if (rval == -EEXIST) {
-               struct xfs_dir2_leaf_entry *ents;
+               struct xfs_dir3_icleaf_hdr      leafhdr;
+
                /*
                 * Find the leaf entry.
                 */
                blk = &state->path.blk[state->path.active - 1];
                ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);
-               leaf = blk->bp->b_addr;
-               ents = args->dp->d_ops->leaf_ents_p(leaf);
-               lep = &ents[blk->index];
                ASSERT(state->extravalid);
+
+               xfs_dir2_leaf_hdr_from_disk(state->mp, &leafhdr,
+                                           blk->bp->b_addr);
                /*
                 * Point to the data entry.
                 */
@@ -2207,13 +2246,13 @@ xfs_dir2_node_replace(
                dep = (xfs_dir2_data_entry_t *)
                      ((char *)hdr +
                       xfs_dir2_dataptr_to_off(args->geo,
-                                              be32_to_cpu(lep->address)));
+                               be32_to_cpu(leafhdr.ents[blk->index].address)));
                ASSERT(inum != be64_to_cpu(dep->inumber));
                /*
                 * Fill in the new inode number and log the entry.
                 */
                dep->inumber = cpu_to_be64(inum);
-               args->dp->d_ops->data_put_ftype(dep, ftype);
+               xfs_dir2_data_put_ftype(state->mp, dep, ftype);
                xfs_dir2_data_log_entry(args, state->extrablk.bp, dep);
                rval = 0;
        }
@@ -2270,7 +2309,7 @@ xfs_dir2_node_trim_free(
        if (!bp)
                return 0;
        free = bp->b_addr;
-       dp->d_ops->free_hdr_from_disk(&freehdr, free);
+       xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, free);
 
        /*
         * If there are used entries, there's nothing to do.
index 59f9fb2..c031c53 100644 (file)
@@ -8,7 +8,41 @@
 
 struct dir_context;
 
+/*
+ * In-core version of the leaf and free block headers to abstract the
+ * differences in the v2 and v3 disk format of the headers.
+ */
+struct xfs_dir3_icleaf_hdr {
+       uint32_t                forw;
+       uint32_t                back;
+       uint16_t                magic;
+       uint16_t                count;
+       uint16_t                stale;
+
+       /*
+        * Pointer to the on-disk format entries, which are behind the
+        * variable size (v4 vs v5) header in the on-disk block.
+        */
+       struct xfs_dir2_leaf_entry *ents;
+};
+
+struct xfs_dir3_icfree_hdr {
+       uint32_t                magic;
+       uint32_t                firstdb;
+       uint32_t                nvalid;
+       uint32_t                nused;
+
+       /*
+        * Pointer to the on-disk format entries, which are behind the
+        * variable size (v4 vs v5) header in the on-disk block.
+        */
+       __be16                  *bests;
+};
+
 /* xfs_dir2.c */
+xfs_dahash_t xfs_ascii_ci_hashname(struct xfs_name *name);
+enum xfs_dacmp xfs_ascii_ci_compname(struct xfs_da_args *args,
+               const unsigned char *name, int len);
 extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
                                xfs_dir2_db_t *dbp);
 extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
@@ -26,6 +60,15 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
                struct xfs_buf *lbp, struct xfs_buf *dbp);
 
 /* xfs_dir2_data.c */
+struct xfs_dir2_data_free *xfs_dir2_data_bestfree_p(struct xfs_mount *mp,
+               struct xfs_dir2_data_hdr *hdr);
+__be16 *xfs_dir2_data_entry_tag_p(struct xfs_mount *mp,
+               struct xfs_dir2_data_entry *dep);
+uint8_t xfs_dir2_data_get_ftype(struct xfs_mount *mp,
+               struct xfs_dir2_data_entry *dep);
+void xfs_dir2_data_put_ftype(struct xfs_mount *mp,
+               struct xfs_dir2_data_entry *dep, uint8_t ftype);
+
 #ifdef DEBUG
 extern void xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
 #else
@@ -34,10 +77,10 @@ extern void xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
 
 extern xfs_failaddr_t __xfs_dir3_data_check(struct xfs_inode *dp,
                struct xfs_buf *bp);
-extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp,
-               xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp);
-extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno,
-               xfs_daddr_t mapped_bno);
+int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp,
+               xfs_dablk_t bno, unsigned int flags, struct xfs_buf **bpp);
+int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno,
+               unsigned int flags);
 
 extern struct xfs_dir2_data_free *
 xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr,
@@ -47,10 +90,14 @@ extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
                struct xfs_buf **bpp);
 
 /* xfs_dir2_leaf.c */
-extern int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
-               xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp);
-extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
-               xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp);
+void xfs_dir2_leaf_hdr_from_disk(struct xfs_mount *mp,
+               struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from);
+void xfs_dir2_leaf_hdr_to_disk(struct xfs_mount *mp, struct xfs_dir2_leaf *to,
+               struct xfs_dir3_icleaf_hdr *from);
+int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
+               xfs_dablk_t fbno, struct xfs_buf **bpp);
+int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
+               xfs_dablk_t fbno, struct xfs_buf **bpp);
 extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
                struct xfs_buf *dbp);
 extern int xfs_dir2_leaf_addname(struct xfs_da_args *args);
@@ -62,7 +109,8 @@ extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr,
 extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno,
                struct xfs_buf **bpp, uint16_t magic);
 extern void xfs_dir3_leaf_log_ents(struct xfs_da_args *args,
-               struct xfs_buf *bp, int first, int last);
+               struct xfs_dir3_icleaf_hdr *hdr, struct xfs_buf *bp, int first,
+               int last);
 extern void xfs_dir3_leaf_log_header(struct xfs_da_args *args,
                struct xfs_buf *bp);
 extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args);
@@ -79,10 +127,11 @@ xfs_dir3_leaf_find_entry(struct xfs_dir3_icleaf_hdr *leafhdr,
 extern int xfs_dir2_node_to_leaf(struct xfs_da_state *state);
 
 extern xfs_failaddr_t xfs_dir3_leaf_check_int(struct xfs_mount *mp,
-               struct xfs_inode *dp, struct xfs_dir3_icleaf_hdr *hdr,
-               struct xfs_dir2_leaf *leaf);
+               struct xfs_dir3_icleaf_hdr *hdr, struct xfs_dir2_leaf *leaf);
 
 /* xfs_dir2_node.c */
+void xfs_dir2_free_hdr_from_disk(struct xfs_mount *mp,
+               struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from);
 extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args,
                struct xfs_buf *lbp);
 extern xfs_dahash_t xfs_dir2_leaf_lasthash(struct xfs_inode *dp,
@@ -108,6 +157,14 @@ extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
                xfs_dablk_t fbno, struct xfs_buf **bpp);
 
 /* xfs_dir2_sf.c */
+xfs_ino_t xfs_dir2_sf_get_ino(struct xfs_mount *mp, struct xfs_dir2_sf_hdr *hdr,
+               struct xfs_dir2_sf_entry *sfep);
+xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *hdr);
+void xfs_dir2_sf_put_parent_ino(struct xfs_dir2_sf_hdr *hdr, xfs_ino_t ino);
+uint8_t xfs_dir2_sf_get_ftype(struct xfs_mount *mp,
+               struct xfs_dir2_sf_entry *sfep);
+struct xfs_dir2_sf_entry *xfs_dir2_sf_nextentry(struct xfs_mount *mp,
+               struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep);
 extern int xfs_dir2_block_sfsize(struct xfs_inode *dp,
                struct xfs_dir2_data_hdr *block, struct xfs_dir2_sf_hdr *sfhp);
 extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp,
@@ -123,4 +180,39 @@ extern xfs_failaddr_t xfs_dir2_sf_verify(struct xfs_inode *ip);
 extern int xfs_readdir(struct xfs_trans *tp, struct xfs_inode *dp,
                       struct dir_context *ctx, size_t bufsize);
 
+static inline unsigned int
+xfs_dir2_data_entsize(
+       struct xfs_mount        *mp,
+       unsigned int            namelen)
+{
+       unsigned int            len;
+
+       len = offsetof(struct xfs_dir2_data_entry, name[0]) + namelen +
+                       sizeof(xfs_dir2_data_off_t) /* tag */;
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               len += sizeof(uint8_t);
+       return round_up(len, XFS_DIR2_DATA_ALIGN);
+}
+
+static inline xfs_dahash_t
+xfs_dir2_hashname(
+       struct xfs_mount        *mp,
+       struct xfs_name         *name)
+{
+       if (unlikely(xfs_sb_version_hasasciici(&mp->m_sb)))
+               return xfs_ascii_ci_hashname(name);
+       return xfs_da_hashname(name->name, name->len);
+}
+
+static inline enum xfs_dacmp
+xfs_dir2_compname(
+       struct xfs_da_args      *args,
+       const unsigned char     *name,
+       int                     len)
+{
+       if (unlikely(xfs_sb_version_hasasciici(&args->dp->i_mount->m_sb)))
+               return xfs_ascii_ci_compname(args, name, len);
+       return xfs_da_compname(args, name, len);
+}
+
 #endif /* __XFS_DIR2_PRIV_H__ */
index 85f14fc..8b94d33 100644 (file)
@@ -37,6 +37,126 @@ static void xfs_dir2_sf_check(xfs_da_args_t *args);
 static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
 static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
 
+static int
+xfs_dir2_sf_entsize(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_hdr  *hdr,
+       int                     len)
+{
+       int                     count = len;
+
+       count += sizeof(struct xfs_dir2_sf_entry);      /* namelen + offset */
+       count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */
+
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               count += sizeof(uint8_t);
+       return count;
+}
+
+struct xfs_dir2_sf_entry *
+xfs_dir2_sf_nextentry(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_hdr  *hdr,
+       struct xfs_dir2_sf_entry *sfep)
+{
+       return (void *)sfep + xfs_dir2_sf_entsize(mp, hdr, sfep->namelen);
+}
+
+/*
+ * In short-form directory entries the inode numbers are stored at variable
+ * offset behind the entry name. If the entry stores a filetype value, then it
+ * sits between the name and the inode number.  The actual inode numbers can
+ * come in two formats as well, either 4 bytes or 8 bytes wide.
+ */
+xfs_ino_t
+xfs_dir2_sf_get_ino(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_sf_hdr          *hdr,
+       struct xfs_dir2_sf_entry        *sfep)
+{
+       uint8_t                         *from = sfep->name + sfep->namelen;
+
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               from++;
+
+       if (!hdr->i8count)
+               return get_unaligned_be32(from);
+       return get_unaligned_be64(from) & XFS_MAXINUMBER;
+}
+
+static void
+xfs_dir2_sf_put_ino(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_sf_hdr          *hdr,
+       struct xfs_dir2_sf_entry        *sfep,
+       xfs_ino_t                       ino)
+{
+       uint8_t                         *to = sfep->name + sfep->namelen;
+
+       ASSERT(ino <= XFS_MAXINUMBER);
+
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               to++;
+
+       if (hdr->i8count)
+               put_unaligned_be64(ino, to);
+       else
+               put_unaligned_be32(ino, to);
+}
+
+xfs_ino_t
+xfs_dir2_sf_get_parent_ino(
+       struct xfs_dir2_sf_hdr  *hdr)
+{
+       if (!hdr->i8count)
+               return get_unaligned_be32(hdr->parent);
+       return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
+}
+
+void
+xfs_dir2_sf_put_parent_ino(
+       struct xfs_dir2_sf_hdr          *hdr,
+       xfs_ino_t                       ino)
+{
+       ASSERT(ino <= XFS_MAXINUMBER);
+
+       if (hdr->i8count)
+               put_unaligned_be64(ino, hdr->parent);
+       else
+               put_unaligned_be32(ino, hdr->parent);
+}
+
+/*
+ * The file type field is stored at the end of the name for filetype enabled
+ * shortform directories, or not at all otherwise.
+ */
+uint8_t
+xfs_dir2_sf_get_ftype(
+       struct xfs_mount                *mp,
+       struct xfs_dir2_sf_entry        *sfep)
+{
+       if (xfs_sb_version_hasftype(&mp->m_sb)) {
+               uint8_t                 ftype = sfep->name[sfep->namelen];
+
+               if (ftype < XFS_DIR3_FT_MAX)
+                       return ftype;
+       }
+
+       return XFS_DIR3_FT_UNKNOWN;
+}
+
+static void
+xfs_dir2_sf_put_ftype(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_entry *sfep,
+       uint8_t                 ftype)
+{
+       ASSERT(ftype < XFS_DIR3_FT_MAX);
+
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               sfep->name[sfep->namelen] = ftype;
+}
+
 /*
  * Given a block directory (dp/block), calculate its size as a shortform (sf)
  * directory and a header for the sf directory, if it will fit it the
@@ -125,7 +245,7 @@ xfs_dir2_block_sfsize(
         */
        sfhp->count = count;
        sfhp->i8count = i8count;
-       dp->d_ops->sf_put_parent_ino(sfhp, parent);
+       xfs_dir2_sf_put_parent_ino(sfhp, parent);
        return size;
 }
 
@@ -135,64 +255,48 @@ xfs_dir2_block_sfsize(
  */
 int                                            /* error */
 xfs_dir2_block_to_sf(
-       xfs_da_args_t           *args,          /* operation arguments */
+       struct xfs_da_args      *args,          /* operation arguments */
        struct xfs_buf          *bp,
        int                     size,           /* shortform directory size */
-       xfs_dir2_sf_hdr_t       *sfhp)          /* shortform directory hdr */
+       struct xfs_dir2_sf_hdr  *sfhp)          /* shortform directory hdr */
 {
-       xfs_dir2_data_hdr_t     *hdr;           /* block header */
-       xfs_dir2_data_entry_t   *dep;           /* data entry pointer */
-       xfs_inode_t             *dp;            /* incore directory inode */
-       xfs_dir2_data_unused_t  *dup;           /* unused data pointer */
-       char                    *endptr;        /* end of data entries */
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     error;          /* error return value */
        int                     logflags;       /* inode logging flags */
-       xfs_mount_t             *mp;            /* filesystem mount point */
-       char                    *ptr;           /* current data pointer */
-       xfs_dir2_sf_entry_t     *sfep;          /* shortform entry */
-       xfs_dir2_sf_hdr_t       *sfp;           /* shortform directory header */
-       xfs_dir2_sf_hdr_t       *dst;           /* temporary data buffer */
+       struct xfs_dir2_sf_entry *sfep;         /* shortform entry */
+       struct xfs_dir2_sf_hdr  *sfp;           /* shortform directory header */
+       unsigned int            offset = args->geo->data_entry_offset;
+       unsigned int            end;
 
        trace_xfs_dir2_block_to_sf(args);
 
-       dp = args->dp;
-       mp = dp->i_mount;
-
-       /*
-        * allocate a temporary destination buffer the size of the inode
-        * to format the data into. Once we have formatted the data, we
-        * can free the block and copy the formatted data into the inode literal
-        * area.
-        */
-       dst = kmem_alloc(mp->m_sb.sb_inodesize, 0);
-       hdr = bp->b_addr;
-
        /*
-        * Copy the header into the newly allocate local space.
+        * Allocate a temporary destination buffer the size of the inode to
+        * format the data into.  Once we have formatted the data, we can free
+        * the block and copy the formatted data into the inode literal area.
         */
-       sfp = (xfs_dir2_sf_hdr_t *)dst;
+       sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
        memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
 
        /*
-        * Set up to loop over the block's entries.
+        * Loop over the active and unused entries.  Stop when we reach the
+        * leaf/tail portion of the block.
         */
-       ptr = (char *)dp->d_ops->data_entry_p(hdr);
-       endptr = xfs_dir3_data_endp(args->geo, hdr);
+       end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
        sfep = xfs_dir2_sf_firstentry(sfp);
-       /*
-        * Loop over the active and unused entries.
-        * Stop when we reach the leaf/tail portion of the block.
-        */
-       while (ptr < endptr) {
+       while (offset < end) {
+               struct xfs_dir2_data_unused     *dup = bp->b_addr + offset;
+               struct xfs_dir2_data_entry      *dep = bp->b_addr + offset;
+
                /*
                 * If it's unused, just skip over it.
                 */
-               dup = (xfs_dir2_data_unused_t *)ptr;
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-                       ptr += be16_to_cpu(dup->length);
+                       offset += be16_to_cpu(dup->length);
                        continue;
                }
-               dep = (xfs_dir2_data_entry_t *)ptr;
+
                /*
                 * Skip .
                 */
@@ -204,24 +308,22 @@ xfs_dir2_block_to_sf(
                else if (dep->namelen == 2 &&
                         dep->name[0] == '.' && dep->name[1] == '.')
                        ASSERT(be64_to_cpu(dep->inumber) ==
-                              dp->d_ops->sf_get_parent_ino(sfp));
+                              xfs_dir2_sf_get_parent_ino(sfp));
                /*
                 * Normal entry, copy it into shortform.
                 */
                else {
                        sfep->namelen = dep->namelen;
-                       xfs_dir2_sf_put_offset(sfep,
-                               (xfs_dir2_data_aoff_t)
-                               ((char *)dep - (char *)hdr));
+                       xfs_dir2_sf_put_offset(sfep, offset);
                        memcpy(sfep->name, dep->name, dep->namelen);
-                       dp->d_ops->sf_put_ino(sfp, sfep,
+                       xfs_dir2_sf_put_ino(mp, sfp, sfep,
                                              be64_to_cpu(dep->inumber));
-                       dp->d_ops->sf_put_ftype(sfep,
-                                       dp->d_ops->data_get_ftype(dep));
+                       xfs_dir2_sf_put_ftype(mp, sfep,
+                                       xfs_dir2_data_get_ftype(mp, dep));
 
-                       sfep = dp->d_ops->sf_nextentry(sfp, sfep);
+                       sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
                }
-               ptr += dp->d_ops->data_entsize(dep->namelen);
+               offset += xfs_dir2_data_entsize(mp, dep->namelen);
        }
        ASSERT((char *)sfep - (char *)sfp == size);
 
@@ -240,7 +342,7 @@ xfs_dir2_block_to_sf(
         * Convert the inode to local format and copy the data in.
         */
        ASSERT(dp->i_df.if_bytes == 0);
-       xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size);
+       xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
        dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
        dp->i_d.di_size = size;
 
@@ -248,7 +350,7 @@ xfs_dir2_block_to_sf(
        xfs_dir2_sf_check(args);
 out:
        xfs_trans_log_inode(args->trans, dp, logflags);
-       kmem_free(dst);
+       kmem_free(sfp);
        return error;
 }
 
@@ -277,13 +379,7 @@ xfs_dir2_sf_addname(
        ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
        dp = args->dp;
        ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Make sure the shortform value has some of its header.
-        */
-       if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return -EIO;
-       }
+       ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
        ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
        ASSERT(dp->i_df.if_u1.if_data != NULL);
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -291,7 +387,7 @@ xfs_dir2_sf_addname(
        /*
         * Compute entry (and change in) size.
         */
-       incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen);
+       incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
        objchange = 0;
 
        /*
@@ -364,18 +460,17 @@ xfs_dir2_sf_addname_easy(
        xfs_dir2_data_aoff_t    offset,         /* offset to use for new ent */
        int                     new_isize)      /* new directory size */
 {
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     byteoff;        /* byte offset in sf dir */
-       xfs_inode_t             *dp;            /* incore directory inode */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
 
-       dp = args->dp;
-
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
        byteoff = (int)((char *)sfep - (char *)sfp);
        /*
         * Grow the in-inode space.
         */
-       xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen),
+       xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
                          XFS_DATA_FORK);
        /*
         * Need to set up again due to realloc of the inode data.
@@ -388,8 +483,8 @@ xfs_dir2_sf_addname_easy(
        sfep->namelen = args->namelen;
        xfs_dir2_sf_put_offset(sfep, offset);
        memcpy(sfep->name, args->name, sfep->namelen);
-       dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
-       dp->d_ops->sf_put_ftype(sfep, args->filetype);
+       xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
+       xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
 
        /*
         * Update the header and inode.
@@ -416,9 +511,10 @@ xfs_dir2_sf_addname_hard(
        int                     objchange,      /* changing inode number size */
        int                     new_isize)      /* new directory size */
 {
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     add_datasize;   /* data size need for new ent */
        char                    *buf;           /* buffer for old */
-       xfs_inode_t             *dp;            /* incore directory inode */
        int                     eof;            /* reached end of old dir */
        int                     nbytes;         /* temp for byte copies */
        xfs_dir2_data_aoff_t    new_offset;     /* next offset value */
@@ -432,8 +528,6 @@ xfs_dir2_sf_addname_hard(
        /*
         * Copy the old directory to the stack buffer.
         */
-       dp = args->dp;
-
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
        old_isize = (int)dp->i_d.di_size;
        buf = kmem_alloc(old_isize, 0);
@@ -444,13 +538,13 @@ xfs_dir2_sf_addname_hard(
         * to insert the new entry.
         * If it's going to end up at the end then oldsfep will point there.
         */
-       for (offset = dp->d_ops->data_first_offset,
+       for (offset = args->geo->data_first_offset,
              oldsfep = xfs_dir2_sf_firstentry(oldsfp),
-             add_datasize = dp->d_ops->data_entsize(args->namelen),
+             add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
              eof = (char *)oldsfep == &buf[old_isize];
             !eof;
-            offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen),
-             oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep),
+            offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
+             oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
              eof = (char *)oldsfep == &buf[old_isize]) {
                new_offset = xfs_dir2_sf_get_offset(oldsfep);
                if (offset + add_datasize <= new_offset)
@@ -479,8 +573,8 @@ xfs_dir2_sf_addname_hard(
        sfep->namelen = args->namelen;
        xfs_dir2_sf_put_offset(sfep, offset);
        memcpy(sfep->name, args->name, sfep->namelen);
-       dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
-       dp->d_ops->sf_put_ftype(sfep, args->filetype);
+       xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
+       xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
        sfp->count++;
        if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
                sfp->i8count++;
@@ -488,7 +582,7 @@ xfs_dir2_sf_addname_hard(
         * If there's more left to copy, do that.
         */
        if (!eof) {
-               sfep = dp->d_ops->sf_nextentry(sfp, sfep);
+               sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
                memcpy(sfep, oldsfep, old_isize - nbytes);
        }
        kmem_free(buf);
@@ -510,7 +604,8 @@ xfs_dir2_sf_addname_pick(
        xfs_dir2_sf_entry_t     **sfepp,        /* out(1): new entry ptr */
        xfs_dir2_data_aoff_t    *offsetp)       /* out(1): new offset */
 {
-       xfs_inode_t             *dp;            /* incore directory inode */
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     holefit;        /* found hole it will fit in */
        int                     i;              /* entry number */
        xfs_dir2_data_aoff_t    offset;         /* data block offset */
@@ -519,11 +614,9 @@ xfs_dir2_sf_addname_pick(
        int                     size;           /* entry's data size */
        int                     used;           /* data bytes used */
 
-       dp = args->dp;
-
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       size = dp->d_ops->data_entsize(args->namelen);
-       offset = dp->d_ops->data_first_offset;
+       size = xfs_dir2_data_entsize(mp, args->namelen);
+       offset = args->geo->data_first_offset;
        sfep = xfs_dir2_sf_firstentry(sfp);
        holefit = 0;
        /*
@@ -535,8 +628,8 @@ xfs_dir2_sf_addname_pick(
                if (!holefit)
                        holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
                offset = xfs_dir2_sf_get_offset(sfep) +
-                        dp->d_ops->data_entsize(sfep->namelen);
-               sfep = dp->d_ops->sf_nextentry(sfp, sfep);
+                        xfs_dir2_data_entsize(mp, sfep->namelen);
+               sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
        }
        /*
         * Calculate data bytes used excluding the new entry, if this
@@ -578,7 +671,8 @@ static void
 xfs_dir2_sf_check(
        xfs_da_args_t           *args)          /* operation arguments */
 {
-       xfs_inode_t             *dp;            /* incore directory inode */
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     i;              /* entry number */
        int                     i8count;        /* number of big inode#s */
        xfs_ino_t               ino;            /* entry inode number */
@@ -586,23 +680,21 @@ xfs_dir2_sf_check(
        xfs_dir2_sf_entry_t     *sfep;          /* shortform dir entry */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
 
-       dp = args->dp;
-
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       offset = dp->d_ops->data_first_offset;
-       ino = dp->d_ops->sf_get_parent_ino(sfp);
+       offset = args->geo->data_first_offset;
+       ino = xfs_dir2_sf_get_parent_ino(sfp);
        i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
 
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
             i < sfp->count;
-            i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
+            i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
                ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
-               ino = dp->d_ops->sf_get_ino(sfp, sfep);
+               ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
                i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
                offset =
                        xfs_dir2_sf_get_offset(sfep) +
-                       dp->d_ops->data_entsize(sfep->namelen);
-               ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX);
+                       xfs_dir2_data_entsize(mp, sfep->namelen);
+               ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
        }
        ASSERT(i8count == sfp->i8count);
        ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
@@ -622,22 +714,16 @@ xfs_dir2_sf_verify(
        struct xfs_dir2_sf_entry        *sfep;
        struct xfs_dir2_sf_entry        *next_sfep;
        char                            *endp;
-       const struct xfs_dir_ops        *dops;
        struct xfs_ifork                *ifp;
        xfs_ino_t                       ino;
        int                             i;
        int                             i8count;
        int                             offset;
-       int                             size;
+       int64_t                         size;
        int                             error;
        uint8_t                         filetype;
 
        ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
-       /*
-        * xfs_iread calls us before xfs_setup_inode sets up ip->d_ops,
-        * so we can only trust the mountpoint to have the right pointer.
-        */
-       dops = xfs_dir_get_ops(mp, NULL);
 
        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
        sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
@@ -653,12 +739,12 @@ xfs_dir2_sf_verify(
        endp = (char *)sfp + size;
 
        /* Check .. entry */
-       ino = dops->sf_get_parent_ino(sfp);
+       ino = xfs_dir2_sf_get_parent_ino(sfp);
        i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
        error = xfs_dir_ino_validate(mp, ino);
        if (error)
                return __this_address;
-       offset = dops->data_first_offset;
+       offset = mp->m_dir_geo->data_first_offset;
 
        /* Check all reported entries */
        sfep = xfs_dir2_sf_firstentry(sfp);
@@ -680,7 +766,7 @@ xfs_dir2_sf_verify(
                 * within the data buffer.  The next entry starts after the
                 * name component, so nextentry is an acceptable test.
                 */
-               next_sfep = dops->sf_nextentry(sfp, sfep);
+               next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
                if (endp < (char *)next_sfep)
                        return __this_address;
 
@@ -689,19 +775,19 @@ xfs_dir2_sf_verify(
                        return __this_address;
 
                /* Check the inode number. */
-               ino = dops->sf_get_ino(sfp, sfep);
+               ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
                i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
                error = xfs_dir_ino_validate(mp, ino);
                if (error)
                        return __this_address;
 
                /* Check the file type. */
-               filetype = dops->sf_get_ftype(sfep);
+               filetype = xfs_dir2_sf_get_ftype(mp, sfep);
                if (filetype >= XFS_DIR3_FT_MAX)
                        return __this_address;
 
                offset = xfs_dir2_sf_get_offset(sfep) +
-                               dops->data_entsize(sfep->namelen);
+                               xfs_dir2_data_entsize(mp, sfep->namelen);
 
                sfep = next_sfep;
        }
@@ -763,7 +849,7 @@ xfs_dir2_sf_create(
        /*
         * Now can put in the inode number, since i8count is set.
         */
-       dp->d_ops->sf_put_parent_ino(sfp, pino);
+       xfs_dir2_sf_put_parent_ino(sfp, pino);
        sfp->count = 0;
        dp->i_d.di_size = size;
        xfs_dir2_sf_check(args);
@@ -779,7 +865,8 @@ int                                         /* error */
 xfs_dir2_sf_lookup(
        xfs_da_args_t           *args)          /* operation arguments */
 {
-       xfs_inode_t             *dp;            /* incore directory inode */
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     i;              /* entry index */
        int                     error;
        xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
@@ -790,16 +877,9 @@ xfs_dir2_sf_lookup(
        trace_xfs_dir2_sf_lookup(args);
 
        xfs_dir2_sf_check(args);
-       dp = args->dp;
 
        ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Bail out if the directory is way too short.
-        */
-       if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return -EIO;
-       }
+       ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
        ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
        ASSERT(dp->i_df.if_u1.if_data != NULL);
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -818,7 +898,7 @@ xfs_dir2_sf_lookup(
         */
        if (args->namelen == 2 &&
            args->name[0] == '.' && args->name[1] == '.') {
-               args->inumber = dp->d_ops->sf_get_parent_ino(sfp);
+               args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
                args->cmpresult = XFS_CMP_EXACT;
                args->filetype = XFS_DIR3_FT_DIR;
                return -EEXIST;
@@ -828,18 +908,17 @@ xfs_dir2_sf_lookup(
         */
        ci_sfep = NULL;
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
-            i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
+            i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
                /*
                 * Compare name and if it's an exact match, return the inode
                 * number. If it's the first case-insensitive match, store the
                 * inode number and continue looking for an exact match.
                 */
-               cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
-                                                               sfep->namelen);
+               cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
                if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
                        args->cmpresult = cmp;
-                       args->inumber = dp->d_ops->sf_get_ino(sfp, sfep);
-                       args->filetype = dp->d_ops->sf_get_ftype(sfep);
+                       args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
+                       args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
                        if (cmp == XFS_CMP_EXACT)
                                return -EEXIST;
                        ci_sfep = sfep;
@@ -864,8 +943,9 @@ int                                         /* error */
 xfs_dir2_sf_removename(
        xfs_da_args_t           *args)
 {
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     byteoff;        /* offset of removed entry */
-       xfs_inode_t             *dp;            /* incore directory inode */
        int                     entsize;        /* this entry's size */
        int                     i;              /* shortform entry index */
        int                     newsize;        /* new inode size */
@@ -875,17 +955,9 @@ xfs_dir2_sf_removename(
 
        trace_xfs_dir2_sf_removename(args);
 
-       dp = args->dp;
-
        ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
        oldsize = (int)dp->i_d.di_size;
-       /*
-        * Bail out if the directory is way too short.
-        */
-       if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return -EIO;
-       }
+       ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
        ASSERT(dp->i_df.if_bytes == oldsize);
        ASSERT(dp->i_df.if_u1.if_data != NULL);
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -895,10 +967,10 @@ xfs_dir2_sf_removename(
         * Find the one we're deleting.
         */
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
-            i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
+            i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
                if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
                                                                XFS_CMP_EXACT) {
-                       ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
+                       ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
                               args->inumber);
                        break;
                }
@@ -912,7 +984,7 @@ xfs_dir2_sf_removename(
         * Calculate sizes.
         */
        byteoff = (int)((char *)sfep - (char *)sfp);
-       entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
+       entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
        newsize = oldsize - entsize;
        /*
         * Copy the part if any after the removed entry, sliding it down.
@@ -944,6 +1016,27 @@ xfs_dir2_sf_removename(
        return 0;
 }
 
+/*
+ * Check whether the sf dir replace operation need more blocks.
+ */
+bool
+xfs_dir2_sf_replace_needblock(
+       struct xfs_inode        *dp,
+       xfs_ino_t               inum)
+{
+       int                     newsize;
+       struct xfs_dir2_sf_hdr  *sfp;
+
+       if (dp->i_d.di_format != XFS_DINODE_FMT_LOCAL)
+               return false;
+
+       sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
+       newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
+
+       return inum > XFS_DIR2_MAX_SHORT_INUM &&
+              sfp->i8count == 0 && newsize > XFS_IFORK_DSIZE(dp);
+}
+
 /*
  * Replace the inode number of an entry in a shortform directory.
  */
@@ -951,7 +1044,8 @@ int                                                /* error */
 xfs_dir2_sf_replace(
        xfs_da_args_t           *args)          /* operation arguments */
 {
-       xfs_inode_t             *dp;            /* incore directory inode */
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        int                     i;              /* entry index */
        xfs_ino_t               ino=0;          /* entry old inode number */
        int                     i8elevated;     /* sf_toino8 set i8count=1 */
@@ -960,16 +1054,8 @@ xfs_dir2_sf_replace(
 
        trace_xfs_dir2_sf_replace(args);
 
-       dp = args->dp;
-
        ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Bail out if the shortform directory is way too small.
-        */
-       if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return -EIO;
-       }
+       ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
        ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
        ASSERT(dp->i_df.if_u1.if_data != NULL);
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -980,17 +1066,14 @@ xfs_dir2_sf_replace(
         */
        if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
                int     error;                  /* error return value */
-               int     newsize;                /* new inode size */
 
-               newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
                /*
                 * Won't fit as shortform, convert to block then do replace.
                 */
-               if (newsize > XFS_IFORK_DSIZE(dp)) {
+               if (xfs_dir2_sf_replace_needblock(dp, args->inumber)) {
                        error = xfs_dir2_sf_to_block(args);
-                       if (error) {
+                       if (error)
                                return error;
-                       }
                        return xfs_dir2_block_replace(args);
                }
                /*
@@ -1008,22 +1091,23 @@ xfs_dir2_sf_replace(
         */
        if (args->namelen == 2 &&
            args->name[0] == '.' && args->name[1] == '.') {
-               ino = dp->d_ops->sf_get_parent_ino(sfp);
+               ino = xfs_dir2_sf_get_parent_ino(sfp);
                ASSERT(args->inumber != ino);
-               dp->d_ops->sf_put_parent_ino(sfp, args->inumber);
+               xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
        }
        /*
         * Normal entry, look for the name.
         */
        else {
                for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
-                    i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
+                    i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
                        if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
                                                                XFS_CMP_EXACT) {
-                               ino = dp->d_ops->sf_get_ino(sfp, sfep);
+                               ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
                                ASSERT(args->inumber != ino);
-                               dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
-                               dp->d_ops->sf_put_ftype(sfep, args->filetype);
+                               xfs_dir2_sf_put_ino(mp, sfp, sfep,
+                                               args->inumber);
+                               xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
                                break;
                        }
                }
@@ -1076,8 +1160,9 @@ static void
 xfs_dir2_sf_toino4(
        xfs_da_args_t           *args)          /* operation arguments */
 {
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        char                    *buf;           /* old dir's buffer */
-       xfs_inode_t             *dp;            /* incore directory inode */
        int                     i;              /* entry index */
        int                     newsize;        /* new inode size */
        xfs_dir2_sf_entry_t     *oldsfep;       /* old sf entry */
@@ -1088,8 +1173,6 @@ xfs_dir2_sf_toino4(
 
        trace_xfs_dir2_sf_toino4(args);
 
-       dp = args->dp;
-
        /*
         * Copy the old directory to the buffer.
         * Then nuke it from the inode, and add the new buffer to the inode.
@@ -1116,21 +1199,22 @@ xfs_dir2_sf_toino4(
         */
        sfp->count = oldsfp->count;
        sfp->i8count = 0;
-       dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp));
+       xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
        /*
         * Copy the entries field by field.
         */
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
                    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
             i < sfp->count;
-            i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
-                 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
+            i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
+                 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
                sfep->namelen = oldsfep->namelen;
                memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
                memcpy(sfep->name, oldsfep->name, sfep->namelen);
-               dp->d_ops->sf_put_ino(sfp, sfep,
-                                     dp->d_ops->sf_get_ino(oldsfp, oldsfep));
-               dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep));
+               xfs_dir2_sf_put_ino(mp, sfp, sfep,
+                               xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
+               xfs_dir2_sf_put_ftype(mp, sfep,
+                               xfs_dir2_sf_get_ftype(mp, oldsfep));
        }
        /*
         * Clean up the inode.
@@ -1149,8 +1233,9 @@ static void
 xfs_dir2_sf_toino8(
        xfs_da_args_t           *args)          /* operation arguments */
 {
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        char                    *buf;           /* old dir's buffer */
-       xfs_inode_t             *dp;            /* incore directory inode */
        int                     i;              /* entry index */
        int                     newsize;        /* new inode size */
        xfs_dir2_sf_entry_t     *oldsfep;       /* old sf entry */
@@ -1161,8 +1246,6 @@ xfs_dir2_sf_toino8(
 
        trace_xfs_dir2_sf_toino8(args);
 
-       dp = args->dp;
-
        /*
         * Copy the old directory to the buffer.
         * Then nuke it from the inode, and add the new buffer to the inode.
@@ -1189,21 +1272,22 @@ xfs_dir2_sf_toino8(
         */
        sfp->count = oldsfp->count;
        sfp->i8count = 1;
-       dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp));
+       xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
        /*
         * Copy the entries field by field.
         */
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
                    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
             i < sfp->count;
-            i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
-                 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
+            i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
+                 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
                sfep->namelen = oldsfep->namelen;
                memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
                memcpy(sfep->name, oldsfep->name, sfep->namelen);
-               dp->d_ops->sf_put_ino(sfp, sfep,
-                                     dp->d_ops->sf_get_ino(oldsfp, oldsfep));
-               dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep));
+               xfs_dir2_sf_put_ino(mp, sfp, sfep,
+                               xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
+               xfs_dir2_sf_put_ftype(mp, sfep,
+                               xfs_dir2_sf_get_ftype(mp, oldsfep));
        }
        /*
         * Clean up the inode.
index e8bd688..bedc1e7 100644 (file)
@@ -35,10 +35,10 @@ xfs_calc_dquots_per_chunk(
 
 xfs_failaddr_t
 xfs_dquot_verify(
-       struct xfs_mount *mp,
-       xfs_disk_dquot_t *ddq,
-       xfs_dqid_t       id,
-       uint             type)    /* used only during quotacheck */
+       struct xfs_mount        *mp,
+       struct xfs_disk_dquot   *ddq,
+       xfs_dqid_t              id,
+       uint                    type)   /* used only during quotacheck */
 {
        /*
         * We can encounter an uninitialized dquot buffer for 2 reasons:
index c968b60..1b7dcba 100644 (file)
@@ -920,13 +920,13 @@ static inline uint xfs_dinode_size(int version)
  * This enum is used in string mapping in xfs_trace.h; please keep the
  * TRACE_DEFINE_ENUMs for it up to date.
  */
-typedef enum xfs_dinode_fmt {
+enum xfs_dinode_fmt {
        XFS_DINODE_FMT_DEV,             /* xfs_dev_t */
        XFS_DINODE_FMT_LOCAL,           /* bulk data */
        XFS_DINODE_FMT_EXTENTS,         /* struct xfs_bmbt_rec */
        XFS_DINODE_FMT_BTREE,           /* struct xfs_bmdr_block */
        XFS_DINODE_FMT_UUID             /* added long ago, but never used */
-} xfs_dinode_fmt_t;
+};
 
 #define XFS_INODE_FORMAT_STR \
        { XFS_DINODE_FMT_DEV,           "dev" }, \
@@ -1144,11 +1144,11 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 
 /*
  * This is the main portion of the on-disk representation of quota
- * information for a user. This is the q_core of the xfs_dquot_t that
+ * information for a user. This is the q_core of the struct xfs_dquot that
  * is kept in kernel memory. We pad this with some more expansion room
  * to construct the on disk structure.
  */
-typedef struct xfs_disk_dquot {
+struct xfs_disk_dquot {
        __be16          d_magic;        /* dquot magic = XFS_DQUOT_MAGIC */
        __u8            d_version;      /* dquot version */
        __u8            d_flags;        /* XFS_DQ_USER/PROJ/GROUP */
@@ -1171,15 +1171,15 @@ typedef struct  xfs_disk_dquot {
        __be32          d_rtbtimer;     /* similar to above; for RT disk blocks */
        __be16          d_rtbwarns;     /* warnings issued wrt RT disk blocks */
        __be16          d_pad;
-} xfs_disk_dquot_t;
+};
 
 /*
  * This is what goes on disk. This is separated from the xfs_disk_dquot because
  * carrying the unnecessary padding would be a waste of memory.
  */
 typedef struct xfs_dqblk {
-       xfs_disk_dquot_t  dd_diskdq;    /* portion that lives incore as well */
-       char              dd_fill[4];   /* filling for posterity */
+       struct xfs_disk_dquot   dd_diskdq; /* portion living incore as well */
+       char                    dd_fill[4];/* filling for posterity */
 
        /*
         * These two are only present on filesystems with the CRC bits set.
index e9371a8..ef95ca0 100644 (file)
@@ -324,7 +324,7 @@ typedef struct xfs_growfs_rt {
  * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
  */
 typedef struct xfs_bstime {
-       time_t          tv_sec;         /* seconds              */
+       __kernel_long_t tv_sec;         /* seconds              */
        __s32           tv_nsec;        /* and nanoseconds      */
 } xfs_bstime_t;
 
@@ -416,7 +416,7 @@ struct xfs_bulkstat {
 
 /*
  * Project quota id helpers (previously projid was 16bit only
- * and using two 16bit values to hold new 32bit projid was choosen
+ * and using two 16bit values to hold new 32bit projid was chosen
  * to retain compatibility with "old" filesystems).
  */
 static inline uint32_t
index 588d446..988cde7 100644 (file)
@@ -544,7 +544,10 @@ xfs_inobt_insert_sprec(
                                             nrec->ir_free, &i);
                if (error)
                        goto error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
 
                goto out;
        }
@@ -557,17 +560,23 @@ xfs_inobt_insert_sprec(
                error = xfs_inobt_get_rec(cur, &rec, &i);
                if (error)
                        goto error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error);
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                                       rec.ir_startino == nrec->ir_startino,
-                                       error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
+               if (XFS_IS_CORRUPT(mp, rec.ir_startino != nrec->ir_startino)) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
 
                /*
                 * This should never fail. If we have coexisting records that
                 * cannot merge, something is seriously wrong.
                 */
-               XFS_WANT_CORRUPTED_GOTO(mp, __xfs_inobt_can_merge(nrec, &rec),
-                                       error);
+               if (XFS_IS_CORRUPT(mp, !__xfs_inobt_can_merge(nrec, &rec))) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
 
                trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino,
                                         rec.ir_holemask, nrec->ir_startino,
@@ -1057,7 +1066,8 @@ xfs_ialloc_next_rec(
                error = xfs_inobt_get_rec(cur, rec, &i);
                if (error)
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+                       return -EFSCORRUPTED;
        }
 
        return 0;
@@ -1081,7 +1091,8 @@ xfs_ialloc_get_rec(
                error = xfs_inobt_get_rec(cur, rec, &i);
                if (error)
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+                       return -EFSCORRUPTED;
        }
 
        return 0;
@@ -1161,12 +1172,18 @@ xfs_dialloc_ag_inobt(
                error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                error = xfs_inobt_get_rec(cur, &rec, &j);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, j == 1, error0);
+               if (XFS_IS_CORRUPT(mp, j != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
 
                if (rec.ir_freecount > 0) {
                        /*
@@ -1321,19 +1338,28 @@ xfs_dialloc_ag_inobt(
        error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
        if (error)
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
 
        for (;;) {
                error = xfs_inobt_get_rec(cur, &rec, &i);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
                if (rec.ir_freecount > 0)
                        break;
                error = xfs_btree_increment(cur, 0, &i);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error0;
+               }
        }
 
 alloc_inode:
@@ -1393,7 +1419,8 @@ xfs_dialloc_ag_finobt_near(
                error = xfs_inobt_get_rec(lcur, rec, &i);
                if (error)
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(lcur->bc_mp, i == 1);
+               if (XFS_IS_CORRUPT(lcur->bc_mp, i != 1))
+                       return -EFSCORRUPTED;
 
                /*
                 * See if we've landed in the parent inode record. The finobt
@@ -1416,10 +1443,16 @@ xfs_dialloc_ag_finobt_near(
                error = xfs_inobt_get_rec(rcur, &rrec, &j);
                if (error)
                        goto error_rcur;
-               XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, j == 1, error_rcur);
+               if (XFS_IS_CORRUPT(lcur->bc_mp, j != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error_rcur;
+               }
        }
 
-       XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, i == 1 || j == 1, error_rcur);
+       if (XFS_IS_CORRUPT(lcur->bc_mp, i != 1 && j != 1)) {
+               error = -EFSCORRUPTED;
+               goto error_rcur;
+       }
        if (i == 1 && j == 1) {
                /*
                 * Both the left and right records are valid. Choose the closer
@@ -1472,7 +1505,8 @@ xfs_dialloc_ag_finobt_newino(
                        error = xfs_inobt_get_rec(cur, rec, &i);
                        if (error)
                                return error;
-                       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+                       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+                               return -EFSCORRUPTED;
                        return 0;
                }
        }
@@ -1483,12 +1517,14 @@ xfs_dialloc_ag_finobt_newino(
        error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+               return -EFSCORRUPTED;
 
        error = xfs_inobt_get_rec(cur, rec, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+               return -EFSCORRUPTED;
 
        return 0;
 }
@@ -1510,20 +1546,24 @@ xfs_dialloc_ag_update_inobt(
        error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+               return -EFSCORRUPTED;
 
        error = xfs_inobt_get_rec(cur, &rec, &i);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
+       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1))
+               return -EFSCORRUPTED;
        ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) %
                                   XFS_INODES_PER_CHUNK) == 0);
 
        rec.ir_free &= ~XFS_INOBT_MASK(offset);
        rec.ir_freecount--;
 
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, (rec.ir_free == frec->ir_free) &&
-                                 (rec.ir_freecount == frec->ir_freecount));
+       if (XFS_IS_CORRUPT(cur->bc_mp,
+                          rec.ir_free != frec->ir_free ||
+                          rec.ir_freecount != frec->ir_freecount))
+               return -EFSCORRUPTED;
 
        return xfs_inobt_update(cur, &rec);
 }
@@ -1933,14 +1973,20 @@ xfs_difree_inobt(
                        __func__, error);
                goto error0;
        }
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        error = xfs_inobt_get_rec(cur, &rec, &i);
        if (error) {
                xfs_warn(mp, "%s: xfs_inobt_get_rec() returned error %d.",
                        __func__, error);
                goto error0;
        }
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error0;
+       }
        /*
         * Get the offset in the inode chunk.
         */
@@ -2052,7 +2098,10 @@ xfs_difree_finobt(
                 * freed an inode in a previously fully allocated chunk. If not,
                 * something is out of sync.
                 */
-               XFS_WANT_CORRUPTED_GOTO(mp, ibtrec->ir_freecount == 1, error);
+               if (XFS_IS_CORRUPT(mp, ibtrec->ir_freecount != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
 
                error = xfs_inobt_insert_rec(cur, ibtrec->ir_holemask,
                                             ibtrec->ir_count,
@@ -2075,14 +2124,20 @@ xfs_difree_finobt(
        error = xfs_inobt_get_rec(cur, &rec, &i);
        if (error)
                goto error;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto error;
+       }
 
        rec.ir_free |= XFS_INOBT_MASK(offset);
        rec.ir_freecount++;
 
-       XFS_WANT_CORRUPTED_GOTO(mp, (rec.ir_free == ibtrec->ir_free) &&
-                               (rec.ir_freecount == ibtrec->ir_freecount),
-                               error);
+       if (XFS_IS_CORRUPT(mp,
+                          rec.ir_free != ibtrec->ir_free ||
+                          rec.ir_freecount != ibtrec->ir_freecount)) {
+               error = -EFSCORRUPTED;
+               goto error;
+       }
 
        /*
         * The content of inobt records should always match between the inobt
index 7bc8740..5245180 100644 (file)
@@ -596,7 +596,7 @@ xfs_iext_realloc_root(
        struct xfs_ifork        *ifp,
        struct xfs_iext_cursor  *cur)
 {
-       size_t new_size = ifp->if_bytes + sizeof(struct xfs_iext_rec);
+       int64_t new_size = ifp->if_bytes + sizeof(struct xfs_iext_rec);
        void *new;
 
        /* account for the prev/next pointers */
index 28ab3c5..8afacfe 100644 (file)
@@ -213,13 +213,12 @@ xfs_inode_from_disk(
        to->di_version = from->di_version;
        if (to->di_version == 1) {
                set_nlink(inode, be16_to_cpu(from->di_onlink));
-               to->di_projid_lo = 0;
-               to->di_projid_hi = 0;
+               to->di_projid = 0;
                to->di_version = 2;
        } else {
                set_nlink(inode, be32_to_cpu(from->di_nlink));
-               to->di_projid_lo = be16_to_cpu(from->di_projid_lo);
-               to->di_projid_hi = be16_to_cpu(from->di_projid_hi);
+               to->di_projid = (prid_t)be16_to_cpu(from->di_projid_hi) << 16 |
+                                       be16_to_cpu(from->di_projid_lo);
        }
 
        to->di_format = from->di_format;
@@ -256,8 +255,8 @@ xfs_inode_from_disk(
        if (to->di_version == 3) {
                inode_set_iversion_queried(inode,
                                           be64_to_cpu(from->di_changecount));
-               to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec);
-               to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec);
+               to->di_crtime.tv_sec = be32_to_cpu(from->di_crtime.t_sec);
+               to->di_crtime.tv_nsec = be32_to_cpu(from->di_crtime.t_nsec);
                to->di_flags2 = be64_to_cpu(from->di_flags2);
                to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
        }
@@ -279,8 +278,8 @@ xfs_inode_to_disk(
        to->di_format = from->di_format;
        to->di_uid = cpu_to_be32(from->di_uid);
        to->di_gid = cpu_to_be32(from->di_gid);
-       to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
-       to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
+       to->di_projid_lo = cpu_to_be16(from->di_projid & 0xffff);
+       to->di_projid_hi = cpu_to_be16(from->di_projid >> 16);
 
        memset(to->di_pad, 0, sizeof(to->di_pad));
        to->di_atime.t_sec = cpu_to_be32(inode->i_atime.tv_sec);
@@ -306,8 +305,8 @@ xfs_inode_to_disk(
 
        if (from->di_version == 3) {
                to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
-               to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
-               to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
+               to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.tv_sec);
+               to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.tv_nsec);
                to->di_flags2 = cpu_to_be64(from->di_flags2);
                to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
                to->di_ino = cpu_to_be64(ip->i_ino);
@@ -632,8 +631,6 @@ xfs_iread(
        if ((iget_flags & XFS_IGET_CREATE) &&
            xfs_sb_version_hascrc(&mp->m_sb) &&
            !(mp->m_flags & XFS_MOUNT_IKEEP)) {
-               /* initialise the on-disk inode core */
-               memset(&ip->i_d, 0, sizeof(ip->i_d));
                VFS_I(ip)->i_generation = prandom_u32();
                ip->i_d.di_version = 3;
                return 0;
index ab0f841..fd94b10 100644 (file)
@@ -21,8 +21,7 @@ struct xfs_icdinode {
        uint16_t        di_flushiter;   /* incremented on flush */
        uint32_t        di_uid;         /* owner's user id */
        uint32_t        di_gid;         /* owner's group id */
-       uint16_t        di_projid_lo;   /* lower part of owner's project id */
-       uint16_t        di_projid_hi;   /* higher part of owner's project id */
+       uint32_t        di_projid;      /* owner's project id */
        xfs_fsize_t     di_size;        /* number of bytes in file */
        xfs_rfsblock_t  di_nblocks;     /* # of direct & btree blocks used */
        xfs_extlen_t    di_extsize;     /* basic/minimum extent size for file */
@@ -37,7 +36,7 @@ struct xfs_icdinode {
        uint64_t        di_flags2;      /* more random flags */
        uint32_t        di_cowextsize;  /* basic cow extent size for file */
 
-       xfs_ictimestamp_t di_crtime;    /* time created */
+       struct timespec64 di_crtime;    /* time created */
 };
 
 /*
index c643bee..ad2b9c3 100644 (file)
@@ -75,11 +75,15 @@ xfs_iformat_fork(
                        error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
                        break;
                default:
+                       xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
+                                       dip, sizeof(*dip), __this_address);
                        return -EFSCORRUPTED;
                }
                break;
 
        default:
+               xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
+                               sizeof(*dip), __this_address);
                return -EFSCORRUPTED;
        }
        if (error)
@@ -110,14 +114,16 @@ xfs_iformat_fork(
                error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
                break;
        default:
+               xfs_inode_verifier_error(ip, error, __func__, dip,
+                               sizeof(*dip), __this_address);
                error = -EFSCORRUPTED;
                break;
        }
        if (error) {
-               kmem_zone_free(xfs_ifork_zone, ip->i_afp);
+               kmem_cache_free(xfs_ifork_zone, ip->i_afp);
                ip->i_afp = NULL;
                if (ip->i_cowfp)
-                       kmem_zone_free(xfs_ifork_zone, ip->i_cowfp);
+                       kmem_cache_free(xfs_ifork_zone, ip->i_cowfp);
                ip->i_cowfp = NULL;
                xfs_idestroy_fork(ip, XFS_DATA_FORK);
        }
@@ -129,7 +135,7 @@ xfs_init_local_fork(
        struct xfs_inode        *ip,
        int                     whichfork,
        const void              *data,
-       int                     size)
+       int64_t                 size)
 {
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
        int                     mem_size = size, real_size = 0;
@@ -467,11 +473,11 @@ xfs_iroot_realloc(
 void
 xfs_idata_realloc(
        struct xfs_inode        *ip,
-       int                     byte_diff,
+       int64_t                 byte_diff,
        int                     whichfork)
 {
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
-       int                     new_size = (int)ifp->if_bytes + byte_diff;
+       int64_t                 new_size = ifp->if_bytes + byte_diff;
 
        ASSERT(new_size >= 0);
        ASSERT(new_size <= XFS_IFORK_SIZE(ip, whichfork));
@@ -525,10 +531,10 @@ xfs_idestroy_fork(
        }
 
        if (whichfork == XFS_ATTR_FORK) {
-               kmem_zone_free(xfs_ifork_zone, ip->i_afp);
+               kmem_cache_free(xfs_ifork_zone, ip->i_afp);
                ip->i_afp = NULL;
        } else if (whichfork == XFS_COW_FORK) {
-               kmem_zone_free(xfs_ifork_zone, ip->i_cowfp);
+               kmem_cache_free(xfs_ifork_zone, ip->i_cowfp);
                ip->i_cowfp = NULL;
        }
 }
@@ -552,7 +558,7 @@ xfs_iextents_copy(
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
        struct xfs_iext_cursor  icur;
        struct xfs_bmbt_irec    rec;
-       int                     copied = 0;
+       int64_t                 copied = 0;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
        ASSERT(ifp->if_bytes > 0);
index 00c62ce..500333d 100644 (file)
@@ -13,16 +13,16 @@ struct xfs_dinode;
  * File incore extent information, present for each of data & attr forks.
  */
 struct xfs_ifork {
-       int                     if_bytes;       /* bytes in if_u1 */
-       unsigned int            if_seq;         /* fork mod counter */
+       int64_t                 if_bytes;       /* bytes in if_u1 */
        struct xfs_btree_block  *if_broot;      /* file's incore btree root */
-       short                   if_broot_bytes; /* bytes allocated for root */
-       unsigned char           if_flags;       /* per-fork flags */
+       unsigned int            if_seq;         /* fork mod counter */
        int                     if_height;      /* height of the extent tree */
        union {
                void            *if_root;       /* extent tree root */
                char            *if_data;       /* inline file data */
        } if_u1;
+       short                   if_broot_bytes; /* bytes allocated for root */
+       unsigned char           if_flags;       /* per-fork flags */
 };
 
 /*
@@ -87,18 +87,24 @@ struct xfs_ifork {
 #define XFS_IFORK_MAXEXT(ip, w) \
        (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t))
 
+#define xfs_ifork_has_extents(ip, w) \
+       (XFS_IFORK_FORMAT((ip), (w)) == XFS_DINODE_FMT_EXTENTS || \
+        XFS_IFORK_FORMAT((ip), (w)) == XFS_DINODE_FMT_BTREE)
+
 struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state);
 
 int            xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *);
 void           xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *,
                                struct xfs_inode_log_item *, int);
 void           xfs_idestroy_fork(struct xfs_inode *, int);
-void           xfs_idata_realloc(struct xfs_inode *, int, int);
+void           xfs_idata_realloc(struct xfs_inode *ip, int64_t byte_diff,
+                               int whichfork);
 void           xfs_iroot_realloc(struct xfs_inode *, int, int);
 int            xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
 int            xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
                                  int);
-void           xfs_init_local_fork(struct xfs_inode *, int, const void *, int);
+void           xfs_init_local_fork(struct xfs_inode *ip, int whichfork,
+                               const void *data, int64_t size);
 
 xfs_extnum_t   xfs_iext_count(struct xfs_ifork *ifp);
 void           xfs_iext_insert(struct xfs_inode *, struct xfs_iext_cursor *cur,
index e5f97c6..8ef31d7 100644 (file)
@@ -432,9 +432,9 @@ static inline uint xfs_log_dinode_size(int version)
 }
 
 /*
- * Buffer Log Format defintions
+ * Buffer Log Format definitions
  *
- * These are the physical dirty bitmap defintions for the log format structure.
+ * These are the physical dirty bitmap definitions for the log format structure.
  */
 #define        XFS_BLF_CHUNK           128
 #define        XFS_BLF_SHIFT           7
index f3d18ea..3bf6716 100644 (file)
@@ -30,14 +30,14 @@ typedef struct xlog_recover_item {
        xfs_log_iovec_t         *ri_buf;        /* ptr to regions buffer */
 } xlog_recover_item_t;
 
-typedef struct xlog_recover {
+struct xlog_recover {
        struct hlist_node       r_list;
        xlog_tid_t              r_log_tid;      /* log's transaction id */
        xfs_trans_header_t      r_theader;      /* trans header for partial */
        int                     r_state;        /* not needed */
        xfs_lsn_t               r_lsn;          /* xact lsn */
        struct list_head        r_itemq;        /* q for items */
-} xlog_recover_t;
+};
 
 #define ITEM_TYPE(i)   (*(unsigned short *)(i)->ri_buf[0].i_addr)
 
index 9a7fadb..d7d702e 100644 (file)
@@ -200,7 +200,10 @@ xfs_refcount_insert(
        error = xfs_btree_insert(cur, i);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
 out_error:
        if (error)
@@ -227,10 +230,16 @@ xfs_refcount_delete(
        error = xfs_refcount_get_rec(cur, &irec, &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
        trace_xfs_refcount_delete(cur->bc_mp, cur->bc_private.a.agno, &irec);
        error = xfs_btree_delete(cur, i);
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
        if (error)
                goto out_error;
        error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec);
@@ -349,7 +358,10 @@ xfs_refcount_split_extent(
        error = xfs_refcount_get_rec(cur, &rcext, &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
        if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno)
                return 0;
 
@@ -371,7 +383,10 @@ xfs_refcount_split_extent(
        error = xfs_refcount_insert(cur, &tmp, &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
        return error;
 
 out_error:
@@ -410,19 +425,27 @@ xfs_refcount_merge_center_extents(
                        &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        error = xfs_refcount_delete(cur, &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        if (center->rc_refcount > 1) {
                error = xfs_refcount_delete(cur, &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
        }
 
        /* Enlarge the left extent. */
@@ -430,7 +453,10 @@ xfs_refcount_merge_center_extents(
                        &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        left->rc_blockcount = extlen;
        error = xfs_refcount_update(cur, left);
@@ -469,14 +495,18 @@ xfs_refcount_merge_left_extent(
                                &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                error = xfs_refcount_delete(cur, &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
        }
 
        /* Enlarge the left extent. */
@@ -484,7 +514,10 @@ xfs_refcount_merge_left_extent(
                        &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        left->rc_blockcount += cleft->rc_blockcount;
        error = xfs_refcount_update(cur, left);
@@ -526,14 +559,18 @@ xfs_refcount_merge_right_extent(
                        &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                error = xfs_refcount_delete(cur, &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
        }
 
        /* Enlarge the right extent. */
@@ -541,7 +578,10 @@ xfs_refcount_merge_right_extent(
                        &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        right->rc_startblock -= cright->rc_blockcount;
        right->rc_blockcount += cright->rc_blockcount;
@@ -587,7 +627,10 @@ xfs_refcount_find_left_extents(
        error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        if (xfs_refc_next(&tmp) != agbno)
                return 0;
@@ -605,8 +648,10 @@ xfs_refcount_find_left_extents(
                error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                /* if tmp starts at the end of our range, just use that */
                if (tmp.rc_startblock == agbno)
@@ -671,7 +716,10 @@ xfs_refcount_find_right_extents(
        error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        if (tmp.rc_startblock != agbno + aglen)
                return 0;
@@ -689,8 +737,10 @@ xfs_refcount_find_right_extents(
                error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
-                               out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                /* if tmp ends at the end of our range, just use that */
                if (xfs_refc_next(&tmp) == agbno + aglen)
@@ -913,8 +963,11 @@ xfs_refcount_adjust_extents(
                                                &found_tmp);
                                if (error)
                                        goto out_error;
-                               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                                               found_tmp == 1, out_error);
+                               if (XFS_IS_CORRUPT(cur->bc_mp,
+                                                  found_tmp != 1)) {
+                                       error = -EFSCORRUPTED;
+                                       goto out_error;
+                               }
                                cur->bc_private.a.priv.refc.nr_ops++;
                        } else {
                                fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
@@ -955,8 +1008,10 @@ xfs_refcount_adjust_extents(
                        error = xfs_refcount_delete(cur, &found_rec);
                        if (error)
                                goto out_error;
-                       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                                       found_rec == 1, out_error);
+                       if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto out_error;
+                       }
                        cur->bc_private.a.priv.refc.nr_ops++;
                        goto advloop;
                } else {
@@ -1122,7 +1177,7 @@ xfs_refcount_finish_one(
                                XFS_ALLOC_FLAG_FREEING, &agbp);
                if (error)
                        return error;
-               if (!agbp)
+               if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
                        return -EFSCORRUPTED;
 
                rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
@@ -1272,7 +1327,10 @@ xfs_refcount_find_shared(
        error = xfs_refcount_get_rec(cur, &tmp, &i);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error);
+       if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        /* If the extent ends before the start, look at the next one */
        if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) {
@@ -1284,7 +1342,10 @@ xfs_refcount_find_shared(
                error = xfs_refcount_get_rec(cur, &tmp, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
        }
 
        /* If the extent starts after the range we want, bail out */
@@ -1312,7 +1373,10 @@ xfs_refcount_find_shared(
                error = xfs_refcount_get_rec(cur, &tmp, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                if (tmp.rc_startblock >= agbno + aglen ||
                    tmp.rc_startblock != *fbno + *flen)
                        break;
@@ -1413,8 +1477,11 @@ xfs_refcount_adjust_cow_extents(
        switch (adj) {
        case XFS_REFCOUNT_ADJUST_COW_ALLOC:
                /* Adding a CoW reservation, there should be nothing here. */
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                               ext.rc_startblock >= agbno + aglen, out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp,
+                                  agbno + aglen > ext.rc_startblock)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                tmp.rc_startblock = agbno;
                tmp.rc_blockcount = aglen;
@@ -1426,17 +1493,25 @@ xfs_refcount_adjust_cow_extents(
                                &found_tmp);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                               found_tmp == 1, out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_tmp != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                break;
        case XFS_REFCOUNT_ADJUST_COW_FREE:
                /* Removing a CoW reservation, there should be one extent. */
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                       ext.rc_startblock == agbno, out_error);
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                       ext.rc_blockcount == aglen, out_error);
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                       ext.rc_refcount == 1, out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_startblock != agbno)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
+               if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount != aglen)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
+               if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_refcount != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                ext.rc_refcount = 0;
                trace_xfs_refcount_modify_extent(cur->bc_mp,
@@ -1444,8 +1519,10 @@ xfs_refcount_adjust_cow_extents(
                error = xfs_refcount_delete(cur, &found_rec);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
-                               found_rec == 1, out_error);
+               if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                break;
        default:
                ASSERT(0);
@@ -1584,14 +1661,15 @@ struct xfs_refcount_recovery {
 /* Stuff an extent on the recovery list. */
 STATIC int
 xfs_refcount_recover_extent(
-       struct xfs_btree_cur            *cur,
+       struct xfs_btree_cur            *cur,
        union xfs_btree_rec             *rec,
        void                            *priv)
 {
        struct list_head                *debris = priv;
        struct xfs_refcount_recovery    *rr;
 
-       if (be32_to_cpu(rec->refc.rc_refcount) != 1)
+       if (XFS_IS_CORRUPT(cur->bc_mp,
+                          be32_to_cpu(rec->refc.rc_refcount) != 1))
                return -EFSCORRUPTED;
 
        rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), 0);
index 38e9414..ff9412f 100644 (file)
@@ -113,7 +113,10 @@ xfs_rmap_insert(
        error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 0, done);
+       if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 
        rcur->bc_rec.r.rm_startblock = agbno;
        rcur->bc_rec.r.rm_blockcount = len;
@@ -123,7 +126,10 @@ xfs_rmap_insert(
        error = xfs_btree_insert(rcur, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
+       if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 done:
        if (error)
                trace_xfs_rmap_insert_error(rcur->bc_mp,
@@ -149,12 +155,18 @@ xfs_rmap_delete(
        error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
+       if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 
        error = xfs_btree_delete(rcur, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
+       if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 done:
        if (error)
                trace_xfs_rmap_delete_error(rcur->bc_mp,
@@ -406,24 +418,39 @@ xfs_rmap_free_check_owner(
                return 0;
 
        /* Make sure the unwritten flag matches. */
-       XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
-                       (rec->rm_flags & XFS_RMAP_UNWRITTEN), out);
+       if (XFS_IS_CORRUPT(mp,
+                          (flags & XFS_RMAP_UNWRITTEN) !=
+                          (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
+               error = -EFSCORRUPTED;
+               goto out;
+       }
 
        /* Make sure the owner matches what we expect to find in the tree. */
-       XFS_WANT_CORRUPTED_GOTO(mp, owner == rec->rm_owner, out);
+       if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
+               error = -EFSCORRUPTED;
+               goto out;
+       }
 
        /* Check the offset, if necessary. */
        if (XFS_RMAP_NON_INODE_OWNER(owner))
                goto out;
 
        if (flags & XFS_RMAP_BMBT_BLOCK) {
-               XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_flags & XFS_RMAP_BMBT_BLOCK,
-                               out);
+               if (XFS_IS_CORRUPT(mp,
+                                  !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
        } else {
-               XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_offset <= offset, out);
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                               ltoff + rec->rm_blockcount >= offset + len,
-                               out);
+               if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
+               if (XFS_IS_CORRUPT(mp,
+                                  offset + len > ltoff + rec->rm_blockcount)) {
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
        }
 
 out:
@@ -482,12 +509,18 @@ xfs_rmap_unmap(
        error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        error = xfs_rmap_get_rec(cur, &ltrec, &i);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
        trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
                        cur->bc_private.a.agno, ltrec.rm_startblock,
                        ltrec.rm_blockcount, ltrec.rm_owner,
@@ -502,8 +535,12 @@ xfs_rmap_unmap(
         * be the case that the "left" extent goes all the way to EOFS.
         */
        if (owner == XFS_RMAP_OWN_NULL) {
-               XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock +
-                                               ltrec.rm_blockcount, out_error);
+               if (XFS_IS_CORRUPT(mp,
+                                  bno <
+                                  ltrec.rm_startblock + ltrec.rm_blockcount)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                goto out_done;
        }
 
@@ -526,15 +563,22 @@ xfs_rmap_unmap(
                error = xfs_rmap_get_rec(cur, &rtrec, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                if (rtrec.rm_startblock >= bno + len)
                        goto out_done;
        }
 
        /* Make sure the extent we found covers the entire freeing range. */
-       XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
-                       ltrec.rm_startblock + ltrec.rm_blockcount >=
-                       bno + len, out_error);
+       if (XFS_IS_CORRUPT(mp,
+                          ltrec.rm_startblock > bno ||
+                          ltrec.rm_startblock + ltrec.rm_blockcount <
+                          bno + len)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        /* Check owner information. */
        error = xfs_rmap_free_check_owner(mp, ltoff, &ltrec, len, owner,
@@ -551,7 +595,10 @@ xfs_rmap_unmap(
                error = xfs_btree_delete(cur, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
        } else if (ltrec.rm_startblock == bno) {
                /*
                 * overlap left hand side of extent: move the start, trim the
@@ -743,7 +790,10 @@ xfs_rmap_map(
                error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, have_lt != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
                                cur->bc_private.a.agno, ltrec.rm_startblock,
                                ltrec.rm_blockcount, ltrec.rm_owner,
@@ -753,9 +803,12 @@ xfs_rmap_map(
                        have_lt = 0;
        }
 
-       XFS_WANT_CORRUPTED_GOTO(mp,
-               have_lt == 0 ||
-               ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error);
+       if (XFS_IS_CORRUPT(mp,
+                          have_lt != 0 &&
+                          ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        /*
         * Increment the cursor to see if we have a right-adjacent record to our
@@ -769,9 +822,14 @@ xfs_rmap_map(
                error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
-               XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock,
-                                       out_error);
+               if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
+               if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
                        cur->bc_private.a.agno, gtrec.rm_startblock,
                        gtrec.rm_blockcount, gtrec.rm_owner,
@@ -821,7 +879,10 @@ xfs_rmap_map(
                        error = xfs_btree_delete(cur, &i);
                        if (error)
                                goto out_error;
-                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+                       if (XFS_IS_CORRUPT(mp, i != 1)) {
+                               error = -EFSCORRUPTED;
+                               goto out_error;
+                       }
                }
 
                /* point the cursor back to the left record and update */
@@ -865,7 +926,10 @@ xfs_rmap_map(
                error = xfs_btree_insert(cur, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
        }
 
        trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
@@ -957,12 +1021,18 @@ xfs_rmap_convert(
        error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 
        error = xfs_rmap_get_rec(cur, &PREV, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
        trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
                        cur->bc_private.a.agno, PREV.rm_startblock,
                        PREV.rm_blockcount, PREV.rm_owner,
@@ -995,10 +1065,16 @@ xfs_rmap_convert(
                error = xfs_rmap_get_rec(cur, &LEFT, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                               LEFT.rm_startblock + LEFT.rm_blockcount <= bno,
-                               done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
+               if (XFS_IS_CORRUPT(mp,
+                                  LEFT.rm_startblock + LEFT.rm_blockcount >
+                                  bno)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
                                cur->bc_private.a.agno, LEFT.rm_startblock,
                                LEFT.rm_blockcount, LEFT.rm_owner,
@@ -1017,7 +1093,10 @@ xfs_rmap_convert(
        error = xfs_btree_increment(cur, 0, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
        error = xfs_btree_increment(cur, 0, &i);
        if (error)
                goto done;
@@ -1026,9 +1105,14 @@ xfs_rmap_convert(
                error = xfs_rmap_get_rec(cur, &RIGHT, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
-               XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock,
-                                       done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
+               if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
                                cur->bc_private.a.agno, RIGHT.rm_startblock,
                                RIGHT.rm_blockcount, RIGHT.rm_owner,
@@ -1055,7 +1139,10 @@ xfs_rmap_convert(
        error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 
        /*
         * Switch out based on the FILLING and CONTIG state bits.
@@ -1071,7 +1158,10 @@ xfs_rmap_convert(
                error = xfs_btree_increment(cur, 0, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
                                RIGHT.rm_startblock, RIGHT.rm_blockcount,
                                RIGHT.rm_owner, RIGHT.rm_offset,
@@ -1079,11 +1169,17 @@ xfs_rmap_convert(
                error = xfs_btree_delete(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                error = xfs_btree_decrement(cur, 0, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
                                PREV.rm_startblock, PREV.rm_blockcount,
                                PREV.rm_owner, PREV.rm_offset,
@@ -1091,11 +1187,17 @@ xfs_rmap_convert(
                error = xfs_btree_delete(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                error = xfs_btree_decrement(cur, 0, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW = LEFT;
                NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
                error = xfs_rmap_update(cur, &NEW);
@@ -1115,11 +1217,17 @@ xfs_rmap_convert(
                error = xfs_btree_delete(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                error = xfs_btree_decrement(cur, 0, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW = LEFT;
                NEW.rm_blockcount += PREV.rm_blockcount;
                error = xfs_rmap_update(cur, &NEW);
@@ -1135,7 +1243,10 @@ xfs_rmap_convert(
                error = xfs_btree_increment(cur, 0, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
                                RIGHT.rm_startblock, RIGHT.rm_blockcount,
                                RIGHT.rm_owner, RIGHT.rm_offset,
@@ -1143,11 +1254,17 @@ xfs_rmap_convert(
                error = xfs_btree_delete(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                error = xfs_btree_decrement(cur, 0, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW = PREV;
                NEW.rm_blockcount = len + RIGHT.rm_blockcount;
                NEW.rm_flags = newext;
@@ -1214,7 +1331,10 @@ xfs_rmap_convert(
                error = xfs_btree_insert(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                break;
 
        case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
@@ -1253,7 +1373,10 @@ xfs_rmap_convert(
                                oldext, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+               if (XFS_IS_CORRUPT(mp, i != 0)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_startblock = bno;
                NEW.rm_owner = owner;
                NEW.rm_offset = offset;
@@ -1265,7 +1388,10 @@ xfs_rmap_convert(
                error = xfs_btree_insert(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                break;
 
        case 0:
@@ -1295,7 +1421,10 @@ xfs_rmap_convert(
                error = xfs_btree_insert(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                /*
                 * Reset the cursor to the position of the new extent
                 * we are about to insert as we can't trust it after
@@ -1305,7 +1434,10 @@ xfs_rmap_convert(
                                oldext, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+               if (XFS_IS_CORRUPT(mp, i != 0)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                /* new middle extent - newext */
                cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
                cur->bc_rec.r.rm_flags |= newext;
@@ -1314,7 +1446,10 @@ xfs_rmap_convert(
                error = xfs_btree_insert(cur, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                break;
 
        case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
@@ -1383,7 +1518,10 @@ xfs_rmap_convert_shared(
                        &PREV, &i);
        if (error)
                goto done;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto done;
+       }
 
        ASSERT(PREV.rm_offset <= offset);
        ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
@@ -1406,9 +1544,12 @@ xfs_rmap_convert_shared(
                goto done;
        if (i) {
                state |= RMAP_LEFT_VALID;
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                               LEFT.rm_startblock + LEFT.rm_blockcount <= bno,
-                               done);
+               if (XFS_IS_CORRUPT(mp,
+                                  LEFT.rm_startblock + LEFT.rm_blockcount >
+                                  bno)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
                        state |= RMAP_LEFT_CONTIG;
        }
@@ -1423,9 +1564,14 @@ xfs_rmap_convert_shared(
                error = xfs_rmap_get_rec(cur, &RIGHT, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
-               XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock,
-                               done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
+               if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
                                cur->bc_private.a.agno, RIGHT.rm_startblock,
                                RIGHT.rm_blockcount, RIGHT.rm_owner,
@@ -1472,7 +1618,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1495,7 +1644,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount += PREV.rm_blockcount;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1518,7 +1670,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount += RIGHT.rm_blockcount;
                NEW.rm_flags = RIGHT.rm_flags;
                error = xfs_rmap_update(cur, &NEW);
@@ -1538,7 +1693,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_flags = newext;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1570,7 +1728,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount += len;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1612,7 +1773,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount = offset - NEW.rm_offset;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1644,7 +1808,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount -= len;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1679,7 +1846,10 @@ xfs_rmap_convert_shared(
                                NEW.rm_offset, NEW.rm_flags, &i);
                if (error)
                        goto done;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto done;
+               }
                NEW.rm_blockcount = offset - NEW.rm_offset;
                error = xfs_rmap_update(cur, &NEW);
                if (error)
@@ -1765,25 +1935,44 @@ xfs_rmap_unmap_shared(
                        &ltrec, &i);
        if (error)
                goto out_error;
-       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+       if (XFS_IS_CORRUPT(mp, i != 1)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
        ltoff = ltrec.rm_offset;
 
        /* Make sure the extent we found covers the entire freeing range. */
-       XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
-               ltrec.rm_startblock + ltrec.rm_blockcount >=
-               bno + len, out_error);
+       if (XFS_IS_CORRUPT(mp,
+                          ltrec.rm_startblock > bno ||
+                          ltrec.rm_startblock + ltrec.rm_blockcount <
+                          bno + len)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        /* Make sure the owner matches what we expect to find in the tree. */
-       XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner, out_error);
+       if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        /* Make sure the unwritten flag matches. */
-       XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
-                       (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
+       if (XFS_IS_CORRUPT(mp,
+                          (flags & XFS_RMAP_UNWRITTEN) !=
+                          (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        /* Check the offset. */
-       XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_offset <= offset, out_error);
-       XFS_WANT_CORRUPTED_GOTO(mp, offset <= ltoff + ltrec.rm_blockcount,
-                       out_error);
+       if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
+       if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
+               error = -EFSCORRUPTED;
+               goto out_error;
+       }
 
        if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
                /* Exact match, simply remove the record from rmap tree. */
@@ -1836,7 +2025,10 @@ xfs_rmap_unmap_shared(
                                ltrec.rm_offset, ltrec.rm_flags, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                ltrec.rm_blockcount -= len;
                error = xfs_rmap_update(cur, &ltrec);
                if (error)
@@ -1862,7 +2054,10 @@ xfs_rmap_unmap_shared(
                                ltrec.rm_offset, ltrec.rm_flags, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                ltrec.rm_blockcount = bno - ltrec.rm_startblock;
                error = xfs_rmap_update(cur, &ltrec);
                if (error)
@@ -1938,7 +2133,10 @@ xfs_rmap_map_shared(
                error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
                trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
                        cur->bc_private.a.agno, gtrec.rm_startblock,
                        gtrec.rm_blockcount, gtrec.rm_owner,
@@ -1987,7 +2185,10 @@ xfs_rmap_map_shared(
                                ltrec.rm_offset, ltrec.rm_flags, &i);
                if (error)
                        goto out_error;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_error;
+               }
 
                error = xfs_rmap_update(cur, &ltrec);
                if (error)
@@ -2199,7 +2400,7 @@ xfs_rmap_finish_one(
                error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
                if (error)
                        return error;
-               if (!agbp)
+               if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
                        return -EFSCORRUPTED;
 
                rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
index 8ea1efc..f42c74c 100644 (file)
@@ -15,7 +15,7 @@
 #include "xfs_bmap.h"
 #include "xfs_trans.h"
 #include "xfs_rtalloc.h"
-
+#include "xfs_error.h"
 
 /*
  * Realtime allocator bitmap functions shared with userspace.
@@ -70,7 +70,7 @@ xfs_rtbuf_get(
        if (error)
                return error;
 
-       if (nmap == 0 || !xfs_bmap_is_real_extent(&map))
+       if (XFS_IS_CORRUPT(mp, nmap == 0 || !xfs_bmap_is_real_extent(&map)))
                return -EFSCORRUPTED;
 
        ASSERT(map.br_startblock != NULLFSBLOCK);
index ac6cdca..0ac6975 100644 (file)
@@ -10,6 +10,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
+#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
index a9ad909..2b8ccb5 100644 (file)
@@ -55,7 +55,7 @@ xfs_trans_ichgtime(
        int                     flags)
 {
        struct inode            *inode = VFS_I(ip);
-       struct timespec64 tv;
+       struct timespec64       tv;
 
        ASSERT(tp);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
@@ -66,10 +66,8 @@ xfs_trans_ichgtime(
                inode->i_mtime = tv;
        if (flags & XFS_ICHGTIME_CHG)
                inode->i_ctime = tv;
-       if (flags & XFS_ICHGTIME_CREATE) {
-               ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
-               ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
-       }
+       if (flags & XFS_ICHGTIME_CREATE)
+               ip->i_d.di_crtime = tv;
 }
 
 /*
index d12bbd5..c55cd9a 100644 (file)
@@ -718,7 +718,7 @@ xfs_calc_clear_agi_bucket_reservation(
 
 /*
  * Adjusting quota limits.
- *    the xfs_disk_dquot_t: sizeof(struct xfs_disk_dquot)
+ *    the disk quota buffer: sizeof(struct xfs_disk_dquot)
  */
 STATIC uint
 xfs_calc_qm_setqlim_reservation(void)
@@ -742,7 +742,7 @@ xfs_calc_qm_dqalloc_reservation(
 
 /*
  * Turning off quotas.
- *    the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2
+ *    the quota off logitems: sizeof(struct xfs_qoff_logitem) * 2
  *    the superblock for the quota flags: sector size
  */
 STATIC uint
@@ -755,7 +755,7 @@ xfs_calc_qm_quotaoff_reservation(
 
 /*
  * End of turning off quotas.
- *    the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2
+ *    the quota off logitems: sizeof(struct xfs_qoff_logitem) * 2
  */
 STATIC uint
 xfs_calc_qm_quotaoff_end_reservation(void)
index 300b3e9..397d947 100644 (file)
@@ -21,7 +21,6 @@ typedef int32_t               xfs_suminfo_t;  /* type of bitmap summary info */
 typedef uint32_t       xfs_rtword_t;   /* word type for bitmap manipulations */
 
 typedef int64_t                xfs_lsn_t;      /* log sequence number */
-typedef int32_t                xfs_tid_t;      /* transaction identifier */
 
 typedef uint32_t       xfs_dablk_t;    /* dir/attr block number (in file) */
 typedef uint32_t       xfs_dahash_t;   /* dir/attr hash value */
@@ -33,7 +32,6 @@ typedef uint64_t      xfs_fileoff_t;  /* block number in a file */
 typedef uint64_t       xfs_filblks_t;  /* number of blocks in a file */
 
 typedef int64_t                xfs_srtblock_t; /* signed version of xfs_rtblock_t */
-typedef int64_t                xfs_sfiloff_t;  /* signed block number in a file */
 
 /*
  * New verifiers will return the instruction address of the failing check.
index 0edc7f8..d9f0dd4 100644 (file)
@@ -398,15 +398,14 @@ out:
 STATIC int
 xchk_xattr_rec(
        struct xchk_da_btree            *ds,
-       int                             level,
-       void                            *rec)
+       int                             level)
 {
        struct xfs_mount                *mp = ds->state->mp;
-       struct xfs_attr_leaf_entry      *ent = rec;
-       struct xfs_da_state_blk         *blk;
+       struct xfs_da_state_blk         *blk = &ds->state->path.blk[level];
        struct xfs_attr_leaf_name_local *lentry;
        struct xfs_attr_leaf_name_remote        *rentry;
        struct xfs_buf                  *bp;
+       struct xfs_attr_leaf_entry      *ent;
        xfs_dahash_t                    calc_hash;
        xfs_dahash_t                    hash;
        int                             nameidx;
@@ -414,7 +413,9 @@ xchk_xattr_rec(
        unsigned int                    badflags;
        int                             error;
 
-       blk = &ds->state->path.blk[level];
+       ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+
+       ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
 
        /* Check the whole block, if necessary. */
        error = xchk_xattr_block(ds, level);
index 3d47d11..18a684e 100644 (file)
@@ -294,5 +294,6 @@ xfs_bitmap_set_btblocks(
        struct xfs_bitmap       *bitmap,
        struct xfs_btree_cur    *cur)
 {
-       return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock, bitmap);
+       return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock,
+                       XFS_BTREE_VISIT_ALL, bitmap);
 }
index 003a772..2e50d14 100644 (file)
 static inline bool
 xchk_should_terminate(
        struct xfs_scrub        *sc,
-       int                             *error)
+       int                     *error)
 {
+       /*
+        * If preemption is disabled, we need to yield to the scheduler every
+        * few seconds so that we don't run afoul of the soft lockup watchdog
+        * or RCU stall detector.
+        */
+       cond_resched();
+
        if (fatal_signal_pending(current)) {
                if (*error == 0)
                        *error = -EAGAIN;
index 77ff9f9..97a15b6 100644 (file)
@@ -77,40 +77,18 @@ xchk_da_set_corrupt(
                        __return_address);
 }
 
-/* Find an entry at a certain level in a da btree. */
-STATIC void *
-xchk_da_btree_entry(
-       struct xchk_da_btree    *ds,
-       int                     level,
-       int                     rec)
+static struct xfs_da_node_entry *
+xchk_da_btree_node_entry(
+       struct xchk_da_btree            *ds,
+       int                             level)
 {
-       char                    *ents;
-       struct xfs_da_state_blk *blk;
-       void                    *baddr;
+       struct xfs_da_state_blk         *blk = &ds->state->path.blk[level];
+       struct xfs_da3_icnode_hdr       hdr;
 
-       /* Dispatch the entry finding function. */
-       blk = &ds->state->path.blk[level];
-       baddr = blk->bp->b_addr;
-       switch (blk->magic) {
-       case XFS_ATTR_LEAF_MAGIC:
-       case XFS_ATTR3_LEAF_MAGIC:
-               ents = (char *)xfs_attr3_leaf_entryp(baddr);
-               return ents + (rec * sizeof(struct xfs_attr_leaf_entry));
-       case XFS_DIR2_LEAFN_MAGIC:
-       case XFS_DIR3_LEAFN_MAGIC:
-               ents = (char *)ds->dargs.dp->d_ops->leaf_ents_p(baddr);
-               return ents + (rec * sizeof(struct xfs_dir2_leaf_entry));
-       case XFS_DIR2_LEAF1_MAGIC:
-       case XFS_DIR3_LEAF1_MAGIC:
-               ents = (char *)ds->dargs.dp->d_ops->leaf_ents_p(baddr);
-               return ents + (rec * sizeof(struct xfs_dir2_leaf_entry));
-       case XFS_DA_NODE_MAGIC:
-       case XFS_DA3_NODE_MAGIC:
-               ents = (char *)ds->dargs.dp->d_ops->node_tree_p(baddr);
-               return ents + (rec * sizeof(struct xfs_da_node_entry));
-       }
+       ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
 
-       return NULL;
+       xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
+       return hdr.btree + blk->index;
 }
 
 /* Scrub a da btree hash (key). */
@@ -120,7 +98,6 @@ xchk_da_btree_hash(
        int                             level,
        __be32                          *hashp)
 {
-       struct xfs_da_state_blk         *blks;
        struct xfs_da_node_entry        *entry;
        xfs_dahash_t                    hash;
        xfs_dahash_t                    parent_hash;
@@ -135,8 +112,7 @@ xchk_da_btree_hash(
                return 0;
 
        /* Is this hash no larger than the parent hash? */
-       blks = ds->state->path.blk;
-       entry = xchk_da_btree_entry(ds, level - 1, blks[level - 1].index);
+       entry = xchk_da_btree_node_entry(ds, level - 1);
        parent_hash = be32_to_cpu(entry->hashval);
        if (parent_hash < hash)
                xchk_da_set_corrupt(ds, level);
@@ -355,8 +331,8 @@ xchk_da_btree_block(
                goto out_nobuf;
 
        /* Read the buffer. */
-       error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
-                       &blk->bp, dargs->whichfork,
+       error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
+                       XFS_DABUF_MAP_HOLE_OK, &blk->bp, dargs->whichfork,
                        &xchk_da_btree_buf_ops);
        if (!xchk_da_process_error(ds, level, &error))
                goto out_nobuf;
@@ -433,8 +409,8 @@ xchk_da_btree_block(
                                XFS_BLFT_DA_NODE_BUF);
                blk->magic = XFS_DA_NODE_MAGIC;
                node = blk->bp->b_addr;
-               ip->d_ops->node_hdr_from_disk(&nodehdr, node);
-               btree = ip->d_ops->node_tree_p(node);
+               xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
+               btree = nodehdr.btree;
                *pmaxrecs = nodehdr.count;
                blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
                if (level == 0) {
@@ -479,14 +455,12 @@ xchk_da_btree(
        struct xfs_mount                *mp = sc->mp;
        struct xfs_da_state_blk         *blks;
        struct xfs_da_node_entry        *key;
-       void                            *rec;
        xfs_dablk_t                     blkno;
        int                             level;
        int                             error;
 
        /* Skip short format data structures; no btree to scan. */
-       if (XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_BTREE)
+       if (!xfs_ifork_has_extents(sc->ip, whichfork))
                return 0;
 
        /* Set up initial da state. */
@@ -538,9 +512,7 @@ xchk_da_btree(
                        }
 
                        /* Dispatch record scrubbing. */
-                       rec = xchk_da_btree_entry(&ds, level,
-                                       blks[level].index);
-                       error = scrub_fn(&ds, level, rec);
+                       error = scrub_fn(&ds, level);
                        if (error)
                                break;
                        if (xchk_should_terminate(sc, &error) ||
@@ -562,7 +534,7 @@ xchk_da_btree(
                }
 
                /* Hashes in order for scrub? */
-               key = xchk_da_btree_entry(&ds, level, blks[level].index);
+               key = xchk_da_btree_node_entry(&ds, level);
                error = xchk_da_btree_hash(&ds, level, &key->hashval);
                if (error)
                        goto out;
index cb3f000..1f3515c 100644 (file)
@@ -28,8 +28,7 @@ struct xchk_da_btree {
        int                     tree_level;
 };
 
-typedef int (*xchk_da_btree_rec_fn)(struct xchk_da_btree *ds,
-               int level, void *rec);
+typedef int (*xchk_da_btree_rec_fn)(struct xchk_da_btree *ds, int level);
 
 /* Check for da btree operation errors. */
 bool xchk_da_process_error(struct xchk_da_btree *ds, int level, int *error);
index 1e2e117..266da4e 100644 (file)
@@ -113,6 +113,9 @@ xchk_dir_actor(
        offset = xfs_dir2_db_to_da(mp->m_dir_geo,
                        xfs_dir2_dataptr_to_db(mp->m_dir_geo, pos));
 
+       if (xchk_should_terminate(sdc->sc, &error))
+               return error;
+
        /* Does this inode number make sense? */
        if (!xfs_verify_dir_ino(mp, ino)) {
                xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset);
@@ -179,15 +182,17 @@ out:
 STATIC int
 xchk_dir_rec(
        struct xchk_da_btree            *ds,
-       int                             level,
-       void                            *rec)
+       int                             level)
 {
+       struct xfs_da_state_blk         *blk = &ds->state->path.blk[level];
        struct xfs_mount                *mp = ds->state->mp;
-       struct xfs_dir2_leaf_entry      *ent = rec;
        struct xfs_inode                *dp = ds->dargs.dp;
+       struct xfs_da_geometry          *geo = mp->m_dir_geo;
        struct xfs_dir2_data_entry      *dent;
        struct xfs_buf                  *bp;
-       char                            *p, *endp;
+       struct xfs_dir2_leaf_entry      *ent;
+       unsigned int                    end;
+       unsigned int                    iter_off;
        xfs_ino_t                       ino;
        xfs_dablk_t                     rec_bno;
        xfs_dir2_db_t                   db;
@@ -195,9 +200,16 @@ xchk_dir_rec(
        xfs_dir2_dataptr_t              ptr;
        xfs_dahash_t                    calc_hash;
        xfs_dahash_t                    hash;
+       struct xfs_dir3_icleaf_hdr      hdr;
        unsigned int                    tag;
        int                             error;
 
+       ASSERT(blk->magic == XFS_DIR2_LEAF1_MAGIC ||
+              blk->magic == XFS_DIR2_LEAFN_MAGIC);
+
+       xfs_dir2_leaf_hdr_from_disk(mp, &hdr, blk->bp->b_addr);
+       ent = hdr.ents + blk->index;
+
        /* Check the hash of the entry. */
        error = xchk_da_btree_hash(ds, level, &ent->hashval);
        if (error)
@@ -209,15 +221,16 @@ xchk_dir_rec(
                return 0;
 
        /* Find the directory entry's location. */
-       db = xfs_dir2_dataptr_to_db(mp->m_dir_geo, ptr);
-       off = xfs_dir2_dataptr_to_off(mp->m_dir_geo, ptr);
-       rec_bno = xfs_dir2_db_to_da(mp->m_dir_geo, db);
+       db = xfs_dir2_dataptr_to_db(geo, ptr);
+       off = xfs_dir2_dataptr_to_off(geo, ptr);
+       rec_bno = xfs_dir2_db_to_da(geo, db);
 
-       if (rec_bno >= mp->m_dir_geo->leafblk) {
+       if (rec_bno >= geo->leafblk) {
                xchk_da_set_corrupt(ds, level);
                goto out;
        }
-       error = xfs_dir3_data_read(ds->dargs.trans, dp, rec_bno, -2, &bp);
+       error = xfs_dir3_data_read(ds->dargs.trans, dp, rec_bno,
+                       XFS_DABUF_MAP_HOLE_OK, &bp);
        if (!xchk_fblock_process_error(ds->sc, XFS_DATA_FORK, rec_bno,
                        &error))
                goto out;
@@ -230,38 +243,37 @@ xchk_dir_rec(
        if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
                goto out_relse;
 
-       dent = (struct xfs_dir2_data_entry *)(((char *)bp->b_addr) + off);
+       dent = bp->b_addr + off;
 
        /* Make sure we got a real directory entry. */
-       p = (char *)mp->m_dir_inode_ops->data_entry_p(bp->b_addr);
-       endp = xfs_dir3_data_endp(mp->m_dir_geo, bp->b_addr);
-       if (!endp) {
+       iter_off = geo->data_entry_offset;
+       end = xfs_dir3_data_end_offset(geo, bp->b_addr);
+       if (!end) {
                xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
                goto out_relse;
        }
-       while (p < endp) {
-               struct xfs_dir2_data_entry      *dep;
-               struct xfs_dir2_data_unused     *dup;
+       for (;;) {
+               struct xfs_dir2_data_entry      *dep = bp->b_addr + iter_off;
+               struct xfs_dir2_data_unused     *dup = bp->b_addr + iter_off;
+
+               if (iter_off >= end) {
+                       xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+                       goto out_relse;
+               }
 
-               dup = (struct xfs_dir2_data_unused *)p;
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-                       p += be16_to_cpu(dup->length);
+                       iter_off += be16_to_cpu(dup->length);
                        continue;
                }
-               dep = (struct xfs_dir2_data_entry *)p;
                if (dep == dent)
                        break;
-               p += mp->m_dir_inode_ops->data_entsize(dep->namelen);
-       }
-       if (p >= endp) {
-               xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
-               goto out_relse;
+               iter_off += xfs_dir2_data_entsize(mp, dep->namelen);
        }
 
        /* Retrieve the entry, sanity check it, and compare hashes. */
        ino = be64_to_cpu(dent->inumber);
        hash = be32_to_cpu(ent->hashval);
-       tag = be16_to_cpup(dp->d_ops->data_entry_tag_p(dent));
+       tag = be16_to_cpup(xfs_dir2_data_entry_tag_p(mp, dent));
        if (!xfs_verify_dir_ino(mp, ino) || tag != off)
                xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
        if (dent->namelen == 0) {
@@ -319,19 +331,15 @@ xchk_directory_data_bestfree(
        struct xfs_buf                  *bp;
        struct xfs_dir2_data_free       *bf;
        struct xfs_mount                *mp = sc->mp;
-       const struct xfs_dir_ops        *d_ops;
-       char                            *ptr;
-       char                            *endptr;
        u16                             tag;
        unsigned int                    nr_bestfrees = 0;
        unsigned int                    nr_frees = 0;
        unsigned int                    smallest_bestfree;
        int                             newlen;
-       int                             offset;
+       unsigned int                    offset;
+       unsigned int                    end;
        int                             error;
 
-       d_ops = sc->ip->d_ops;
-
        if (is_block) {
                /* dir block format */
                if (lblk != XFS_B_TO_FSBT(mp, XFS_DIR2_DATA_OFFSET))
@@ -339,7 +347,7 @@ xchk_directory_data_bestfree(
                error = xfs_dir3_block_read(sc->tp, sc->ip, &bp);
        } else {
                /* dir data format */
-               error = xfs_dir3_data_read(sc->tp, sc->ip, lblk, -1, &bp);
+               error = xfs_dir3_data_read(sc->tp, sc->ip, lblk, 0, &bp);
        }
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
                goto out;
@@ -351,7 +359,7 @@ xchk_directory_data_bestfree(
                goto out_buf;
 
        /* Do the bestfrees correspond to actual free space? */
-       bf = d_ops->data_bestfree_p(bp->b_addr);
+       bf = xfs_dir2_data_bestfree_p(mp, bp->b_addr);
        smallest_bestfree = UINT_MAX;
        for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
                offset = be16_to_cpu(dfp->offset);
@@ -361,13 +369,13 @@ xchk_directory_data_bestfree(
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                        goto out_buf;
                }
-               dup = (struct xfs_dir2_data_unused *)(bp->b_addr + offset);
+               dup = bp->b_addr + offset;
                tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
 
                /* bestfree doesn't match the entry it points at? */
                if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG) ||
                    be16_to_cpu(dup->length) != be16_to_cpu(dfp->length) ||
-                   tag != ((char *)dup - (char *)bp->b_addr)) {
+                   tag != offset) {
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                        goto out_buf;
                }
@@ -383,30 +391,30 @@ xchk_directory_data_bestfree(
        }
 
        /* Make sure the bestfrees are actually the best free spaces. */
-       ptr = (char *)d_ops->data_entry_p(bp->b_addr);
-       endptr = xfs_dir3_data_endp(mp->m_dir_geo, bp->b_addr);
+       offset = mp->m_dir_geo->data_entry_offset;
+       end = xfs_dir3_data_end_offset(mp->m_dir_geo, bp->b_addr);
 
        /* Iterate the entries, stopping when we hit or go past the end. */
-       while (ptr < endptr) {
-               dup = (struct xfs_dir2_data_unused *)ptr;
+       while (offset < end) {
+               dup = bp->b_addr + offset;
+
                /* Skip real entries */
                if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG)) {
-                       struct xfs_dir2_data_entry      *dep;
+                       struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
 
-                       dep = (struct xfs_dir2_data_entry *)ptr;
-                       newlen = d_ops->data_entsize(dep->namelen);
+                       newlen = xfs_dir2_data_entsize(mp, dep->namelen);
                        if (newlen <= 0) {
                                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
                                                lblk);
                                goto out_buf;
                        }
-                       ptr += newlen;
+                       offset += newlen;
                        continue;
                }
 
                /* Spot check this free entry */
                tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
-               if (tag != ((char *)dup - (char *)bp->b_addr)) {
+               if (tag != offset) {
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                        goto out_buf;
                }
@@ -425,13 +433,13 @@ xchk_directory_data_bestfree(
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                        goto out_buf;
                }
-               ptr += newlen;
-               if (ptr <= endptr)
+               offset += newlen;
+               if (offset <= end)
                        nr_frees++;
        }
 
        /* We're required to fill all the space. */
-       if (ptr != endptr)
+       if (offset != end)
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
 
        /* Did we see at least as many free slots as there are bestfrees? */
@@ -458,7 +466,7 @@ xchk_directory_check_freesp(
 {
        struct xfs_dir2_data_free       *dfp;
 
-       dfp = sc->ip->d_ops->data_bestfree_p(dbp->b_addr);
+       dfp = xfs_dir2_data_bestfree_p(sc->mp, dbp->b_addr);
 
        if (len != be16_to_cpu(dfp->length))
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
@@ -475,12 +483,10 @@ xchk_directory_leaf1_bestfree(
        xfs_dablk_t                     lblk)
 {
        struct xfs_dir3_icleaf_hdr      leafhdr;
-       struct xfs_dir2_leaf_entry      *ents;
        struct xfs_dir2_leaf_tail       *ltp;
        struct xfs_dir2_leaf            *leaf;
        struct xfs_buf                  *dbp;
        struct xfs_buf                  *bp;
-       const struct xfs_dir_ops        *d_ops = sc->ip->d_ops;
        struct xfs_da_geometry          *geo = sc->mp->m_dir_geo;
        __be16                          *bestp;
        __u16                           best;
@@ -492,14 +498,13 @@ xchk_directory_leaf1_bestfree(
        int                             error;
 
        /* Read the free space block. */
-       error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
+       error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, &bp);
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
                goto out;
        xchk_buffer_recheck(sc, bp);
 
        leaf = bp->b_addr;
-       d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
-       ents = d_ops->leaf_ents_p(leaf);
+       xfs_dir2_leaf_hdr_from_disk(sc->ip->i_mount, &leafhdr, leaf);
        ltp = xfs_dir2_leaf_tail_p(geo, leaf);
        bestcount = be32_to_cpu(ltp->bestcount);
        bestp = xfs_dir2_leaf_bests_p(ltp);
@@ -521,24 +526,25 @@ xchk_directory_leaf1_bestfree(
        }
 
        /* Is the leaf count even remotely sane? */
-       if (leafhdr.count > d_ops->leaf_max_ents(geo)) {
+       if (leafhdr.count > geo->leaf_max_ents) {
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                goto out;
        }
 
        /* Leaves and bests don't overlap in leaf format. */
-       if ((char *)&ents[leafhdr.count] > (char *)bestp) {
+       if ((char *)&leafhdr.ents[leafhdr.count] > (char *)bestp) {
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                goto out;
        }
 
        /* Check hash value order, count stale entries.  */
        for (i = 0; i < leafhdr.count; i++) {
-               hash = be32_to_cpu(ents[i].hashval);
+               hash = be32_to_cpu(leafhdr.ents[i].hashval);
                if (i > 0 && lasthash > hash)
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
                lasthash = hash;
-               if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
+               if (leafhdr.ents[i].address ==
+                   cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
                        stale++;
        }
        if (leafhdr.stale != stale)
@@ -552,7 +558,7 @@ xchk_directory_leaf1_bestfree(
                if (best == NULLDATAOFF)
                        continue;
                error = xfs_dir3_data_read(sc->tp, sc->ip,
-                               i * args->geo->fsbcount, -1, &dbp);
+                               i * args->geo->fsbcount, 0, &dbp);
                if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
                                &error))
                        break;
@@ -575,7 +581,6 @@ xchk_directory_free_bestfree(
        struct xfs_dir3_icfree_hdr      freehdr;
        struct xfs_buf                  *dbp;
        struct xfs_buf                  *bp;
-       __be16                          *bestp;
        __u16                           best;
        unsigned int                    stale = 0;
        int                             i;
@@ -595,17 +600,16 @@ xchk_directory_free_bestfree(
        }
 
        /* Check all the entries. */
-       sc->ip->d_ops->free_hdr_from_disk(&freehdr, bp->b_addr);
-       bestp = sc->ip->d_ops->free_bests_p(bp->b_addr);
-       for (i = 0; i < freehdr.nvalid; i++, bestp++) {
-               best = be16_to_cpu(*bestp);
+       xfs_dir2_free_hdr_from_disk(sc->ip->i_mount, &freehdr, bp->b_addr);
+       for (i = 0; i < freehdr.nvalid; i++) {
+               best = be16_to_cpu(freehdr.bests[i]);
                if (best == NULLDATAOFF) {
                        stale++;
                        continue;
                }
                error = xfs_dir3_data_read(sc->tp, sc->ip,
                                (freehdr.firstdb + i) * args->geo->fsbcount,
-                               -1, &dbp);
+                               0, &dbp);
                if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
                                &error))
                        break;
index 98f82d7..7251c66 100644 (file)
@@ -104,7 +104,7 @@ next_loop_perag:
                pag = NULL;
                error = 0;
 
-               if (fatal_signal_pending(current))
+               if (xchk_should_terminate(sc, &error))
                        break;
        }
 
@@ -163,6 +163,7 @@ xchk_fscount_aggregate_agcounts(
        uint64_t                delayed;
        xfs_agnumber_t          agno;
        int                     tries = 8;
+       int                     error = 0;
 
 retry:
        fsc->icount = 0;
@@ -196,10 +197,13 @@ retry:
 
                xfs_perag_put(pag);
 
-               if (fatal_signal_pending(current))
+               if (xchk_should_terminate(sc, &error))
                        break;
        }
 
+       if (error)
+               return error;
+
        /*
         * The global incore space reservation is taken from the incore
         * counters, so leave that out of the computation.
index b2f6028..83d27cd 100644 (file)
@@ -11,6 +11,7 @@
 #include "xfs_sb.h"
 #include "xfs_health.h"
 #include "scrub/scrub.h"
+#include "scrub/health.h"
 
 /*
  * Scrub and In-Core Filesystem Health Assessments
index c962bd5..5705adc 100644 (file)
@@ -32,8 +32,10 @@ xchk_setup_parent(
 
 struct xchk_parent_ctx {
        struct dir_context      dc;
+       struct xfs_scrub        *sc;
        xfs_ino_t               ino;
        xfs_nlink_t             nlink;
+       bool                    cancelled;
 };
 
 /* Look for a single entry in a directory pointing to an inode. */
@@ -47,11 +49,21 @@ xchk_parent_actor(
        unsigned                type)
 {
        struct xchk_parent_ctx  *spc;
+       int                     error = 0;
 
        spc = container_of(dc, struct xchk_parent_ctx, dc);
        if (spc->ino == ino)
                spc->nlink++;
-       return 0;
+
+       /*
+        * If we're facing a fatal signal, bail out.  Store the cancellation
+        * status separately because the VFS readdir code squashes error codes
+        * into short directory reads.
+        */
+       if (xchk_should_terminate(spc->sc, &error))
+               spc->cancelled = true;
+
+       return error;
 }
 
 /* Count the number of dentries in the parent dir that point to this inode. */
@@ -62,10 +74,9 @@ xchk_parent_count_parent_dentries(
        xfs_nlink_t             *nlink)
 {
        struct xchk_parent_ctx  spc = {
-               .dc.actor = xchk_parent_actor,
-               .dc.pos = 0,
-               .ino = sc->ip->i_ino,
-               .nlink = 0,
+               .dc.actor       = xchk_parent_actor,
+               .ino            = sc->ip->i_ino,
+               .sc             = sc,
        };
        size_t                  bufsize;
        loff_t                  oldpos;
@@ -80,7 +91,7 @@ xchk_parent_count_parent_dentries(
         */
        lock_mode = xfs_ilock_data_map_shared(parent);
        if (parent->i_d.di_nextents > 0)
-               error = xfs_dir3_data_readahead(parent, 0, -1);
+               error = xfs_dir3_data_readahead(parent, 0, 0);
        xfs_iunlock(parent, lock_mode);
        if (error)
                return error;
@@ -97,6 +108,10 @@ xchk_parent_count_parent_dentries(
                error = xfs_readdir(sc->tp, parent, &spc.dc, bufsize);
                if (error)
                        goto out;
+               if (spc.cancelled) {
+                       error = -EAGAIN;
+                       goto out;
+               }
                if (oldpos == spc.dc.pos)
                        break;
                oldpos = spc.dc.pos;
index 0a33b44..905a345 100644 (file)
@@ -93,6 +93,10 @@ xchk_quota_item(
        unsigned long long      rcount;
        xfs_ino_t               fs_icount;
        xfs_dqid_t              id = be32_to_cpu(d->d_id);
+       int                     error = 0;
+
+       if (xchk_should_terminate(sc, &error))
+               return error;
 
        /*
         * Except for the root dquot, the actual dquot we got must either have
@@ -178,6 +182,9 @@ xchk_quota_item(
        if (id != 0 && rhard != 0 && rcount > rhard)
                xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
 
+       if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+               return -EFSCORRUPTED;
+
        return 0;
 }
 
index 15c8c5f..f1775bb 100644 (file)
@@ -16,6 +16,7 @@
 #include "xfs_qm.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
+#include "xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
index 96d7071..91693fc 100644 (file)
 #include "xfs_inode.h"
 #include "xfs_attr.h"
 #include "xfs_trace.h"
-#include <linux/posix_acl_xattr.h>
+#include "xfs_error.h"
+#include "xfs_acl.h"
 
+#include <linux/posix_acl_xattr.h>
 
 /*
  * Locking scheme:
@@ -23,6 +25,7 @@
 
 STATIC struct posix_acl *
 xfs_acl_from_disk(
+       struct xfs_mount        *mp,
        const struct xfs_acl    *aclp,
        int                     len,
        int                     max_entries)
@@ -32,11 +35,18 @@ xfs_acl_from_disk(
        const struct xfs_acl_entry *ace;
        unsigned int count, i;
 
-       if (len < sizeof(*aclp))
+       if (len < sizeof(*aclp)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp,
+                               len);
                return ERR_PTR(-EFSCORRUPTED);
+       }
+
        count = be32_to_cpu(aclp->acl_cnt);
-       if (count > max_entries || XFS_ACL_SIZE(count) != len)
+       if (count > max_entries || XFS_ACL_SIZE(count) != len) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp,
+                               len);
                return ERR_PTR(-EFSCORRUPTED);
+       }
 
        acl = posix_acl_alloc(count, GFP_KERNEL);
        if (!acl)
@@ -145,7 +155,7 @@ xfs_get_acl(struct inode *inode, int type)
                if (error != -ENOATTR)
                        acl = ERR_PTR(error);
        } else  {
-               acl = xfs_acl_from_disk(xfs_acl, len,
+               acl = xfs_acl_from_disk(ip->i_mount, xfs_acl, len,
                                        XFS_ACL_MAX_ENTRIES(ip->i_mount));
                kmem_free(xfs_acl);
        }
index 5936507..3a688eb 100644 (file)
@@ -30,32 +30,6 @@ XFS_WPC(struct iomap_writepage_ctx *ctx)
        return container_of(ctx, struct xfs_writepage_ctx, ctx);
 }
 
-struct block_device *
-xfs_find_bdev_for_inode(
-       struct inode            *inode)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-
-       if (XFS_IS_REALTIME_INODE(ip))
-               return mp->m_rtdev_targp->bt_bdev;
-       else
-               return mp->m_ddev_targp->bt_bdev;
-}
-
-struct dax_device *
-xfs_find_daxdev_for_inode(
-       struct inode            *inode)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-
-       if (XFS_IS_REALTIME_INODE(ip))
-               return mp->m_rtdev_targp->bt_daxdev;
-       else
-               return mp->m_ddev_targp->bt_daxdev;
-}
-
 /*
  * Fast and loose check if this write could update the on-disk inode size.
  */
@@ -609,9 +583,11 @@ xfs_dax_writepages(
        struct address_space    *mapping,
        struct writeback_control *wbc)
 {
-       xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
+       struct xfs_inode        *ip = XFS_I(mapping->host);
+
+       xfs_iflags_clear(ip, XFS_ITRUNCATED);
        return dax_writeback_mapping_range(mapping,
-                       xfs_find_bdev_for_inode(mapping->host), wbc);
+                       xfs_inode_buftarg(ip)->bt_bdev, wbc);
 }
 
 STATIC sector_t
@@ -634,7 +610,7 @@ xfs_vm_bmap(
         */
        if (xfs_is_cow_inode(ip) || XFS_IS_REALTIME_INODE(ip))
                return 0;
-       return iomap_bmap(mapping, block, &xfs_iomap_ops);
+       return iomap_bmap(mapping, block, &xfs_read_iomap_ops);
 }
 
 STATIC int
@@ -642,7 +618,7 @@ xfs_vm_readpage(
        struct file             *unused,
        struct page             *page)
 {
-       return iomap_readpage(page, &xfs_iomap_ops);
+       return iomap_readpage(page, &xfs_read_iomap_ops);
 }
 
 STATIC int
@@ -652,7 +628,7 @@ xfs_vm_readpages(
        struct list_head        *pages,
        unsigned                nr_pages)
 {
-       return iomap_readpages(mapping, pages, nr_pages, &xfs_iomap_ops);
+       return iomap_readpages(mapping, pages, nr_pages, &xfs_read_iomap_ops);
 }
 
 static int
@@ -661,8 +637,9 @@ xfs_iomap_swapfile_activate(
        struct file                     *swap_file,
        sector_t                        *span)
 {
-       sis->bdev = xfs_find_bdev_for_inode(file_inode(swap_file));
-       return iomap_swapfile_activate(sis, swap_file, span, &xfs_iomap_ops);
+       sis->bdev = xfs_inode_buftarg(XFS_I(file_inode(swap_file)))->bt_bdev;
+       return iomap_swapfile_activate(sis, swap_file, span,
+                       &xfs_read_iomap_ops);
 }
 
 const struct address_space_operations xfs_address_space_operations = {
index 687b11f..e0bd684 100644 (file)
@@ -11,7 +11,4 @@ extern const struct address_space_operations xfs_dax_aops;
 
 int    xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size);
 
-extern struct block_device *xfs_find_bdev_for_inode(struct inode *);
-extern struct dax_device *xfs_find_daxdev_for_inode(struct inode *);
-
 #endif /* __XFS_AOPS_H__ */
index a640a28..5ff4952 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_attr_leaf.h"
 #include "xfs_quota.h"
 #include "xfs_dir2.h"
+#include "xfs_error.h"
 
 /*
  * Look at all the extents for this logical region,
@@ -190,37 +191,35 @@ xfs_attr3_leaf_inactive(
  */
 STATIC int
 xfs_attr3_node_inactive(
-       struct xfs_trans **trans,
-       struct xfs_inode *dp,
-       struct xfs_buf  *bp,
-       int             level)
+       struct xfs_trans        **trans,
+       struct xfs_inode        *dp,
+       struct xfs_buf          *bp,
+       int                     level)
 {
-       xfs_da_blkinfo_t *info;
-       xfs_da_intnode_t *node;
-       xfs_dablk_t child_fsb;
-       xfs_daddr_t parent_blkno, child_blkno;
-       int error, i;
-       struct xfs_buf *child_bp;
-       struct xfs_da_node_entry *btree;
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_da_blkinfo   *info;
+       xfs_dablk_t             child_fsb;
+       xfs_daddr_t             parent_blkno, child_blkno;
+       struct xfs_buf          *child_bp;
        struct xfs_da3_icnode_hdr ichdr;
+       int                     error, i;
 
        /*
         * Since this code is recursive (gasp!) we must protect ourselves.
         */
        if (level > XFS_DA_NODE_MAXDEPTH) {
                xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
-               return -EIO;
+               xfs_buf_corruption_error(bp);
+               return -EFSCORRUPTED;
        }
 
-       node = bp->b_addr;
-       dp->d_ops->node_hdr_from_disk(&ichdr, node);
+       xfs_da3_node_hdr_from_disk(dp->i_mount, &ichdr, bp->b_addr);
        parent_blkno = bp->b_bn;
        if (!ichdr.count) {
                xfs_trans_brelse(*trans, bp);
                return 0;
        }
-       btree = dp->d_ops->node_tree_p(node);
-       child_fsb = be32_to_cpu(btree[0].before);
+       child_fsb = be32_to_cpu(ichdr.btree[0].before);
        xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
 
        /*
@@ -235,7 +234,7 @@ xfs_attr3_node_inactive(
                 * traversal of the tree so we may deal with many blocks
                 * before we come back to this one.
                 */
-               error = xfs_da3_node_read(*trans, dp, child_fsb, -1, &child_bp,
+               error = xfs_da3_node_read(*trans, dp, child_fsb, &child_bp,
                                          XFS_ATTR_FORK);
                if (error)
                        return error;
@@ -258,8 +257,9 @@ xfs_attr3_node_inactive(
                        error = xfs_attr3_leaf_inactive(trans, dp, child_bp);
                        break;
                default:
-                       error = -EIO;
+                       xfs_buf_corruption_error(child_bp);
                        xfs_trans_brelse(*trans, child_bp);
+                       error = -EFSCORRUPTED;
                        break;
                }
                if (error)
@@ -268,10 +268,16 @@ xfs_attr3_node_inactive(
                /*
                 * Remove the subsidiary block from the cache and from the log.
                 */
-               error = xfs_da_get_buf(*trans, dp, 0, child_blkno, &child_bp,
-                                      XFS_ATTR_FORK);
-               if (error)
+               child_bp = xfs_trans_get_buf(*trans, mp->m_ddev_targp,
+                               child_blkno,
+                               XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0);
+               if (!child_bp)
+                       return -EIO;
+               error = bp->b_error;
+               if (error) {
+                       xfs_trans_brelse(*trans, child_bp);
                        return error;
+               }
                xfs_trans_binval(*trans, child_bp);
 
                /*
@@ -279,13 +285,15 @@ xfs_attr3_node_inactive(
                 * child block number.
                 */
                if (i + 1 < ichdr.count) {
-                       error = xfs_da3_node_read(*trans, dp, 0, parent_blkno,
-                                                &bp, XFS_ATTR_FORK);
+                       struct xfs_da3_icnode_hdr phdr;
+
+                       error = xfs_da3_node_read_mapped(*trans, dp,
+                                       parent_blkno, &bp, XFS_ATTR_FORK);
                        if (error)
                                return error;
-                       node = bp->b_addr;
-                       btree = dp->d_ops->node_tree_p(node);
-                       child_fsb = be32_to_cpu(btree[i + 1].before);
+                       xfs_da3_node_hdr_from_disk(dp->i_mount, &phdr,
+                                                 bp->b_addr);
+                       child_fsb = be32_to_cpu(phdr.btree[i + 1].before);
                        xfs_trans_brelse(*trans, bp);
                }
                /*
@@ -310,6 +318,7 @@ xfs_attr3_root_inactive(
        struct xfs_trans        **trans,
        struct xfs_inode        *dp)
 {
+       struct xfs_mount        *mp = dp->i_mount;
        struct xfs_da_blkinfo   *info;
        struct xfs_buf          *bp;
        xfs_daddr_t             blkno;
@@ -321,7 +330,7 @@ xfs_attr3_root_inactive(
         * the extents in reverse order the extent containing
         * block 0 must still be there.
         */
-       error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
+       error = xfs_da3_node_read(*trans, dp, 0, &bp, XFS_ATTR_FORK);
        if (error)
                return error;
        blkno = bp->b_bn;
@@ -341,7 +350,8 @@ xfs_attr3_root_inactive(
                error = xfs_attr3_leaf_inactive(trans, dp, bp);
                break;
        default:
-               error = -EIO;
+               error = -EFSCORRUPTED;
+               xfs_buf_corruption_error(bp);
                xfs_trans_brelse(*trans, bp);
                break;
        }
@@ -351,9 +361,15 @@ xfs_attr3_root_inactive(
        /*
         * Invalidate the incore copy of the root block.
         */
-       error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK);
-       if (error)
+       bp = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno,
+                       XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0);
+       if (!bp)
+               return -EIO;
+       error = bp->b_error;
+       if (error) {
+               xfs_trans_brelse(*trans, bp);
                return error;
+       }
        xfs_trans_binval(*trans, bp);   /* remove from cache */
        /*
         * Commit the invalidate and start the next transaction.
index 00758fd..d37743b 100644 (file)
@@ -49,14 +49,16 @@ xfs_attr_shortform_compare(const void *a, const void *b)
  * we can begin returning them to the user.
  */
 static int
-xfs_attr_shortform_list(xfs_attr_list_context_t *context)
+xfs_attr_shortform_list(
+       struct xfs_attr_list_context    *context)
 {
-       attrlist_cursor_kern_t *cursor;
-       xfs_attr_sf_sort_t *sbuf, *sbp;
-       xfs_attr_shortform_t *sf;
-       xfs_attr_sf_entry_t *sfe;
-       xfs_inode_t *dp;
-       int sbsize, nsbuf, count, i;
+       struct attrlist_cursor_kern     *cursor;
+       struct xfs_attr_sf_sort         *sbuf, *sbp;
+       struct xfs_attr_shortform       *sf;
+       struct xfs_attr_sf_entry        *sfe;
+       struct xfs_inode                *dp;
+       int                             sbsize, nsbuf, count, i;
+       int                             error = 0;
 
        ASSERT(context != NULL);
        dp = context->dp;
@@ -84,6 +86,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
            (XFS_ISRESET_CURSOR(cursor) &&
             (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
                for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
+                       if (XFS_IS_CORRUPT(context->dp->i_mount,
+                                          !xfs_attr_namecheck(sfe->nameval,
+                                                              sfe->namelen)))
+                               return -EFSCORRUPTED;
                        context->put_listent(context,
                                             sfe->flags,
                                             sfe->nameval,
@@ -161,10 +167,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
                        break;
                }
        }
-       if (i == nsbuf) {
-               kmem_free(sbuf);
-               return 0;
-       }
+       if (i == nsbuf)
+               goto out;
 
        /*
         * Loop putting entries into the user buffer.
@@ -174,6 +178,12 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
                        cursor->hashval = sbp->hash;
                        cursor->offset = 0;
                }
+               if (XFS_IS_CORRUPT(context->dp->i_mount,
+                                  !xfs_attr_namecheck(sbp->name,
+                                                      sbp->namelen))) {
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
                context->put_listent(context,
                                     sbp->flags,
                                     sbp->name,
@@ -183,9 +193,9 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
                        break;
                cursor->offset++;
        }
-
+out:
        kmem_free(sbuf);
-       return 0;
+       return error;
 }
 
 /*
@@ -213,7 +223,7 @@ xfs_attr_node_list_lookup(
        ASSERT(*pbp == NULL);
        cursor->blkno = 0;
        for (;;) {
-               error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
+               error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
                                XFS_ATTR_FORK);
                if (error)
                        return error;
@@ -229,7 +239,7 @@ xfs_attr_node_list_lookup(
                        goto out_corruptbuf;
                }
 
-               dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+               xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
 
                /* Tree taller than we can handle; bail out! */
                if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
@@ -243,7 +253,7 @@ xfs_attr_node_list_lookup(
                else
                        expected_level--;
 
-               btree = dp->d_ops->node_tree_p(node);
+               btree = nodehdr.btree;
                for (i = 0; i < nodehdr.count; btree++, i++) {
                        if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
                                cursor->blkno = be32_to_cpu(btree->before);
@@ -258,7 +268,7 @@ xfs_attr_node_list_lookup(
                        return 0;
 
                /* We can't point back to the root. */
-               if (cursor->blkno == 0)
+               if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
                        return -EFSCORRUPTED;
        }
 
@@ -269,6 +279,7 @@ xfs_attr_node_list_lookup(
        return 0;
 
 out_corruptbuf:
+       xfs_buf_corruption_error(bp);
        xfs_trans_brelse(tp, bp);
        return -EFSCORRUPTED;
 }
@@ -284,7 +295,7 @@ xfs_attr_node_list(
        struct xfs_buf                  *bp;
        struct xfs_inode                *dp = context->dp;
        struct xfs_mount                *mp = dp->i_mount;
-       int                             error;
+       int                             error = 0;
 
        trace_xfs_attr_node_list(context);
 
@@ -298,8 +309,8 @@ xfs_attr_node_list(
         */
        bp = NULL;
        if (cursor->blkno > 0) {
-               error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
-                                             &bp, XFS_ATTR_FORK);
+               error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
+                               XFS_ATTR_FORK);
                if ((error != 0) && (error != -EFSCORRUPTED))
                        return error;
                if (bp) {
@@ -358,24 +369,27 @@ xfs_attr_node_list(
         */
        for (;;) {
                leaf = bp->b_addr;
-               xfs_attr3_leaf_list_int(bp, context);
+               error = xfs_attr3_leaf_list_int(bp, context);
+               if (error)
+                       break;
                xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
                if (context->seen_enough || leafhdr.forw == 0)
                        break;
                cursor->blkno = leafhdr.forw;
                xfs_trans_brelse(context->tp, bp);
-               error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
+               error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
+                                           &bp);
                if (error)
                        return error;
        }
        xfs_trans_brelse(context->tp, bp);
-       return 0;
+       return error;
 }
 
 /*
  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
  */
-void
+int
 xfs_attr3_leaf_list_int(
        struct xfs_buf                  *bp,
        struct xfs_attr_list_context    *context)
@@ -417,7 +431,7 @@ xfs_attr3_leaf_list_int(
                }
                if (i == ichdr.count) {
                        trace_xfs_attr_list_notfound(context);
-                       return;
+                       return 0;
                }
        } else {
                entry = &entries[0];
@@ -457,6 +471,9 @@ xfs_attr3_leaf_list_int(
                        valuelen = be32_to_cpu(name_rmt->valuelen);
                }
 
+               if (XFS_IS_CORRUPT(context->dp->i_mount,
+                                  !xfs_attr_namecheck(name, namelen)))
+                       return -EFSCORRUPTED;
                context->put_listent(context, entry->flags,
                                              name, namelen, valuelen);
                if (context->seen_enough)
@@ -464,7 +481,7 @@ xfs_attr3_leaf_list_int(
                cursor->offset++;
        }
        trace_xfs_attr_list_leaf_end(context);
-       return;
+       return 0;
 }
 
 /*
@@ -479,13 +496,13 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
        trace_xfs_attr_leaf_list(context);
 
        context->cursor->blkno = 0;
-       error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
+       error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
        if (error)
                return error;
 
-       xfs_attr3_leaf_list_int(bp, context);
+       error = xfs_attr3_leaf_list_int(bp, context);
        xfs_trans_brelse(context->tp, bp);
-       return 0;
+       return error;
 }
 
 int
index 83d24e9..ee6f422 100644 (file)
@@ -21,7 +21,7 @@
 #include "xfs_icache.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_trans_space.h"
-
+#include "xfs_error.h"
 
 kmem_zone_t    *xfs_bui_zone;
 kmem_zone_t    *xfs_bud_zone;
@@ -35,7 +35,7 @@ void
 xfs_bui_item_free(
        struct xfs_bui_log_item *buip)
 {
-       kmem_zone_free(xfs_bui_zone, buip);
+       kmem_cache_free(xfs_bui_zone, buip);
 }
 
 /*
@@ -201,7 +201,7 @@ xfs_bud_item_release(
        struct xfs_bud_log_item *budp = BUD_ITEM(lip);
 
        xfs_bui_release(budp->bud_buip);
-       kmem_zone_free(xfs_bud_zone, budp);
+       kmem_cache_free(xfs_bud_zone, budp);
 }
 
 static const struct xfs_item_ops xfs_bud_item_ops = {
@@ -456,7 +456,7 @@ xfs_bui_recover(
        if (buip->bui_format.bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
                set_bit(XFS_BUI_RECOVERED, &buip->bui_flags);
                xfs_bui_release(buip);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /*
@@ -490,7 +490,7 @@ xfs_bui_recover(
                 */
                set_bit(XFS_BUI_RECOVERED, &buip->bui_flags);
                xfs_bui_release(buip);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
@@ -525,6 +525,7 @@ xfs_bui_recover(
                type = bui_type;
                break;
        default:
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto err_inode;
        }
index 4f44370..2efd78a 100644 (file)
@@ -53,15 +53,16 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
  */
 int
 xfs_zero_extent(
-       struct xfs_inode *ip,
-       xfs_fsblock_t   start_fsb,
-       xfs_off_t       count_fsb)
+       struct xfs_inode        *ip,
+       xfs_fsblock_t           start_fsb,
+       xfs_off_t               count_fsb)
 {
-       struct xfs_mount *mp = ip->i_mount;
-       xfs_daddr_t     sector = xfs_fsb_to_db(ip, start_fsb);
-       sector_t        block = XFS_BB_TO_FSBT(mp, sector);
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
+       xfs_daddr_t             sector = xfs_fsb_to_db(ip, start_fsb);
+       sector_t                block = XFS_BB_TO_FSBT(mp, sector);
 
-       return blkdev_issue_zeroout(xfs_find_bdev_for_inode(VFS_I(ip)),
+       return blkdev_issue_zeroout(target->bt_bdev,
                block << (mp->m_super->s_blocksize_bits - 9),
                count_fsb << (mp->m_super->s_blocksize_bits - 9),
                GFP_NOFS, 0);
@@ -164,13 +165,6 @@ xfs_bmap_rtalloc(
                xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
                        ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
                                        XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
-
-               /* Zero the extent if we were asked to do so */
-               if (ap->datatype & XFS_ALLOC_USERDATA_ZERO) {
-                       error = xfs_zero_extent(ap->ip, ap->blkno, ap->length);
-                       if (error)
-                               return error;
-               }
        } else {
                ap->length = 0;
        }
@@ -178,29 +172,6 @@ xfs_bmap_rtalloc(
 }
 #endif /* CONFIG_XFS_RT */
 
-/*
- * Check if the endoff is outside the last extent. If so the caller will grow
- * the allocation to a stripe unit boundary.  All offsets are considered outside
- * the end of file for an empty fork, so 1 is returned in *eof in that case.
- */
-int
-xfs_bmap_eof(
-       struct xfs_inode        *ip,
-       xfs_fileoff_t           endoff,
-       int                     whichfork,
-       int                     *eof)
-{
-       struct xfs_bmbt_irec    rec;
-       int                     error;
-
-       error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof);
-       if (error || *eof)
-               return error;
-
-       *eof = endoff >= rec.br_startoff + rec.br_blockcount;
-       return 0;
-}
-
 /*
  * Extent tree block counting routines.
  */
@@ -228,106 +199,6 @@ xfs_bmap_count_leaves(
        return numrecs;
 }
 
-/*
- * Count leaf blocks given a range of extent records originally
- * in btree format.
- */
-STATIC void
-xfs_bmap_disk_count_leaves(
-       struct xfs_mount        *mp,
-       struct xfs_btree_block  *block,
-       int                     numrecs,
-       xfs_filblks_t           *count)
-{
-       int             b;
-       xfs_bmbt_rec_t  *frp;
-
-       for (b = 1; b <= numrecs; b++) {
-               frp = XFS_BMBT_REC_ADDR(mp, block, b);
-               *count += xfs_bmbt_disk_get_blockcount(frp);
-       }
-}
-
-/*
- * Recursively walks each level of a btree
- * to count total fsblocks in use.
- */
-STATIC int
-xfs_bmap_count_tree(
-       struct xfs_mount        *mp,
-       struct xfs_trans        *tp,
-       struct xfs_ifork        *ifp,
-       xfs_fsblock_t           blockno,
-       int                     levelin,
-       xfs_extnum_t            *nextents,
-       xfs_filblks_t           *count)
-{
-       int                     error;
-       struct xfs_buf          *bp, *nbp;
-       int                     level = levelin;
-       __be64                  *pp;
-       xfs_fsblock_t           bno = blockno;
-       xfs_fsblock_t           nextbno;
-       struct xfs_btree_block  *block, *nextblock;
-       int                     numrecs;
-
-       error = xfs_btree_read_bufl(mp, tp, bno, &bp, XFS_BMAP_BTREE_REF,
-                                               &xfs_bmbt_buf_ops);
-       if (error)
-               return error;
-       *count += 1;
-       block = XFS_BUF_TO_BLOCK(bp);
-
-       if (--level) {
-               /* Not at node above leaves, count this level of nodes */
-               nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
-               while (nextbno != NULLFSBLOCK) {
-                       error = xfs_btree_read_bufl(mp, tp, nextbno, &nbp,
-                                               XFS_BMAP_BTREE_REF,
-                                               &xfs_bmbt_buf_ops);
-                       if (error)
-                               return error;
-                       *count += 1;
-                       nextblock = XFS_BUF_TO_BLOCK(nbp);
-                       nextbno = be64_to_cpu(nextblock->bb_u.l.bb_rightsib);
-                       xfs_trans_brelse(tp, nbp);
-               }
-
-               /* Dive to the next level */
-               pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
-               bno = be64_to_cpu(*pp);
-               error = xfs_bmap_count_tree(mp, tp, ifp, bno, level, nextents,
-                               count);
-               if (error) {
-                       xfs_trans_brelse(tp, bp);
-                       XFS_ERROR_REPORT("xfs_bmap_count_tree(1)",
-                                        XFS_ERRLEVEL_LOW, mp);
-                       return -EFSCORRUPTED;
-               }
-               xfs_trans_brelse(tp, bp);
-       } else {
-               /* count all level 1 nodes and their leaves */
-               for (;;) {
-                       nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
-                       numrecs = be16_to_cpu(block->bb_numrecs);
-                       (*nextents) += numrecs;
-                       xfs_bmap_disk_count_leaves(mp, block, numrecs, count);
-                       xfs_trans_brelse(tp, bp);
-                       if (nextbno == NULLFSBLOCK)
-                               break;
-                       bno = nextbno;
-                       error = xfs_btree_read_bufl(mp, tp, bno, &bp,
-                                               XFS_BMAP_BTREE_REF,
-                                               &xfs_bmbt_buf_ops);
-                       if (error)
-                               return error;
-                       *count += 1;
-                       block = XFS_BUF_TO_BLOCK(bp);
-               }
-       }
-       return 0;
-}
-
 /*
  * Count fsblocks of the given fork.  Delayed allocation extents are
  * not counted towards the totals.
@@ -340,26 +211,19 @@ xfs_bmap_count_blocks(
        xfs_extnum_t            *nextents,
        xfs_filblks_t           *count)
 {
-       struct xfs_mount        *mp;    /* file system mount structure */
-       __be64                  *pp;    /* pointer to block address */
-       struct xfs_btree_block  *block; /* current btree block */
-       struct xfs_ifork        *ifp;   /* fork structure */
-       xfs_fsblock_t           bno;    /* block # of "block" */
-       int                     level;  /* btree level, for checking */
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_btree_cur    *cur;
+       xfs_extlen_t            btblocks = 0;
        int                     error;
 
-       bno = NULLFSBLOCK;
-       mp = ip->i_mount;
        *nextents = 0;
        *count = 0;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
+
        if (!ifp)
                return 0;
 
        switch (XFS_IFORK_FORMAT(ip, whichfork)) {
-       case XFS_DINODE_FMT_EXTENTS:
-               *nextents = xfs_bmap_count_leaves(ifp, count);
-               return 0;
        case XFS_DINODE_FMT_BTREE:
                if (!(ifp->if_flags & XFS_IFEXTENTS)) {
                        error = xfs_iread_extents(tp, ip, whichfork);
@@ -367,26 +231,23 @@ xfs_bmap_count_blocks(
                                return error;
                }
 
+               cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
+               error = xfs_btree_count_blocks(cur, &btblocks);
+               xfs_btree_del_cursor(cur, error);
+               if (error)
+                       return error;
+
                /*
-                * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
+                * xfs_btree_count_blocks includes the root block contained in
+                * the inode fork in @btblocks, so subtract one because we're
+                * only interested in allocated disk blocks.
                 */
-               block = ifp->if_broot;
-               level = be16_to_cpu(block->bb_level);
-               ASSERT(level > 0);
-               pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
-               bno = be64_to_cpu(*pp);
-               ASSERT(bno != NULLFSBLOCK);
-               ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
-               ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
-
-               error = xfs_bmap_count_tree(mp, tp, ifp, bno, level,
-                               nextents, count);
-               if (error) {
-                       XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)",
-                                       XFS_ERRLEVEL_LOW, mp);
-                       return -EFSCORRUPTED;
-               }
-               return 0;
+               *count += btblocks - 1;
+
+               /* fall through */
+       case XFS_DINODE_FMT_EXTENTS:
+               *nextents = xfs_bmap_count_leaves(ifp, count);
+               break;
        }
 
        return 0;
@@ -964,8 +825,8 @@ xfs_alloc_file_space(
                xfs_trans_ijoin(tp, ip, 0);
 
                error = xfs_bmapi_write(tp, ip, startoffset_fsb,
-                                       allocatesize_fsb, alloc_type, resblks,
-                                       imapp, &nimaps);
+                                       allocatesize_fsb, alloc_type, 0, imapp,
+                                       &nimaps);
                if (error)
                        goto error0;
 
@@ -1039,6 +900,7 @@ out_trans_cancel:
        goto out_unlock;
 }
 
+/* Caller must first wait for the completion of any pending DIOs if required. */
 int
 xfs_flush_unmap_range(
        struct xfs_inode        *ip,
@@ -1050,9 +912,6 @@ xfs_flush_unmap_range(
        xfs_off_t               rounding, start, end;
        int                     error;
 
-       /* wait for the completion of any pending DIOs */
-       inode_dio_wait(inode);
-
        rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE);
        start = round_down(offset, rounding);
        end = round_up(offset + len, rounding) - 1;
@@ -1084,10 +943,6 @@ xfs_free_file_space(
        if (len <= 0)   /* if nothing being freed */
                return 0;
 
-       error = xfs_flush_unmap_range(ip, offset, len);
-       if (error)
-               return error;
-
        startoffset_fsb = XFS_B_TO_FSB(mp, offset);
        endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
 
@@ -1113,7 +968,8 @@ xfs_free_file_space(
                return 0;
        if (offset + len > XFS_ISIZE(ip))
                len = XFS_ISIZE(ip) - offset;
-       error = iomap_zero_range(VFS_I(ip), offset, len, NULL, &xfs_iomap_ops);
+       error = iomap_zero_range(VFS_I(ip), offset, len, NULL,
+                       &xfs_buffered_write_iomap_ops);
        if (error)
                return error;
 
@@ -1131,43 +987,6 @@ xfs_free_file_space(
        return error;
 }
 
-/*
- * Preallocate and zero a range of a file. This mechanism has the allocation
- * semantics of fallocate and in addition converts data in the range to zeroes.
- */
-int
-xfs_zero_file_space(
-       struct xfs_inode        *ip,
-       xfs_off_t               offset,
-       xfs_off_t               len)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       uint                    blksize;
-       int                     error;
-
-       trace_xfs_zero_file_space(ip);
-
-       blksize = 1 << mp->m_sb.sb_blocklog;
-
-       /*
-        * Punch a hole and prealloc the range. We use hole punch rather than
-        * unwritten extent conversion for two reasons:
-        *
-        * 1.) Hole punch handles partial block zeroing for us.
-        *
-        * 2.) If prealloc returns ENOSPC, the file range is still zero-valued
-        * by virtue of the hole punch.
-        */
-       error = xfs_free_file_space(ip, offset, len);
-       if (error || xfs_is_always_cow_inode(ip))
-               return error;
-
-       return xfs_alloc_file_space(ip, round_down(offset, blksize),
-                                    round_up(offset + len, blksize) -
-                                    round_down(offset, blksize),
-                                    XFS_BMAPI_PREALLOC);
-}
-
 static int
 xfs_prepare_shift(
        struct xfs_inode        *ip,
@@ -1750,6 +1569,14 @@ xfs_swap_extents(
                goto out_unlock;
        }
 
+       error = xfs_qm_dqattach(ip);
+       if (error)
+               goto out_unlock;
+
+       error = xfs_qm_dqattach(tip);
+       if (error)
+               goto out_unlock;
+
        error = xfs_swap_extent_flush(ip);
        if (error)
                goto out_unlock;
index 7a78229..9f99316 100644 (file)
@@ -30,8 +30,6 @@ xfs_bmap_rtalloc(struct xfs_bmalloca *ap)
 }
 #endif /* CONFIG_XFS_RT */
 
-int    xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
-                    int whichfork, int *eof);
 int    xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
                xfs_fileoff_t start_fsb, xfs_fileoff_t length);
 
@@ -59,8 +57,6 @@ int   xfs_alloc_file_space(struct xfs_inode *ip, xfs_off_t offset,
                             xfs_off_t len, int alloc_type);
 int    xfs_free_file_space(struct xfs_inode *ip, xfs_off_t offset,
                            xfs_off_t len);
-int    xfs_zero_file_space(struct xfs_inode *ip, xfs_off_t offset,
-                           xfs_off_t len);
 int    xfs_collapse_file_space(struct xfs_inode *, xfs_off_t offset,
                                xfs_off_t len);
 int    xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset,
index 0abba17..a0229c3 100644 (file)
@@ -238,7 +238,7 @@ _xfs_buf_alloc(
         */
        error = xfs_buf_get_maps(bp, nmaps);
        if (error)  {
-               kmem_zone_free(xfs_buf_zone, bp);
+               kmem_cache_free(xfs_buf_zone, bp);
                return NULL;
        }
 
@@ -304,7 +304,7 @@ _xfs_buf_free_pages(
  *     The buffer must not be on any hash - use xfs_buf_rele instead for
  *     hashed and refcounted buffers
  */
-void
+static void
 xfs_buf_free(
        xfs_buf_t               *bp)
 {
@@ -328,7 +328,7 @@ xfs_buf_free(
                kmem_free(bp->b_addr);
        _xfs_buf_free_pages(bp);
        xfs_buf_free_maps(bp);
-       kmem_zone_free(xfs_buf_zone, bp);
+       kmem_cache_free(xfs_buf_zone, bp);
 }
 
 /*
@@ -461,7 +461,7 @@ _xfs_buf_map_pages(
                unsigned nofs_flag;
 
                /*
-                * vm_map_ram() will allocate auxillary structures (e.g.
+                * vm_map_ram() will allocate auxiliary structures (e.g.
                 * pagetables) with GFP_KERNEL, yet we are likely to be under
                 * GFP_NOFS context here. Hence we need to tell memory reclaim
                 * that we are in such a context via PF_MEMALLOC_NOFS to prevent
@@ -949,7 +949,7 @@ xfs_buf_get_uncached(
        _xfs_buf_free_pages(bp);
  fail_free_buf:
        xfs_buf_free_maps(bp);
-       kmem_zone_free(xfs_buf_zone, bp);
+       kmem_cache_free(xfs_buf_zone, bp);
  fail:
        return NULL;
 }
@@ -1261,8 +1261,7 @@ xfs_buf_ioapply_map(
        int             map,
        int             *buf_offset,
        int             *count,
-       int             op,
-       int             op_flags)
+       int             op)
 {
        int             page_index;
        int             total_nr_pages = bp->b_page_count;
@@ -1297,7 +1296,7 @@ next_chunk:
        bio->bi_iter.bi_sector = sector;
        bio->bi_end_io = xfs_buf_bio_end_io;
        bio->bi_private = bp;
-       bio_set_op_attrs(bio, op, op_flags);
+       bio->bi_opf = op;
 
        for (; size && nr_pages; nr_pages--, page_index++) {
                int     rbytes, nbytes = PAGE_SIZE - offset;
@@ -1342,7 +1341,6 @@ _xfs_buf_ioapply(
 {
        struct blk_plug plug;
        int             op;
-       int             op_flags = 0;
        int             offset;
        int             size;
        int             i;
@@ -1384,15 +1382,14 @@ _xfs_buf_ioapply(
                                dump_stack();
                        }
                }
-       } else if (bp->b_flags & XBF_READ_AHEAD) {
-               op = REQ_OP_READ;
-               op_flags = REQ_RAHEAD;
        } else {
                op = REQ_OP_READ;
+               if (bp->b_flags & XBF_READ_AHEAD)
+                       op |= REQ_RAHEAD;
        }
 
        /* we only use the buffer cache for meta-data */
-       op_flags |= REQ_META;
+       op |= REQ_META;
 
        /*
         * Walk all the vectors issuing IO on them. Set up the initial offset
@@ -1404,7 +1401,7 @@ _xfs_buf_ioapply(
        size = BBTOB(bp->b_length);
        blk_start_plug(&plug);
        for (i = 0; i < bp->b_map_count; i++) {
-               xfs_buf_ioapply_map(bp, i, &offset, &size, op, op_flags);
+               xfs_buf_ioapply_map(bp, i, &offset, &size, op);
                if (bp->b_error)
                        break;
                if (size <= 0)
@@ -2063,8 +2060,9 @@ xfs_buf_delwri_pushbuf(
 int __init
 xfs_buf_init(void)
 {
-       xfs_buf_zone = kmem_zone_init_flags(sizeof(xfs_buf_t), "xfs_buf",
-                                               KM_ZONE_HWALIGN, NULL);
+       xfs_buf_zone = kmem_cache_create("xfs_buf",
+                                        sizeof(struct xfs_buf), 0,
+                                        SLAB_HWCACHE_ALIGN, NULL);
        if (!xfs_buf_zone)
                goto out;
 
@@ -2077,7 +2075,7 @@ xfs_buf_init(void)
 void
 xfs_buf_terminate(void)
 {
-       kmem_zone_destroy(xfs_buf_zone);
+       kmem_cache_destroy(xfs_buf_zone);
 }
 
 void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
index f6ce17d..56e081d 100644 (file)
@@ -244,7 +244,6 @@ int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr,
 void xfs_buf_hold(struct xfs_buf *bp);
 
 /* Releasing Buffers */
-extern void xfs_buf_free(xfs_buf_t *);
 extern void xfs_buf_rele(xfs_buf_t *);
 
 /* Locking and Unlocking Buffers */
index d74fbd1..3458a12 100644 (file)
@@ -763,7 +763,7 @@ xfs_buf_item_init(
        error = xfs_buf_item_get_format(bip, bp->b_map_count);
        ASSERT(error == 0);
        if (error) {    /* to stop gcc throwing set-but-unused warnings */
-               kmem_zone_free(xfs_buf_item_zone, bip);
+               kmem_cache_free(xfs_buf_item_zone, bip);
                return error;
        }
 
@@ -851,7 +851,7 @@ xfs_buf_item_log_segment(
         * first_bit and last_bit.
         */
        while ((bits_to_set - bits_set) >= NBWORD) {
-               *wordp |= 0xffffffff;
+               *wordp = 0xffffffff;
                bits_set += NBWORD;
                wordp++;
        }
@@ -939,7 +939,7 @@ xfs_buf_item_free(
 {
        xfs_buf_item_free_format(bip);
        kmem_free(bip->bli_item.li_lv_shadow);
-       kmem_zone_free(xfs_buf_item_zone, bip);
+       kmem_cache_free(xfs_buf_item_zone, bip);
 }
 
 /*
index 283df89..0d3b640 100644 (file)
@@ -17,6 +17,7 @@
 #include "xfs_trace.h"
 #include "xfs_bmap.h"
 #include "xfs_trans.h"
+#include "xfs_error.h"
 
 /*
  * Directory file type support functions
@@ -47,6 +48,7 @@ xfs_dir2_sf_getdents(
 {
        int                     i;              /* shortform entry number */
        struct xfs_inode        *dp = args->dp; /* incore directory inode */
+       struct xfs_mount        *mp = dp->i_mount;
        xfs_dir2_dataptr_t      off;            /* current entry's offset */
        xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
@@ -68,15 +70,15 @@ xfs_dir2_sf_getdents(
                return 0;
 
        /*
-        * Precalculate offsets for . and .. as we will always need them.
-        *
-        * XXX(hch): the second argument is sometimes 0 and sometimes
-        * geo->datablk
+        * Precalculate offsets for "." and ".." as we will always need them.
+        * This relies on the fact that directories always start with the
+        * entries for "." and "..".
         */
        dot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
-                                               dp->d_ops->data_dot_offset);
+                       geo->data_entry_offset);
        dotdot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
-                                               dp->d_ops->data_dotdot_offset);
+                       geo->data_entry_offset +
+                       xfs_dir2_data_entsize(mp, sizeof(".") - 1));
 
        /*
         * Put . entry unless we're starting past it.
@@ -91,7 +93,7 @@ xfs_dir2_sf_getdents(
         * Put .. entry unless we're starting past it.
         */
        if (ctx->pos <= dotdot_offset) {
-               ino = dp->d_ops->sf_get_parent_ino(sfp);
+               ino = xfs_dir2_sf_get_parent_ino(sfp);
                ctx->pos = dotdot_offset & 0x7fffffff;
                if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
                        return 0;
@@ -108,17 +110,21 @@ xfs_dir2_sf_getdents(
                                xfs_dir2_sf_get_offset(sfep));
 
                if (ctx->pos > off) {
-                       sfep = dp->d_ops->sf_nextentry(sfp, sfep);
+                       sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
                        continue;
                }
 
-               ino = dp->d_ops->sf_get_ino(sfp, sfep);
-               filetype = dp->d_ops->sf_get_ftype(sfep);
+               ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
+               filetype = xfs_dir2_sf_get_ftype(mp, sfep);
                ctx->pos = off & 0x7fffffff;
+               if (XFS_IS_CORRUPT(dp->i_mount,
+                                  !xfs_dir2_namecheck(sfep->name,
+                                                      sfep->namelen)))
+                       return -EFSCORRUPTED;
                if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
-                           xfs_dir3_get_dtype(dp->i_mount, filetype)))
+                           xfs_dir3_get_dtype(mp, filetype)))
                        return 0;
-               sfep = dp->d_ops->sf_nextentry(sfp, sfep);
+               sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
        }
 
        ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
@@ -135,17 +141,14 @@ xfs_dir2_block_getdents(
        struct dir_context      *ctx)
 {
        struct xfs_inode        *dp = args->dp; /* incore directory inode */
-       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        struct xfs_buf          *bp;            /* buffer for block */
-       xfs_dir2_data_entry_t   *dep;           /* block data entry */
-       xfs_dir2_data_unused_t  *dup;           /* block unused entry */
-       char                    *endptr;        /* end of the data entries */
        int                     error;          /* error return value */
-       char                    *ptr;           /* current data entry */
        int                     wantoff;        /* starting block offset */
        xfs_off_t               cook;
        struct xfs_da_geometry  *geo = args->geo;
        int                     lock_mode;
+       unsigned int            offset;
+       unsigned int            end;
 
        /*
         * If the block number in the offset is out of range, we're done.
@@ -164,56 +167,55 @@ xfs_dir2_block_getdents(
         * We'll skip entries before this.
         */
        wantoff = xfs_dir2_dataptr_to_off(geo, ctx->pos);
-       hdr = bp->b_addr;
        xfs_dir3_data_check(dp, bp);
-       /*
-        * Set up values for the loop.
-        */
-       ptr = (char *)dp->d_ops->data_entry_p(hdr);
-       endptr = xfs_dir3_data_endp(geo, hdr);
 
        /*
         * Loop over the data portion of the block.
         * Each object is a real entry (dep) or an unused one (dup).
         */
-       while (ptr < endptr) {
+       offset = geo->data_entry_offset;
+       end = xfs_dir3_data_end_offset(geo, bp->b_addr);
+       while (offset < end) {
+               struct xfs_dir2_data_unused     *dup = bp->b_addr + offset;
+               struct xfs_dir2_data_entry      *dep = bp->b_addr + offset;
                uint8_t filetype;
 
-               dup = (xfs_dir2_data_unused_t *)ptr;
                /*
                 * Unused, skip it.
                 */
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-                       ptr += be16_to_cpu(dup->length);
+                       offset += be16_to_cpu(dup->length);
                        continue;
                }
 
-               dep = (xfs_dir2_data_entry_t *)ptr;
-
                /*
                 * Bump pointer for the next iteration.
                 */
-               ptr += dp->d_ops->data_entsize(dep->namelen);
+               offset += xfs_dir2_data_entsize(dp->i_mount, dep->namelen);
+
                /*
                 * The entry is before the desired starting point, skip it.
                 */
-               if ((char *)dep - (char *)hdr < wantoff)
+               if (offset < wantoff)
                        continue;
 
-               cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
-                                           (char *)dep - (char *)hdr);
+               cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, offset);
 
                ctx->pos = cook & 0x7fffffff;
-               filetype = dp->d_ops->data_get_ftype(dep);
+               filetype = xfs_dir2_data_get_ftype(dp->i_mount, dep);
                /*
                 * If it didn't fit, set the final offset to here & return.
                 */
+               if (XFS_IS_CORRUPT(dp->i_mount,
+                                  !xfs_dir2_namecheck(dep->name,
+                                                      dep->namelen))) {
+                       error = -EFSCORRUPTED;
+                       goto out_rele;
+               }
                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
                            be64_to_cpu(dep->inumber),
-                           xfs_dir3_get_dtype(dp->i_mount, filetype))) {
-                       xfs_trans_brelse(args->trans, bp);
-                       return 0;
-               }
+                           xfs_dir3_get_dtype(dp->i_mount, filetype)))
+                       goto out_rele;
        }
 
        /*
@@ -222,8 +224,9 @@ xfs_dir2_block_getdents(
         */
        ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
                                                                0x7fffffff;
+out_rele:
        xfs_trans_brelse(args->trans, bp);
-       return 0;
+       return error;
 }
 
 /*
@@ -276,7 +279,7 @@ xfs_dir2_leaf_readbuf(
        new_off = xfs_dir2_da_to_byte(geo, map.br_startoff);
        if (new_off > *cur_off)
                *cur_off = new_off;
-       error = xfs_dir3_data_read(args->trans, dp, map.br_startoff, -1, &bp);
+       error = xfs_dir3_data_read(args->trans, dp, map.br_startoff, 0, &bp);
        if (error)
                goto out;
 
@@ -311,7 +314,8 @@ xfs_dir2_leaf_readbuf(
                                break;
                        }
                        if (next_ra > *ra_blk) {
-                               xfs_dir3_data_readahead(dp, next_ra, -2);
+                               xfs_dir3_data_readahead(dp, next_ra,
+                                                       XFS_DABUF_MAP_HOLE_OK);
                                *ra_blk = next_ra;
                        }
                        ra_want -= geo->fsbcount;
@@ -343,17 +347,17 @@ xfs_dir2_leaf_getdents(
        size_t                  bufsize)
 {
        struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
        struct xfs_buf          *bp = NULL;     /* data block buffer */
-       xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_data_entry_t   *dep;           /* data entry */
        xfs_dir2_data_unused_t  *dup;           /* unused entry */
-       char                    *ptr = NULL;    /* pointer to current data */
        struct xfs_da_geometry  *geo = args->geo;
        xfs_dablk_t             rablk = 0;      /* current readahead block */
        xfs_dir2_off_t          curoff;         /* current overall offset */
        int                     length;         /* temporary length value */
        int                     byteoff;        /* offset in current block */
        int                     lock_mode;
+       unsigned int            offset = 0;
        int                     error = 0;      /* error return value */
 
        /*
@@ -380,7 +384,7 @@ xfs_dir2_leaf_getdents(
                 * If we have no buffer, or we're off the end of the
                 * current buffer, need to get another one.
                 */
-               if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) {
+               if (!bp || offset >= geo->blksize) {
                        if (bp) {
                                xfs_trans_brelse(args->trans, bp);
                                bp = NULL;
@@ -393,36 +397,35 @@ xfs_dir2_leaf_getdents(
                        if (error || !bp)
                                break;
 
-                       hdr = bp->b_addr;
                        xfs_dir3_data_check(dp, bp);
                        /*
                         * Find our position in the block.
                         */
-                       ptr = (char *)dp->d_ops->data_entry_p(hdr);
+                       offset = geo->data_entry_offset;
                        byteoff = xfs_dir2_byte_to_off(geo, curoff);
                        /*
                         * Skip past the header.
                         */
                        if (byteoff == 0)
-                               curoff += dp->d_ops->data_entry_offset;
+                               curoff += geo->data_entry_offset;
                        /*
                         * Skip past entries until we reach our offset.
                         */
                        else {
-                               while ((char *)ptr - (char *)hdr < byteoff) {
-                                       dup = (xfs_dir2_data_unused_t *)ptr;
+                               while (offset < byteoff) {
+                                       dup = bp->b_addr + offset;
 
                                        if (be16_to_cpu(dup->freetag)
                                                  == XFS_DIR2_DATA_FREE_TAG) {
 
                                                length = be16_to_cpu(dup->length);
-                                               ptr += length;
+                                               offset += length;
                                                continue;
                                        }
-                                       dep = (xfs_dir2_data_entry_t *)ptr;
-                                       length =
-                                          dp->d_ops->data_entsize(dep->namelen);
-                                       ptr += length;
+                                       dep = bp->b_addr + offset;
+                                       length = xfs_dir2_data_entsize(mp,
+                                                       dep->namelen);
+                                       offset += length;
                                }
                                /*
                                 * Now set our real offset.
@@ -430,32 +433,38 @@ xfs_dir2_leaf_getdents(
                                curoff =
                                        xfs_dir2_db_off_to_byte(geo,
                                            xfs_dir2_byte_to_db(geo, curoff),
-                                           (char *)ptr - (char *)hdr);
-                               if (ptr >= (char *)hdr + geo->blksize) {
+                                           offset);
+                               if (offset >= geo->blksize)
                                        continue;
-                               }
                        }
                }
+
                /*
-                * We have a pointer to an entry.
-                * Is it a live one?
+                * We have a pointer to an entry.  Is it a live one?
                 */
-               dup = (xfs_dir2_data_unused_t *)ptr;
+               dup = bp->b_addr + offset;
+
                /*
                 * No, it's unused, skip over it.
                 */
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
                        length = be16_to_cpu(dup->length);
-                       ptr += length;
+                       offset += length;
                        curoff += length;
                        continue;
                }
 
-               dep = (xfs_dir2_data_entry_t *)ptr;
-               length = dp->d_ops->data_entsize(dep->namelen);
-               filetype = dp->d_ops->data_get_ftype(dep);
+               dep = bp->b_addr + offset;
+               length = xfs_dir2_data_entsize(mp, dep->namelen);
+               filetype = xfs_dir2_data_get_ftype(mp, dep);
 
                ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
+               if (XFS_IS_CORRUPT(dp->i_mount,
+                                  !xfs_dir2_namecheck(dep->name,
+                                                      dep->namelen))) {
+                       error = -EFSCORRUPTED;
+                       break;
+               }
                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
                            be64_to_cpu(dep->inumber),
                            xfs_dir3_get_dtype(dp->i_mount, filetype)))
@@ -464,7 +473,7 @@ xfs_dir2_leaf_getdents(
                /*
                 * Advance to next entry in the block.
                 */
-               ptr += length;
+               offset += length;
                curoff += length;
                /* bufsize may have just been a guess; don't go negative */
                bufsize = bufsize > length ? bufsize - length : 0;
index 8ec7aab..cae6136 100644 (file)
@@ -13,6 +13,7 @@
 #include "xfs_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_alloc.h"
+#include "xfs_discard.h"
 #include "xfs_error.h"
 #include "xfs_extent_busy.h"
 #include "xfs_trace.h"
@@ -70,7 +71,10 @@ xfs_trim_extents(
                error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
                if (error)
                        goto out_del_cursor;
-               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_del_cursor);
+               if (XFS_IS_CORRUPT(mp, i != 1)) {
+                       error = -EFSCORRUPTED;
+                       goto out_del_cursor;
+               }
                ASSERT(flen <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest));
 
                /*
index aeb95e7..2bff21c 100644 (file)
@@ -48,7 +48,7 @@ static struct lock_class_key xfs_dquot_project_class;
  */
 void
 xfs_qm_dqdestroy(
-       xfs_dquot_t     *dqp)
+       struct xfs_dquot        *dqp)
 {
        ASSERT(list_empty(&dqp->q_lru));
 
@@ -56,7 +56,7 @@ xfs_qm_dqdestroy(
        mutex_destroy(&dqp->q_qlock);
 
        XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot);
-       kmem_zone_free(xfs_qm_dqzone, dqp);
+       kmem_cache_free(xfs_qm_dqzone, dqp);
 }
 
 /*
@@ -113,8 +113,8 @@ xfs_qm_adjust_dqlimits(
  */
 void
 xfs_qm_adjust_dqtimers(
-       xfs_mount_t             *mp,
-       xfs_disk_dquot_t        *d)
+       struct xfs_mount        *mp,
+       struct xfs_disk_dquot   *d)
 {
        ASSERT(d->d_id);
 
@@ -305,8 +305,8 @@ xfs_dquot_disk_alloc(
        /* Create the block mapping. */
        xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
        error = xfs_bmapi_write(tp, quotip, dqp->q_fileoffset,
-                       XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA,
-                       XFS_QM_DQALLOC_SPACE_RES(mp), &map, &nmaps);
+                       XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA, 0, &map,
+                       &nmaps);
        if (error)
                return error;
        ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
@@ -497,7 +497,7 @@ xfs_dquot_from_disk(
        struct xfs_disk_dquot   *ddqp = bp->b_addr + dqp->q_bufoffset;
 
        /* copy everything from disk dquot to the incore dquot */
-       memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
+       memcpy(&dqp->q_core, ddqp, sizeof(struct xfs_disk_dquot));
 
        /*
         * Reservation counters are defined as reservation plus current usage
@@ -833,7 +833,7 @@ xfs_qm_id_for_quotatype(
        case XFS_DQ_GROUP:
                return ip->i_d.di_gid;
        case XFS_DQ_PROJ:
-               return xfs_get_projid(ip);
+               return ip->i_d.di_projid;
        }
        ASSERT(0);
        return 0;
@@ -989,7 +989,7 @@ xfs_qm_dqput(
  */
 void
 xfs_qm_dqrele(
-       xfs_dquot_t     *dqp)
+       struct xfs_dquot        *dqp)
 {
        if (!dqp)
                return;
@@ -1018,8 +1018,8 @@ xfs_qm_dqflush_done(
        struct xfs_buf          *bp,
        struct xfs_log_item     *lip)
 {
-       xfs_dq_logitem_t        *qip = (struct xfs_dq_logitem *)lip;
-       xfs_dquot_t             *dqp = qip->qli_dquot;
+       struct xfs_dq_logitem   *qip = (struct xfs_dq_logitem *)lip;
+       struct xfs_dquot        *dqp = qip->qli_dquot;
        struct xfs_ail          *ailp = lip->li_ailp;
 
        /*
@@ -1126,11 +1126,11 @@ xfs_qm_dqflush(
                xfs_buf_relse(bp);
                xfs_dqfunlock(dqp);
                xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /* This is the only portion of data that needs to persist */
-       memcpy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t));
+       memcpy(ddqp, &dqp->q_core, sizeof(struct xfs_disk_dquot));
 
        /*
         * Clear the dirty field and remember the flush lsn for later use.
@@ -1188,8 +1188,8 @@ out_unlock:
  */
 void
 xfs_dqlock2(
-       xfs_dquot_t     *d1,
-       xfs_dquot_t     *d2)
+       struct xfs_dquot        *d1,
+       struct xfs_dquot        *d2)
 {
        if (d1 && d2) {
                ASSERT(d1 != d2);
@@ -1211,20 +1211,22 @@ xfs_dqlock2(
 int __init
 xfs_qm_init(void)
 {
-       xfs_qm_dqzone =
-               kmem_zone_init(sizeof(struct xfs_dquot), "xfs_dquot");
+       xfs_qm_dqzone = kmem_cache_create("xfs_dquot",
+                                         sizeof(struct xfs_dquot),
+                                         0, 0, NULL);
        if (!xfs_qm_dqzone)
                goto out;
 
-       xfs_qm_dqtrxzone =
-               kmem_zone_init(sizeof(struct xfs_dquot_acct), "xfs_dqtrx");
+       xfs_qm_dqtrxzone = kmem_cache_create("xfs_dqtrx",
+                                            sizeof(struct xfs_dquot_acct),
+                                            0, 0, NULL);
        if (!xfs_qm_dqtrxzone)
                goto out_free_dqzone;
 
        return 0;
 
 out_free_dqzone:
-       kmem_zone_destroy(xfs_qm_dqzone);
+       kmem_cache_destroy(xfs_qm_dqzone);
 out:
        return -ENOMEM;
 }
@@ -1232,8 +1234,8 @@ out:
 void
 xfs_qm_exit(void)
 {
-       kmem_zone_destroy(xfs_qm_dqtrxzone);
-       kmem_zone_destroy(xfs_qm_dqzone);
+       kmem_cache_destroy(xfs_qm_dqtrxzone);
+       kmem_cache_destroy(xfs_qm_dqzone);
 }
 
 /*
index 4fe8570..fe3e46d 100644 (file)
@@ -30,33 +30,36 @@ enum {
 /*
  * The incore dquot structure
  */
-typedef struct xfs_dquot {
-       uint             dq_flags;      /* various flags (XFS_DQ_*) */
-       struct list_head q_lru;         /* global free list of dquots */
-       struct xfs_mount*q_mount;       /* filesystem this relates to */
-       uint             q_nrefs;       /* # active refs from inodes */
-       xfs_daddr_t      q_blkno;       /* blkno of dquot buffer */
-       int              q_bufoffset;   /* off of dq in buffer (# dquots) */
-       xfs_fileoff_t    q_fileoffset;  /* offset in quotas file */
-
-       xfs_disk_dquot_t q_core;        /* actual usage & quotas */
-       xfs_dq_logitem_t q_logitem;     /* dquot log item */
-       xfs_qcnt_t       q_res_bcount;  /* total regular nblks used+reserved */
-       xfs_qcnt_t       q_res_icount;  /* total inos allocd+reserved */
-       xfs_qcnt_t       q_res_rtbcount;/* total realtime blks used+reserved */
-       xfs_qcnt_t       q_prealloc_lo_wmark;/* prealloc throttle wmark */
-       xfs_qcnt_t       q_prealloc_hi_wmark;/* prealloc disabled wmark */
-       int64_t          q_low_space[XFS_QLOWSP_MAX];
-       struct mutex     q_qlock;       /* quota lock */
-       struct completion q_flush;      /* flush completion queue */
-       atomic_t          q_pincount;   /* dquot pin count */
-       wait_queue_head_t q_pinwait;    /* dquot pinning wait queue */
-} xfs_dquot_t;
+struct xfs_dquot {
+       uint                    dq_flags;
+       struct list_head        q_lru;
+       struct xfs_mount        *q_mount;
+       uint                    q_nrefs;
+       xfs_daddr_t             q_blkno;
+       int                     q_bufoffset;
+       xfs_fileoff_t           q_fileoffset;
+
+       struct xfs_disk_dquot   q_core;
+       struct xfs_dq_logitem   q_logitem;
+       /* total regular nblks used+reserved */
+       xfs_qcnt_t              q_res_bcount;
+       /* total inos allocd+reserved */
+       xfs_qcnt_t              q_res_icount;
+       /* total realtime blks used+reserved */
+       xfs_qcnt_t              q_res_rtbcount;
+       xfs_qcnt_t              q_prealloc_lo_wmark;
+       xfs_qcnt_t              q_prealloc_hi_wmark;
+       int64_t                 q_low_space[XFS_QLOWSP_MAX];
+       struct mutex            q_qlock;
+       struct completion       q_flush;
+       atomic_t                q_pincount;
+       struct wait_queue_head  q_pinwait;
+};
 
 /*
  * Lock hierarchy for q_qlock:
  *     XFS_QLOCK_NORMAL is the implicit default,
- *     XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2
+ *     XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2
  */
 enum {
        XFS_QLOCK_NORMAL = 0,
@@ -64,21 +67,21 @@ enum {
 };
 
 /*
- * Manage the q_flush completion queue embedded in the dquot.  This completion
+ * Manage the q_flush completion queue embedded in the dquot. This completion
  * queue synchronizes processes attempting to flush the in-core dquot back to
  * disk.
  */
-static inline void xfs_dqflock(xfs_dquot_t *dqp)
+static inline void xfs_dqflock(struct xfs_dquot *dqp)
 {
        wait_for_completion(&dqp->q_flush);
 }
 
-static inline bool xfs_dqflock_nowait(xfs_dquot_t *dqp)
+static inline bool xfs_dqflock_nowait(struct xfs_dquot *dqp)
 {
        return try_wait_for_completion(&dqp->q_flush);
 }
 
-static inline void xfs_dqfunlock(xfs_dquot_t *dqp)
+static inline void xfs_dqfunlock(struct xfs_dquot *dqp)
 {
        complete(&dqp->q_flush);
 }
@@ -112,7 +115,7 @@ static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
        }
 }
 
-static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
+static inline struct xfs_dquot *xfs_inode_dquot(struct xfs_inode *ip, int type)
 {
        switch (type & XFS_DQ_ALLTYPES) {
        case XFS_DQ_USER:
@@ -147,31 +150,30 @@ static inline bool xfs_dquot_lowsp(struct xfs_dquot *dqp)
 #define XFS_QM_ISPDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_PROJ)
 #define XFS_QM_ISGDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_GROUP)
 
-extern void            xfs_qm_dqdestroy(xfs_dquot_t *);
-extern int             xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **);
-extern void            xfs_qm_dqunpin_wait(xfs_dquot_t *);
-extern void            xfs_qm_adjust_dqtimers(xfs_mount_t *,
-                                       xfs_disk_dquot_t *);
-extern void            xfs_qm_adjust_dqlimits(struct xfs_mount *,
-                                              struct xfs_dquot *);
-extern xfs_dqid_t      xfs_qm_id_for_quotatype(struct xfs_inode *ip,
-                                       uint type);
-extern int             xfs_qm_dqget(struct xfs_mount *mp, xfs_dqid_t id,
+void           xfs_qm_dqdestroy(struct xfs_dquot *dqp);
+int            xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf **bpp);
+void           xfs_qm_dqunpin_wait(struct xfs_dquot *dqp);
+void           xfs_qm_adjust_dqtimers(struct xfs_mount *mp,
+                                               struct xfs_disk_dquot *d);
+void           xfs_qm_adjust_dqlimits(struct xfs_mount *mp,
+                                               struct xfs_dquot *d);
+xfs_dqid_t     xfs_qm_id_for_quotatype(struct xfs_inode *ip, uint type);
+int            xfs_qm_dqget(struct xfs_mount *mp, xfs_dqid_t id,
                                        uint type, bool can_alloc,
                                        struct xfs_dquot **dqpp);
-extern int             xfs_qm_dqget_inode(struct xfs_inode *ip, uint type,
-                                       bool can_alloc,
-                                       struct xfs_dquot **dqpp);
-extern int             xfs_qm_dqget_next(struct xfs_mount *mp, xfs_dqid_t id,
+int            xfs_qm_dqget_inode(struct xfs_inode *ip, uint type,
+                                               bool can_alloc,
+                                               struct xfs_dquot **dqpp);
+int            xfs_qm_dqget_next(struct xfs_mount *mp, xfs_dqid_t id,
                                        uint type, struct xfs_dquot **dqpp);
-extern int             xfs_qm_dqget_uncached(struct xfs_mount *mp,
-                                       xfs_dqid_t id, uint type,
-                                       struct xfs_dquot **dqpp);
-extern void            xfs_qm_dqput(xfs_dquot_t *);
+int            xfs_qm_dqget_uncached(struct xfs_mount *mp,
+                                               xfs_dqid_t id, uint type,
+                                               struct xfs_dquot **dqpp);
+void           xfs_qm_dqput(struct xfs_dquot *dqp);
 
-extern void            xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
+void           xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
 
-extern void            xfs_dquot_set_prealloc_limits(struct xfs_dquot *);
+void           xfs_dquot_set_prealloc_limits(struct xfs_dquot *);
 
 static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
 {
index 1aed34c..3bb19e5 100644 (file)
@@ -11,25 +11,27 @@ struct xfs_trans;
 struct xfs_mount;
 struct xfs_qoff_logitem;
 
-typedef struct xfs_dq_logitem {
-       struct xfs_log_item      qli_item;         /* common portion */
-       struct xfs_dquot        *qli_dquot;        /* dquot ptr */
-       xfs_lsn_t                qli_flush_lsn;    /* lsn at last flush */
-} xfs_dq_logitem_t;
+struct xfs_dq_logitem {
+       struct xfs_log_item     qli_item;       /* common portion */
+       struct xfs_dquot        *qli_dquot;     /* dquot ptr */
+       xfs_lsn_t               qli_flush_lsn;  /* lsn at last flush */
+};
 
-typedef struct xfs_qoff_logitem {
-       struct xfs_log_item      qql_item;      /* common portion */
-       struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
+struct xfs_qoff_logitem {
+       struct xfs_log_item     qql_item;       /* common portion */
+       struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
        unsigned int            qql_flags;
-} xfs_qoff_logitem_t;
+};
 
 
-extern void               xfs_qm_dquot_logitem_init(struct xfs_dquot *);
-extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *,
-                                       struct xfs_qoff_logitem *, uint);
-extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *,
-                                       struct xfs_qoff_logitem *, uint);
-extern void               xfs_trans_log_quotaoff_item(struct xfs_trans *,
-                                       struct xfs_qoff_logitem *);
+void xfs_qm_dquot_logitem_init(struct xfs_dquot *dqp);
+struct xfs_qoff_logitem        *xfs_qm_qoff_logitem_init(struct xfs_mount *mp,
+               struct xfs_qoff_logitem *start,
+               uint flags);
+struct xfs_qoff_logitem        *xfs_trans_get_qoff_item(struct xfs_trans *tp,
+               struct xfs_qoff_logitem *startqoff,
+               uint flags);
+void xfs_trans_log_quotaoff_item(struct xfs_trans *tp,
+               struct xfs_qoff_logitem *qlp);
 
 #endif /* __XFS_DQUOT_ITEM_H__ */
index 849fd44..331765a 100644 (file)
@@ -257,7 +257,7 @@ xfs_errortag_test(
 
        xfs_warn_ratelimited(mp,
 "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
-                       expression, file, line, mp->m_fsname);
+                       expression, file, line, mp->m_super->s_id);
        return true;
 }
 
@@ -329,18 +329,39 @@ xfs_corruption_error(
        const char              *tag,
        int                     level,
        struct xfs_mount        *mp,
-       void                    *buf,
+       const void              *buf,
        size_t                  bufsize,
        const char              *filename,
        int                     linenum,
        xfs_failaddr_t          failaddr)
 {
-       if (level <= xfs_error_level)
+       if (buf && level <= xfs_error_level)
                xfs_hex_dump(buf, bufsize);
        xfs_error_report(tag, level, mp, filename, linenum, failaddr);
        xfs_alert(mp, "Corruption detected. Unmount and run xfs_repair");
 }
 
+/*
+ * Complain about the kinds of metadata corruption that we can't detect from a
+ * verifier, such as incorrect inter-block relationship data.  Does not set
+ * bp->b_error.
+ */
+void
+xfs_buf_corruption_error(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_mount;
+
+       xfs_alert_tag(mp, XFS_PTAG_VERIFIER_ERROR,
+                 "Metadata corruption detected at %pS, %s block 0x%llx",
+                 __return_address, bp->b_ops->name, bp->b_bn);
+
+       xfs_alert(mp, "Unmount and run xfs_repair");
+
+       if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
+               xfs_stack_trace();
+}
+
 /*
  * Warnings specifically for verifier errors.  Differentiate CRC vs. invalid
  * values, and omit the stack trace unless the error level is tuned high.
@@ -350,7 +371,7 @@ xfs_buf_verifier_error(
        struct xfs_buf          *bp,
        int                     error,
        const char              *name,
-       void                    *buf,
+       const void              *buf,
        size_t                  bufsz,
        xfs_failaddr_t          failaddr)
 {
@@ -402,7 +423,7 @@ xfs_inode_verifier_error(
        struct xfs_inode        *ip,
        int                     error,
        const char              *name,
-       void                    *buf,
+       const void              *buf,
        size_t                  bufsz,
        xfs_failaddr_t          failaddr)
 {
index 602aa7d..31a5d32 100644 (file)
@@ -12,16 +12,17 @@ extern void xfs_error_report(const char *tag, int level, struct xfs_mount *mp,
                        const char *filename, int linenum,
                        xfs_failaddr_t failaddr);
 extern void xfs_corruption_error(const char *tag, int level,
-                       struct xfs_mount *mp, void *buf, size_t bufsize,
+                       struct xfs_mount *mp, const void *buf, size_t bufsize,
                        const char *filename, int linenum,
                        xfs_failaddr_t failaddr);
+void xfs_buf_corruption_error(struct xfs_buf *bp);
 extern void xfs_buf_verifier_error(struct xfs_buf *bp, int error,
-                       const char *name, void *buf, size_t bufsz,
+                       const char *name, const void *buf, size_t bufsz,
                        xfs_failaddr_t failaddr);
 extern void xfs_verifier_error(struct xfs_buf *bp, int error,
                        xfs_failaddr_t failaddr);
 extern void xfs_inode_verifier_error(struct xfs_inode *ip, int error,
-                       const char *name, void *buf, size_t bufsz,
+                       const char *name, const void *buf, size_t bufsz,
                        xfs_failaddr_t failaddr);
 
 #define        XFS_ERROR_REPORT(e, lvl, mp)    \
@@ -37,32 +38,6 @@ extern void xfs_inode_verifier_error(struct xfs_inode *ip, int error,
 /* Dump 128 bytes of any corrupt buffer */
 #define XFS_CORRUPTION_DUMP_LEN                (128)
 
-/*
- * Macros to set EFSCORRUPTED & return/branch.
- */
-#define        XFS_WANT_CORRUPTED_GOTO(mp, x, l)       \
-       { \
-               int fs_is_ok = (x); \
-               ASSERT(fs_is_ok); \
-               if (unlikely(!fs_is_ok)) { \
-                       XFS_ERROR_REPORT("XFS_WANT_CORRUPTED_GOTO", \
-                                        XFS_ERRLEVEL_LOW, mp); \
-                       error = -EFSCORRUPTED; \
-                       goto l; \
-               } \
-       }
-
-#define        XFS_WANT_CORRUPTED_RETURN(mp, x)        \
-       { \
-               int fs_is_ok = (x); \
-               ASSERT(fs_is_ok); \
-               if (unlikely(!fs_is_ok)) { \
-                       XFS_ERROR_REPORT("XFS_WANT_CORRUPTED_RETURN", \
-                                        XFS_ERRLEVEL_LOW, mp); \
-                       return -EFSCORRUPTED; \
-               } \
-       }
-
 #ifdef DEBUG
 extern int xfs_errortag_init(struct xfs_mount *mp);
 extern void xfs_errortag_del(struct xfs_mount *mp);
index 2183d87..3991e59 100644 (file)
@@ -367,7 +367,7 @@ restart:
                 * If this is a metadata allocation, try to reuse the busy
                 * extent instead of trimming the allocation.
                 */
-               if (!xfs_alloc_is_userdata(args->datatype) &&
+               if (!(args->datatype & XFS_ALLOC_USERDATA) &&
                    !(busyp->flags & XFS_EXTENT_BUSY_DISCARDED)) {
                        if (!xfs_extent_busy_update_extent(args->mp, args->pag,
                                                          busyp, fbno, flen,
index e44efc4..6ea847f 100644 (file)
@@ -21,7 +21,7 @@
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_trace.h"
-
+#include "xfs_error.h"
 
 kmem_zone_t    *xfs_efi_zone;
 kmem_zone_t    *xfs_efd_zone;
@@ -39,7 +39,7 @@ xfs_efi_item_free(
        if (efip->efi_format.efi_nextents > XFS_EFI_MAX_FAST_EXTENTS)
                kmem_free(efip);
        else
-               kmem_zone_free(xfs_efi_zone, efip);
+               kmem_cache_free(xfs_efi_zone, efip);
 }
 
 /*
@@ -228,6 +228,7 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
                }
                return 0;
        }
+       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
        return -EFSCORRUPTED;
 }
 
@@ -243,7 +244,7 @@ xfs_efd_item_free(struct xfs_efd_log_item *efdp)
        if (efdp->efd_format.efd_nextents > XFS_EFD_MAX_FAST_EXTENTS)
                kmem_free(efdp);
        else
-               kmem_zone_free(xfs_efd_zone, efdp);
+               kmem_cache_free(xfs_efd_zone, efdp);
 }
 
 /*
@@ -624,7 +625,7 @@ xfs_efi_recover(
                         */
                        set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
                        xfs_efi_release(efip);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
        }
 
index c062013..c932501 100644 (file)
@@ -188,7 +188,8 @@ xfs_file_dio_aio_read(
        file_accessed(iocb->ki_filp);
 
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
-       ret = iomap_dio_rw(iocb, to, &xfs_iomap_ops, NULL, is_sync_kiocb(iocb));
+       ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL,
+                       is_sync_kiocb(iocb));
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
        return ret;
@@ -215,7 +216,7 @@ xfs_file_dax_read(
                xfs_ilock(ip, XFS_IOLOCK_SHARED);
        }
 
-       ret = dax_iomap_rw(iocb, to, &xfs_iomap_ops);
+       ret = dax_iomap_rw(iocb, to, &xfs_read_iomap_ops);
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
        file_accessed(iocb->ki_filp);
@@ -351,7 +352,7 @@ restart:
        
                trace_xfs_zero_eof(ip, isize, iocb->ki_pos - isize);
                error = iomap_zero_range(inode, isize, iocb->ki_pos - isize,
-                               NULL, &xfs_iomap_ops);
+                               NULL, &xfs_buffered_write_iomap_ops);
                if (error)
                        return error;
        } else
@@ -486,8 +487,7 @@ xfs_file_dio_aio_write(
        int                     unaligned_io = 0;
        int                     iolock;
        size_t                  count = iov_iter_count(from);
-       struct xfs_buftarg      *target = XFS_IS_REALTIME_INODE(ip) ?
-                                       mp->m_rtdev_targp : mp->m_ddev_targp;
+       struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
 
        /* DIO must be aligned to device logical sector size */
        if ((iocb->ki_pos | count) & target->bt_logical_sectormask)
@@ -551,7 +551,8 @@ xfs_file_dio_aio_write(
         * If unaligned, this is the only IO in-flight. Wait on it before we
         * release the iolock to prevent subsequent overlapping IO.
         */
-       ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, &xfs_dio_write_ops,
+       ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
+                          &xfs_dio_write_ops,
                           is_sync_kiocb(iocb) || unaligned_io);
 out:
        xfs_iunlock(ip, iolock);
@@ -591,7 +592,7 @@ xfs_file_dax_write(
        count = iov_iter_count(from);
 
        trace_xfs_file_dax_write(ip, count, pos);
-       ret = dax_iomap_rw(iocb, from, &xfs_iomap_ops);
+       ret = dax_iomap_rw(iocb, from, &xfs_direct_write_iomap_ops);
        if (ret > 0 && iocb->ki_pos > i_size_read(inode)) {
                i_size_write(inode, iocb->ki_pos);
                error = xfs_setfilesize(ip, pos, ret);
@@ -638,7 +639,8 @@ write_retry:
        current->backing_dev_info = inode_to_bdi(inode);
 
        trace_xfs_file_buffered_write(ip, iov_iter_count(from), iocb->ki_pos);
-       ret = iomap_file_buffered_write(iocb, from, &xfs_iomap_ops);
+       ret = iomap_file_buffered_write(iocb, from,
+                       &xfs_buffered_write_iomap_ops);
        if (likely(ret >= 0))
                iocb->ki_pos += ret;
 
@@ -815,6 +817,36 @@ xfs_file_fallocate(
        if (error)
                goto out_unlock;
 
+       /*
+        * Must wait for all AIO to complete before we continue as AIO can
+        * change the file size on completion without holding any locks we
+        * currently hold. We must do this first because AIO can update both
+        * the on disk and in memory inode sizes, and the operations that follow
+        * require the in-memory size to be fully up-to-date.
+        */
+       inode_dio_wait(inode);
+
+       /*
+        * Now AIO and DIO has drained we flush and (if necessary) invalidate
+        * the cached range over the first operation we are about to run.
+        *
+        * We care about zero and collapse here because they both run a hole
+        * punch over the range first. Because that can zero data, and the range
+        * of invalidation for the shift operations is much larger, we still do
+        * the required flush for collapse in xfs_prepare_shift().
+        *
+        * Insert has the same range requirements as collapse, and we extend the
+        * file first which can zero data. Hence insert has the same
+        * flush/invalidate requirements as collapse and so they are both
+        * handled at the right time by xfs_prepare_shift().
+        */
+       if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE |
+                   FALLOC_FL_COLLAPSE_RANGE)) {
+               error = xfs_flush_unmap_range(ip, offset, len);
+               if (error)
+                       goto out_unlock;
+       }
+
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                error = xfs_free_file_space(ip, offset, len);
                if (error)
@@ -878,16 +910,30 @@ xfs_file_fallocate(
                }
 
                if (mode & FALLOC_FL_ZERO_RANGE) {
-                       error = xfs_zero_file_space(ip, offset, len);
+                       /*
+                        * Punch a hole and prealloc the range.  We use a hole
+                        * punch rather than unwritten extent conversion for two
+                        * reasons:
+                        *
+                        *   1.) Hole punch handles partial block zeroing for us.
+                        *   2.) If prealloc returns ENOSPC, the file range is
+                        *       still zero-valued by virtue of the hole punch.
+                        */
+                       unsigned int blksize = i_blocksize(inode);
+
+                       trace_xfs_zero_file_space(ip);
+
+                       error = xfs_free_file_space(ip, offset, len);
+                       if (error)
+                               goto out_unlock;
+
+                       len = round_up(offset + len, blksize) -
+                             round_down(offset, blksize);
+                       offset = round_down(offset, blksize);
                } else if (mode & FALLOC_FL_UNSHARE_RANGE) {
                        error = xfs_reflink_unshare(ip, offset, len);
                        if (error)
                                goto out_unlock;
-
-                       if (!xfs_is_always_cow_inode(ip)) {
-                               error = xfs_alloc_file_space(ip, offset, len,
-                                               XFS_BMAPI_PREALLOC);
-                       }
                } else {
                        /*
                         * If always_cow mode we can't use preallocations and
@@ -897,12 +943,14 @@ xfs_file_fallocate(
                                error = -EOPNOTSUPP;
                                goto out_unlock;
                        }
+               }
 
+               if (!xfs_is_always_cow_inode(ip)) {
                        error = xfs_alloc_file_space(ip, offset, len,
                                                     XFS_BMAPI_PREALLOC);
+                       if (error)
+                               goto out_unlock;
                }
-               if (error)
-                       goto out_unlock;
        }
 
        if (file->f_flags & O_DSYNC)
@@ -1056,7 +1104,7 @@ xfs_dir_open(
         */
        mode = xfs_ilock_data_map_shared(ip);
        if (ip->i_d.di_nextents > 0)
-               error = xfs_dir3_data_readahead(ip, 0, -1);
+               error = xfs_dir3_data_readahead(ip, 0, 0);
        xfs_iunlock(ip, mode);
        return error;
 }
@@ -1153,12 +1201,16 @@ __xfs_filemap_fault(
        if (IS_DAX(inode)) {
                pfn_t pfn;
 
-               ret = dax_iomap_fault(vmf, pe_size, &pfn, NULL, &xfs_iomap_ops);
+               ret = dax_iomap_fault(vmf, pe_size, &pfn, NULL,
+                               (write_fault && !vmf->cow_page) ?
+                                &xfs_direct_write_iomap_ops :
+                                &xfs_read_iomap_ops);
                if (ret & VM_FAULT_NEEDDSYNC)
                        ret = dax_finish_sync_fault(vmf, pe_size, pfn);
        } else {
                if (write_fault)
-                       ret = iomap_page_mkwrite(vmf, &xfs_iomap_ops);
+                       ret = iomap_page_mkwrite(vmf,
+                                       &xfs_buffered_write_iomap_ops);
                else
                        ret = filemap_fault(vmf);
        }
@@ -1222,22 +1274,22 @@ static const struct vm_operations_struct xfs_file_vm_ops = {
 
 STATIC int
 xfs_file_mmap(
-       struct file     *filp,
-       struct vm_area_struct *vma)
+       struct file             *file,
+       struct vm_area_struct   *vma)
 {
-       struct dax_device       *dax_dev;
+       struct inode            *inode = file_inode(file);
+       struct xfs_buftarg      *target = xfs_inode_buftarg(XFS_I(inode));
 
-       dax_dev = xfs_find_daxdev_for_inode(file_inode(filp));
        /*
         * We don't support synchronous mappings for non-DAX files and
         * for DAX files if underneath dax_device is not synchronous.
         */
-       if (!daxdev_mapping_supported(vma, dax_dev))
+       if (!daxdev_mapping_supported(vma, target->bt_daxdev))
                return -EOPNOTSUPP;
 
-       file_accessed(filp);
+       file_accessed(file);
        vma->vm_ops = &xfs_file_vm_ops;
-       if (IS_DAX(file_inode(filp)))
+       if (IS_DAX(inode))
                vma->vm_flags |= VM_HUGEPAGE;
        return 0;
 }
index 574a7a8..5f12b5d 100644 (file)
@@ -18,6 +18,7 @@
 #include "xfs_trace.h"
 #include "xfs_ag_resv.h"
 #include "xfs_trans.h"
+#include "xfs_filestream.h"
 
 struct xfs_fstrm_item {
        struct xfs_mru_cache_elem       mru;
@@ -374,7 +375,7 @@ xfs_filestream_new_ag(
                startag = (item->ag + 1) % mp->m_sb.sb_agcount;
        }
 
-       if (xfs_alloc_is_userdata(ap->datatype))
+       if (ap->datatype & XFS_ALLOC_USERDATA)
                flags |= XFS_PICK_USERDATA;
        if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
                flags |= XFS_PICK_LOWSPACE;
index d082143..918456c 100644 (file)
@@ -146,6 +146,7 @@ xfs_fsmap_owner_from_rmap(
                dest->fmr_owner = XFS_FMR_OWN_FREE;
                break;
        default:
+               ASSERT(0);
                return -EFSCORRUPTED;
        }
        return 0;
index 944add5..8dc2e54 100644 (file)
@@ -44,7 +44,7 @@ xfs_inode_alloc(
        if (!ip)
                return NULL;
        if (inode_init_always(mp->m_super, VFS_I(ip))) {
-               kmem_zone_free(xfs_inode_zone, ip);
+               kmem_cache_free(xfs_inode_zone, ip);
                return NULL;
        }
 
@@ -104,7 +104,7 @@ xfs_inode_free_callback(
                ip->i_itemp = NULL;
        }
 
-       kmem_zone_free(xfs_inode_zone, ip);
+       kmem_cache_free(xfs_inode_zone, ip);
 }
 
 static void
@@ -1419,7 +1419,7 @@ xfs_inode_match_id(
                return 0;
 
        if ((eofb->eof_flags & XFS_EOF_FLAGS_PRID) &&
-           xfs_get_projid(ip) != eofb->eof_prid)
+           ip->i_d.di_projid != eofb->eof_prid)
                return 0;
 
        return 1;
@@ -1443,7 +1443,7 @@ xfs_inode_match_id_union(
                return 1;
 
        if ((eofb->eof_flags & XFS_EOF_FLAGS_PRID) &&
-           xfs_get_projid(ip) == eofb->eof_prid)
+           ip->i_d.di_projid == eofb->eof_prid)
                return 1;
 
        return 0;
index 3ebd1b7..490fee2 100644 (file)
@@ -55,7 +55,7 @@ STATIC void
 xfs_icreate_item_release(
        struct xfs_log_item     *lip)
 {
-       kmem_zone_free(xfs_icreate_zone, ICR_ITEM(lip));
+       kmem_cache_free(xfs_icreate_zone, ICR_ITEM(lip));
 }
 
 static const struct xfs_item_ops xfs_icreate_item_ops = {
index 18f4b26..401da19 100644 (file)
@@ -55,6 +55,12 @@ xfs_extlen_t
 xfs_get_extsz_hint(
        struct xfs_inode        *ip)
 {
+       /*
+        * No point in aligning allocations if we need to COW to actually
+        * write to them.
+        */
+       if (xfs_is_always_cow_inode(ip))
+               return 0;
        if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize)
                return ip->i_d.di_extsize;
        if (XFS_IS_REALTIME_INODE(ip))
@@ -809,7 +815,7 @@ xfs_ialloc(
        ip->i_d.di_uid = xfs_kuid_to_uid(current_fsuid());
        ip->i_d.di_gid = xfs_kgid_to_gid(current_fsgid());
        inode->i_rdev = rdev;
-       xfs_set_projid(ip, prid);
+       ip->i_d.di_projid = prid;
 
        if (pip && XFS_INHERIT_GID(pip)) {
                ip->i_d.di_gid = pip->i_d.di_gid;
@@ -845,8 +851,7 @@ xfs_ialloc(
                inode_set_iversion(inode, 1);
                ip->i_d.di_flags2 = 0;
                ip->i_d.di_cowextsize = 0;
-               ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
-               ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
+               ip->i_d.di_crtime = tv;
        }
 
 
@@ -1418,7 +1423,7 @@ xfs_link(
         * the tree quota mechanism could be circumvented.
         */
        if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    (xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
+                    tdp->i_d.di_projid != sip->i_d.di_projid)) {
                error = -EXDEV;
                goto error_return;
        }
@@ -2130,8 +2135,10 @@ xfs_iunlink_update_bucket(
         * passed in because either we're adding or removing ourselves from the
         * head of the list.
         */
-       if (old_value == new_agino)
+       if (old_value == new_agino) {
+               xfs_buf_corruption_error(agibp);
                return -EFSCORRUPTED;
+       }
 
        agi->agi_unlinked[bucket_index] = cpu_to_be32(new_agino);
        offset = offsetof(struct xfs_agi, agi_unlinked) +
@@ -2194,6 +2201,8 @@ xfs_iunlink_update_inode(
        /* Make sure the old pointer isn't garbage. */
        old_value = be32_to_cpu(dip->di_next_unlinked);
        if (!xfs_verify_agino_or_null(mp, agno, old_value)) {
+               xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
+                               sizeof(*dip), __this_address);
                error = -EFSCORRUPTED;
                goto out;
        }
@@ -2205,8 +2214,11 @@ xfs_iunlink_update_inode(
         */
        *old_next_agino = old_value;
        if (old_value == next_agino) {
-               if (next_agino != NULLAGINO)
+               if (next_agino != NULLAGINO) {
+                       xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
+                                       dip, sizeof(*dip), __this_address);
                        error = -EFSCORRUPTED;
+               }
                goto out;
        }
 
@@ -2257,8 +2269,10 @@ xfs_iunlink(
         */
        next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
        if (next_agino == agino ||
-           !xfs_verify_agino_or_null(mp, agno, next_agino))
+           !xfs_verify_agino_or_null(mp, agno, next_agino)) {
+               xfs_buf_corruption_error(agibp);
                return -EFSCORRUPTED;
+       }
 
        if (next_agino != NULLAGINO) {
                struct xfs_perag        *pag;
@@ -3196,6 +3210,7 @@ xfs_rename(
        struct xfs_trans        *tp;
        struct xfs_inode        *wip = NULL;            /* whiteout inode */
        struct xfs_inode        *inodes[__XFS_SORT_INODES];
+       struct xfs_buf          *agibp;
        int                     num_inodes = __XFS_SORT_INODES;
        bool                    new_parent = (src_dp != target_dp);
        bool                    src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
@@ -3270,7 +3285,7 @@ xfs_rename(
         * tree quota mechanism would be circumvented.
         */
        if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
+                    target_dp->i_d.di_projid != src_ip->i_d.di_projid)) {
                error = -EXDEV;
                goto out_trans_cancel;
        }
@@ -3327,7 +3342,6 @@ xfs_rename(
                        goto out_trans_cancel;
 
                xfs_bumplink(tp, wip);
-               xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE);
                VFS_I(wip)->i_state &= ~I_LINKABLE;
        }
 
@@ -3361,6 +3375,22 @@ xfs_rename(
                 * In case there is already an entry with the same
                 * name at the destination directory, remove it first.
                 */
+
+               /*
+                * Check whether the replace operation will need to allocate
+                * blocks.  This happens when the shortform directory lacks
+                * space and we have to convert it to a block format directory.
+                * When more blocks are necessary, we must lock the AGI first
+                * to preserve locking order (AGI -> AGF).
+                */
+               if (xfs_dir2_sf_replace_needblock(target_dp, src_ip->i_ino)) {
+                       error = xfs_read_agi(mp, tp,
+                                       XFS_INO_TO_AGNO(mp, target_ip->i_ino),
+                                       &agibp);
+                       if (error)
+                               goto out_trans_cancel;
+               }
+
                error = xfs_dir_replace(tp, target_dp, target_name,
                                        src_ip->i_ino, spaceres);
                if (error)
index 558173f..492e539 100644 (file)
@@ -37,9 +37,6 @@ typedef struct xfs_inode {
        struct xfs_ifork        *i_cowfp;       /* copy on write extents */
        struct xfs_ifork        i_df;           /* data fork */
 
-       /* operations vectors */
-       const struct xfs_dir_ops *d_ops;                /* directory ops vector */
-
        /* Transaction and locking information. */
        struct xfs_inode_log_item *i_itemp;     /* logging information */
        mrlock_t                i_lock;         /* inode lock */
@@ -177,30 +174,11 @@ xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned short flags)
        return ret;
 }
 
-/*
- * Project quota id helpers (previously projid was 16bit only
- * and using two 16bit values to hold new 32bit projid was chosen
- * to retain compatibility with "old" filesystems).
- */
-static inline prid_t
-xfs_get_projid(struct xfs_inode *ip)
-{
-       return (prid_t)ip->i_d.di_projid_hi << 16 | ip->i_d.di_projid_lo;
-}
-
-static inline void
-xfs_set_projid(struct xfs_inode *ip,
-               prid_t projid)
-{
-       ip->i_d.di_projid_hi = (uint16_t) (projid >> 16);
-       ip->i_d.di_projid_lo = (uint16_t) (projid & 0xffff);
-}
-
 static inline prid_t
 xfs_get_initial_prid(struct xfs_inode *dp)
 {
        if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               return xfs_get_projid(dp);
+               return dp->i_d.di_projid;
 
        return XFS_PROJID_DEFAULT;
 }
@@ -219,6 +197,13 @@ static inline bool xfs_inode_has_cow_data(struct xfs_inode *ip)
        return ip->i_cowfp && ip->i_cowfp->if_bytes;
 }
 
+/*
+ * Return the buftarg used for data allocations on a given inode.
+ */
+#define xfs_inode_buftarg(ip) \
+       (XFS_IS_REALTIME_INODE(ip) ? \
+               (ip)->i_mount->m_rtdev_targp : (ip)->i_mount->m_ddev_targp)
+
 /*
  * In-core inode flags.
  */
index bb8f076..8bd5d0d 100644 (file)
@@ -17,6 +17,7 @@
 #include "xfs_trans_priv.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
+#include "xfs_error.h"
 
 #include <linux/iversion.h>
 
@@ -309,8 +310,8 @@ xfs_inode_to_log_dinode(
        to->di_format = from->di_format;
        to->di_uid = from->di_uid;
        to->di_gid = from->di_gid;
-       to->di_projid_lo = from->di_projid_lo;
-       to->di_projid_hi = from->di_projid_hi;
+       to->di_projid_lo = from->di_projid & 0xffff;
+       to->di_projid_hi = from->di_projid >> 16;
 
        memset(to->di_pad, 0, sizeof(to->di_pad));
        memset(to->di_pad3, 0, sizeof(to->di_pad3));
@@ -340,8 +341,8 @@ xfs_inode_to_log_dinode(
 
        if (from->di_version == 3) {
                to->di_changecount = inode_peek_iversion(inode);
-               to->di_crtime.t_sec = from->di_crtime.t_sec;
-               to->di_crtime.t_nsec = from->di_crtime.t_nsec;
+               to->di_crtime.t_sec = from->di_crtime.tv_sec;
+               to->di_crtime.t_nsec = from->di_crtime.tv_nsec;
                to->di_flags2 = from->di_flags2;
                to->di_cowextsize = from->di_cowextsize;
                to->di_ino = ip->i_ino;
@@ -666,7 +667,7 @@ xfs_inode_item_destroy(
        xfs_inode_t     *ip)
 {
        kmem_free(ip->i_itemp->ili_item.li_lv_shadow);
-       kmem_zone_free(xfs_ili_zone, ip->i_itemp);
+       kmem_cache_free(xfs_ili_zone, ip->i_itemp);
 }
 
 
@@ -828,8 +829,10 @@ xfs_inode_item_format_convert(
 {
        struct xfs_inode_log_format_32  *in_f32 = buf->i_addr;
 
-       if (buf->i_len != sizeof(*in_f32))
+       if (buf->i_len != sizeof(*in_f32)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
                return -EFSCORRUPTED;
+       }
 
        in_f->ilf_type = in_f32->ilf_type;
        in_f->ilf_size = in_f32->ilf_size;
index d58f0d6..7b35d62 100644 (file)
@@ -33,6 +33,8 @@
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_health.h"
+#include "xfs_reflink.h"
+#include "xfs_ioctl.h"
 
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -290,82 +292,6 @@ xfs_readlink_by_handle(
        return error;
 }
 
-int
-xfs_set_dmattrs(
-       xfs_inode_t     *ip,
-       uint            evmask,
-       uint16_t        state)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       xfs_trans_t     *tp;
-       int             error;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return -EIO;
-
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp);
-       if (error)
-               return error;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       ip->i_d.di_dmevmask = evmask;
-       ip->i_d.di_dmstate  = state;
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       error = xfs_trans_commit(tp);
-
-       return error;
-}
-
-STATIC int
-xfs_fssetdm_by_handle(
-       struct file             *parfilp,
-       void                    __user *arg)
-{
-       int                     error;
-       struct fsdmidata        fsd;
-       xfs_fsop_setdm_handlereq_t dmhreq;
-       struct dentry           *dentry;
-
-       if (!capable(CAP_MKNOD))
-               return -EPERM;
-       if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
-               return -EFAULT;
-
-       error = mnt_want_write_file(parfilp);
-       if (error)
-               return error;
-
-       dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq);
-       if (IS_ERR(dentry)) {
-               mnt_drop_write_file(parfilp);
-               return PTR_ERR(dentry);
-       }
-
-       if (IS_IMMUTABLE(d_inode(dentry)) || IS_APPEND(d_inode(dentry))) {
-               error = -EPERM;
-               goto out;
-       }
-
-       if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
-               error = -EFAULT;
-               goto out;
-       }
-
-       error = xfs_set_dmattrs(XFS_I(d_inode(dentry)), fsd.fsd_dmevmask,
-                                fsd.fsd_dmstate);
-
- out:
-       mnt_drop_write_file(parfilp);
-       dput(dentry);
-       return error;
-}
-
 STATIC int
 xfs_attrlist_by_handle(
        struct file             *parfilp,
@@ -588,13 +514,12 @@ xfs_attrmulti_by_handle(
 int
 xfs_ioc_space(
        struct file             *filp,
-       unsigned int            cmd,
        xfs_flock64_t           *bf)
 {
        struct inode            *inode = file_inode(filp);
        struct xfs_inode        *ip = XFS_I(inode);
        struct iattr            iattr;
-       enum xfs_prealloc_flags flags = 0;
+       enum xfs_prealloc_flags flags = XFS_PREALLOC_CLEAR;
        uint                    iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
        int                     error;
 
@@ -607,6 +532,9 @@ xfs_ioc_space(
        if (!S_ISREG(inode->i_mode))
                return -EINVAL;
 
+       if (xfs_is_always_cow_inode(ip))
+               return -EOPNOTSUPP;
+
        if (filp->f_flags & O_DSYNC)
                flags |= XFS_PREALLOC_SYNC;
        if (filp->f_mode & FMODE_NOCMTIME)
@@ -620,6 +548,7 @@ xfs_ioc_space(
        error = xfs_break_layouts(inode, &iolock, BREAK_UNMAP);
        if (error)
                goto out_unlock;
+       inode_dio_wait(inode);
 
        switch (bf->l_whence) {
        case 0: /*SEEK_SET*/
@@ -635,73 +564,21 @@ xfs_ioc_space(
                goto out_unlock;
        }
 
-       /*
-        * length of <= 0 for resv/unresv/zero is invalid.  length for
-        * alloc/free is ignored completely and we have no idea what userspace
-        * might have set it to, so set it to zero to allow range
-        * checks to pass.
-        */
-       switch (cmd) {
-       case XFS_IOC_ZERO_RANGE:
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_RESVSP64:
-       case XFS_IOC_UNRESVSP:
-       case XFS_IOC_UNRESVSP64:
-               if (bf->l_len <= 0) {
-                       error = -EINVAL;
-                       goto out_unlock;
-               }
-               break;
-       default:
-               bf->l_len = 0;
-               break;
-       }
-
-       if (bf->l_start < 0 ||
-           bf->l_start > inode->i_sb->s_maxbytes ||
-           bf->l_start + bf->l_len < 0 ||
-           bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) {
+       if (bf->l_start < 0 || bf->l_start > inode->i_sb->s_maxbytes) {
                error = -EINVAL;
                goto out_unlock;
        }
 
-       switch (cmd) {
-       case XFS_IOC_ZERO_RANGE:
-               flags |= XFS_PREALLOC_SET;
-               error = xfs_zero_file_space(ip, bf->l_start, bf->l_len);
-               break;
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_RESVSP64:
-               flags |= XFS_PREALLOC_SET;
-               error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len,
-                                               XFS_BMAPI_PREALLOC);
-               break;
-       case XFS_IOC_UNRESVSP:
-       case XFS_IOC_UNRESVSP64:
-               error = xfs_free_file_space(ip, bf->l_start, bf->l_len);
-               break;
-       case XFS_IOC_ALLOCSP:
-       case XFS_IOC_ALLOCSP64:
-       case XFS_IOC_FREESP:
-       case XFS_IOC_FREESP64:
-               flags |= XFS_PREALLOC_CLEAR;
-               if (bf->l_start > XFS_ISIZE(ip)) {
-                       error = xfs_alloc_file_space(ip, XFS_ISIZE(ip),
-                                       bf->l_start - XFS_ISIZE(ip), 0);
-                       if (error)
-                               goto out_unlock;
-               }
-
-               iattr.ia_valid = ATTR_SIZE;
-               iattr.ia_size = bf->l_start;
-
-               error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
-               break;
-       default:
-               ASSERT(0);
-               error = -EINVAL;
+       if (bf->l_start > XFS_ISIZE(ip)) {
+               error = xfs_alloc_file_space(ip, XFS_ISIZE(ip),
+                               bf->l_start - XFS_ISIZE(ip), 0);
+               if (error)
+                       goto out_unlock;
        }
 
+       iattr.ia_valid = ATTR_SIZE;
+       iattr.ia_size = bf->l_start;
+       error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
        if (error)
                goto out_unlock;
 
@@ -1116,7 +993,7 @@ xfs_fill_fsxattr(
        fa->fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
        fa->fsx_cowextsize = ip->i_d.di_cowextsize <<
                        ip->i_mount->m_sb.sb_blocklog;
-       fa->fsx_projid = xfs_get_projid(ip);
+       fa->fsx_projid = ip->i_d.di_projid;
 
        if (attr) {
                if (ip->i_afp) {
@@ -1311,10 +1188,9 @@ xfs_ioctl_setattr_dax_invalidate(
         * have to check the device for dax support or flush pagecache.
         */
        if (fa->fsx_xflags & FS_XFLAG_DAX) {
-               if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
-                       return -EINVAL;
-               if (!bdev_dax_supported(xfs_find_bdev_for_inode(VFS_I(ip)),
-                               sb->s_blocksize))
+               struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
+
+               if (!bdev_dax_supported(target->bt_bdev, sb->s_blocksize))
                        return -EINVAL;
        }
 
@@ -1569,7 +1445,7 @@ xfs_ioctl_setattr(
        }
 
        if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp) &&
-           xfs_get_projid(ip) != fa->fsx_projid) {
+           ip->i_d.di_projid != fa->fsx_projid) {
                code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp,
                                capable(CAP_FOWNER) ?  XFS_QMOPT_FORCE_RES : 0);
                if (code)       /* out of quota */
@@ -1606,13 +1482,13 @@ xfs_ioctl_setattr(
                VFS_I(ip)->i_mode &= ~(S_ISUID|S_ISGID);
 
        /* Change the ownerships and register project quota modifications */
-       if (xfs_get_projid(ip) != fa->fsx_projid) {
+       if (ip->i_d.di_projid != fa->fsx_projid) {
                if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
                        olddquot = xfs_qm_vop_chown(tp, ip,
                                                &ip->i_pdquot, pdqp);
                }
                ASSERT(ip->i_d.di_version > 1);
-               xfs_set_projid(ip, fa->fsx_projid);
+               ip->i_d.di_projid = fa->fsx_projid;
        }
 
        /*
@@ -2122,24 +1998,17 @@ xfs_file_ioctl(
                return xfs_ioc_setlabel(filp, mp, arg);
        case XFS_IOC_ALLOCSP:
        case XFS_IOC_FREESP:
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_UNRESVSP:
        case XFS_IOC_ALLOCSP64:
-       case XFS_IOC_FREESP64:
-       case XFS_IOC_RESVSP64:
-       case XFS_IOC_UNRESVSP64:
-       case XFS_IOC_ZERO_RANGE: {
+       case XFS_IOC_FREESP64: {
                xfs_flock64_t           bf;
 
                if (copy_from_user(&bf, arg, sizeof(bf)))
                        return -EFAULT;
-               return xfs_ioc_space(filp, cmd, &bf);
+               return xfs_ioc_space(filp, &bf);
        }
        case XFS_IOC_DIOINFO: {
-               struct dioattr  da;
-               xfs_buftarg_t   *target =
-                       XFS_IS_REALTIME_INODE(ip) ?
-                       mp->m_rtdev_targp : mp->m_ddev_targp;
+               struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
+               struct dioattr          da;
 
                da.d_mem =  da.d_miniosz = target->bt_logical_sectorsize;
                da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
@@ -2183,22 +2052,6 @@ xfs_file_ioctl(
        case XFS_IOC_SETXFLAGS:
                return xfs_ioc_setxflags(ip, filp, arg);
 
-       case XFS_IOC_FSSETDM: {
-               struct fsdmidata        dmi;
-
-               if (copy_from_user(&dmi, arg, sizeof(dmi)))
-                       return -EFAULT;
-
-               error = mnt_want_write_file(filp);
-               if (error)
-                       return error;
-
-               error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask,
-                               dmi.fsd_dmstate);
-               mnt_drop_write_file(filp);
-               return error;
-       }
-
        case XFS_IOC_GETBMAP:
        case XFS_IOC_GETBMAPA:
        case XFS_IOC_GETBMAPX:
@@ -2226,8 +2079,6 @@ xfs_file_ioctl(
                        return -EFAULT;
                return xfs_open_by_handle(filp, &hreq);
        }
-       case XFS_IOC_FSSETDM_BY_HANDLE:
-               return xfs_fssetdm_by_handle(filp, arg);
 
        case XFS_IOC_READLINK_BY_HANDLE: {
                xfs_fsop_handlereq_t    hreq;
index 654c0bb..420bd95 100644 (file)
@@ -9,7 +9,6 @@
 extern int
 xfs_ioc_space(
        struct file             *filp,
-       unsigned int            cmd,
        xfs_flock64_t           *bf);
 
 int
@@ -71,12 +70,6 @@ xfs_file_compat_ioctl(
        unsigned int            cmd,
        unsigned long           arg);
 
-extern int
-xfs_set_dmattrs(
-       struct xfs_inode        *ip,
-       uint                    evmask,
-       uint16_t                state);
-
 struct xfs_ibulk;
 struct xfs_bstat;
 struct xfs_inogrp;
index 1e08bf7..c4c4f09 100644 (file)
@@ -500,44 +500,6 @@ xfs_compat_attrmulti_by_handle(
        return error;
 }
 
-STATIC int
-xfs_compat_fssetdm_by_handle(
-       struct file             *parfilp,
-       void                    __user *arg)
-{
-       int                     error;
-       struct fsdmidata        fsd;
-       compat_xfs_fsop_setdm_handlereq_t dmhreq;
-       struct dentry           *dentry;
-
-       if (!capable(CAP_MKNOD))
-               return -EPERM;
-       if (copy_from_user(&dmhreq, arg,
-                          sizeof(compat_xfs_fsop_setdm_handlereq_t)))
-               return -EFAULT;
-
-       dentry = xfs_compat_handlereq_to_dentry(parfilp, &dmhreq.hreq);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-
-       if (IS_IMMUTABLE(d_inode(dentry)) || IS_APPEND(d_inode(dentry))) {
-               error = -EPERM;
-               goto out;
-       }
-
-       if (copy_from_user(&fsd, compat_ptr(dmhreq.data), sizeof(fsd))) {
-               error = -EFAULT;
-               goto out;
-       }
-
-       error = xfs_set_dmattrs(XFS_I(d_inode(dentry)), fsd.fsd_dmevmask,
-                                fsd.fsd_dmstate);
-
-out:
-       dput(dentry);
-       return error;
-}
-
 long
 xfs_file_compat_ioctl(
        struct file             *filp,
@@ -557,18 +519,13 @@ xfs_file_compat_ioctl(
        case XFS_IOC_ALLOCSP_32:
        case XFS_IOC_FREESP_32:
        case XFS_IOC_ALLOCSP64_32:
-       case XFS_IOC_FREESP64_32:
-       case XFS_IOC_RESVSP_32:
-       case XFS_IOC_UNRESVSP_32:
-       case XFS_IOC_RESVSP64_32:
-       case XFS_IOC_UNRESVSP64_32:
-       case XFS_IOC_ZERO_RANGE_32: {
+       case XFS_IOC_FREESP64_32: {
                struct xfs_flock64      bf;
 
                if (xfs_compat_flock64_copyin(&bf, arg))
                        return -EFAULT;
                cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
-               return xfs_ioc_space(filp, cmd, &bf);
+               return xfs_ioc_space(filp, &bf);
        }
        case XFS_IOC_FSGEOMETRY_V1_32:
                return xfs_compat_ioc_fsgeometry_v1(mp, arg);
@@ -651,8 +608,6 @@ xfs_file_compat_ioctl(
                return xfs_compat_attrlist_by_handle(filp, arg);
        case XFS_IOC_ATTRMULTI_BY_HANDLE_32:
                return xfs_compat_attrmulti_by_handle(filp, arg);
-       case XFS_IOC_FSSETDM_BY_HANDLE_32:
-               return xfs_compat_fssetdm_by_handle(filp, arg);
        default:
                /* try the native version */
                return xfs_file_ioctl(filp, cmd, (unsigned long)arg);
index 7985344..8c7743c 100644 (file)
@@ -99,7 +99,7 @@ typedef struct compat_xfs_fsop_handlereq {
        _IOWR('X', 108, struct compat_xfs_fsop_handlereq)
 
 /* The bstat field in the swapext struct needs translation */
-typedef struct compat_xfs_swapext {
+struct compat_xfs_swapext {
        int64_t                 sx_version;     /* version */
        int64_t                 sx_fdtarget;    /* fd of target file */
        int64_t                 sx_fdtmp;       /* fd of tmp file */
@@ -107,7 +107,7 @@ typedef struct compat_xfs_swapext {
        xfs_off_t               sx_length;      /* leng from offset */
        char                    sx_pad[16];     /* pad space, unused */
        struct compat_xfs_bstat sx_stat;        /* stat of target b4 copy */
-} __compat_packed compat_xfs_swapext_t;
+} __compat_packed;
 
 #define XFS_IOC_SWAPEXT_32     _IOWR('X', 109, struct compat_xfs_swapext)
 
@@ -143,15 +143,6 @@ typedef struct compat_xfs_fsop_attrmulti_handlereq {
 #define XFS_IOC_ATTRMULTI_BY_HANDLE_32 \
        _IOW('X', 123, struct compat_xfs_fsop_attrmulti_handlereq)
 
-typedef struct compat_xfs_fsop_setdm_handlereq {
-       struct compat_xfs_fsop_handlereq hreq;  /* handle information   */
-       /* ptr to struct fsdmidata */
-       compat_uptr_t                   data;   /* DMAPI data   */
-} compat_xfs_fsop_setdm_handlereq_t;
-
-#define XFS_IOC_FSSETDM_BY_HANDLE_32 \
-       _IOW('X', 121, struct compat_xfs_fsop_setdm_handlereq)
-
 #ifdef BROKEN_X86_ALIGNMENT
 /* on ia32 l_start is on a 32-bit boundary */
 typedef struct compat_xfs_flock64 {
index 95719e1..28e2d1f 100644 (file)
@@ -29,8 +29,8 @@
 #include "xfs_reflink.h"
 
 
-#define XFS_WRITEIO_ALIGN(mp,off)      (((off) >> mp->m_writeio_log) \
-                                               << mp->m_writeio_log)
+#define XFS_ALLOC_ALIGN(mp, off) \
+       (((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
 
 static int
 xfs_alert_fsblock_zero(
@@ -57,6 +57,7 @@ xfs_bmbt_to_iomap(
        u16                     flags)
 {
        struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
 
        if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
                return xfs_alert_fsblock_zero(ip, imap);
@@ -77,8 +78,8 @@ xfs_bmbt_to_iomap(
        }
        iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff);
        iomap->length = XFS_FSB_TO_B(mp, imap->br_blockcount);
-       iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip));
-       iomap->dax_dev = xfs_find_daxdev_for_inode(VFS_I(ip));
+       iomap->bdev = target->bt_bdev;
+       iomap->dax_dev = target->bt_daxdev;
        iomap->flags = flags;
 
        if (xfs_ipincount(ip) &&
@@ -94,18 +95,30 @@ xfs_hole_to_iomap(
        xfs_fileoff_t           offset_fsb,
        xfs_fileoff_t           end_fsb)
 {
+       struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
+
        iomap->addr = IOMAP_NULL_ADDR;
        iomap->type = IOMAP_HOLE;
        iomap->offset = XFS_FSB_TO_B(ip->i_mount, offset_fsb);
        iomap->length = XFS_FSB_TO_B(ip->i_mount, end_fsb - offset_fsb);
-       iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip));
-       iomap->dax_dev = xfs_find_daxdev_for_inode(VFS_I(ip));
+       iomap->bdev = target->bt_bdev;
+       iomap->dax_dev = target->bt_daxdev;
+}
+
+static inline xfs_fileoff_t
+xfs_iomap_end_fsb(
+       struct xfs_mount        *mp,
+       loff_t                  offset,
+       loff_t                  count)
+{
+       ASSERT(offset <= mp->m_super->s_maxbytes);
+       return min(XFS_B_TO_FSB(mp, offset + count),
+                  XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes));
 }
 
-xfs_extlen_t
+static xfs_extlen_t
 xfs_eof_alignment(
-       struct xfs_inode        *ip,
-       xfs_extlen_t            extsize)
+       struct xfs_inode        *ip)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_extlen_t            align = 0;
@@ -128,111 +141,80 @@ xfs_eof_alignment(
                        align = 0;
        }
 
-       /*
-        * Always round up the allocation request to an extent boundary
-        * (when file on a real-time subvolume or has di_extsize hint).
-        */
-       if (extsize) {
-               if (align)
-                       align = roundup_64(align, extsize);
-               else
-                       align = extsize;
-       }
-
        return align;
 }
 
-STATIC int
+/*
+ * Check if last_fsb is outside the last extent, and if so grow it to the next
+ * stripe unit boundary.
+ */
+xfs_fileoff_t
 xfs_iomap_eof_align_last_fsb(
        struct xfs_inode        *ip,
-       xfs_extlen_t            extsize,
-       xfs_fileoff_t           *last_fsb)
+       xfs_fileoff_t           end_fsb)
 {
-       xfs_extlen_t            align = xfs_eof_alignment(ip, extsize);
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+       xfs_extlen_t            extsz = xfs_get_extsz_hint(ip);
+       xfs_extlen_t            align = xfs_eof_alignment(ip);
+       struct xfs_bmbt_irec    irec;
+       struct xfs_iext_cursor  icur;
+
+       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
+
+       /*
+        * Always round up the allocation request to the extent hint boundary.
+        */
+       if (extsz) {
+               if (align)
+                       align = roundup_64(align, extsz);
+               else
+                       align = extsz;
+       }
 
        if (align) {
-               xfs_fileoff_t   new_last_fsb = roundup_64(*last_fsb, align);
-               int             eof, error;
+               xfs_fileoff_t   aligned_end_fsb = roundup_64(end_fsb, align);
 
-               error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof);
-               if (error)
-                       return error;
-               if (eof)
-                       *last_fsb = new_last_fsb;
+               xfs_iext_last(ifp, &icur);
+               if (!xfs_iext_get_extent(ifp, &icur, &irec) ||
+                   aligned_end_fsb >= irec.br_startoff + irec.br_blockcount)
+                       return aligned_end_fsb;
        }
-       return 0;
+
+       return end_fsb;
 }
 
 int
 xfs_iomap_write_direct(
-       xfs_inode_t     *ip,
-       xfs_off_t       offset,
-       size_t          count,
-       xfs_bmbt_irec_t *imap,
-       int             nmaps)
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           offset_fsb,
+       xfs_fileoff_t           count_fsb,
+       struct xfs_bmbt_irec    *imap)
 {
-       xfs_mount_t     *mp = ip->i_mount;
-       xfs_fileoff_t   offset_fsb;
-       xfs_fileoff_t   last_fsb;
-       xfs_filblks_t   count_fsb, resaligned;
-       xfs_extlen_t    extsz;
-       int             nimaps;
-       int             quota_flag;
-       int             rt;
-       xfs_trans_t     *tp;
-       uint            qblocks, resblks, resrtextents;
-       int             error;
-       int             lockmode;
-       int             bmapi_flags = XFS_BMAPI_PREALLOC;
-       uint            tflags = 0;
-
-       rt = XFS_IS_REALTIME_INODE(ip);
-       extsz = xfs_get_extsz_hint(ip);
-       lockmode = XFS_ILOCK_SHARED;    /* locked by caller */
-
-       ASSERT(xfs_isilocked(ip, lockmode));
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_trans        *tp;
+       xfs_filblks_t           resaligned;
+       int                     nimaps;
+       int                     quota_flag;
+       uint                    qblocks, resblks;
+       unsigned int            resrtextents = 0;
+       int                     error;
+       int                     bmapi_flags = XFS_BMAPI_PREALLOC;
+       uint                    tflags = 0;
 
-       offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
-       if ((offset + count) > XFS_ISIZE(ip)) {
-               /*
-                * Assert that the in-core extent list is present since this can
-                * call xfs_iread_extents() and we only have the ilock shared.
-                * This should be safe because the lock was held around a bmapi
-                * call in the caller and we only need it to access the in-core
-                * list.
-                */
-               ASSERT(XFS_IFORK_PTR(ip, XFS_DATA_FORK)->if_flags &
-                                                               XFS_IFEXTENTS);
-               error = xfs_iomap_eof_align_last_fsb(ip, extsz, &last_fsb);
-               if (error)
-                       goto out_unlock;
-       } else {
-               if (nmaps && (imap->br_startblock == HOLESTARTBLOCK))
-                       last_fsb = min(last_fsb, (xfs_fileoff_t)
-                                       imap->br_blockcount +
-                                       imap->br_startoff);
-       }
-       count_fsb = last_fsb - offset_fsb;
        ASSERT(count_fsb > 0);
-       resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb, extsz);
 
-       if (unlikely(rt)) {
+       resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb,
+                                          xfs_get_extsz_hint(ip));
+       if (unlikely(XFS_IS_REALTIME_INODE(ip))) {
                resrtextents = qblocks = resaligned;
                resrtextents /= mp->m_sb.sb_rextsize;
                resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
                quota_flag = XFS_QMOPT_RES_RTBLKS;
        } else {
-               resrtextents = 0;
                resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
                quota_flag = XFS_QMOPT_RES_REGBLKS;
        }
 
-       /*
-        * Drop the shared lock acquired by the caller, attach the dquot if
-        * necessary and move on to transaction setup.
-        */
-       xfs_iunlock(ip, lockmode);
        error = xfs_qm_dqattach(ip);
        if (error)
                return error;
@@ -262,8 +244,7 @@ xfs_iomap_write_direct(
        if (error)
                return error;
 
-       lockmode = XFS_ILOCK_EXCL;
-       xfs_ilock(ip, lockmode);
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
 
        error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
        if (error)
@@ -276,8 +257,8 @@ xfs_iomap_write_direct(
         * caller gave to us.
         */
        nimaps = 1;
-       error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
-                               bmapi_flags, resblks, imap, &nimaps);
+       error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flags, 0,
+                               imap, &nimaps);
        if (error)
                goto out_res_cancel;
 
@@ -300,7 +281,7 @@ xfs_iomap_write_direct(
                error = xfs_alert_fsblock_zero(ip, imap);
 
 out_unlock:
-       xfs_iunlock(ip, lockmode);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 
 out_res_cancel:
@@ -409,19 +390,19 @@ xfs_iomap_prealloc_size(
        if (offset + count <= XFS_ISIZE(ip))
                return 0;
 
-       if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) &&
-           (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_writeio_blocks)))
+       if (!(mp->m_flags & XFS_MOUNT_ALLOCSIZE) &&
+           (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_allocsize_blocks)))
                return 0;
 
        /*
         * If an explicit allocsize is set, the file is small, or we
         * are writing behind a hole, then use the minimum prealloc:
         */
-       if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) ||
+       if ((mp->m_flags & XFS_MOUNT_ALLOCSIZE) ||
            XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
            !xfs_iext_peek_prev_extent(ifp, icur, &prev) ||
            prev.br_startoff + prev.br_blockcount < offset_fsb)
-               return mp->m_writeio_blocks;
+               return mp->m_allocsize_blocks;
 
        /*
         * Determine the initial size of the preallocation. We are beyond the
@@ -514,226 +495,13 @@ xfs_iomap_prealloc_size(
        while (alloc_blocks && alloc_blocks >= freesp)
                alloc_blocks >>= 4;
 check_writeio:
-       if (alloc_blocks < mp->m_writeio_blocks)
-               alloc_blocks = mp->m_writeio_blocks;
+       if (alloc_blocks < mp->m_allocsize_blocks)
+               alloc_blocks = mp->m_allocsize_blocks;
        trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift,
-                                     mp->m_writeio_blocks);
+                                     mp->m_allocsize_blocks);
        return alloc_blocks;
 }
 
-static int
-xfs_file_iomap_begin_delay(
-       struct inode            *inode,
-       loff_t                  offset,
-       loff_t                  count,
-       unsigned                flags,
-       struct iomap            *iomap)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_fileoff_t           offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       xfs_fileoff_t           maxbytes_fsb =
-               XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
-       xfs_fileoff_t           end_fsb;
-       struct xfs_bmbt_irec    imap, cmap;
-       struct xfs_iext_cursor  icur, ccur;
-       xfs_fsblock_t           prealloc_blocks = 0;
-       bool                    eof = false, cow_eof = false, shared = false;
-       u16                     iomap_flags = 0;
-       int                     whichfork = XFS_DATA_FORK;
-       int                     error = 0;
-
-       ASSERT(!XFS_IS_REALTIME_INODE(ip));
-       ASSERT(!xfs_get_extsz_hint(ip));
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-       if (unlikely(XFS_TEST_ERROR(
-           (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
-            mp, XFS_ERRTAG_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
-               error = -EFSCORRUPTED;
-               goto out_unlock;
-       }
-
-       XFS_STATS_INC(mp, xs_blk_mapw);
-
-       if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
-               if (error)
-                       goto out_unlock;
-       }
-
-       end_fsb = min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb);
-
-       /*
-        * Search the data fork fork first to look up our source mapping.  We
-        * always need the data fork map, as we have to return it to the
-        * iomap code so that the higher level write code can read data in to
-        * perform read-modify-write cycles for unaligned writes.
-        */
-       eof = !xfs_iext_lookup_extent(ip, &ip->i_df, offset_fsb, &icur, &imap);
-       if (eof)
-               imap.br_startoff = end_fsb; /* fake hole until the end */
-
-       /* We never need to allocate blocks for zeroing a hole. */
-       if ((flags & IOMAP_ZERO) && imap.br_startoff > offset_fsb) {
-               xfs_hole_to_iomap(ip, iomap, offset_fsb, imap.br_startoff);
-               goto out_unlock;
-       }
-
-       /*
-        * Search the COW fork extent list even if we did not find a data fork
-        * extent.  This serves two purposes: first this implements the
-        * speculative preallocation using cowextsize, so that we also unshare
-        * block adjacent to shared blocks instead of just the shared blocks
-        * themselves.  Second the lookup in the extent list is generally faster
-        * than going out to the shared extent tree.
-        */
-       if (xfs_is_cow_inode(ip)) {
-               if (!ip->i_cowfp) {
-                       ASSERT(!xfs_is_reflink_inode(ip));
-                       xfs_ifork_init_cow(ip);
-               }
-               cow_eof = !xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb,
-                               &ccur, &cmap);
-               if (!cow_eof && cmap.br_startoff <= offset_fsb) {
-                       trace_xfs_reflink_cow_found(ip, &cmap);
-                       whichfork = XFS_COW_FORK;
-                       goto done;
-               }
-       }
-
-       if (imap.br_startoff <= offset_fsb) {
-               /*
-                * For reflink files we may need a delalloc reservation when
-                * overwriting shared extents.   This includes zeroing of
-                * existing extents that contain data.
-                */
-               if (!xfs_is_cow_inode(ip) ||
-                   ((flags & IOMAP_ZERO) && imap.br_state != XFS_EXT_NORM)) {
-                       trace_xfs_iomap_found(ip, offset, count, XFS_DATA_FORK,
-                                       &imap);
-                       goto done;
-               }
-
-               xfs_trim_extent(&imap, offset_fsb, end_fsb - offset_fsb);
-
-               /* Trim the mapping to the nearest shared extent boundary. */
-               error = xfs_inode_need_cow(ip, &imap, &shared);
-               if (error)
-                       goto out_unlock;
-
-               /* Not shared?  Just report the (potentially capped) extent. */
-               if (!shared) {
-                       trace_xfs_iomap_found(ip, offset, count, XFS_DATA_FORK,
-                                       &imap);
-                       goto done;
-               }
-
-               /*
-                * Fork all the shared blocks from our write offset until the
-                * end of the extent.
-                */
-               whichfork = XFS_COW_FORK;
-               end_fsb = imap.br_startoff + imap.br_blockcount;
-       } else {
-               /*
-                * We cap the maximum length we map here to MAX_WRITEBACK_PAGES
-                * pages to keep the chunks of work done where somewhat
-                * symmetric with the work writeback does.  This is a completely
-                * arbitrary number pulled out of thin air.
-                *
-                * Note that the values needs to be less than 32-bits wide until
-                * the lower level functions are updated.
-                */
-               count = min_t(loff_t, count, 1024 * PAGE_SIZE);
-               end_fsb = min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb);
-
-               if (xfs_is_always_cow_inode(ip))
-                       whichfork = XFS_COW_FORK;
-       }
-
-       error = xfs_qm_dqattach_locked(ip, false);
-       if (error)
-               goto out_unlock;
-
-       if (eof) {
-               prealloc_blocks = xfs_iomap_prealloc_size(ip, whichfork, offset,
-                               count, &icur);
-               if (prealloc_blocks) {
-                       xfs_extlen_t    align;
-                       xfs_off_t       end_offset;
-                       xfs_fileoff_t   p_end_fsb;
-
-                       end_offset = XFS_WRITEIO_ALIGN(mp, offset + count - 1);
-                       p_end_fsb = XFS_B_TO_FSBT(mp, end_offset) +
-                                       prealloc_blocks;
-
-                       align = xfs_eof_alignment(ip, 0);
-                       if (align)
-                               p_end_fsb = roundup_64(p_end_fsb, align);
-
-                       p_end_fsb = min(p_end_fsb, maxbytes_fsb);
-                       ASSERT(p_end_fsb > offset_fsb);
-                       prealloc_blocks = p_end_fsb - end_fsb;
-               }
-       }
-
-retry:
-       error = xfs_bmapi_reserve_delalloc(ip, whichfork, offset_fsb,
-                       end_fsb - offset_fsb, prealloc_blocks,
-                       whichfork == XFS_DATA_FORK ? &imap : &cmap,
-                       whichfork == XFS_DATA_FORK ? &icur : &ccur,
-                       whichfork == XFS_DATA_FORK ? eof : cow_eof);
-       switch (error) {
-       case 0:
-               break;
-       case -ENOSPC:
-       case -EDQUOT:
-               /* retry without any preallocation */
-               trace_xfs_delalloc_enospc(ip, offset, count);
-               if (prealloc_blocks) {
-                       prealloc_blocks = 0;
-                       goto retry;
-               }
-               /*FALLTHRU*/
-       default:
-               goto out_unlock;
-       }
-
-       /*
-        * Flag newly allocated delalloc blocks with IOMAP_F_NEW so we punch
-        * them out if the write happens to fail.
-        */
-       if (whichfork == XFS_DATA_FORK) {
-               iomap_flags |= IOMAP_F_NEW;
-               trace_xfs_iomap_alloc(ip, offset, count, whichfork, &imap);
-       } else {
-               trace_xfs_iomap_alloc(ip, offset, count, whichfork, &cmap);
-       }
-done:
-       if (whichfork == XFS_COW_FORK) {
-               if (imap.br_startoff > offset_fsb) {
-                       xfs_trim_extent(&cmap, offset_fsb,
-                                       imap.br_startoff - offset_fsb);
-                       error = xfs_bmbt_to_iomap(ip, iomap, &cmap,
-                                       IOMAP_F_SHARED);
-                       goto out_unlock;
-               }
-               /* ensure we only report blocks we have a reservation for */
-               xfs_trim_extent(&imap, cmap.br_startoff, cmap.br_blockcount);
-               shared = true;
-       }
-       if (shared)
-               iomap_flags |= IOMAP_F_SHARED;
-       error = xfs_bmbt_to_iomap(ip, iomap, &imap, iomap_flags);
-out_unlock:
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       return error;
-}
-
 int
 xfs_iomap_write_unwritten(
        xfs_inode_t     *ip,
@@ -771,6 +539,11 @@ xfs_iomap_write_unwritten(
         */
        resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;
 
+       /* Attach dquots so that bmbt splits are accounted correctly. */
+       error = xfs_qm_dqattach(ip);
+       if (error)
+               return error;
+
        do {
                /*
                 * Set up a transaction to convert the range of extents
@@ -789,6 +562,11 @@ xfs_iomap_write_unwritten(
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, ip, 0);
 
+               error = xfs_trans_reserve_quota_nblks(tp, ip, resblks, 0,
+                               XFS_QMOPT_RES_REGBLKS);
+               if (error)
+                       goto error_on_bmapi_transaction;
+
                /*
                 * Modify the unwritten extent state of the buffer.
                 */
@@ -846,23 +624,42 @@ error_on_bmapi_transaction:
 static inline bool
 imap_needs_alloc(
        struct inode            *inode,
+       unsigned                flags,
        struct xfs_bmbt_irec    *imap,
        int                     nimaps)
 {
-       return !nimaps ||
-               imap->br_startblock == HOLESTARTBLOCK ||
-               imap->br_startblock == DELAYSTARTBLOCK ||
-               (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN);
+       /* don't allocate blocks when just zeroing */
+       if (flags & IOMAP_ZERO)
+               return false;
+       if (!nimaps ||
+           imap->br_startblock == HOLESTARTBLOCK ||
+           imap->br_startblock == DELAYSTARTBLOCK)
+               return true;
+       /* we convert unwritten extents before copying the data for DAX */
+       if (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN)
+               return true;
+       return false;
 }
 
 static inline bool
-needs_cow_for_zeroing(
+imap_needs_cow(
+       struct xfs_inode        *ip,
+       unsigned int            flags,
        struct xfs_bmbt_irec    *imap,
        int                     nimaps)
 {
-       return nimaps &&
-               imap->br_startblock != HOLESTARTBLOCK &&
-               imap->br_state != XFS_EXT_UNWRITTEN;
+       if (!xfs_is_cow_inode(ip))
+               return false;
+
+       /* when zeroing we don't have to COW holes or unwritten extents */
+       if (flags & IOMAP_ZERO) {
+               if (!nimaps ||
+                   imap->br_startblock == HOLESTARTBLOCK ||
+                   imap->br_state == XFS_EXT_UNWRITTEN)
+                       return false;
+       }
+
+       return true;
 }
 
 static int
@@ -878,15 +675,8 @@ xfs_ilock_for_iomap(
         * COW writes may allocate delalloc space or convert unwritten COW
         * extents, so we need to make sure to take the lock exclusively here.
         */
-       if (xfs_is_cow_inode(ip) && is_write) {
-               /*
-                * FIXME: It could still overwrite on unshared extents and not
-                * need allocation.
-                */
-               if (flags & IOMAP_NOWAIT)
-                       return -EAGAIN;
+       if (xfs_is_cow_inode(ip) && is_write)
                mode = XFS_ILOCK_EXCL;
-       }
 
        /*
         * Extents not yet cached requires exclusive access, don't block.  This
@@ -923,7 +713,7 @@ relock:
 }
 
 static int
-xfs_file_iomap_begin(
+xfs_direct_write_iomap_begin(
        struct inode            *inode,
        loff_t                  offset,
        loff_t                  length,
@@ -933,103 +723,63 @@ xfs_file_iomap_begin(
 {
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_bmbt_irec    imap;
-       xfs_fileoff_t           offset_fsb, end_fsb;
+       struct xfs_bmbt_irec    imap, cmap;
+       xfs_fileoff_t           offset_fsb = XFS_B_TO_FSBT(mp, offset);
+       xfs_fileoff_t           end_fsb = xfs_iomap_end_fsb(mp, offset, length);
        int                     nimaps = 1, error = 0;
        bool                    shared = false;
        u16                     iomap_flags = 0;
        unsigned                lockmode;
 
+       ASSERT(flags & (IOMAP_WRITE | IOMAP_ZERO));
+
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && !(flags & IOMAP_DIRECT) &&
-                       !IS_DAX(inode) && !xfs_get_extsz_hint(ip)) {
-               /* Reserve delalloc blocks for regular writeback. */
-               return xfs_file_iomap_begin_delay(inode, offset, length, flags,
-                               iomap);
-       }
-
        /*
-        * Lock the inode in the manner required for the specified operation and
-        * check for as many conditions that would result in blocking as
-        * possible. This removes most of the non-blocking checks from the
-        * mapping code below.
-        */
-       error = xfs_ilock_for_iomap(ip, flags, &lockmode);
+        * Writes that span EOF might trigger an IO size update on completion,
+        * so consider them to be dirty for the purposes of O_DSYNC even if
+        * there is no other metadata changes pending or have been made here.
+        */
+       if (offset + length > i_size_read(inode))
+               iomap_flags |= IOMAP_F_DIRTY;
+
+       error = xfs_ilock_for_iomap(ip, flags, &lockmode);
        if (error)
                return error;
 
-       ASSERT(offset <= mp->m_super->s_maxbytes);
-       if (offset > mp->m_super->s_maxbytes - length)
-               length = mp->m_super->s_maxbytes - offset;
-       offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       end_fsb = XFS_B_TO_FSB(mp, offset + length);
-
        error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
                               &nimaps, 0);
        if (error)
                goto out_unlock;
 
-       if (flags & IOMAP_REPORT) {
-               /* Trim the mapping to the nearest shared extent boundary. */
-               error = xfs_reflink_trim_around_shared(ip, &imap, &shared);
-               if (error)
+       if (imap_needs_cow(ip, flags, &imap, nimaps)) {
+               error = -EAGAIN;
+               if (flags & IOMAP_NOWAIT)
                        goto out_unlock;
-       }
-
-       /* Non-modifying mapping requested, so we are done */
-       if (!(flags & (IOMAP_WRITE | IOMAP_ZERO)))
-               goto out_found;
-
-       /*
-        * Break shared extents if necessary. Checks for non-blocking IO have
-        * been done up front, so we don't need to do them here.
-        */
-       if (xfs_is_cow_inode(ip)) {
-               struct xfs_bmbt_irec    cmap;
-               bool                    directio = (flags & IOMAP_DIRECT);
-
-               /* if zeroing doesn't need COW allocation, then we are done. */
-               if ((flags & IOMAP_ZERO) &&
-                   !needs_cow_for_zeroing(&imap, nimaps))
-                       goto out_found;
 
                /* may drop and re-acquire the ilock */
-               cmap = imap;
-               error = xfs_reflink_allocate_cow(ip, &cmap, &shared, &lockmode,
-                               directio);
+               error = xfs_reflink_allocate_cow(ip, &imap, &cmap, &shared,
+                               &lockmode, flags & IOMAP_DIRECT);
                if (error)
                        goto out_unlock;
-
-               /*
-                * For buffered writes we need to report the address of the
-                * previous block (if there was any) so that the higher level
-                * write code can perform read-modify-write operations; we
-                * won't need the CoW fork mapping until writeback.  For direct
-                * I/O, which must be block aligned, we need to report the
-                * newly allocated address.  If the data fork has a hole, copy
-                * the COW fork mapping to avoid allocating to the data fork.
-                */
-               if (directio || imap.br_startblock == HOLESTARTBLOCK)
-                       imap = cmap;
-
+               if (shared)
+                       goto out_found_cow;
                end_fsb = imap.br_startoff + imap.br_blockcount;
                length = XFS_FSB_TO_B(mp, end_fsb) - offset;
        }
 
-       /* Don't need to allocate over holes when doing zeroing operations. */
-       if (flags & IOMAP_ZERO)
-               goto out_found;
+       if (imap_needs_alloc(inode, flags, &imap, nimaps))
+               goto allocate_blocks;
 
-       if (!imap_needs_alloc(inode, &imap, nimaps))
-               goto out_found;
+       xfs_iunlock(ip, lockmode);
+       trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap);
+       return xfs_bmbt_to_iomap(ip, iomap, &imap, iomap_flags);
 
-       /* If nowait is set bail since we are going to make allocations. */
-       if (flags & IOMAP_NOWAIT) {
-               error = -EAGAIN;
+allocate_blocks:
+       error = -EAGAIN;
+       if (flags & IOMAP_NOWAIT)
                goto out_unlock;
-       }
 
        /*
         * We cap the maximum length we map to a sane size  to keep the chunks
@@ -1041,57 +791,273 @@ xfs_file_iomap_begin(
         * lower level functions are updated.
         */
        length = min_t(loff_t, length, 1024 * PAGE_SIZE);
+       end_fsb = xfs_iomap_end_fsb(mp, offset, length);
 
-       /*
-        * xfs_iomap_write_direct() expects the shared lock. It is unlocked on
-        * return.
-        */
-       if (lockmode == XFS_ILOCK_EXCL)
-               xfs_ilock_demote(ip, lockmode);
-       error = xfs_iomap_write_direct(ip, offset, length, &imap,
-                       nimaps);
+       if (offset + length > XFS_ISIZE(ip))
+               end_fsb = xfs_iomap_eof_align_last_fsb(ip, end_fsb);
+       else if (nimaps && imap.br_startblock == HOLESTARTBLOCK)
+               end_fsb = min(end_fsb, imap.br_startoff + imap.br_blockcount);
+       xfs_iunlock(ip, lockmode);
+
+       error = xfs_iomap_write_direct(ip, offset_fsb, end_fsb - offset_fsb,
+                       &imap);
        if (error)
                return error;
 
-       iomap_flags |= IOMAP_F_NEW;
        trace_xfs_iomap_alloc(ip, offset, length, XFS_DATA_FORK, &imap);
+       return xfs_bmbt_to_iomap(ip, iomap, &imap, iomap_flags | IOMAP_F_NEW);
+
+out_found_cow:
+       xfs_iunlock(ip, lockmode);
+       length = XFS_FSB_TO_B(mp, cmap.br_startoff + cmap.br_blockcount);
+       trace_xfs_iomap_found(ip, offset, length - offset, XFS_COW_FORK, &cmap);
+       if (imap.br_startblock != HOLESTARTBLOCK) {
+               error = xfs_bmbt_to_iomap(ip, srcmap, &imap, 0);
+               if (error)
+                       return error;
+       }
+       return xfs_bmbt_to_iomap(ip, iomap, &cmap, IOMAP_F_SHARED);
+
+out_unlock:
+       xfs_iunlock(ip, lockmode);
+       return error;
+}
+
+const struct iomap_ops xfs_direct_write_iomap_ops = {
+       .iomap_begin            = xfs_direct_write_iomap_begin,
+};
+
+static int
+xfs_buffered_write_iomap_begin(
+       struct inode            *inode,
+       loff_t                  offset,
+       loff_t                  count,
+       unsigned                flags,
+       struct iomap            *iomap,
+       struct iomap            *srcmap)
+{
+       struct xfs_inode        *ip = XFS_I(inode);
+       struct xfs_mount        *mp = ip->i_mount;
+       xfs_fileoff_t           offset_fsb = XFS_B_TO_FSBT(mp, offset);
+       xfs_fileoff_t           end_fsb = xfs_iomap_end_fsb(mp, offset, count);
+       struct xfs_bmbt_irec    imap, cmap;
+       struct xfs_iext_cursor  icur, ccur;
+       xfs_fsblock_t           prealloc_blocks = 0;
+       bool                    eof = false, cow_eof = false, shared = false;
+       int                     allocfork = XFS_DATA_FORK;
+       int                     error = 0;
+
+       /* we can't use delayed allocations when using extent size hints */
+       if (xfs_get_extsz_hint(ip))
+               return xfs_direct_write_iomap_begin(inode, offset, count,
+                               flags, iomap, srcmap);
+
+       ASSERT(!XFS_IS_REALTIME_INODE(ip));
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, XFS_DATA_FORK)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               error = -EFSCORRUPTED;
+               goto out_unlock;
+       }
+
+       XFS_STATS_INC(mp, xs_blk_mapw);
+
+       if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) {
+               error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+               if (error)
+                       goto out_unlock;
+       }
 
-out_finish:
        /*
-        * Writes that span EOF might trigger an IO size update on completion,
-        * so consider them to be dirty for the purposes of O_DSYNC even if
-        * there is no other metadata changes pending or have been made here.
+        * Search the data fork fork first to look up our source mapping.  We
+        * always need the data fork map, as we have to return it to the
+        * iomap code so that the higher level write code can read data in to
+        * perform read-modify-write cycles for unaligned writes.
         */
-       if ((flags & IOMAP_WRITE) && offset + length > i_size_read(inode))
-               iomap_flags |= IOMAP_F_DIRTY;
-       if (shared)
-               iomap_flags |= IOMAP_F_SHARED;
-       return xfs_bmbt_to_iomap(ip, iomap, &imap, iomap_flags);
+       eof = !xfs_iext_lookup_extent(ip, &ip->i_df, offset_fsb, &icur, &imap);
+       if (eof)
+               imap.br_startoff = end_fsb; /* fake hole until the end */
 
-out_found:
-       ASSERT(nimaps);
-       xfs_iunlock(ip, lockmode);
-       trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap);
-       goto out_finish;
+       /* We never need to allocate blocks for zeroing a hole. */
+       if ((flags & IOMAP_ZERO) && imap.br_startoff > offset_fsb) {
+               xfs_hole_to_iomap(ip, iomap, offset_fsb, imap.br_startoff);
+               goto out_unlock;
+       }
+
+       /*
+        * Search the COW fork extent list even if we did not find a data fork
+        * extent.  This serves two purposes: first this implements the
+        * speculative preallocation using cowextsize, so that we also unshare
+        * block adjacent to shared blocks instead of just the shared blocks
+        * themselves.  Second the lookup in the extent list is generally faster
+        * than going out to the shared extent tree.
+        */
+       if (xfs_is_cow_inode(ip)) {
+               if (!ip->i_cowfp) {
+                       ASSERT(!xfs_is_reflink_inode(ip));
+                       xfs_ifork_init_cow(ip);
+               }
+               cow_eof = !xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb,
+                               &ccur, &cmap);
+               if (!cow_eof && cmap.br_startoff <= offset_fsb) {
+                       trace_xfs_reflink_cow_found(ip, &cmap);
+                       goto found_cow;
+               }
+       }
+
+       if (imap.br_startoff <= offset_fsb) {
+               /*
+                * For reflink files we may need a delalloc reservation when
+                * overwriting shared extents.   This includes zeroing of
+                * existing extents that contain data.
+                */
+               if (!xfs_is_cow_inode(ip) ||
+                   ((flags & IOMAP_ZERO) && imap.br_state != XFS_EXT_NORM)) {
+                       trace_xfs_iomap_found(ip, offset, count, XFS_DATA_FORK,
+                                       &imap);
+                       goto found_imap;
+               }
+
+               xfs_trim_extent(&imap, offset_fsb, end_fsb - offset_fsb);
+
+               /* Trim the mapping to the nearest shared extent boundary. */
+               error = xfs_inode_need_cow(ip, &imap, &shared);
+               if (error)
+                       goto out_unlock;
+
+               /* Not shared?  Just report the (potentially capped) extent. */
+               if (!shared) {
+                       trace_xfs_iomap_found(ip, offset, count, XFS_DATA_FORK,
+                                       &imap);
+                       goto found_imap;
+               }
+
+               /*
+                * Fork all the shared blocks from our write offset until the
+                * end of the extent.
+                */
+               allocfork = XFS_COW_FORK;
+               end_fsb = imap.br_startoff + imap.br_blockcount;
+       } else {
+               /*
+                * We cap the maximum length we map here to MAX_WRITEBACK_PAGES
+                * pages to keep the chunks of work done where somewhat
+                * symmetric with the work writeback does.  This is a completely
+                * arbitrary number pulled out of thin air.
+                *
+                * Note that the values needs to be less than 32-bits wide until
+                * the lower level functions are updated.
+                */
+               count = min_t(loff_t, count, 1024 * PAGE_SIZE);
+               end_fsb = xfs_iomap_end_fsb(mp, offset, count);
+
+               if (xfs_is_always_cow_inode(ip))
+                       allocfork = XFS_COW_FORK;
+       }
+
+       error = xfs_qm_dqattach_locked(ip, false);
+       if (error)
+               goto out_unlock;
+
+       if (eof) {
+               prealloc_blocks = xfs_iomap_prealloc_size(ip, allocfork, offset,
+                               count, &icur);
+               if (prealloc_blocks) {
+                       xfs_extlen_t    align;
+                       xfs_off_t       end_offset;
+                       xfs_fileoff_t   p_end_fsb;
+
+                       end_offset = XFS_ALLOC_ALIGN(mp, offset + count - 1);
+                       p_end_fsb = XFS_B_TO_FSBT(mp, end_offset) +
+                                       prealloc_blocks;
+
+                       align = xfs_eof_alignment(ip);
+                       if (align)
+                               p_end_fsb = roundup_64(p_end_fsb, align);
+
+                       p_end_fsb = min(p_end_fsb,
+                               XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes));
+                       ASSERT(p_end_fsb > offset_fsb);
+                       prealloc_blocks = p_end_fsb - end_fsb;
+               }
+       }
+
+retry:
+       error = xfs_bmapi_reserve_delalloc(ip, allocfork, offset_fsb,
+                       end_fsb - offset_fsb, prealloc_blocks,
+                       allocfork == XFS_DATA_FORK ? &imap : &cmap,
+                       allocfork == XFS_DATA_FORK ? &icur : &ccur,
+                       allocfork == XFS_DATA_FORK ? eof : cow_eof);
+       switch (error) {
+       case 0:
+               break;
+       case -ENOSPC:
+       case -EDQUOT:
+               /* retry without any preallocation */
+               trace_xfs_delalloc_enospc(ip, offset, count);
+               if (prealloc_blocks) {
+                       prealloc_blocks = 0;
+                       goto retry;
+               }
+               /*FALLTHRU*/
+       default:
+               goto out_unlock;
+       }
+
+       if (allocfork == XFS_COW_FORK) {
+               trace_xfs_iomap_alloc(ip, offset, count, allocfork, &cmap);
+               goto found_cow;
+       }
+
+       /*
+        * Flag newly allocated delalloc blocks with IOMAP_F_NEW so we punch
+        * them out if the write happens to fail.
+        */
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       trace_xfs_iomap_alloc(ip, offset, count, allocfork, &imap);
+       return xfs_bmbt_to_iomap(ip, iomap, &imap, IOMAP_F_NEW);
+
+found_imap:
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       return xfs_bmbt_to_iomap(ip, iomap, &imap, 0);
+
+found_cow:
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       if (imap.br_startoff <= offset_fsb) {
+               error = xfs_bmbt_to_iomap(ip, srcmap, &imap, 0);
+               if (error)
+                       return error;
+       } else {
+               xfs_trim_extent(&cmap, offset_fsb,
+                               imap.br_startoff - offset_fsb);
+       }
+       return xfs_bmbt_to_iomap(ip, iomap, &cmap, IOMAP_F_SHARED);
 
 out_unlock:
-       xfs_iunlock(ip, lockmode);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 }
 
 static int
-xfs_file_iomap_end_delalloc(
-       struct xfs_inode        *ip,
+xfs_buffered_write_iomap_end(
+       struct inode            *inode,
        loff_t                  offset,
        loff_t                  length,
        ssize_t                 written,
+       unsigned                flags,
        struct iomap            *iomap)
 {
+       struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           start_fsb;
        xfs_fileoff_t           end_fsb;
        int                     error = 0;
 
+       if (iomap->type != IOMAP_DELALLOC)
+               return 0;
+
        /*
         * Behave as if the write failed if drop writes is enabled. Set the NEW
         * flag to force delalloc cleanup.
@@ -1136,24 +1102,51 @@ xfs_file_iomap_end_delalloc(
        return 0;
 }
 
+const struct iomap_ops xfs_buffered_write_iomap_ops = {
+       .iomap_begin            = xfs_buffered_write_iomap_begin,
+       .iomap_end              = xfs_buffered_write_iomap_end,
+};
+
 static int
-xfs_file_iomap_end(
+xfs_read_iomap_begin(
        struct inode            *inode,
        loff_t                  offset,
        loff_t                  length,
-       ssize_t                 written,
        unsigned                flags,
-       struct iomap            *iomap)
+       struct iomap            *iomap,
+       struct iomap            *srcmap)
 {
-       if ((flags & IOMAP_WRITE) && iomap->type == IOMAP_DELALLOC)
-               return xfs_file_iomap_end_delalloc(XFS_I(inode), offset,
-                               length, written, iomap);
-       return 0;
+       struct xfs_inode        *ip = XFS_I(inode);
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_bmbt_irec    imap;
+       xfs_fileoff_t           offset_fsb = XFS_B_TO_FSBT(mp, offset);
+       xfs_fileoff_t           end_fsb = xfs_iomap_end_fsb(mp, offset, length);
+       int                     nimaps = 1, error = 0;
+       bool                    shared = false;
+       unsigned                lockmode;
+
+       ASSERT(!(flags & (IOMAP_WRITE | IOMAP_ZERO)));
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return -EIO;
+
+       error = xfs_ilock_for_iomap(ip, flags, &lockmode);
+       if (error)
+               return error;
+       error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
+                              &nimaps, 0);
+       if (!error && (flags & IOMAP_REPORT))
+               error = xfs_reflink_trim_around_shared(ip, &imap, &shared);
+       xfs_iunlock(ip, lockmode);
+
+       if (error)
+               return error;
+       trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap);
+       return xfs_bmbt_to_iomap(ip, iomap, &imap, shared ? IOMAP_F_SHARED : 0);
 }
 
-const struct iomap_ops xfs_iomap_ops = {
-       .iomap_begin            = xfs_file_iomap_begin,
-       .iomap_end              = xfs_file_iomap_end,
+const struct iomap_ops xfs_read_iomap_ops = {
+       .iomap_begin            = xfs_read_iomap_begin,
 };
 
 static int
@@ -1196,8 +1189,7 @@ xfs_seek_iomap_begin(
                /*
                 * Fake a hole until the end of the file.
                 */
-               data_fsb = min(XFS_B_TO_FSB(mp, offset + length),
-                              XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes));
+               data_fsb = xfs_iomap_end_fsb(mp, offset, length);
        }
 
        /*
index 71d0ae4..7d37035 100644 (file)
 struct xfs_inode;
 struct xfs_bmbt_irec;
 
-int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t,
-                       struct xfs_bmbt_irec *, int);
+int xfs_iomap_write_direct(struct xfs_inode *ip, xfs_fileoff_t offset_fsb,
+               xfs_fileoff_t count_fsb, struct xfs_bmbt_irec *imap);
 int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t, bool);
+xfs_fileoff_t xfs_iomap_eof_align_last_fsb(struct xfs_inode *ip,
+               xfs_fileoff_t end_fsb);
 
 int xfs_bmbt_to_iomap(struct xfs_inode *, struct iomap *,
                struct xfs_bmbt_irec *, u16);
-xfs_extlen_t xfs_eof_alignment(struct xfs_inode *ip, xfs_extlen_t extsize);
 
 static inline xfs_filblks_t
 xfs_aligned_fsb_count(
@@ -39,7 +40,9 @@ xfs_aligned_fsb_count(
        return count_fsb;
 }
 
-extern const struct iomap_ops xfs_iomap_ops;
+extern const struct iomap_ops xfs_buffered_write_iomap_ops;
+extern const struct iomap_ops xfs_direct_write_iomap_ops;
+extern const struct iomap_ops xfs_read_iomap_ops;
 extern const struct iomap_ops xfs_seek_iomap_ops;
 extern const struct iomap_ops xfs_xattr_iomap_ops;
 
index fe285d1..8afe69c 100644 (file)
@@ -20,6 +20,7 @@
 #include "xfs_symlink.h"
 #include "xfs_dir2.h"
 #include "xfs_iomap.h"
+#include "xfs_error.h"
 
 #include <linux/xattr.h>
 #include <linux/posix_acl.h>
@@ -470,20 +471,57 @@ xfs_vn_get_link_inline(
        struct inode            *inode,
        struct delayed_call     *done)
 {
+       struct xfs_inode        *ip = XFS_I(inode);
        char                    *link;
 
-       ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE);
+       ASSERT(ip->i_df.if_flags & XFS_IFINLINE);
 
        /*
         * The VFS crashes on a NULL pointer, so return -EFSCORRUPTED if
         * if_data is junk.
         */
-       link = XFS_I(inode)->i_df.if_u1.if_data;
-       if (!link)
+       link = ip->i_df.if_u1.if_data;
+       if (XFS_IS_CORRUPT(ip->i_mount, !link))
                return ERR_PTR(-EFSCORRUPTED);
        return link;
 }
 
+static uint32_t
+xfs_stat_blksize(
+       struct xfs_inode        *ip)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+
+       /*
+        * If the file blocks are being allocated from a realtime volume, then
+        * always return the realtime extent size.
+        */
+       if (XFS_IS_REALTIME_INODE(ip))
+               return xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;
+
+       /*
+        * Allow large block sizes to be reported to userspace programs if the
+        * "largeio" mount option is used.
+        *
+        * If compatibility mode is specified, simply return the basic unit of
+        * caching so that we don't get inefficient read/modify/write I/O from
+        * user apps. Otherwise....
+        *
+        * If the underlying volume is a stripe, then return the stripe width in
+        * bytes as the recommended I/O size. It is not a stripe and we've set a
+        * default buffered I/O size, return that, otherwise return the compat
+        * default.
+        */
+       if (mp->m_flags & XFS_MOUNT_LARGEIO) {
+               if (mp->m_swidth)
+                       return mp->m_swidth << mp->m_sb.sb_blocklog;
+               if (mp->m_flags & XFS_MOUNT_ALLOCSIZE)
+                       return 1U << mp->m_allocsize_log;
+       }
+
+       return PAGE_SIZE;
+}
+
 STATIC int
 xfs_vn_getattr(
        const struct path       *path,
@@ -516,8 +554,7 @@ xfs_vn_getattr(
        if (ip->i_d.di_version == 3) {
                if (request_mask & STATX_BTIME) {
                        stat->result_mask |= STATX_BTIME;
-                       stat->btime.tv_sec = ip->i_d.di_crtime.t_sec;
-                       stat->btime.tv_nsec = ip->i_d.di_crtime.t_nsec;
+                       stat->btime = ip->i_d.di_crtime;
                }
        }
 
@@ -543,16 +580,7 @@ xfs_vn_getattr(
                stat->rdev = inode->i_rdev;
                break;
        default:
-               if (XFS_IS_REALTIME_INODE(ip)) {
-                       /*
-                        * If the file blocks are being allocated from a
-                        * realtime volume, then return the inode's realtime
-                        * extent size or the realtime volume's extent size.
-                        */
-                       stat->blksize =
-                               xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;
-               } else
-                       stat->blksize = xfs_preferred_iosize(mp);
+               stat->blksize = xfs_stat_blksize(ip);
                stat->rdev = 0;
                break;
        }
@@ -664,7 +692,7 @@ xfs_setattr_nonsize(
                ASSERT(gdqp == NULL);
                error = xfs_qm_vop_dqalloc(ip, xfs_kuid_to_uid(uid),
                                           xfs_kgid_to_gid(gid),
-                                          xfs_get_projid(ip),
+                                          ip->i_d.di_projid,
                                           qflags, &udqp, &gdqp, NULL);
                if (error)
                        return error;
@@ -883,10 +911,10 @@ xfs_setattr_size(
        if (newsize > oldsize) {
                trace_xfs_zero_eof(ip, oldsize, newsize - oldsize);
                error = iomap_zero_range(inode, oldsize, newsize - oldsize,
-                               &did_zeroing, &xfs_iomap_ops);
+                               &did_zeroing, &xfs_buffered_write_iomap_ops);
        } else {
                error = iomap_truncate_page(inode, newsize, &did_zeroing,
-                               &xfs_iomap_ops);
+                               &xfs_buffered_write_iomap_ops);
        }
 
        if (error)
@@ -1114,7 +1142,7 @@ xfs_vn_fiemap(
                                &xfs_xattr_iomap_ops);
        } else {
                error = iomap_fiemap(inode, fieinfo, start, length,
-                               &xfs_iomap_ops);
+                               &xfs_read_iomap_ops);
        }
        xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED);
 
@@ -1227,7 +1255,7 @@ xfs_inode_supports_dax(
                return false;
 
        /* Device has to support DAX too. */
-       return xfs_find_daxdev_for_inode(VFS_I(ip)) != NULL;
+       return xfs_inode_buftarg(ip)->bt_daxdev != NULL;
 }
 
 STATIC void
@@ -1290,9 +1318,7 @@ xfs_setup_inode(
                lockdep_set_class(&inode->i_rwsem,
                                  &inode->i_sb->s_type->i_mutex_dir_key);
                lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class);
-               ip->d_ops = ip->i_mount->m_dir_inode_ops;
        } else {
-               ip->d_ops = ip->i_mount->m_nondir_inode_ops;
                lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class);
        }
 
index 884950a..4b31c29 100644 (file)
@@ -84,7 +84,7 @@ xfs_bulkstat_one_int(
        /* xfs_iget returns the following without needing
         * further change.
         */
-       buf->bs_projectid = xfs_get_projid(ip);
+       buf->bs_projectid = ip->i_d.di_projid;
        buf->bs_ino = ino;
        buf->bs_uid = dic->di_uid;
        buf->bs_gid = dic->di_gid;
@@ -97,8 +97,8 @@ xfs_bulkstat_one_int(
        buf->bs_mtime_nsec = inode->i_mtime.tv_nsec;
        buf->bs_ctime = inode->i_ctime.tv_sec;
        buf->bs_ctime_nsec = inode->i_ctime.tv_nsec;
-       buf->bs_btime = dic->di_crtime.t_sec;
-       buf->bs_btime_nsec = dic->di_crtime.t_nsec;
+       buf->bs_btime = dic->di_crtime.tv_sec;
+       buf->bs_btime_nsec = dic->di_crtime.tv_nsec;
        buf->bs_gen = inode->i_generation;
        buf->bs_mode = inode->i_mode;
 
index aa375cf..233dcc8 100644 (file)
@@ -298,7 +298,8 @@ xfs_iwalk_ag_start(
        error = xfs_inobt_get_rec(*curpp, irec, has_more);
        if (error)
                return error;
-       XFS_WANT_CORRUPTED_RETURN(mp, *has_more == 1);
+       if (XFS_IS_CORRUPT(mp, *has_more != 1))
+               return -EFSCORRUPTED;
 
        /*
         * If the LE lookup yielded an inobt record before the cursor position,
index ca15105..8738bb0 100644 (file)
@@ -223,26 +223,32 @@ int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
                char *data, unsigned int op);
 
 #define ASSERT_ALWAYS(expr)    \
-       (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+       (likely(expr) ? (void)0 : assfail(NULL, #expr, __FILE__, __LINE__))
 
 #ifdef DEBUG
 #define ASSERT(expr)   \
-       (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+       (likely(expr) ? (void)0 : assfail(NULL, #expr, __FILE__, __LINE__))
 
 #else  /* !DEBUG */
 
 #ifdef XFS_WARN
 
 #define ASSERT(expr)   \
-       (likely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__))
+       (likely(expr) ? (void)0 : asswarn(NULL, #expr, __FILE__, __LINE__))
 
 #else  /* !DEBUG && !XFS_WARN */
 
-#define ASSERT(expr)   ((void)0)
+#define ASSERT(expr)           ((void)0)
 
 #endif /* XFS_WARN */
 #endif /* DEBUG */
 
+#define XFS_IS_CORRUPT(mp, expr)       \
+       (unlikely(expr) ? xfs_corruption_error(#expr, XFS_ERRLEVEL_LOW, (mp), \
+                                              NULL, 0, __FILE__, __LINE__, \
+                                              __this_address), \
+                         true : false)
+
 #define STATIC static noinline
 
 #ifdef CONFIG_XFS_RT
index 641d07f..6a147c6 100644 (file)
@@ -57,10 +57,6 @@ xlog_state_get_iclog_space(
        struct xlog_ticket      *ticket,
        int                     *continued_write,
        int                     *logoffsetp);
-STATIC int
-xlog_state_release_iclog(
-       struct xlog             *log,
-       struct xlog_in_core     *iclog);
 STATIC void
 xlog_state_switch_iclogs(
        struct xlog             *log,
@@ -83,7 +79,10 @@ STATIC void
 xlog_ungrant_log_space(
        struct xlog             *log,
        struct xlog_ticket      *ticket);
-
+STATIC void
+xlog_sync(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog);
 #if defined(DEBUG)
 STATIC void
 xlog_verify_dest_ptr(
@@ -552,16 +551,71 @@ xfs_log_done(
        return lsn;
 }
 
+static bool
+__xlog_state_release_iclog(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog)
+{
+       lockdep_assert_held(&log->l_icloglock);
+
+       if (iclog->ic_state == XLOG_STATE_WANT_SYNC) {
+               /* update tail before writing to iclog */
+               xfs_lsn_t tail_lsn = xlog_assign_tail_lsn(log->l_mp);
+
+               iclog->ic_state = XLOG_STATE_SYNCING;
+               iclog->ic_header.h_tail_lsn = cpu_to_be64(tail_lsn);
+               xlog_verify_tail_lsn(log, iclog, tail_lsn);
+               /* cycle incremented when incrementing curr_block */
+               return true;
+       }
+
+       ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
+       return false;
+}
+
+/*
+ * Flush iclog to disk if this is the last reference to the given iclog and the
+ * it is in the WANT_SYNC state.
+ */
+static int
+xlog_state_release_iclog(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog)
+{
+       lockdep_assert_held(&log->l_icloglock);
+
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
+               return -EIO;
+
+       if (atomic_dec_and_test(&iclog->ic_refcnt) &&
+           __xlog_state_release_iclog(log, iclog)) {
+               spin_unlock(&log->l_icloglock);
+               xlog_sync(log, iclog);
+               spin_lock(&log->l_icloglock);
+       }
+
+       return 0;
+}
+
 int
 xfs_log_release_iclog(
-       struct xfs_mount        *mp,
+       struct xfs_mount        *mp,
        struct xlog_in_core     *iclog)
 {
-       if (xlog_state_release_iclog(mp->m_log, iclog)) {
+       struct xlog             *log = mp->m_log;
+       bool                    sync;
+
+       if (iclog->ic_state == XLOG_STATE_IOERROR) {
                xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                return -EIO;
        }
 
+       if (atomic_dec_and_lock(&iclog->ic_refcnt, &log->l_icloglock)) {
+               sync = __xlog_state_release_iclog(log, iclog);
+               spin_unlock(&log->l_icloglock);
+               if (sync)
+                       xlog_sync(log, iclog);
+       }
        return 0;
 }
 
@@ -866,10 +920,7 @@ out_err:
        iclog = log->l_iclog;
        atomic_inc(&iclog->ic_refcnt);
        xlog_state_want_sync(log, iclog);
-       spin_unlock(&log->l_icloglock);
        error = xlog_state_release_iclog(log, iclog);
-
-       spin_lock(&log->l_icloglock);
        switch (iclog->ic_state) {
        default:
                if (!XLOG_FORCED_SHUTDOWN(log)) {
@@ -924,8 +975,8 @@ xfs_log_unmount_write(xfs_mount_t *mp)
 #ifdef DEBUG
        first_iclog = iclog = log->l_iclog;
        do {
-               if (!(iclog->ic_state & XLOG_STATE_IOERROR)) {
-                       ASSERT(iclog->ic_state & XLOG_STATE_ACTIVE);
+               if (iclog->ic_state != XLOG_STATE_IOERROR) {
+                       ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
                        ASSERT(iclog->ic_offset == 0);
                }
                iclog = iclog->ic_next;
@@ -950,21 +1001,17 @@ xfs_log_unmount_write(xfs_mount_t *mp)
                spin_lock(&log->l_icloglock);
                iclog = log->l_iclog;
                atomic_inc(&iclog->ic_refcnt);
-
                xlog_state_want_sync(log, iclog);
-               spin_unlock(&log->l_icloglock);
                error =  xlog_state_release_iclog(log, iclog);
-
-               spin_lock(&log->l_icloglock);
-
-               if ( ! (   iclog->ic_state == XLOG_STATE_ACTIVE
-                       || iclog->ic_state == XLOG_STATE_DIRTY
-                       || iclog->ic_state == XLOG_STATE_IOERROR) ) {
-
-                               xlog_wait(&iclog->ic_force_wait,
-                                                       &log->l_icloglock);
-               } else {
+               switch (iclog->ic_state) {
+               case XLOG_STATE_ACTIVE:
+               case XLOG_STATE_DIRTY:
+               case XLOG_STATE_IOERROR:
                        spin_unlock(&log->l_icloglock);
+                       break;
+               default:
+                       xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
+                       break;
                }
        }
 
@@ -1254,7 +1301,7 @@ xlog_ioend_work(
                 * didn't succeed.
                 */
                aborted = true;
-       } else if (iclog->ic_state & XLOG_STATE_IOERROR) {
+       } else if (iclog->ic_state == XLOG_STATE_IOERROR) {
                aborted = true;
        }
 
@@ -1479,7 +1526,7 @@ xlog_alloc_log(
 
        log->l_ioend_workqueue = alloc_workqueue("xfs-log/%s",
                        WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_HIGHPRI, 0,
-                       mp->m_fsname);
+                       mp->m_super->s_id);
        if (!log->l_ioend_workqueue)
                goto out_free_iclog;
 
@@ -1727,7 +1774,7 @@ xlog_write_iclog(
         * across the log IO to archieve that.
         */
        down(&iclog->ic_sema);
-       if (unlikely(iclog->ic_state & XLOG_STATE_IOERROR)) {
+       if (unlikely(iclog->ic_state == XLOG_STATE_IOERROR)) {
                /*
                 * It would seem logical to return EIO here, but we rely on
                 * the log state machine to propagate I/O errors instead of
@@ -1735,13 +1782,11 @@ xlog_write_iclog(
                 * the buffer manually, the code needs to be kept in sync
                 * with the I/O completion path.
                 */
-               xlog_state_done_syncing(iclog, XFS_LI_ABORTED);
+               xlog_state_done_syncing(iclog, true);
                up(&iclog->ic_sema);
                return;
        }
 
-       iclog->ic_io_size = count;
-
        bio_init(&iclog->ic_bio, iclog->ic_bvec, howmany(count, PAGE_SIZE));
        bio_set_dev(&iclog->ic_bio, log->l_targ->bt_bdev);
        iclog->ic_bio.bi_iter.bi_sector = log->l_logBBstart + bno;
@@ -1751,9 +1796,9 @@ xlog_write_iclog(
        if (need_flush)
                iclog->ic_bio.bi_opf |= REQ_PREFLUSH;
 
-       xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, iclog->ic_io_size);
+       xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count);
        if (is_vmalloc_addr(iclog->ic_data))
-               flush_kernel_vmap_range(iclog->ic_data, iclog->ic_io_size);
+               flush_kernel_vmap_range(iclog->ic_data, count);
 
        /*
         * If this log buffer would straddle the end of the log we will have
@@ -1969,7 +2014,6 @@ xlog_dealloc_log(
 /*
  * Update counters atomically now that memcpy is done.
  */
-/* ARGSUSED */
 static inline void
 xlog_state_finish_copy(
        struct xlog             *log,
@@ -1977,16 +2021,11 @@ xlog_state_finish_copy(
        int                     record_cnt,
        int                     copy_bytes)
 {
-       spin_lock(&log->l_icloglock);
+       lockdep_assert_held(&log->l_icloglock);
 
        be32_add_cpu(&iclog->ic_header.h_num_logops, record_cnt);
        iclog->ic_offset += copy_bytes;
-
-       spin_unlock(&log->l_icloglock);
-}      /* xlog_state_finish_copy */
-
-
-
+}
 
 /*
  * print out info relating to regions written which consume
@@ -2263,15 +2302,18 @@ xlog_write_copy_finish(
        int                     log_offset,
        struct xlog_in_core     **commit_iclog)
 {
+       int                     error;
+
        if (*partial_copy) {
                /*
                 * This iclog has already been marked WANT_SYNC by
                 * xlog_state_get_iclog_space.
                 */
+               spin_lock(&log->l_icloglock);
                xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt);
                *record_cnt = 0;
                *data_cnt = 0;
-               return xlog_state_release_iclog(log, iclog);
+               goto release_iclog;
        }
 
        *partial_copy = 0;
@@ -2279,21 +2321,25 @@ xlog_write_copy_finish(
 
        if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) {
                /* no more space in this iclog - push it. */
+               spin_lock(&log->l_icloglock);
                xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt);
                *record_cnt = 0;
                *data_cnt = 0;
 
-               spin_lock(&log->l_icloglock);
                xlog_state_want_sync(log, iclog);
-               spin_unlock(&log->l_icloglock);
-
                if (!commit_iclog)
-                       return xlog_state_release_iclog(log, iclog);
+                       goto release_iclog;
+               spin_unlock(&log->l_icloglock);
                ASSERT(flags & XLOG_COMMIT_TRANS);
                *commit_iclog = iclog;
        }
 
        return 0;
+
+release_iclog:
+       error = xlog_state_release_iclog(log, iclog);
+       spin_unlock(&log->l_icloglock);
+       return error;
 }
 
 /*
@@ -2355,7 +2401,7 @@ xlog_write(
        int                     contwr = 0;
        int                     record_cnt = 0;
        int                     data_cnt = 0;
-       int                     error;
+       int                     error = 0;
 
        *start_lsn = 0;
 
@@ -2506,13 +2552,17 @@ next_lv:
 
        ASSERT(len == 0);
 
+       spin_lock(&log->l_icloglock);
        xlog_state_finish_copy(log, iclog, record_cnt, data_cnt);
-       if (!commit_iclog)
-               return xlog_state_release_iclog(log, iclog);
+       if (commit_iclog) {
+               ASSERT(flags & XLOG_COMMIT_TRANS);
+               *commit_iclog = iclog;
+       } else {
+               error = xlog_state_release_iclog(log, iclog);
+       }
+       spin_unlock(&log->l_icloglock);
 
-       ASSERT(flags & XLOG_COMMIT_TRANS);
-       *commit_iclog = iclog;
-       return 0;
+       return error;
 }
 
 
@@ -2548,7 +2598,7 @@ xlog_state_clean_iclog(
        int                     changed = 0;
 
        /* Prepare the completed iclog. */
-       if (!(dirty_iclog->ic_state & XLOG_STATE_IOERROR))
+       if (dirty_iclog->ic_state != XLOG_STATE_IOERROR)
                dirty_iclog->ic_state = XLOG_STATE_DIRTY;
 
        /* Walk all the iclogs to update the ordered active state. */
@@ -2639,7 +2689,8 @@ xlog_get_lowest_lsn(
        xfs_lsn_t               lowest_lsn = 0, lsn;
 
        do {
-               if (iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))
+               if (iclog->ic_state == XLOG_STATE_ACTIVE ||
+                   iclog->ic_state == XLOG_STATE_DIRTY)
                        continue;
 
                lsn = be64_to_cpu(iclog->ic_header.h_lsn);
@@ -2699,61 +2750,48 @@ static bool
 xlog_state_iodone_process_iclog(
        struct xlog             *log,
        struct xlog_in_core     *iclog,
-       struct xlog_in_core     *completed_iclog,
        bool                    *ioerror)
 {
        xfs_lsn_t               lowest_lsn;
        xfs_lsn_t               header_lsn;
 
-       /* Skip all iclogs in the ACTIVE & DIRTY states */
-       if (iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))
+       switch (iclog->ic_state) {
+       case XLOG_STATE_ACTIVE:
+       case XLOG_STATE_DIRTY:
+               /*
+                * Skip all iclogs in the ACTIVE & DIRTY states:
+                */
                return false;
-
-       /*
-        * Between marking a filesystem SHUTDOWN and stopping the log, we do
-        * flush all iclogs to disk (if there wasn't a log I/O error). So, we do
-        * want things to go smoothly in case of just a SHUTDOWN  w/o a
-        * LOG_IO_ERROR.
-        */
-       if (iclog->ic_state & XLOG_STATE_IOERROR) {
+       case XLOG_STATE_IOERROR:
+               /*
+                * Between marking a filesystem SHUTDOWN and stopping the log,
+                * we do flush all iclogs to disk (if there wasn't a log I/O
+                * error). So, we do want things to go smoothly in case of just
+                * a SHUTDOWN w/o a LOG_IO_ERROR.
+                */
                *ioerror = true;
                return false;
-       }
-
-       /*
-        * Can only perform callbacks in order.  Since this iclog is not in the
-        * DONE_SYNC/ DO_CALLBACK state, we skip the rest and just try to clean
-        * up.  If we set our iclog to DO_CALLBACK, we will not process it when
-        * we retry since a previous iclog is in the CALLBACK and the state
-        * cannot change since we are holding the l_icloglock.
-        */
-       if (!(iclog->ic_state &
-                       (XLOG_STATE_DONE_SYNC | XLOG_STATE_DO_CALLBACK))) {
-               if (completed_iclog &&
-                   (completed_iclog->ic_state == XLOG_STATE_DONE_SYNC)) {
-                       completed_iclog->ic_state = XLOG_STATE_DO_CALLBACK;
-               }
+       case XLOG_STATE_DONE_SYNC:
+               /*
+                * Now that we have an iclog that is in the DONE_SYNC state, do
+                * one more check here to see if we have chased our tail around.
+                * If this is not the lowest lsn iclog, then we will leave it
+                * for another completion to process.
+                */
+               header_lsn = be64_to_cpu(iclog->ic_header.h_lsn);
+               lowest_lsn = xlog_get_lowest_lsn(log);
+               if (lowest_lsn && XFS_LSN_CMP(lowest_lsn, header_lsn) < 0)
+                       return false;
+               xlog_state_set_callback(log, iclog, header_lsn);
+               return false;
+       default:
+               /*
+                * Can only perform callbacks in order.  Since this iclog is not
+                * in the DONE_SYNC state, we skip the rest and just try to
+                * clean up.
+                */
                return true;
        }
-
-       /*
-        * We now have an iclog that is in either the DO_CALLBACK or DONE_SYNC
-        * states. The other states (WANT_SYNC, SYNCING, or CALLBACK were caught
-        * by the above if and are going to clean (i.e. we aren't doing their
-        * callbacks) see the above if.
-        *
-        * We will do one more check here to see if we have chased our tail
-        * around. If this is not the lowest lsn iclog, then we will leave it
-        * for another completion to process.
-        */
-       header_lsn = be64_to_cpu(iclog->ic_header.h_lsn);
-       lowest_lsn = xlog_get_lowest_lsn(log);
-       if (lowest_lsn && XFS_LSN_CMP(lowest_lsn, header_lsn) < 0)
-               return false;
-
-       xlog_state_set_callback(log, iclog, header_lsn);
-       return false;
-
 }
 
 /*
@@ -2770,6 +2808,8 @@ xlog_state_do_iclog_callbacks(
        struct xlog             *log,
        struct xlog_in_core     *iclog,
        bool                    aborted)
+               __releases(&log->l_icloglock)
+               __acquires(&log->l_icloglock)
 {
        spin_unlock(&log->l_icloglock);
        spin_lock(&iclog->ic_callback_lock);
@@ -2792,57 +2832,13 @@ xlog_state_do_iclog_callbacks(
        spin_unlock(&iclog->ic_callback_lock);
 }
 
-#ifdef DEBUG
-/*
- * Make one last gasp attempt to see if iclogs are being left in limbo.  If the
- * above loop finds an iclog earlier than the current iclog and in one of the
- * syncing states, the current iclog is put into DO_CALLBACK and the callbacks
- * are deferred to the completion of the earlier iclog. Walk the iclogs in order
- * and make sure that no iclog is in DO_CALLBACK unless an earlier iclog is in
- * one of the syncing states.
- *
- * Note that SYNCING|IOERROR is a valid state so we cannot just check for
- * ic_state == SYNCING.
- */
-static void
-xlog_state_callback_check_state(
-       struct xlog             *log)
-{
-       struct xlog_in_core     *first_iclog = log->l_iclog;
-       struct xlog_in_core     *iclog = first_iclog;
-
-       do {
-               ASSERT(iclog->ic_state != XLOG_STATE_DO_CALLBACK);
-               /*
-                * Terminate the loop if iclogs are found in states
-                * which will cause other threads to clean up iclogs.
-                *
-                * SYNCING - i/o completion will go through logs
-                * DONE_SYNC - interrupt thread should be waiting for
-                *              l_icloglock
-                * IOERROR - give up hope all ye who enter here
-                */
-               if (iclog->ic_state == XLOG_STATE_WANT_SYNC ||
-                   iclog->ic_state & XLOG_STATE_SYNCING ||
-                   iclog->ic_state == XLOG_STATE_DONE_SYNC ||
-                   iclog->ic_state == XLOG_STATE_IOERROR )
-                       break;
-               iclog = iclog->ic_next;
-       } while (first_iclog != iclog);
-}
-#else
-#define xlog_state_callback_check_state(l)     ((void)0)
-#endif
-
 STATIC void
 xlog_state_do_callback(
        struct xlog             *log,
-       bool                    aborted,
-       struct xlog_in_core     *ciclog)
+       bool                    aborted)
 {
        struct xlog_in_core     *iclog;
        struct xlog_in_core     *first_iclog;
-       bool                    did_callbacks = false;
        bool                    cycled_icloglock;
        bool                    ioerror;
        int                     flushcnt = 0;
@@ -2866,11 +2862,11 @@ xlog_state_do_callback(
 
                do {
                        if (xlog_state_iodone_process_iclog(log, iclog,
-                                                       ciclog, &ioerror))
+                                                       &ioerror))
                                break;
 
-                       if (!(iclog->ic_state &
-                             (XLOG_STATE_CALLBACK | XLOG_STATE_IOERROR))) {
+                       if (iclog->ic_state != XLOG_STATE_CALLBACK &&
+                           iclog->ic_state != XLOG_STATE_IOERROR) {
                                iclog = iclog->ic_next;
                                continue;
                        }
@@ -2886,8 +2882,6 @@ xlog_state_do_callback(
                        iclog = iclog->ic_next;
                } while (first_iclog != iclog);
 
-               did_callbacks |= cycled_icloglock;
-
                if (repeats > 5000) {
                        flushcnt += repeats;
                        repeats = 0;
@@ -2897,10 +2891,8 @@ xlog_state_do_callback(
                }
        } while (!ioerror && cycled_icloglock);
 
-       if (did_callbacks)
-               xlog_state_callback_check_state(log);
-
-       if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR))
+       if (log->l_iclog->ic_state == XLOG_STATE_ACTIVE ||
+           log->l_iclog->ic_state == XLOG_STATE_IOERROR)
                wake_up_all(&log->l_flush_wait);
 
        spin_unlock(&log->l_icloglock);
@@ -2929,8 +2921,6 @@ xlog_state_done_syncing(
 
        spin_lock(&log->l_icloglock);
 
-       ASSERT(iclog->ic_state == XLOG_STATE_SYNCING ||
-              iclog->ic_state == XLOG_STATE_IOERROR);
        ASSERT(atomic_read(&iclog->ic_refcnt) == 0);
 
        /*
@@ -2939,8 +2929,10 @@ xlog_state_done_syncing(
         * and none should ever be attempted to be written to disk
         * again.
         */
-       if (iclog->ic_state != XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_SYNCING)
                iclog->ic_state = XLOG_STATE_DONE_SYNC;
+       else
+               ASSERT(iclog->ic_state == XLOG_STATE_IOERROR);
 
        /*
         * Someone could be sleeping prior to writing out the next
@@ -2949,7 +2941,7 @@ xlog_state_done_syncing(
         */
        wake_up_all(&iclog->ic_write_wait);
        spin_unlock(&log->l_icloglock);
-       xlog_state_do_callback(log, aborted, iclog);    /* also cleans log */
+       xlog_state_do_callback(log, aborted);   /* also cleans log */
 }      /* xlog_state_done_syncing */
 
 
@@ -2983,7 +2975,6 @@ xlog_state_get_iclog_space(
        int               log_offset;
        xlog_rec_header_t *head;
        xlog_in_core_t    *iclog;
-       int               error;
 
 restart:
        spin_lock(&log->l_icloglock);
@@ -3032,24 +3023,22 @@ restart:
         * can fit into remaining data section.
         */
        if (iclog->ic_size - iclog->ic_offset < 2*sizeof(xlog_op_header_t)) {
+               int             error = 0;
+
                xlog_state_switch_iclogs(log, iclog, iclog->ic_size);
 
                /*
-                * If I'm the only one writing to this iclog, sync it to disk.
-                * We need to do an atomic compare and decrement here to avoid
-                * racing with concurrent atomic_dec_and_lock() calls in
+                * If we are the only one writing to this iclog, sync it to
+                * disk.  We need to do an atomic compare and decrement here to
+                * avoid racing with concurrent atomic_dec_and_lock() calls in
                 * xlog_state_release_iclog() when there is more than one
                 * reference to the iclog.
                 */
-               if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1)) {
-                       /* we are the only one */
-                       spin_unlock(&log->l_icloglock);
+               if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1))
                        error = xlog_state_release_iclog(log, iclog);
-                       if (error)
-                               return error;
-               } else {
-                       spin_unlock(&log->l_icloglock);
-               }
+               spin_unlock(&log->l_icloglock);
+               if (error)
+                       return error;
                goto restart;
        }
 
@@ -3160,60 +3149,6 @@ xlog_ungrant_log_space(
        xfs_log_space_wake(log->l_mp);
 }
 
-/*
- * Flush iclog to disk if this is the last reference to the given iclog and
- * the WANT_SYNC bit is set.
- *
- * When this function is entered, the iclog is not necessarily in the
- * WANT_SYNC state.  It may be sitting around waiting to get filled.
- *
- *
- */
-STATIC int
-xlog_state_release_iclog(
-       struct xlog             *log,
-       struct xlog_in_core     *iclog)
-{
-       int             sync = 0;       /* do we sync? */
-
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
-               return -EIO;
-
-       ASSERT(atomic_read(&iclog->ic_refcnt) > 0);
-       if (!atomic_dec_and_lock(&iclog->ic_refcnt, &log->l_icloglock))
-               return 0;
-
-       if (iclog->ic_state & XLOG_STATE_IOERROR) {
-               spin_unlock(&log->l_icloglock);
-               return -EIO;
-       }
-       ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE ||
-              iclog->ic_state == XLOG_STATE_WANT_SYNC);
-
-       if (iclog->ic_state == XLOG_STATE_WANT_SYNC) {
-               /* update tail before writing to iclog */
-               xfs_lsn_t tail_lsn = xlog_assign_tail_lsn(log->l_mp);
-               sync++;
-               iclog->ic_state = XLOG_STATE_SYNCING;
-               iclog->ic_header.h_tail_lsn = cpu_to_be64(tail_lsn);
-               xlog_verify_tail_lsn(log, iclog, tail_lsn);
-               /* cycle incremented when incrementing curr_block */
-       }
-       spin_unlock(&log->l_icloglock);
-
-       /*
-        * We let the log lock go, so it's possible that we hit a log I/O
-        * error or some other SHUTDOWN condition that marks the iclog
-        * as XLOG_STATE_IOERROR before the bwrite. However, we know that
-        * this iclog has consistent data, so we ignore IOERROR
-        * flags after this point.
-        */
-       if (sync)
-               xlog_sync(log, iclog);
-       return 0;
-}      /* xlog_state_release_iclog */
-
-
 /*
  * This routine will mark the current iclog in the ring as WANT_SYNC
  * and move the current iclog pointer to the next iclog in the ring.
@@ -3307,7 +3242,7 @@ xfs_log_force(
 
        spin_lock(&log->l_icloglock);
        iclog = log->l_iclog;
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
                goto out_error;
 
        if (iclog->ic_state == XLOG_STATE_DIRTY ||
@@ -3337,12 +3272,9 @@ xfs_log_force(
                        atomic_inc(&iclog->ic_refcnt);
                        lsn = be64_to_cpu(iclog->ic_header.h_lsn);
                        xlog_state_switch_iclogs(log, iclog, 0);
-                       spin_unlock(&log->l_icloglock);
-
                        if (xlog_state_release_iclog(log, iclog))
-                               return -EIO;
+                               goto out_error;
 
-                       spin_lock(&log->l_icloglock);
                        if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn ||
                            iclog->ic_state == XLOG_STATE_DIRTY)
                                goto out_unlock;
@@ -3367,11 +3299,11 @@ xfs_log_force(
        if (!(flags & XFS_LOG_SYNC))
                goto out_unlock;
 
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
                goto out_error;
        XFS_STATS_INC(mp, xs_log_force_sleep);
        xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
                return -EIO;
        return 0;
 
@@ -3396,7 +3328,7 @@ __xfs_log_force_lsn(
 
        spin_lock(&log->l_icloglock);
        iclog = log->l_iclog;
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
                goto out_error;
 
        while (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) {
@@ -3425,10 +3357,8 @@ __xfs_log_force_lsn(
                 * will go out then.
                 */
                if (!already_slept &&
-                   (iclog->ic_prev->ic_state &
-                    (XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) {
-                       ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
-
+                   (iclog->ic_prev->ic_state == XLOG_STATE_WANT_SYNC ||
+                    iclog->ic_prev->ic_state == XLOG_STATE_SYNCING)) {
                        XFS_STATS_INC(mp, xs_log_force_sleep);
 
                        xlog_wait(&iclog->ic_prev->ic_write_wait,
@@ -3437,24 +3367,23 @@ __xfs_log_force_lsn(
                }
                atomic_inc(&iclog->ic_refcnt);
                xlog_state_switch_iclogs(log, iclog, 0);
-               spin_unlock(&log->l_icloglock);
                if (xlog_state_release_iclog(log, iclog))
-                       return -EIO;
+                       goto out_error;
                if (log_flushed)
                        *log_flushed = 1;
-               spin_lock(&log->l_icloglock);
        }
 
        if (!(flags & XFS_LOG_SYNC) ||
-           (iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY)))
+           (iclog->ic_state == XLOG_STATE_ACTIVE ||
+            iclog->ic_state == XLOG_STATE_DIRTY))
                goto out_unlock;
 
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
                goto out_error;
 
        XFS_STATS_INC(mp, xs_log_force_sleep);
        xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
-       if (iclog->ic_state & XLOG_STATE_IOERROR)
+       if (iclog->ic_state == XLOG_STATE_IOERROR)
                return -EIO;
        return 0;
 
@@ -3517,8 +3446,8 @@ xlog_state_want_sync(
        if (iclog->ic_state == XLOG_STATE_ACTIVE) {
                xlog_state_switch_iclogs(log, iclog, 0);
        } else {
-               ASSERT(iclog->ic_state &
-                       (XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR));
+               ASSERT(iclog->ic_state == XLOG_STATE_WANT_SYNC ||
+                      iclog->ic_state == XLOG_STATE_IOERROR);
        }
 }
 
@@ -3539,7 +3468,7 @@ xfs_log_ticket_put(
 {
        ASSERT(atomic_read(&ticket->t_ref) > 0);
        if (atomic_dec_and_test(&ticket->t_ref))
-               kmem_zone_free(xfs_log_ticket_zone, ticket);
+               kmem_cache_free(xfs_log_ticket_zone, ticket);
 }
 
 xlog_ticket_t *
@@ -3895,7 +3824,7 @@ xlog_state_ioerror(
        xlog_in_core_t  *iclog, *ic;
 
        iclog = log->l_iclog;
-       if (! (iclog->ic_state & XLOG_STATE_IOERROR)) {
+       if (iclog->ic_state != XLOG_STATE_IOERROR) {
                /*
                 * Mark all the incore logs IOERROR.
                 * From now on, no log flushes will result.
@@ -3955,7 +3884,7 @@ xfs_log_force_umount(
         * Somebody could've already done the hard work for us.
         * No need to get locks for this.
         */
-       if (logerror && log->l_iclog->ic_state & XLOG_STATE_IOERROR) {
+       if (logerror && log->l_iclog->ic_state == XLOG_STATE_IOERROR) {
                ASSERT(XLOG_FORCED_SHUTDOWN(log));
                return 1;
        }
@@ -4006,21 +3935,8 @@ xfs_log_force_umount(
        spin_lock(&log->l_cilp->xc_push_lock);
        wake_up_all(&log->l_cilp->xc_commit_wait);
        spin_unlock(&log->l_cilp->xc_push_lock);
-       xlog_state_do_callback(log, true, NULL);
-
-#ifdef XFSERRORDEBUG
-       {
-               xlog_in_core_t  *iclog;
+       xlog_state_do_callback(log, true);
 
-               spin_lock(&log->l_icloglock);
-               iclog = log->l_iclog;
-               do {
-                       ASSERT(iclog->ic_callback == 0);
-                       iclog = iclog->ic_next;
-               } while (iclog != log->l_iclog);
-               spin_unlock(&log->l_icloglock);
-       }
-#endif
        /* return non-zero if log IOERROR transition had already happened */
        return retval;
 }
index ef652ab..48435cf 100644 (file)
@@ -179,7 +179,7 @@ xlog_cil_alloc_shadow_bufs(
 
                        /*
                         * We free and allocate here as a realloc would copy
-                        * unecessary data. We don't use kmem_zalloc() for the
+                        * unnecessary data. We don't use kmem_zalloc() for the
                         * same reason - we don't need to zero the data area in
                         * the buffer, only the log vector header and the iovec
                         * storage.
@@ -682,7 +682,7 @@ xlog_cil_push(
        }
 
 
-       /* check for a previously pushed seqeunce */
+       /* check for a previously pushed sequence */
        if (push_seq < cil->xc_ctx->sequence) {
                spin_unlock(&cil->xc_push_lock);
                goto out_skip;
@@ -847,7 +847,7 @@ restart:
                goto out_abort;
 
        spin_lock(&commit_iclog->ic_callback_lock);
-       if (commit_iclog->ic_state & XLOG_STATE_IOERROR) {
+       if (commit_iclog->ic_state == XLOG_STATE_IOERROR) {
                spin_unlock(&commit_iclog->ic_callback_lock);
                goto out_abort;
        }
index b880c23..b192c5a 100644 (file)
@@ -40,17 +40,15 @@ static inline uint xlog_get_client_id(__be32 i)
 /*
  * In core log state
  */
-#define XLOG_STATE_ACTIVE    0x0001 /* Current IC log being written to */
-#define XLOG_STATE_WANT_SYNC 0x0002 /* Want to sync this iclog; no more writes */
-#define XLOG_STATE_SYNCING   0x0004 /* This IC log is syncing */
-#define XLOG_STATE_DONE_SYNC 0x0008 /* Done syncing to disk */
-#define XLOG_STATE_DO_CALLBACK \
-                            0x0010 /* Process callback functions */
-#define XLOG_STATE_CALLBACK  0x0020 /* Callback functions now */
-#define XLOG_STATE_DIRTY     0x0040 /* Dirty IC log, not ready for ACTIVE status*/
-#define XLOG_STATE_IOERROR   0x0080 /* IO error happened in sync'ing log */
-#define XLOG_STATE_ALL      0x7FFF /* All possible valid flags */
-#define XLOG_STATE_NOTUSED   0x8000 /* This IC log not being used */
+enum xlog_iclog_state {
+       XLOG_STATE_ACTIVE,      /* Current IC log being written to */
+       XLOG_STATE_WANT_SYNC,   /* Want to sync this iclog; no more writes */
+       XLOG_STATE_SYNCING,     /* This IC log is syncing */
+       XLOG_STATE_DONE_SYNC,   /* Done syncing to disk */
+       XLOG_STATE_CALLBACK,    /* Callback functions now */
+       XLOG_STATE_DIRTY,       /* Dirty IC log, not ready for ACTIVE status */
+       XLOG_STATE_IOERROR,     /* IO error happened in sync'ing log */
+};
 
 /*
  * Flags to log ticket
@@ -179,8 +177,6 @@ typedef struct xlog_ticket {
  * - ic_next is the pointer to the next iclog in the ring.
  * - ic_log is a pointer back to the global log structure.
  * - ic_size is the full size of the log buffer, minus the cycle headers.
- * - ic_io_size is the size of the currently pending log buffer write, which
- *     might be smaller than ic_size
  * - ic_offset is the current number of bytes written to in this iclog.
  * - ic_refcnt is bumped when someone is writing to the log.
  * - ic_state is the state of the iclog.
@@ -205,9 +201,8 @@ typedef struct xlog_in_core {
        struct xlog_in_core     *ic_prev;
        struct xlog             *ic_log;
        u32                     ic_size;
-       u32                     ic_io_size;
        u32                     ic_offset;
-       unsigned short          ic_state;
+       enum xlog_iclog_state   ic_state;
        char                    *ic_datap;      /* pointer to iclog data */
 
        /* Callback structures need their own cacheline */
@@ -399,8 +394,6 @@ struct xlog {
        /* The following field are used for debugging; need to hold icloglock */
 #ifdef DEBUG
        void                    *l_iclog_bak[XLOG_MAX_ICLOGS];
-       /* log record crc error injection factor */
-       uint32_t                l_badcrc_factor;
 #endif
        /* log recovery lsn tracking (for buffer submission */
        xfs_lsn_t               l_recovery_lsn;
@@ -542,7 +535,11 @@ xlog_cil_force(struct xlog *log)
  * by a spinlock. This matches the semantics of all the wait queues used in the
  * log code.
  */
-static inline void xlog_wait(wait_queue_head_t *wq, spinlock_t *lock)
+static inline void
+xlog_wait(
+       struct wait_queue_head  *wq,
+       struct spinlock         *lock)
+               __releases(lock)
 {
        DECLARE_WAITQUEUE(wait, current);
 
index c1a514f..99ec3fb 100644 (file)
@@ -103,10 +103,9 @@ xlog_alloc_buffer(
         * Pass log block 0 since we don't have an addr yet, buffer will be
         * verified on read.
         */
-       if (!xlog_verify_bno(log, 0, nbblks)) {
+       if (XFS_IS_CORRUPT(log->l_mp, !xlog_verify_bno(log, 0, nbblks))) {
                xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return NULL;
        }
 
@@ -152,11 +151,10 @@ xlog_do_io(
 {
        int                     error;
 
-       if (!xlog_verify_bno(log, blk_no, nbblks)) {
+       if (XFS_IS_CORRUPT(log->l_mp, !xlog_verify_bno(log, blk_no, nbblks))) {
                xfs_warn(log->l_mp,
                         "Invalid log block/length (0x%llx, 0x%x) for buffer",
                         blk_no, nbblks);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return -EFSCORRUPTED;
        }
 
@@ -244,19 +242,17 @@ xlog_header_check_recover(
         * (XLOG_FMT_UNKNOWN). This stops us from trying to recover
         * a dirty log created in IRIX.
         */
-       if (unlikely(head->h_fmt != cpu_to_be32(XLOG_FMT))) {
+       if (XFS_IS_CORRUPT(mp, head->h_fmt != cpu_to_be32(XLOG_FMT))) {
                xfs_warn(mp,
        "dirty log written in incompatible format - can't recover");
                xlog_header_check_dump(mp, head);
-               XFS_ERROR_REPORT("xlog_header_check_recover(1)",
-                                XFS_ERRLEVEL_HIGH, mp);
                return -EFSCORRUPTED;
-       } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+       }
+       if (XFS_IS_CORRUPT(mp, !uuid_equal(&mp->m_sb.sb_uuid,
+                                          &head->h_fs_uuid))) {
                xfs_warn(mp,
        "dirty log entry has mismatched uuid - can't recover");
                xlog_header_check_dump(mp, head);
-               XFS_ERROR_REPORT("xlog_header_check_recover(2)",
-                                XFS_ERRLEVEL_HIGH, mp);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -279,11 +275,10 @@ xlog_header_check_mount(
                 * by IRIX and continue.
                 */
                xfs_warn(mp, "null uuid in log - IRIX style log");
-       } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+       } else if (XFS_IS_CORRUPT(mp, !uuid_equal(&mp->m_sb.sb_uuid,
+                                                 &head->h_fs_uuid))) {
                xfs_warn(mp, "log has mismatched uuid - can't recover");
                xlog_header_check_dump(mp, head);
-               XFS_ERROR_REPORT("xlog_header_check_mount",
-                                XFS_ERRLEVEL_HIGH, mp);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -471,7 +466,7 @@ xlog_find_verify_log_record(
                        xfs_warn(log->l_mp,
                "Log inconsistent (didn't find previous header)");
                        ASSERT(0);
-                       error = -EIO;
+                       error = -EFSCORRUPTED;
                        goto out;
                }
 
@@ -1347,10 +1342,11 @@ xlog_find_tail(
        error = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, buffer,
                                      &rhead_blk, &rhead, &wrapped);
        if (error < 0)
-               return error;
+               goto done;
        if (!error) {
                xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
-               return -EIO;
+               error = -EFSCORRUPTED;
+               goto done;
        }
        *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
 
@@ -1699,11 +1695,10 @@ xlog_clear_stale_blocks(
                 * the distance from the beginning of the log to the
                 * tail.
                 */
-               if (unlikely(head_block < tail_block || head_block >= log->l_logBBsize)) {
-                       XFS_ERROR_REPORT("xlog_clear_stale_blocks(1)",
-                                        XFS_ERRLEVEL_LOW, log->l_mp);
+               if (XFS_IS_CORRUPT(log->l_mp,
+                                  head_block < tail_block ||
+                                  head_block >= log->l_logBBsize))
                        return -EFSCORRUPTED;
-               }
                tail_distance = tail_block + (log->l_logBBsize - head_block);
        } else {
                /*
@@ -1711,11 +1706,10 @@ xlog_clear_stale_blocks(
                 * so the distance from the head to the tail is just
                 * the tail block minus the head block.
                 */
-               if (unlikely(head_block >= tail_block || head_cycle != (tail_cycle + 1))){
-                       XFS_ERROR_REPORT("xlog_clear_stale_blocks(2)",
-                                        XFS_ERRLEVEL_LOW, log->l_mp);
+               if (XFS_IS_CORRUPT(log->l_mp,
+                                  head_block >= tail_block ||
+                                  head_cycle != tail_cycle + 1))
                        return -EFSCORRUPTED;
-               }
                tail_distance = tail_block - head_block;
        }
 
@@ -2135,13 +2129,11 @@ xlog_recover_do_inode_buffer(
                 */
                logged_nextp = item->ri_buf[item_index].i_addr +
                                next_unlinked_offset - reg_buf_offset;
-               if (unlikely(*logged_nextp == 0)) {
+               if (XFS_IS_CORRUPT(mp, *logged_nextp == 0)) {
                        xfs_alert(mp,
                "Bad inode buffer log record (ptr = "PTR_FMT", bp = "PTR_FMT"). "
                "Trying to replay bad (0) inode di_next_unlinked field.",
                                item, bp);
-                       XFS_ERROR_REPORT("xlog_recover_do_inode_buf",
-                                        XFS_ERRLEVEL_LOW, mp);
                        return -EFSCORRUPTED;
                }
 
@@ -2576,6 +2568,7 @@ xlog_recover_do_reg_buffer(
        int                     bit;
        int                     nbits;
        xfs_failaddr_t          fa;
+       const size_t            size_disk_dquot = sizeof(struct xfs_disk_dquot);
 
        trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f);
 
@@ -2618,7 +2611,7 @@ xlog_recover_do_reg_buffer(
                                        "XFS: NULL dquot in %s.", __func__);
                                goto next;
                        }
-                       if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) {
+                       if (item->ri_buf[i].i_len < size_disk_dquot) {
                                xfs_alert(mp,
                                        "XFS: dquot too small (%d) in %s.",
                                        item->ri_buf[i].i_len, __func__);
@@ -2969,22 +2962,18 @@ xlog_recover_inode_pass2(
         * Make sure the place we're flushing out to really looks
         * like an inode!
         */
-       if (unlikely(!xfs_verify_magic16(bp, dip->di_magic))) {
+       if (XFS_IS_CORRUPT(mp, !xfs_verify_magic16(bp, dip->di_magic))) {
                xfs_alert(mp,
        "%s: Bad inode magic number, dip = "PTR_FMT", dino bp = "PTR_FMT", ino = %Ld",
                        __func__, dip, bp, in_f->ilf_ino);
-               XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)",
-                                XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out_release;
        }
        ldip = item->ri_buf[1].i_addr;
-       if (unlikely(ldip->di_magic != XFS_DINODE_MAGIC)) {
+       if (XFS_IS_CORRUPT(mp, ldip->di_magic != XFS_DINODE_MAGIC)) {
                xfs_alert(mp,
                        "%s: Bad inode log record, rec ptr "PTR_FMT", ino %Ld",
                        __func__, item, in_f->ilf_ino);
-               XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)",
-                                XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out_release;
        }
@@ -3166,7 +3155,7 @@ xlog_recover_inode_pass2(
                default:
                        xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
                        ASSERT(0);
-                       error = -EIO;
+                       error = -EFSCORRUPTED;
                        goto out_release;
                }
        }
@@ -3247,12 +3236,12 @@ xlog_recover_dquot_pass2(
        recddq = item->ri_buf[1].i_addr;
        if (recddq == NULL) {
                xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
-       if (item->ri_buf[1].i_len < sizeof(xfs_disk_dquot_t)) {
+       if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
                xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
                        item->ri_buf[1].i_len, __func__);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /*
@@ -3279,7 +3268,7 @@ xlog_recover_dquot_pass2(
        if (fa) {
                xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
                                dq_f->qlf_id, fa);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        ASSERT(dq_f->qlf_len == 1);
 
@@ -3537,6 +3526,7 @@ xfs_cui_copy_format(
                memcpy(dst_cui_fmt, src_cui_fmt, len);
                return 0;
        }
+       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
        return -EFSCORRUPTED;
 }
 
@@ -3601,8 +3591,10 @@ xlog_recover_cud_pass2(
        struct xfs_ail                  *ailp = log->l_ailp;
 
        cud_formatp = item->ri_buf[0].i_addr;
-       if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format))
+       if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                return -EFSCORRUPTED;
+       }
        cui_id = cud_formatp->cud_cui_id;
 
        /*
@@ -3654,6 +3646,7 @@ xfs_bui_copy_format(
                memcpy(dst_bui_fmt, src_bui_fmt, len);
                return 0;
        }
+       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
        return -EFSCORRUPTED;
 }
 
@@ -3677,8 +3670,10 @@ xlog_recover_bui_pass2(
 
        bui_formatp = item->ri_buf[0].i_addr;
 
-       if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS)
+       if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                return -EFSCORRUPTED;
+       }
        buip = xfs_bui_init(mp);
        error = xfs_bui_copy_format(&item->ri_buf[0], &buip->bui_format);
        if (error) {
@@ -3720,8 +3715,10 @@ xlog_recover_bud_pass2(
        struct xfs_ail                  *ailp = log->l_ailp;
 
        bud_formatp = item->ri_buf[0].i_addr;
-       if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format))
+       if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                return -EFSCORRUPTED;
+       }
        bui_id = bud_formatp->bud_bui_id;
 
        /*
@@ -4018,7 +4015,7 @@ xlog_recover_commit_pass1(
                xfs_warn(log->l_mp, "%s: invalid item type (%d)",
                        __func__, ITEM_TYPE(item));
                ASSERT(0);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 }
 
@@ -4066,7 +4063,7 @@ xlog_recover_commit_pass2(
                xfs_warn(log->l_mp, "%s: invalid item type (%d)",
                        __func__, ITEM_TYPE(item));
                ASSERT(0);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 }
 
@@ -4187,7 +4184,7 @@ xlog_recover_add_to_cont_trans(
                ASSERT(len <= sizeof(struct xfs_trans_header));
                if (len > sizeof(struct xfs_trans_header)) {
                        xfs_warn(log->l_mp, "%s: bad header length", __func__);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                xlog_recover_add_item(&trans->r_itemq);
@@ -4243,13 +4240,13 @@ xlog_recover_add_to_trans(
                        xfs_warn(log->l_mp, "%s: bad header magic number",
                                __func__);
                        ASSERT(0);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                if (len > sizeof(struct xfs_trans_header)) {
                        xfs_warn(log->l_mp, "%s: bad header length", __func__);
                        ASSERT(0);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                /*
@@ -4285,7 +4282,7 @@ xlog_recover_add_to_trans(
                                  in_f->ilf_size);
                        ASSERT(0);
                        kmem_free(ptr);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                item->ri_total = in_f->ilf_size;
@@ -4293,7 +4290,16 @@ xlog_recover_add_to_trans(
                        kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t),
                                    0);
        }
-       ASSERT(item->ri_total > item->ri_cnt);
+
+       if (item->ri_total <= item->ri_cnt) {
+               xfs_warn(log->l_mp,
+       "log item region count (%d) overflowed size (%d)",
+                               item->ri_cnt, item->ri_total);
+               ASSERT(0);
+               kmem_free(ptr);
+               return -EFSCORRUPTED;
+       }
+
        /* Description region is ri_buf[0] */
        item->ri_buf[item->ri_cnt].i_addr = ptr;
        item->ri_buf[item->ri_cnt].i_len  = len;
@@ -4380,7 +4386,7 @@ xlog_recovery_process_trans(
        default:
                xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags);
                ASSERT(0);
-               error = -EIO;
+               error = -EFSCORRUPTED;
                break;
        }
        if (error || freeit)
@@ -4460,7 +4466,7 @@ xlog_recover_process_ophdr(
                xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
                        __func__, ohead->oh_clientid);
                ASSERT(0);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /*
@@ -4470,7 +4476,7 @@ xlog_recover_process_ophdr(
        if (dp + len > end) {
                xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, len);
                WARN_ON(1);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        trans = xlog_recover_ophdr_to_trans(rhash, rhead, ohead);
@@ -5172,8 +5178,10 @@ xlog_recover_process(
                 * If the filesystem is CRC enabled, this mismatch becomes a
                 * fatal log corruption failure.
                 */
-               if (xfs_sb_version_hascrc(&log->l_mp->m_sb))
+               if (xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
+                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                        return -EFSCORRUPTED;
+               }
        }
 
        xlog_unpack_data(rhead, dp, log);
@@ -5190,31 +5198,25 @@ xlog_valid_rec_header(
 {
        int                     hlen;
 
-       if (unlikely(rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))) {
-               XFS_ERROR_REPORT("xlog_valid_rec_header(1)",
-                               XFS_ERRLEVEL_LOW, log->l_mp);
+       if (XFS_IS_CORRUPT(log->l_mp,
+                          rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM)))
                return -EFSCORRUPTED;
-       }
-       if (unlikely(
-           (!rhead->h_version ||
-           (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) {
+       if (XFS_IS_CORRUPT(log->l_mp,
+                          (!rhead->h_version ||
+                          (be32_to_cpu(rhead->h_version) &
+                           (~XLOG_VERSION_OKBITS))))) {
                xfs_warn(log->l_mp, "%s: unrecognised log version (%d).",
                        __func__, be32_to_cpu(rhead->h_version));
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /* LR body must have data or it wouldn't have been written */
        hlen = be32_to_cpu(rhead->h_len);
-       if (unlikely( hlen <= 0 || hlen > INT_MAX )) {
-               XFS_ERROR_REPORT("xlog_valid_rec_header(2)",
-                               XFS_ERRLEVEL_LOW, log->l_mp);
+       if (XFS_IS_CORRUPT(log->l_mp, hlen <= 0 || hlen > INT_MAX))
                return -EFSCORRUPTED;
-       }
-       if (unlikely( blkno > log->l_logBBsize || blkno > INT_MAX )) {
-               XFS_ERROR_REPORT("xlog_valid_rec_header(3)",
-                               XFS_ERRLEVEL_LOW, log->l_mp);
+       if (XFS_IS_CORRUPT(log->l_mp,
+                          blkno > log->l_logBBsize || blkno > INT_MAX))
                return -EFSCORRUPTED;
-       }
        return 0;
 }
 
@@ -5296,8 +5298,12 @@ xlog_do_recovery_pass(
                "invalid iclog size (%d bytes), using lsunit (%d bytes)",
                                         h_size, log->l_mp->m_logbsize);
                                h_size = log->l_mp->m_logbsize;
-                       } else
-                               return -EFSCORRUPTED;
+                       } else {
+                               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
+                                               log->l_mp);
+                               error = -EFSCORRUPTED;
+                               goto bread_err1;
+                       }
                }
 
                if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) &&
index 9804efe..e0f9d3b 100644 (file)
@@ -20,8 +20,8 @@ __xfs_printk(
        const struct xfs_mount  *mp,
        struct va_format        *vaf)
 {
-       if (mp && mp->m_fsname) {
-               printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf);
+       if (mp && mp->m_super) {
+               printk("%sXFS (%s): %pV\n", level, mp->m_super->s_id, vaf);
                return;
        }
        printk("%sXFS: %pV\n", level, vaf);
@@ -86,17 +86,25 @@ xfs_alert_tag(
 }
 
 void
-asswarn(char *expr, char *file, int line)
+asswarn(
+       struct xfs_mount        *mp,
+       char                    *expr,
+       char                    *file,
+       int                     line)
 {
-       xfs_warn(NULL, "Assertion failed: %s, file: %s, line: %d",
+       xfs_warn(mp, "Assertion failed: %s, file: %s, line: %d",
                expr, file, line);
        WARN_ON(1);
 }
 
 void
-assfail(char *expr, char *file, int line)
+assfail(
+       struct xfs_mount        *mp,
+       char                    *expr,
+       char                    *file,
+       int                     line)
 {
-       xfs_emerg(NULL, "Assertion failed: %s, file: %s, line: %d",
+       xfs_emerg(mp, "Assertion failed: %s, file: %s, line: %d",
                expr, file, line);
        if (xfs_globals.bug_on_assert)
                BUG();
@@ -105,7 +113,7 @@ assfail(char *expr, char *file, int line)
 }
 
 void
-xfs_hex_dump(void *p, int length)
+xfs_hex_dump(const void *p, int length)
 {
        print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 16, 1, p, length, 1);
 }
index 34447dc..0b05e10 100644 (file)
@@ -57,9 +57,9 @@ do {                                                                  \
 #define xfs_debug_ratelimited(dev, fmt, ...)                           \
        xfs_printk_ratelimited(xfs_debug, dev, fmt, ##__VA_ARGS__)
 
-extern void assfail(char *expr, char *f, int l);
-extern void asswarn(char *expr, char *f, int l);
+void assfail(struct xfs_mount *mp, char *expr, char *f, int l);
+void asswarn(struct xfs_mount *mp, char *expr, char *f, int l);
 
-extern void xfs_hex_dump(void *p, int length);
+extern void xfs_hex_dump(const void *p, int length);
 
 #endif /* __XFS_MESSAGE_H */
index ba5b6f3..fca6510 100644 (file)
@@ -425,45 +425,6 @@ xfs_update_alignment(xfs_mount_t *mp)
        return 0;
 }
 
-/*
- * Set the default minimum read and write sizes unless
- * already specified in a mount option.
- * We use smaller I/O sizes when the file system
- * is being used for NFS service (wsync mount option).
- */
-STATIC void
-xfs_set_rw_sizes(xfs_mount_t *mp)
-{
-       xfs_sb_t        *sbp = &(mp->m_sb);
-       int             readio_log, writeio_log;
-
-       if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) {
-               if (mp->m_flags & XFS_MOUNT_WSYNC) {
-                       readio_log = XFS_WSYNC_READIO_LOG;
-                       writeio_log = XFS_WSYNC_WRITEIO_LOG;
-               } else {
-                       readio_log = XFS_READIO_LOG_LARGE;
-                       writeio_log = XFS_WRITEIO_LOG_LARGE;
-               }
-       } else {
-               readio_log = mp->m_readio_log;
-               writeio_log = mp->m_writeio_log;
-       }
-
-       if (sbp->sb_blocklog > readio_log) {
-               mp->m_readio_log = sbp->sb_blocklog;
-       } else {
-               mp->m_readio_log = readio_log;
-       }
-       mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog);
-       if (sbp->sb_blocklog > writeio_log) {
-               mp->m_writeio_log = sbp->sb_blocklog;
-       } else {
-               mp->m_writeio_log = writeio_log;
-       }
-       mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog);
-}
-
 /*
  * precalculate the low space thresholds for dynamic speculative preallocation.
  */
@@ -706,7 +667,8 @@ xfs_mountfs(
        /* enable fail_at_unmount as default */
        mp->m_fail_unmount = true;
 
-       error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname);
+       error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype,
+                              NULL, mp->m_super->s_id);
        if (error)
                goto out;
 
@@ -728,9 +690,12 @@ xfs_mountfs(
                goto out_remove_errortag;
 
        /*
-        * Set the minimum read and write sizes
+        * Update the preferred write size based on the information from the
+        * on-disk superblock.
         */
-       xfs_set_rw_sizes(mp);
+       mp->m_allocsize_log =
+               max_t(uint32_t, sbp->sb_blocklog, mp->m_allocsize_log);
+       mp->m_allocsize_blocks = 1U << (mp->m_allocsize_log - sbp->sb_blocklog);
 
        /* set the low space thresholds for dynamic preallocation */
        xfs_set_low_space_thresholds(mp);
@@ -796,9 +761,8 @@ xfs_mountfs(
                goto out_free_dir;
        }
 
-       if (!sbp->sb_logblocks) {
+       if (XFS_IS_CORRUPT(mp, !sbp->sb_logblocks)) {
                xfs_warn(mp, "no log defined");
-               XFS_ERROR_REPORT("xfs_mountfs", XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out_free_perag;
        }
@@ -836,12 +800,10 @@ xfs_mountfs(
 
        ASSERT(rip != NULL);
 
-       if (unlikely(!S_ISDIR(VFS_I(rip)->i_mode))) {
+       if (XFS_IS_CORRUPT(mp, !S_ISDIR(VFS_I(rip)->i_mode))) {
                xfs_warn(mp, "corrupted root inode %llu: not a directory",
                        (unsigned long long)rip->i_ino);
                xfs_iunlock(rip, XFS_ILOCK_EXCL);
-               XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
-                                mp);
                error = -EFSCORRUPTED;
                goto out_rele_rip;
        }
@@ -1277,7 +1239,7 @@ xfs_mod_fdblocks(
        printk_once(KERN_WARNING
                "Filesystem \"%s\": reserve blocks depleted! "
                "Consider increasing reserve pool size.",
-               mp->m_fsname);
+               mp->m_super->s_id);
 fdblocks_enospc:
        spin_unlock(&mp->m_sb_lock);
        return -ENOSPC;
index fdb60e0..88ab09e 100644 (file)
@@ -9,10 +9,8 @@
 struct xlog;
 struct xfs_inode;
 struct xfs_mru_cache;
-struct xfs_nameops;
 struct xfs_ail;
 struct xfs_quotainfo;
-struct xfs_dir_ops;
 struct xfs_da_geometry;
 
 /* dynamic preallocation free space thresholds, 5% down to 1% */
@@ -59,7 +57,6 @@ struct xfs_error_cfg {
 
 typedef struct xfs_mount {
        struct super_block      *m_super;
-       xfs_tid_t               m_tid;          /* next unused tid for fs */
 
        /*
         * Bitsets of per-fs metadata that have been checked and/or are sick.
@@ -89,8 +86,6 @@ typedef struct xfs_mount {
        struct percpu_counter   m_delalloc_blks;
 
        struct xfs_buf          *m_sb_bp;       /* buffer for superblock */
-       char                    *m_fsname;      /* filesystem name */
-       int                     m_fsname_len;   /* strlen of fs name */
        char                    *m_rtname;      /* realtime device name */
        char                    *m_logname;     /* external log device name */
        int                     m_bsize;        /* fs logical block size */
@@ -98,10 +93,8 @@ typedef struct xfs_mount {
        xfs_agnumber_t          m_agirotor;     /* last ag dir inode alloced */
        spinlock_t              m_agirotor_lock;/* .. and lock protecting it */
        xfs_agnumber_t          m_maxagi;       /* highest inode alloc group */
-       uint                    m_readio_log;   /* min read size log bytes */
-       uint                    m_readio_blocks; /* min read size blocks */
-       uint                    m_writeio_log;  /* min write size log bytes */
-       uint                    m_writeio_blocks; /* min write size blocks */
+       uint                    m_allocsize_log;/* min write size log bytes */
+       uint                    m_allocsize_blocks; /* min write size blocks */
        struct xfs_da_geometry  *m_dir_geo;     /* directory block geometry */
        struct xfs_da_geometry  *m_attr_geo;    /* attribute block geometry */
        struct xlog             *m_log;         /* log specific stuff */
@@ -159,10 +152,6 @@ typedef struct xfs_mount {
        int                     m_dalign;       /* stripe unit */
        int                     m_swidth;       /* stripe width */
        uint8_t                 m_sectbb_log;   /* sectlog - BBSHIFT */
-       const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
-       const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */
-       const struct xfs_dir_ops *m_nondir_inode_ops; /* !dir inode ops */
-       uint                    m_chsize;       /* size of next field */
        atomic_t                m_active_trans; /* number trans frozen */
        struct xfs_mru_cache    *m_filestream;  /* per-mount filestream data */
        struct delayed_work     m_reclaim_work; /* background inode reclaim */
@@ -229,7 +218,7 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_ATTR2                (1ULL << 8)     /* allow use of attr2 format */
 #define XFS_MOUNT_GRPID                (1ULL << 9)     /* group-ID assigned from directory */
 #define XFS_MOUNT_NORECOVERY   (1ULL << 10)    /* no recovery - dirty fs */
-#define XFS_MOUNT_DFLT_IOSIZE  (1ULL << 12)    /* set default i/o size */
+#define XFS_MOUNT_ALLOCSIZE    (1ULL << 12)    /* specified allocation size */
 #define XFS_MOUNT_SMALL_INUMS  (1ULL << 14)    /* user wants 32bit inodes */
 #define XFS_MOUNT_32BITINODES  (1ULL << 15)    /* inode32 allocator active */
 #define XFS_MOUNT_NOUUID       (1ULL << 16)    /* ignore uuid during mount */
@@ -238,7 +227,7 @@ typedef struct xfs_mount {
                                                 * allocation */
 #define XFS_MOUNT_RDONLY       (1ULL << 20)    /* read-only fs */
 #define XFS_MOUNT_DIRSYNC      (1ULL << 21)    /* synchronous directory ops */
-#define XFS_MOUNT_COMPAT_IOSIZE        (1ULL << 22)    /* don't report large preferred
+#define XFS_MOUNT_LARGEIO      (1ULL << 22)    /* report large preferred
                                                 * I/O size in stat() */
 #define XFS_MOUNT_FILESTREAMS  (1ULL << 24)    /* enable the filestreams
                                                   allocator */
@@ -246,13 +235,6 @@ typedef struct xfs_mount {
 
 #define XFS_MOUNT_DAX          (1ULL << 62)    /* TEST ONLY! */
 
-
-/*
- * Default minimum read and write sizes.
- */
-#define XFS_READIO_LOG_LARGE   16
-#define XFS_WRITEIO_LOG_LARGE  16
-
 /*
  * Max and min values for mount-option defined I/O
  * preallocation sizes.
@@ -260,37 +242,6 @@ typedef struct xfs_mount {
 #define XFS_MAX_IO_LOG         30      /* 1G */
 #define XFS_MIN_IO_LOG         PAGE_SHIFT
 
-/*
- * Synchronous read and write sizes.  This should be
- * better for NFSv2 wsync filesystems.
- */
-#define        XFS_WSYNC_READIO_LOG    15      /* 32k */
-#define        XFS_WSYNC_WRITEIO_LOG   14      /* 16k */
-
-/*
- * Allow large block sizes to be reported to userspace programs if the
- * "largeio" mount option is used.
- *
- * If compatibility mode is specified, simply return the basic unit of caching
- * so that we don't get inefficient read/modify/write I/O from user apps.
- * Otherwise....
- *
- * If the underlying volume is a stripe, then return the stripe width in bytes
- * as the recommended I/O size. It is not a stripe and we've set a default
- * buffered I/O size, return that, otherwise return the compat default.
- */
-static inline unsigned long
-xfs_preferred_iosize(xfs_mount_t *mp)
-{
-       if (mp->m_flags & XFS_MOUNT_COMPAT_IOSIZE)
-               return PAGE_SIZE;
-       return (mp->m_swidth ?
-               (mp->m_swidth << mp->m_sb.sb_blocklog) :
-               ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) ?
-                       (1 << (int)max(mp->m_readio_log, mp->m_writeio_log)) :
-                       PAGE_SIZE));
-}
-
 #define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \
                                ((mp)->m_flags & XFS_MOUNT_WAS_CLEAN)
 #define XFS_FORCED_SHUTDOWN(mp)        ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
index 9c96493..bb3008d 100644 (file)
@@ -12,6 +12,7 @@
 #include "xfs_trans.h"
 #include "xfs_bmap.h"
 #include "xfs_iomap.h"
+#include "xfs_pnfs.h"
 
 /*
  * Ensure that we do not have any outstanding pNFS layouts that can be used by
@@ -59,7 +60,7 @@ xfs_fs_get_uuid(
 
        printk_once(KERN_NOTICE
 "XFS (%s): using experimental pNFS feature, use at your own risk!\n",
-               mp->m_fsname);
+               mp->m_super->s_id);
 
        if (*len < sizeof(uuid_t))
                return -EINVAL;
@@ -142,39 +143,34 @@ xfs_fs_map_blocks(
        lock_flags = xfs_ilock_data_map_shared(ip);
        error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
                                &imap, &nimaps, bmapi_flags);
-       xfs_iunlock(ip, lock_flags);
 
-       if (error)
-               goto out_unlock;
+       ASSERT(!nimaps || imap.br_startblock != DELAYSTARTBLOCK);
+
+       if (!error && write &&
+           (!nimaps || imap.br_startblock == HOLESTARTBLOCK)) {
+               if (offset + length > XFS_ISIZE(ip))
+                       end_fsb = xfs_iomap_eof_align_last_fsb(ip, end_fsb);
+               else if (nimaps && imap.br_startblock == HOLESTARTBLOCK)
+                       end_fsb = min(end_fsb, imap.br_startoff +
+                                              imap.br_blockcount);
+               xfs_iunlock(ip, lock_flags);
+
+               error = xfs_iomap_write_direct(ip, offset_fsb,
+                               end_fsb - offset_fsb, &imap);
+               if (error)
+                       goto out_unlock;
 
-       if (write) {
-               enum xfs_prealloc_flags flags = 0;
-
-               ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
-
-               if (!nimaps || imap.br_startblock == HOLESTARTBLOCK) {
-                       /*
-                        * xfs_iomap_write_direct() expects to take ownership of
-                        * the shared ilock.
-                        */
-                       xfs_ilock(ip, XFS_ILOCK_SHARED);
-                       error = xfs_iomap_write_direct(ip, offset, length,
-                                                      &imap, nimaps);
-                       if (error)
-                               goto out_unlock;
-
-                       /*
-                        * Ensure the next transaction is committed
-                        * synchronously so that the blocks allocated and
-                        * handed out to the client are guaranteed to be
-                        * present even after a server crash.
-                        */
-                       flags |= XFS_PREALLOC_SET | XFS_PREALLOC_SYNC;
-               }
-
-               error = xfs_update_prealloc_flags(ip, flags);
+               /*
+                * Ensure the next transaction is committed synchronously so
+                * that the blocks allocated and handed out to the client are
+                * guaranteed to be present even after a server crash.
+                */
+               error = xfs_update_prealloc_flags(ip,
+                               XFS_PREALLOC_SET | XFS_PREALLOC_SYNC);
                if (error)
                        goto out_unlock;
+       } else {
+               xfs_iunlock(ip, lock_flags);
        }
        xfs_iunlock(ip, XFS_IOLOCK_EXCL);
 
index ecd8ce1..0b09096 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_qm.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
+#include "xfs_error.h"
 
 /*
  * The global quota manager. There is only one of these for the entire
  * quota functionality, including maintaining the freelist and hash
  * tables of dquots.
  */
-STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
-STATIC int     xfs_qm_init_quotainfo(xfs_mount_t *);
+STATIC int     xfs_qm_init_quotainos(struct xfs_mount *mp);
+STATIC int     xfs_qm_init_quotainfo(struct xfs_mount *mp);
 
-STATIC void    xfs_qm_destroy_quotainos(xfs_quotainfo_t *qi);
+STATIC void    xfs_qm_destroy_quotainos(struct xfs_quotainfo *qi);
 STATIC void    xfs_qm_dqfree_one(struct xfs_dquot *dqp);
 /*
  * We use the batch lookup interface to iterate over the dquots as it
@@ -243,14 +244,14 @@ xfs_qm_unmount_quotas(
 
 STATIC int
 xfs_qm_dqattach_one(
-       xfs_inode_t     *ip,
-       xfs_dqid_t      id,
-       uint            type,
-       bool            doalloc,
-       xfs_dquot_t     **IO_idqpp)
+       struct xfs_inode        *ip,
+       xfs_dqid_t              id,
+       uint                    type,
+       bool                    doalloc,
+       struct xfs_dquot        **IO_idqpp)
 {
-       xfs_dquot_t     *dqp;
-       int             error;
+       struct xfs_dquot        *dqp;
+       int                     error;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        error = 0;
@@ -341,7 +342,7 @@ xfs_qm_dqattach_locked(
        }
 
        if (XFS_IS_PQUOTA_ON(mp) && !ip->i_pdquot) {
-               error = xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
+               error = xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ,
                                doalloc, &ip->i_pdquot);
                if (error)
                        goto done;
@@ -539,12 +540,12 @@ xfs_qm_shrink_count(
 
 STATIC void
 xfs_qm_set_defquota(
-       xfs_mount_t     *mp,
-       uint            type,
-       xfs_quotainfo_t *qinf)
+       struct xfs_mount        *mp,
+       uint                    type,
+       struct xfs_quotainfo    *qinf)
 {
-       xfs_dquot_t             *dqp;
-       struct xfs_def_quota    *defq;
+       struct xfs_dquot        *dqp;
+       struct xfs_def_quota    *defq;
        struct xfs_disk_dquot   *ddqp;
        int                     error;
 
@@ -642,7 +643,7 @@ xfs_qm_init_quotainfo(
 
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
-       qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), 0);
+       qinf = mp->m_quotainfo = kmem_zalloc(sizeof(struct xfs_quotainfo), 0);
 
        error = list_lru_init(&qinf->qi_lru);
        if (error)
@@ -709,9 +710,9 @@ out_free_qinf:
  */
 void
 xfs_qm_destroy_quotainfo(
-       xfs_mount_t     *mp)
+       struct xfs_mount        *mp)
 {
-       xfs_quotainfo_t *qi;
+       struct xfs_quotainfo    *qi;
 
        qi = mp->m_quotainfo;
        ASSERT(qi != NULL);
@@ -754,11 +755,15 @@ xfs_qm_qino_alloc(
                if ((flags & XFS_QMOPT_PQUOTA) &&
                             (mp->m_sb.sb_gquotino != NULLFSINO)) {
                        ino = mp->m_sb.sb_gquotino;
-                       ASSERT(mp->m_sb.sb_pquotino == NULLFSINO);
+                       if (XFS_IS_CORRUPT(mp,
+                                          mp->m_sb.sb_pquotino != NULLFSINO))
+                               return -EFSCORRUPTED;
                } else if ((flags & XFS_QMOPT_GQUOTA) &&
                             (mp->m_sb.sb_pquotino != NULLFSINO)) {
                        ino = mp->m_sb.sb_pquotino;
-                       ASSERT(mp->m_sb.sb_gquotino == NULLFSINO);
+                       if (XFS_IS_CORRUPT(mp,
+                                          mp->m_sb.sb_gquotino != NULLFSINO))
+                               return -EFSCORRUPTED;
                }
                if (ino != NULLFSINO) {
                        error = xfs_iget(mp, NULL, ino, 0, 0, ip);
@@ -1559,7 +1564,7 @@ error_rele:
 
 STATIC void
 xfs_qm_destroy_quotainos(
-       xfs_quotainfo_t *qi)
+       struct xfs_quotainfo    *qi)
 {
        if (qi->qi_uquotaip) {
                xfs_irele(qi->qi_uquotaip);
@@ -1693,7 +1698,7 @@ xfs_qm_vop_dqalloc(
                }
        }
        if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
-               if (xfs_get_projid(ip) != prid) {
+               if (ip->i_d.di_projid != prid) {
                        xfs_iunlock(ip, lockflags);
                        error = xfs_qm_dqget(mp, (xfs_dqid_t)prid, XFS_DQ_PROJ,
                                        true, &pq);
@@ -1737,14 +1742,14 @@ error_rele:
  * Actually transfer ownership, and do dquot modifications.
  * These were already reserved.
  */
-xfs_dquot_t *
+struct xfs_dquot *
 xfs_qm_vop_chown(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       xfs_dquot_t     **IO_olddq,
-       xfs_dquot_t     *newdq)
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       struct xfs_dquot        **IO_olddq,
+       struct xfs_dquot        *newdq)
 {
-       xfs_dquot_t     *prevdq;
+       struct xfs_dquot        *prevdq;
        uint            bfield = XFS_IS_REALTIME_INODE(ip) ?
                                 XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
 
@@ -1827,7 +1832,7 @@ xfs_qm_vop_chown_reserve(
        }
 
        if (XFS_IS_PQUOTA_ON(ip->i_mount) && pdqp &&
-           xfs_get_projid(ip) != be32_to_cpu(pdqp->q_core.d_id)) {
+           ip->i_d.di_projid != be32_to_cpu(pdqp->q_core.d_id)) {
                prjflags = XFS_QMOPT_ENOSPC;
                pdq_delblks = pdqp;
                if (delblks) {
@@ -1928,7 +1933,7 @@ xfs_qm_vop_create_dqattach(
        }
        if (pdqp && XFS_IS_PQUOTA_ON(mp)) {
                ASSERT(ip->i_pdquot == NULL);
-               ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
+               ASSERT(ip->i_d.di_projid == be32_to_cpu(pdqp->q_core.d_id));
 
                ip->i_pdquot = xfs_qm_dqhold(pdqp);
                xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
index b41b750..7823af3 100644 (file)
@@ -54,7 +54,7 @@ struct xfs_def_quota {
  * Various quota information for individual filesystems.
  * The mount structure keeps a pointer to this.
  */
-typedef struct xfs_quotainfo {
+struct xfs_quotainfo {
        struct radix_tree_root qi_uquota_tree;
        struct radix_tree_root qi_gquota_tree;
        struct radix_tree_root qi_pquota_tree;
@@ -76,8 +76,8 @@ typedef struct xfs_quotainfo {
        struct xfs_def_quota    qi_usr_default;
        struct xfs_def_quota    qi_grp_default;
        struct xfs_def_quota    qi_prj_default;
-       struct shrinker  qi_shrinker;
-} xfs_quotainfo_t;
+       struct shrinker qi_shrinker;
+};
 
 static inline struct radix_tree_root *
 xfs_dquot_tree(
index 5d72e88..fc2fa41 100644 (file)
@@ -54,13 +54,13 @@ xfs_fill_statvfs_from_dquot(
  */
 void
 xfs_qm_statvfs(
-       xfs_inode_t             *ip,
+       struct xfs_inode        *ip,
        struct kstatfs          *statp)
 {
-       xfs_mount_t             *mp = ip->i_mount;
-       xfs_dquot_t             *dqp;
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_dquot        *dqp;
 
-       if (!xfs_qm_dqget(mp, xfs_get_projid(ip), XFS_DQ_PROJ, false, &dqp)) {
+       if (!xfs_qm_dqget(mp, ip->i_d.di_projid, XFS_DQ_PROJ, false, &dqp)) {
                xfs_fill_statvfs_from_dquot(statp, dqp);
                xfs_qm_dqput(dqp);
        }
index da7ad03..1ea8276 100644 (file)
 #include "xfs_qm.h"
 #include "xfs_icache.h"
 
-STATIC int     xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
-STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
-                                       uint);
+STATIC int
+xfs_qm_log_quotaoff(
+       struct xfs_mount        *mp,
+       struct xfs_qoff_logitem **qoffstartp,
+       uint                    flags)
+{
+       struct xfs_trans        *tp;
+       int                     error;
+       struct xfs_qoff_logitem *qoffi;
+
+       *qoffstartp = NULL;
+
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_quotaoff, 0, 0, 0, &tp);
+       if (error)
+               goto out;
+
+       qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
+       xfs_trans_log_quotaoff_item(tp, qoffi);
+
+       spin_lock(&mp->m_sb_lock);
+       mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
+       spin_unlock(&mp->m_sb_lock);
+
+       xfs_log_sb(tp);
+
+       /*
+        * We have to make sure that the transaction is secure on disk before we
+        * return and actually stop quota accounting. So, make it synchronous.
+        * We don't care about quotoff's performance.
+        */
+       xfs_trans_set_sync(tp);
+       error = xfs_trans_commit(tp);
+       if (error)
+               goto out;
+
+       *qoffstartp = qoffi;
+out:
+       return error;
+}
+
+STATIC int
+xfs_qm_log_quotaoff_end(
+       struct xfs_mount        *mp,
+       struct xfs_qoff_logitem *startqoff,
+       uint                    flags)
+{
+       struct xfs_trans        *tp;
+       int                     error;
+       struct xfs_qoff_logitem *qoffi;
+
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_equotaoff, 0, 0, 0, &tp);
+       if (error)
+               return error;
+
+       qoffi = xfs_trans_get_qoff_item(tp, startqoff,
+                                       flags & XFS_ALL_QUOTA_ACCT);
+       xfs_trans_log_quotaoff_item(tp, qoffi);
+
+       /*
+        * We have to make sure that the transaction is secure on disk before we
+        * return and actually stop quota accounting. So, make it synchronous.
+        * We don't care about quotoff's performance.
+        */
+       xfs_trans_set_sync(tp);
+       return xfs_trans_commit(tp);
+}
 
 /*
  * Turn off quota accounting and/or enforcement for all udquots and/or
@@ -40,7 +103,7 @@ xfs_qm_scall_quotaoff(
        uint                    dqtype;
        int                     error;
        uint                    inactivate_flags;
-       xfs_qoff_logitem_t      *qoffstart;
+       struct xfs_qoff_logitem *qoffstart;
 
        /*
         * No file system can have quotas enabled on disk but not in core.
@@ -538,74 +601,6 @@ out_unlock:
        return error;
 }
 
-STATIC int
-xfs_qm_log_quotaoff_end(
-       xfs_mount_t             *mp,
-       xfs_qoff_logitem_t      *startqoff,
-       uint                    flags)
-{
-       xfs_trans_t             *tp;
-       int                     error;
-       xfs_qoff_logitem_t      *qoffi;
-
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_equotaoff, 0, 0, 0, &tp);
-       if (error)
-               return error;
-
-       qoffi = xfs_trans_get_qoff_item(tp, startqoff,
-                                       flags & XFS_ALL_QUOTA_ACCT);
-       xfs_trans_log_quotaoff_item(tp, qoffi);
-
-       /*
-        * We have to make sure that the transaction is secure on disk before we
-        * return and actually stop quota accounting. So, make it synchronous.
-        * We don't care about quotoff's performance.
-        */
-       xfs_trans_set_sync(tp);
-       return xfs_trans_commit(tp);
-}
-
-
-STATIC int
-xfs_qm_log_quotaoff(
-       xfs_mount_t            *mp,
-       xfs_qoff_logitem_t     **qoffstartp,
-       uint                   flags)
-{
-       xfs_trans_t            *tp;
-       int                     error;
-       xfs_qoff_logitem_t     *qoffi;
-
-       *qoffstartp = NULL;
-
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_quotaoff, 0, 0, 0, &tp);
-       if (error)
-               goto out;
-
-       qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
-       xfs_trans_log_quotaoff_item(tp, qoffi);
-
-       spin_lock(&mp->m_sb_lock);
-       mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
-       spin_unlock(&mp->m_sb_lock);
-
-       xfs_log_sb(tp);
-
-       /*
-        * We have to make sure that the transaction is secure on disk before we
-        * return and actually stop quota accounting. So, make it synchronous.
-        * We don't care about quotoff's performance.
-        */
-       xfs_trans_set_sync(tp);
-       error = xfs_trans_commit(tp);
-       if (error)
-               goto out;
-
-       *qoffstartp = qoffi;
-out:
-       return error;
-}
-
 /* Fill out the quota context. */
 static void
 xfs_qm_scall_getquota_fill_qc(
index cd6c721..c7de17d 100644 (file)
@@ -201,6 +201,9 @@ xfs_fs_rm_xquota(
        if (XFS_IS_QUOTA_ON(mp))
                return -EINVAL;
 
+       if (uflags & ~(FS_USER_QUOTA | FS_GROUP_QUOTA | FS_PROJ_QUOTA))
+               return -EINVAL;
+
        if (uflags & FS_USER_QUOTA)
                flags |= XFS_DQ_USER;
        if (uflags & FS_GROUP_QUOTA)
index 2328268..8eeed73 100644 (file)
@@ -17,7 +17,7 @@
 #include "xfs_refcount_item.h"
 #include "xfs_log.h"
 #include "xfs_refcount.h"
-
+#include "xfs_error.h"
 
 kmem_zone_t    *xfs_cui_zone;
 kmem_zone_t    *xfs_cud_zone;
@@ -34,7 +34,7 @@ xfs_cui_item_free(
        if (cuip->cui_format.cui_nextents > XFS_CUI_MAX_FAST_EXTENTS)
                kmem_free(cuip);
        else
-               kmem_zone_free(xfs_cui_zone, cuip);
+               kmem_cache_free(xfs_cui_zone, cuip);
 }
 
 /*
@@ -206,7 +206,7 @@ xfs_cud_item_release(
        struct xfs_cud_log_item *cudp = CUD_ITEM(lip);
 
        xfs_cui_release(cudp->cud_cuip);
-       kmem_zone_free(xfs_cud_zone, cudp);
+       kmem_cache_free(xfs_cud_zone, cudp);
 }
 
 static const struct xfs_item_ops xfs_cud_item_ops = {
@@ -497,7 +497,7 @@ xfs_cui_recover(
                         */
                        set_bit(XFS_CUI_RECOVERED, &cuip->cui_flags);
                        xfs_cui_release(cuip);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
        }
 
@@ -536,6 +536,7 @@ xfs_cui_recover(
                        type = refc_type;
                        break;
                default:
+                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                        error = -EFSCORRUPTED;
                        goto abort_error;
                }
index a963411..de45123 100644 (file)
@@ -308,13 +308,13 @@ static int
 xfs_find_trim_cow_extent(
        struct xfs_inode        *ip,
        struct xfs_bmbt_irec    *imap,
+       struct xfs_bmbt_irec    *cmap,
        bool                    *shared,
        bool                    *found)
 {
        xfs_fileoff_t           offset_fsb = imap->br_startoff;
        xfs_filblks_t           count_fsb = imap->br_blockcount;
        struct xfs_iext_cursor  icur;
-       struct xfs_bmbt_irec    got;
 
        *found = false;
 
@@ -322,23 +322,22 @@ xfs_find_trim_cow_extent(
         * If we don't find an overlapping extent, trim the range we need to
         * allocate to fit the hole we found.
         */
-       if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &got))
-               got.br_startoff = offset_fsb + count_fsb;
-       if (got.br_startoff > offset_fsb) {
+       if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, cmap))
+               cmap->br_startoff = offset_fsb + count_fsb;
+       if (cmap->br_startoff > offset_fsb) {
                xfs_trim_extent(imap, imap->br_startoff,
-                               got.br_startoff - imap->br_startoff);
+                               cmap->br_startoff - imap->br_startoff);
                return xfs_inode_need_cow(ip, imap, shared);
        }
 
        *shared = true;
-       if (isnullstartblock(got.br_startblock)) {
-               xfs_trim_extent(imap, got.br_startoff, got.br_blockcount);
+       if (isnullstartblock(cmap->br_startblock)) {
+               xfs_trim_extent(imap, cmap->br_startoff, cmap->br_blockcount);
                return 0;
        }
 
        /* real extent found - no need to allocate */
-       xfs_trim_extent(&got, offset_fsb, count_fsb);
-       *imap = got;
+       xfs_trim_extent(cmap, offset_fsb, count_fsb);
        *found = true;
        return 0;
 }
@@ -348,6 +347,7 @@ int
 xfs_reflink_allocate_cow(
        struct xfs_inode        *ip,
        struct xfs_bmbt_irec    *imap,
+       struct xfs_bmbt_irec    *cmap,
        bool                    *shared,
        uint                    *lockmode,
        bool                    convert_now)
@@ -367,7 +367,7 @@ xfs_reflink_allocate_cow(
                xfs_ifork_init_cow(ip);
        }
 
-       error = xfs_find_trim_cow_extent(ip, imap, shared, &found);
+       error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
        if (error || !*shared)
                return error;
        if (found)
@@ -392,7 +392,7 @@ xfs_reflink_allocate_cow(
        /*
         * Check for an overlapping extent again now that we dropped the ilock.
         */
-       error = xfs_find_trim_cow_extent(ip, imap, shared, &found);
+       error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
        if (error || !*shared)
                goto out_trans_cancel;
        if (found) {
@@ -410,8 +410,8 @@ xfs_reflink_allocate_cow(
        /* Allocate the entire reservation as unwritten blocks. */
        nimaps = 1;
        error = xfs_bmapi_write(tp, ip, imap->br_startoff, imap->br_blockcount,
-                       XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC,
-                       resblks, imap, &nimaps);
+                       XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC, 0, cmap,
+                       &nimaps);
        if (error)
                goto out_unreserve;
 
@@ -427,15 +427,15 @@ xfs_reflink_allocate_cow(
        if (nimaps == 0)
                return -ENOSPC;
 convert:
-       xfs_trim_extent(imap, offset_fsb, count_fsb);
+       xfs_trim_extent(cmap, offset_fsb, count_fsb);
        /*
         * COW fork extents are supposed to remain unwritten until we're ready
         * to initiate a disk write.  For direct I/O we are going to write the
         * data and need the conversion, but for buffered writes we're done.
         */
-       if (!convert_now || imap->br_state == XFS_EXT_NORM)
+       if (!convert_now || cmap->br_state == XFS_EXT_NORM)
                return 0;
-       trace_xfs_reflink_convert_cow(ip, imap);
+       trace_xfs_reflink_convert_cow(ip, cmap);
        return xfs_reflink_convert_cow_locked(ip, offset_fsb, count_fsb);
 
 out_unreserve:
@@ -1270,7 +1270,7 @@ xfs_reflink_zero_posteof(
 
        trace_xfs_zero_eof(ip, isize, pos - isize);
        return iomap_zero_range(VFS_I(ip), isize, pos - isize, NULL,
-                       &xfs_iomap_ops);
+                       &xfs_buffered_write_iomap_ops);
 }
 
 /*
@@ -1381,85 +1381,6 @@ out_unlock:
        return ret;
 }
 
-/*
- * The user wants to preemptively CoW all shared blocks in this file,
- * which enables us to turn off the reflink flag.  Iterate all
- * extents which are not prealloc/delalloc to see which ranges are
- * mentioned in the refcount tree, then read those blocks into the
- * pagecache, dirty them, fsync them back out, and then we can update
- * the inode flag.  What happens if we run out of memory? :)
- */
-STATIC int
-xfs_reflink_dirty_extents(
-       struct xfs_inode        *ip,
-       xfs_fileoff_t           fbno,
-       xfs_filblks_t           end,
-       xfs_off_t               isize)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_agnumber_t          agno;
-       xfs_agblock_t           agbno;
-       xfs_extlen_t            aglen;
-       xfs_agblock_t           rbno;
-       xfs_extlen_t            rlen;
-       xfs_off_t               fpos;
-       xfs_off_t               flen;
-       struct xfs_bmbt_irec    map[2];
-       int                     nmaps;
-       int                     error = 0;
-
-       while (end - fbno > 0) {
-               nmaps = 1;
-               /*
-                * Look for extents in the file.  Skip holes, delalloc, or
-                * unwritten extents; they can't be reflinked.
-                */
-               error = xfs_bmapi_read(ip, fbno, end - fbno, map, &nmaps, 0);
-               if (error)
-                       goto out;
-               if (nmaps == 0)
-                       break;
-               if (!xfs_bmap_is_real_extent(&map[0]))
-                       goto next;
-
-               map[1] = map[0];
-               while (map[1].br_blockcount) {
-                       agno = XFS_FSB_TO_AGNO(mp, map[1].br_startblock);
-                       agbno = XFS_FSB_TO_AGBNO(mp, map[1].br_startblock);
-                       aglen = map[1].br_blockcount;
-
-                       error = xfs_reflink_find_shared(mp, NULL, agno, agbno,
-                                       aglen, &rbno, &rlen, true);
-                       if (error)
-                               goto out;
-                       if (rbno == NULLAGBLOCK)
-                               break;
-
-                       /* Dirty the pages */
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                       fpos = XFS_FSB_TO_B(mp, map[1].br_startoff +
-                                       (rbno - agbno));
-                       flen = XFS_FSB_TO_B(mp, rlen);
-                       if (fpos + flen > isize)
-                               flen = isize - fpos;
-                       error = iomap_file_unshare(VFS_I(ip), fpos, flen,
-                                       &xfs_iomap_ops);
-                       xfs_ilock(ip, XFS_ILOCK_EXCL);
-                       if (error)
-                               goto out;
-
-                       map[1].br_blockcount -= (rbno - agbno + rlen);
-                       map[1].br_startoff += (rbno - agbno + rlen);
-                       map[1].br_startblock += (rbno - agbno + rlen);
-               }
-
-next:
-               fbno = map[0].br_startoff + map[0].br_blockcount;
-       }
-out:
-       return error;
-}
-
 /* Does this inode need the reflink flag? */
 int
 xfs_reflink_inode_has_shared_extents(
@@ -1596,10 +1517,7 @@ xfs_reflink_unshare(
        xfs_off_t               offset,
        xfs_off_t               len)
 {
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_fileoff_t           fbno;
-       xfs_filblks_t           end;
-       xfs_off_t               isize;
+       struct inode            *inode = VFS_I(ip);
        int                     error;
 
        if (!xfs_is_reflink_inode(ip))
@@ -1607,20 +1525,13 @@ xfs_reflink_unshare(
 
        trace_xfs_reflink_unshare(ip, offset, len);
 
-       inode_dio_wait(VFS_I(ip));
+       inode_dio_wait(inode);
 
-       /* Try to CoW the selected ranges */
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       fbno = XFS_B_TO_FSBT(mp, offset);
-       isize = i_size_read(VFS_I(ip));
-       end = XFS_B_TO_FSB(mp, offset + len);
-       error = xfs_reflink_dirty_extents(ip, fbno, end, isize);
+       error = iomap_file_unshare(inode, offset, len,
+                       &xfs_buffered_write_iomap_ops);
        if (error)
-               goto out_unlock;
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-       /* Wait for the IO to finish */
-       error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
+               goto out;
+       error = filemap_write_and_wait(inode->i_mapping);
        if (error)
                goto out;
 
@@ -1628,11 +1539,8 @@ xfs_reflink_unshare(
        error = xfs_reflink_try_clear_inode_flag(ip);
        if (error)
                goto out;
-
        return 0;
 
-out_unlock:
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 out:
        trace_xfs_reflink_unshare_error(ip, error, _RET_IP_);
        return error;
index 28a43b7..d18ad7f 100644 (file)
@@ -25,8 +25,8 @@ extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip,
 bool xfs_inode_need_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
                bool *shared);
 
-extern int xfs_reflink_allocate_cow(struct xfs_inode *ip,
-               struct xfs_bmbt_irec *imap, bool *shared, uint *lockmode,
+int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
+               struct xfs_bmbt_irec *cmap, bool *shared, uint *lockmode,
                bool convert_now);
 extern int xfs_reflink_convert_cow(struct xfs_inode *ip, xfs_off_t offset,
                xfs_off_t count);
index 8939e0e..4911b68 100644 (file)
@@ -17,7 +17,7 @@
 #include "xfs_rmap_item.h"
 #include "xfs_log.h"
 #include "xfs_rmap.h"
-
+#include "xfs_error.h"
 
 kmem_zone_t    *xfs_rui_zone;
 kmem_zone_t    *xfs_rud_zone;
@@ -34,7 +34,7 @@ xfs_rui_item_free(
        if (ruip->rui_format.rui_nextents > XFS_RUI_MAX_FAST_EXTENTS)
                kmem_free(ruip);
        else
-               kmem_zone_free(xfs_rui_zone, ruip);
+               kmem_cache_free(xfs_rui_zone, ruip);
 }
 
 /*
@@ -171,8 +171,10 @@ xfs_rui_copy_format(
        src_rui_fmt = buf->i_addr;
        len = xfs_rui_log_format_sizeof(src_rui_fmt->rui_nextents);
 
-       if (buf->i_len != len)
+       if (buf->i_len != len) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
                return -EFSCORRUPTED;
+       }
 
        memcpy(dst_rui_fmt, src_rui_fmt, len);
        return 0;
@@ -227,7 +229,7 @@ xfs_rud_item_release(
        struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
 
        xfs_rui_release(rudp->rud_ruip);
-       kmem_zone_free(xfs_rud_zone, rudp);
+       kmem_cache_free(xfs_rud_zone, rudp);
 }
 
 static const struct xfs_item_ops xfs_rud_item_ops = {
@@ -539,7 +541,7 @@ xfs_rui_recover(
                         */
                        set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags);
                        xfs_rui_release(ruip);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
        }
 
@@ -581,6 +583,7 @@ xfs_rui_recover(
                        type = XFS_RMAP_FREE;
                        break;
                default:
+                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
                        error = -EFSCORRUPTED;
                        goto abort_error;
                }
index 4a48a8c..d42b5a2 100644 (file)
@@ -792,8 +792,7 @@ xfs_growfs_rt_alloc(
                 */
                nmap = 1;
                error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks,
-                                       XFS_BMAPI_METADATA, resblks, &map,
-                                       &nmap);
+                                       XFS_BMAPI_METADATA, 0, &map, &nmap);
                if (!error && nmap < 1)
                        error = -ENOSPC;
                if (error)
index 0a8cf6b..d9ae27d 100644 (file)
@@ -37,7 +37,8 @@
 #include "xfs_reflink.h"
 
 #include <linux/magic.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 
 static const struct super_operations xfs_super_operations;
 
@@ -50,7 +51,7 @@ static struct xfs_kobj xfs_dbg_kobj;  /* global debug sysfs attrs */
  * Table driven mount option parser.
  */
 enum {
-       Opt_logbufs, Opt_logbsize, Opt_logdev, Opt_rtdev, Opt_biosize,
+       Opt_logbufs, Opt_logbsize, Opt_logdev, Opt_rtdev,
        Opt_wsync, Opt_noalign, Opt_swalloc, Opt_sunit, Opt_swidth, Opt_nouuid,
        Opt_grpid, Opt_nogrpid, Opt_bsdgroups, Opt_sysvgroups,
        Opt_allocsize, Opt_norecovery, Opt_inode64, Opt_inode32, Opt_ikeep,
@@ -58,382 +59,67 @@ enum {
        Opt_filestreams, Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota,
        Opt_prjquota, Opt_uquota, Opt_gquota, Opt_pquota,
        Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce,
-       Opt_discard, Opt_nodiscard, Opt_dax, Opt_err,
+       Opt_discard, Opt_nodiscard, Opt_dax,
 };
 
-static const match_table_t tokens = {
-       {Opt_logbufs,   "logbufs=%u"},  /* number of XFS log buffers */
-       {Opt_logbsize,  "logbsize=%s"}, /* size of XFS log buffers */
-       {Opt_logdev,    "logdev=%s"},   /* log device */
-       {Opt_rtdev,     "rtdev=%s"},    /* realtime I/O device */
-       {Opt_biosize,   "biosize=%u"},  /* log2 of preferred buffered io size */
-       {Opt_wsync,     "wsync"},       /* safe-mode nfs compatible mount */
-       {Opt_noalign,   "noalign"},     /* turn off stripe alignment */
-       {Opt_swalloc,   "swalloc"},     /* turn on stripe width allocation */
-       {Opt_sunit,     "sunit=%u"},    /* data volume stripe unit */
-       {Opt_swidth,    "swidth=%u"},   /* data volume stripe width */
-       {Opt_nouuid,    "nouuid"},      /* ignore filesystem UUID */
-       {Opt_grpid,     "grpid"},       /* group-ID from parent directory */
-       {Opt_nogrpid,   "nogrpid"},     /* group-ID from current process */
-       {Opt_bsdgroups, "bsdgroups"},   /* group-ID from parent directory */
-       {Opt_sysvgroups,"sysvgroups"},  /* group-ID from current process */
-       {Opt_allocsize, "allocsize=%s"},/* preferred allocation size */
-       {Opt_norecovery,"norecovery"},  /* don't run XFS recovery */
-       {Opt_inode64,   "inode64"},     /* inodes can be allocated anywhere */
-       {Opt_inode32,   "inode32"},     /* inode allocation limited to
-                                        * XFS_MAXINUMBER_32 */
-       {Opt_ikeep,     "ikeep"},       /* do not free empty inode clusters */
-       {Opt_noikeep,   "noikeep"},     /* free empty inode clusters */
-       {Opt_largeio,   "largeio"},     /* report large I/O sizes in stat() */
-       {Opt_nolargeio, "nolargeio"},   /* do not report large I/O sizes
-                                        * in stat(). */
-       {Opt_attr2,     "attr2"},       /* do use attr2 attribute format */
-       {Opt_noattr2,   "noattr2"},     /* do not use attr2 attribute format */
-       {Opt_filestreams,"filestreams"},/* use filestreams allocator */
-       {Opt_quota,     "quota"},       /* disk quotas (user) */
-       {Opt_noquota,   "noquota"},     /* no quotas */
-       {Opt_usrquota,  "usrquota"},    /* user quota enabled */
-       {Opt_grpquota,  "grpquota"},    /* group quota enabled */
-       {Opt_prjquota,  "prjquota"},    /* project quota enabled */
-       {Opt_uquota,    "uquota"},      /* user quota (IRIX variant) */
-       {Opt_gquota,    "gquota"},      /* group quota (IRIX variant) */
-       {Opt_pquota,    "pquota"},      /* project quota (IRIX variant) */
-       {Opt_uqnoenforce,"uqnoenforce"},/* user quota limit enforcement */
-       {Opt_gqnoenforce,"gqnoenforce"},/* group quota limit enforcement */
-       {Opt_pqnoenforce,"pqnoenforce"},/* project quota limit enforcement */
-       {Opt_qnoenforce, "qnoenforce"}, /* same as uqnoenforce */
-       {Opt_discard,   "discard"},     /* Discard unused blocks */
-       {Opt_nodiscard, "nodiscard"},   /* Do not discard unused blocks */
-       {Opt_dax,       "dax"},         /* Enable direct access to bdev pages */
-       {Opt_err,       NULL},
+static const struct fs_parameter_spec xfs_param_specs[] = {
+       fsparam_u32("logbufs",          Opt_logbufs),
+       fsparam_string("logbsize",      Opt_logbsize),
+       fsparam_string("logdev",        Opt_logdev),
+       fsparam_string("rtdev",         Opt_rtdev),
+       fsparam_flag("wsync",           Opt_wsync),
+       fsparam_flag("noalign",         Opt_noalign),
+       fsparam_flag("swalloc",         Opt_swalloc),
+       fsparam_u32("sunit",            Opt_sunit),
+       fsparam_u32("swidth",           Opt_swidth),
+       fsparam_flag("nouuid",          Opt_nouuid),
+       fsparam_flag("grpid",           Opt_grpid),
+       fsparam_flag("nogrpid",         Opt_nogrpid),
+       fsparam_flag("bsdgroups",       Opt_bsdgroups),
+       fsparam_flag("sysvgroups",      Opt_sysvgroups),
+       fsparam_string("allocsize",     Opt_allocsize),
+       fsparam_flag("norecovery",      Opt_norecovery),
+       fsparam_flag("inode64",         Opt_inode64),
+       fsparam_flag("inode32",         Opt_inode32),
+       fsparam_flag("ikeep",           Opt_ikeep),
+       fsparam_flag("noikeep",         Opt_noikeep),
+       fsparam_flag("largeio",         Opt_largeio),
+       fsparam_flag("nolargeio",       Opt_nolargeio),
+       fsparam_flag("attr2",           Opt_attr2),
+       fsparam_flag("noattr2",         Opt_noattr2),
+       fsparam_flag("filestreams",     Opt_filestreams),
+       fsparam_flag("quota",           Opt_quota),
+       fsparam_flag("noquota",         Opt_noquota),
+       fsparam_flag("usrquota",        Opt_usrquota),
+       fsparam_flag("grpquota",        Opt_grpquota),
+       fsparam_flag("prjquota",        Opt_prjquota),
+       fsparam_flag("uquota",          Opt_uquota),
+       fsparam_flag("gquota",          Opt_gquota),
+       fsparam_flag("pquota",          Opt_pquota),
+       fsparam_flag("uqnoenforce",     Opt_uqnoenforce),
+       fsparam_flag("gqnoenforce",     Opt_gqnoenforce),
+       fsparam_flag("pqnoenforce",     Opt_pqnoenforce),
+       fsparam_flag("qnoenforce",      Opt_qnoenforce),
+       fsparam_flag("discard",         Opt_discard),
+       fsparam_flag("nodiscard",       Opt_nodiscard),
+       fsparam_flag("dax",             Opt_dax),
+       {}
 };
 
-
-STATIC int
-suffix_kstrtoint(const substring_t *s, unsigned int base, int *res)
-{
-       int     last, shift_left_factor = 0, _res;
-       char    *value;
-       int     ret = 0;
-
-       value = match_strdup(s);
-       if (!value)
-               return -ENOMEM;
-
-       last = strlen(value) - 1;
-       if (value[last] == 'K' || value[last] == 'k') {
-               shift_left_factor = 10;
-               value[last] = '\0';
-       }
-       if (value[last] == 'M' || value[last] == 'm') {
-               shift_left_factor = 20;
-               value[last] = '\0';
-       }
-       if (value[last] == 'G' || value[last] == 'g') {
-               shift_left_factor = 30;
-               value[last] = '\0';
-       }
-
-       if (kstrtoint(value, base, &_res))
-               ret = -EINVAL;
-       kfree(value);
-       *res = _res << shift_left_factor;
-       return ret;
-}
-
-/*
- * This function fills in xfs_mount_t fields based on mount args.
- * Note: the superblock has _not_ yet been read in.
- *
- * Note that this function leaks the various device name allocations on
- * failure.  The caller takes care of them.
- *
- * *sb is const because this is also used to test options on the remount
- * path, and we don't want this to have any side effects at remount time.
- * Today this function does not change *sb, but just to future-proof...
- */
-STATIC int
-xfs_parseargs(
-       struct xfs_mount        *mp,
-       char                    *options)
-{
-       const struct super_block *sb = mp->m_super;
-       char                    *p;
-       substring_t             args[MAX_OPT_ARGS];
-       int                     dsunit = 0;
-       int                     dswidth = 0;
-       int                     iosize = 0;
-       uint8_t                 iosizelog = 0;
-
-       /*
-        * set up the mount name first so all the errors will refer to the
-        * correct device.
-        */
-       mp->m_fsname = kstrndup(sb->s_id, MAXNAMELEN, GFP_KERNEL);
-       if (!mp->m_fsname)
-               return -ENOMEM;
-       mp->m_fsname_len = strlen(mp->m_fsname) + 1;
-
-       /*
-        * Copy binary VFS mount flags we are interested in.
-        */
-       if (sb_rdonly(sb))
-               mp->m_flags |= XFS_MOUNT_RDONLY;
-       if (sb->s_flags & SB_DIRSYNC)
-               mp->m_flags |= XFS_MOUNT_DIRSYNC;
-       if (sb->s_flags & SB_SYNCHRONOUS)
-               mp->m_flags |= XFS_MOUNT_WSYNC;
-
-       /*
-        * Set some default flags that could be cleared by the mount option
-        * parsing.
-        */
-       mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE;
-
-       /*
-        * These can be overridden by the mount option parsing.
-        */
-       mp->m_logbufs = -1;
-       mp->m_logbsize = -1;
-
-       if (!options)
-               goto done;
-
-       while ((p = strsep(&options, ",")) != NULL) {
-               int             token;
-
-               if (!*p)
-                       continue;
-
-               token = match_token(p, tokens, args);
-               switch (token) {
-               case Opt_logbufs:
-                       if (match_int(args, &mp->m_logbufs))
-                               return -EINVAL;
-                       break;
-               case Opt_logbsize:
-                       if (suffix_kstrtoint(args, 10, &mp->m_logbsize))
-                               return -EINVAL;
-                       break;
-               case Opt_logdev:
-                       kfree(mp->m_logname);
-                       mp->m_logname = match_strdup(args);
-                       if (!mp->m_logname)
-                               return -ENOMEM;
-                       break;
-               case Opt_rtdev:
-                       kfree(mp->m_rtname);
-                       mp->m_rtname = match_strdup(args);
-                       if (!mp->m_rtname)
-                               return -ENOMEM;
-                       break;
-               case Opt_allocsize:
-               case Opt_biosize:
-                       if (suffix_kstrtoint(args, 10, &iosize))
-                               return -EINVAL;
-                       iosizelog = ffs(iosize) - 1;
-                       break;
-               case Opt_grpid:
-               case Opt_bsdgroups:
-                       mp->m_flags |= XFS_MOUNT_GRPID;
-                       break;
-               case Opt_nogrpid:
-               case Opt_sysvgroups:
-                       mp->m_flags &= ~XFS_MOUNT_GRPID;
-                       break;
-               case Opt_wsync:
-                       mp->m_flags |= XFS_MOUNT_WSYNC;
-                       break;
-               case Opt_norecovery:
-                       mp->m_flags |= XFS_MOUNT_NORECOVERY;
-                       break;
-               case Opt_noalign:
-                       mp->m_flags |= XFS_MOUNT_NOALIGN;
-                       break;
-               case Opt_swalloc:
-                       mp->m_flags |= XFS_MOUNT_SWALLOC;
-                       break;
-               case Opt_sunit:
-                       if (match_int(args, &dsunit))
-                               return -EINVAL;
-                       break;
-               case Opt_swidth:
-                       if (match_int(args, &dswidth))
-                               return -EINVAL;
-                       break;
-               case Opt_inode32:
-                       mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
-                       break;
-               case Opt_inode64:
-                       mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
-                       break;
-               case Opt_nouuid:
-                       mp->m_flags |= XFS_MOUNT_NOUUID;
-                       break;
-               case Opt_ikeep:
-                       mp->m_flags |= XFS_MOUNT_IKEEP;
-                       break;
-               case Opt_noikeep:
-                       mp->m_flags &= ~XFS_MOUNT_IKEEP;
-                       break;
-               case Opt_largeio:
-                       mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE;
-                       break;
-               case Opt_nolargeio:
-                       mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE;
-                       break;
-               case Opt_attr2:
-                       mp->m_flags |= XFS_MOUNT_ATTR2;
-                       break;
-               case Opt_noattr2:
-                       mp->m_flags &= ~XFS_MOUNT_ATTR2;
-                       mp->m_flags |= XFS_MOUNT_NOATTR2;
-                       break;
-               case Opt_filestreams:
-                       mp->m_flags |= XFS_MOUNT_FILESTREAMS;
-                       break;
-               case Opt_noquota:
-                       mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT;
-                       mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD;
-                       mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE;
-                       break;
-               case Opt_quota:
-               case Opt_uquota:
-               case Opt_usrquota:
-                       mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
-                                        XFS_UQUOTA_ENFD);
-                       break;
-               case Opt_qnoenforce:
-               case Opt_uqnoenforce:
-                       mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
-                       mp->m_qflags &= ~XFS_UQUOTA_ENFD;
-                       break;
-               case Opt_pquota:
-               case Opt_prjquota:
-                       mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
-                                        XFS_PQUOTA_ENFD);
-                       break;
-               case Opt_pqnoenforce:
-                       mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
-                       mp->m_qflags &= ~XFS_PQUOTA_ENFD;
-                       break;
-               case Opt_gquota:
-               case Opt_grpquota:
-                       mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
-                                        XFS_GQUOTA_ENFD);
-                       break;
-               case Opt_gqnoenforce:
-                       mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
-                       mp->m_qflags &= ~XFS_GQUOTA_ENFD;
-                       break;
-               case Opt_discard:
-                       mp->m_flags |= XFS_MOUNT_DISCARD;
-                       break;
-               case Opt_nodiscard:
-                       mp->m_flags &= ~XFS_MOUNT_DISCARD;
-                       break;
-#ifdef CONFIG_FS_DAX
-               case Opt_dax:
-                       mp->m_flags |= XFS_MOUNT_DAX;
-                       break;
-#endif
-               default:
-                       xfs_warn(mp, "unknown mount option [%s].", p);
-                       return -EINVAL;
-               }
-       }
-
-       /*
-        * no recovery flag requires a read-only mount
-        */
-       if ((mp->m_flags & XFS_MOUNT_NORECOVERY) &&
-           !(mp->m_flags & XFS_MOUNT_RDONLY)) {
-               xfs_warn(mp, "no-recovery mounts must be read-only.");
-               return -EINVAL;
-       }
-
-       if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) {
-               xfs_warn(mp,
-       "sunit and swidth options incompatible with the noalign option");
-               return -EINVAL;
-       }
-
-#ifndef CONFIG_XFS_QUOTA
-       if (XFS_IS_QUOTA_RUNNING(mp)) {
-               xfs_warn(mp, "quota support not available in this kernel.");
-               return -EINVAL;
-       }
-#endif
-
-       if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
-               xfs_warn(mp, "sunit and swidth must be specified together");
-               return -EINVAL;
-       }
-
-       if (dsunit && (dswidth % dsunit != 0)) {
-               xfs_warn(mp,
-       "stripe width (%d) must be a multiple of the stripe unit (%d)",
-                       dswidth, dsunit);
-               return -EINVAL;
-       }
-
-done:
-       if (dsunit && !(mp->m_flags & XFS_MOUNT_NOALIGN)) {
-               /*
-                * At this point the superblock has not been read
-                * in, therefore we do not know the block size.
-                * Before the mount call ends we will convert
-                * these to FSBs.
-                */
-               mp->m_dalign = dsunit;
-               mp->m_swidth = dswidth;
-       }
-
-       if (mp->m_logbufs != -1 &&
-           mp->m_logbufs != 0 &&
-           (mp->m_logbufs < XLOG_MIN_ICLOGS ||
-            mp->m_logbufs > XLOG_MAX_ICLOGS)) {
-               xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
-                       mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS);
-               return -EINVAL;
-       }
-       if (mp->m_logbsize != -1 &&
-           mp->m_logbsize !=  0 &&
-           (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
-            mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
-            !is_power_of_2(mp->m_logbsize))) {
-               xfs_warn(mp,
-                       "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
-                       mp->m_logbsize);
-               return -EINVAL;
-       }
-
-       if (iosizelog) {
-               if (iosizelog > XFS_MAX_IO_LOG ||
-                   iosizelog < XFS_MIN_IO_LOG) {
-                       xfs_warn(mp, "invalid log iosize: %d [not %d-%d]",
-                               iosizelog, XFS_MIN_IO_LOG,
-                               XFS_MAX_IO_LOG);
-                       return -EINVAL;
-               }
-
-               mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE;
-               mp->m_readio_log = iosizelog;
-               mp->m_writeio_log = iosizelog;
-       }
-
-       return 0;
-}
+static const struct fs_parameter_description xfs_fs_parameters = {
+       .name           = "xfs",
+       .specs          = xfs_param_specs,
+};
 
 struct proc_xfs_info {
        uint64_t        flag;
        char            *str;
 };
 
-STATIC void
-xfs_showargs(
-       struct xfs_mount        *mp,
-       struct seq_file         *m)
+static int
+xfs_fs_show_options(
+       struct seq_file         *m,
+       struct dentry           *root)
 {
        static struct proc_xfs_info xfs_info_set[] = {
                /* the few simple ones we can get from the mount struct */
@@ -447,30 +133,24 @@ xfs_showargs(
                { XFS_MOUNT_FILESTREAMS,        ",filestreams" },
                { XFS_MOUNT_GRPID,              ",grpid" },
                { XFS_MOUNT_DISCARD,            ",discard" },
-               { XFS_MOUNT_SMALL_INUMS,        ",inode32" },
+               { XFS_MOUNT_LARGEIO,            ",largeio" },
                { XFS_MOUNT_DAX,                ",dax" },
                { 0, NULL }
        };
-       static struct proc_xfs_info xfs_info_unset[] = {
-               /* the few simple ones we can get from the mount struct */
-               { XFS_MOUNT_COMPAT_IOSIZE,      ",largeio" },
-               { XFS_MOUNT_SMALL_INUMS,        ",inode64" },
-               { 0, NULL }
-       };
+       struct xfs_mount        *mp = XFS_M(root->d_sb);
        struct proc_xfs_info    *xfs_infop;
 
        for (xfs_infop = xfs_info_set; xfs_infop->flag; xfs_infop++) {
                if (mp->m_flags & xfs_infop->flag)
                        seq_puts(m, xfs_infop->str);
        }
-       for (xfs_infop = xfs_info_unset; xfs_infop->flag; xfs_infop++) {
-               if (!(mp->m_flags & xfs_infop->flag))
-                       seq_puts(m, xfs_infop->str);
-       }
 
-       if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
+       seq_printf(m, ",inode%d",
+               (mp->m_flags & XFS_MOUNT_SMALL_INUMS) ? 32 : 64);
+
+       if (mp->m_flags & XFS_MOUNT_ALLOCSIZE)
                seq_printf(m, ",allocsize=%dk",
-                               (int)(1 << mp->m_writeio_log) >> 10);
+                          (1 << mp->m_allocsize_log) >> 10);
 
        if (mp->m_logbufs > 0)
                seq_printf(m, ",logbufs=%d", mp->m_logbufs);
@@ -509,6 +189,8 @@ xfs_showargs(
 
        if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT))
                seq_puts(m, ",noquota");
+
+       return 0;
 }
 
 static uint64_t
@@ -807,33 +489,33 @@ xfs_init_mount_workqueues(
        struct xfs_mount        *mp)
 {
        mp->m_buf_workqueue = alloc_workqueue("xfs-buf/%s",
-                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 1, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 1, mp->m_super->s_id);
        if (!mp->m_buf_workqueue)
                goto out;
 
        mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
-                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_super->s_id);
        if (!mp->m_unwritten_workqueue)
                goto out_destroy_buf;
 
        mp->m_cil_workqueue = alloc_workqueue("xfs-cil/%s",
                        WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND,
-                       0, mp->m_fsname);
+                       0, mp->m_super->s_id);
        if (!mp->m_cil_workqueue)
                goto out_destroy_unwritten;
 
        mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
-                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_super->s_id);
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_cil;
 
        mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
-                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_super->s_id);
        if (!mp->m_eofblocks_workqueue)
                goto out_destroy_reclaim;
 
        mp->m_sync_workqueue = alloc_workqueue("xfs-sync/%s", WQ_FREEZABLE, 0,
-                                              mp->m_fsname);
+                                              mp->m_super->s_id);
        if (!mp->m_sync_workqueue)
                goto out_destroy_eofb;
 
@@ -1037,13 +719,13 @@ xfs_fs_drop_inode(
        return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
 }
 
-STATIC void
-xfs_free_fsname(
+static void
+xfs_mount_free(
        struct xfs_mount        *mp)
 {
-       kfree(mp->m_fsname);
        kfree(mp->m_rtname);
        kfree(mp->m_logname);
+       kmem_free(mp);
 }
 
 STATIC int
@@ -1204,181 +886,6 @@ xfs_quiesce_attr(
        xfs_log_quiesce(mp);
 }
 
-STATIC int
-xfs_test_remount_options(
-       struct super_block      *sb,
-       char                    *options)
-{
-       int                     error = 0;
-       struct xfs_mount        *tmp_mp;
-
-       tmp_mp = kmem_zalloc(sizeof(*tmp_mp), KM_MAYFAIL);
-       if (!tmp_mp)
-               return -ENOMEM;
-
-       tmp_mp->m_super = sb;
-       error = xfs_parseargs(tmp_mp, options);
-       xfs_free_fsname(tmp_mp);
-       kmem_free(tmp_mp);
-
-       return error;
-}
-
-STATIC int
-xfs_fs_remount(
-       struct super_block      *sb,
-       int                     *flags,
-       char                    *options)
-{
-       struct xfs_mount        *mp = XFS_M(sb);
-       xfs_sb_t                *sbp = &mp->m_sb;
-       substring_t             args[MAX_OPT_ARGS];
-       char                    *p;
-       int                     error;
-
-       /* First, check for complete junk; i.e. invalid options */
-       error = xfs_test_remount_options(sb, options);
-       if (error)
-               return error;
-
-       sync_filesystem(sb);
-       while ((p = strsep(&options, ",")) != NULL) {
-               int token;
-
-               if (!*p)
-                       continue;
-
-               token = match_token(p, tokens, args);
-               switch (token) {
-               case Opt_inode64:
-                       mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
-                       mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
-                       break;
-               case Opt_inode32:
-                       mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
-                       mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
-                       break;
-               default:
-                       /*
-                        * Logically we would return an error here to prevent
-                        * users from believing they might have changed
-                        * mount options using remount which can't be changed.
-                        *
-                        * But unfortunately mount(8) adds all options from
-                        * mtab and fstab to the mount arguments in some cases
-                        * so we can't blindly reject options, but have to
-                        * check for each specified option if it actually
-                        * differs from the currently set option and only
-                        * reject it if that's the case.
-                        *
-                        * Until that is implemented we return success for
-                        * every remount request, and silently ignore all
-                        * options that we can't actually change.
-                        */
-#if 0
-                       xfs_info(mp,
-               "mount option \"%s\" not supported for remount", p);
-                       return -EINVAL;
-#else
-                       break;
-#endif
-               }
-       }
-
-       /* ro -> rw */
-       if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & SB_RDONLY)) {
-               if (mp->m_flags & XFS_MOUNT_NORECOVERY) {
-                       xfs_warn(mp,
-               "ro->rw transition prohibited on norecovery mount");
-                       return -EINVAL;
-               }
-
-               if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
-                   xfs_sb_has_ro_compat_feature(sbp,
-                                       XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
-                       xfs_warn(mp,
-"ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem",
-                               (sbp->sb_features_ro_compat &
-                                       XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
-                       return -EINVAL;
-               }
-
-               mp->m_flags &= ~XFS_MOUNT_RDONLY;
-
-               /*
-                * If this is the first remount to writeable state we
-                * might have some superblock changes to update.
-                */
-               if (mp->m_update_sb) {
-                       error = xfs_sync_sb(mp, false);
-                       if (error) {
-                               xfs_warn(mp, "failed to write sb changes");
-                               return error;
-                       }
-                       mp->m_update_sb = false;
-               }
-
-               /*
-                * Fill out the reserve pool if it is empty. Use the stashed
-                * value if it is non-zero, otherwise go with the default.
-                */
-               xfs_restore_resvblks(mp);
-               xfs_log_work_queue(mp);
-
-               /* Recover any CoW blocks that never got remapped. */
-               error = xfs_reflink_recover_cow(mp);
-               if (error) {
-                       xfs_err(mp,
-       "Error %d recovering leftover CoW allocations.", error);
-                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
-                       return error;
-               }
-               xfs_start_block_reaping(mp);
-
-               /* Create the per-AG metadata reservation pool .*/
-               error = xfs_fs_reserve_ag_blocks(mp);
-               if (error && error != -ENOSPC)
-                       return error;
-       }
-
-       /* rw -> ro */
-       if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & SB_RDONLY)) {
-               /*
-                * Cancel background eofb scanning so it cannot race with the
-                * final log force+buftarg wait and deadlock the remount.
-                */
-               xfs_stop_block_reaping(mp);
-
-               /* Get rid of any leftover CoW reservations... */
-               error = xfs_icache_free_cowblocks(mp, NULL);
-               if (error) {
-                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
-                       return error;
-               }
-
-               /* Free the per-AG metadata reservation pool. */
-               error = xfs_fs_unreserve_ag_blocks(mp);
-               if (error) {
-                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
-                       return error;
-               }
-
-               /*
-                * Before we sync the metadata, we need to free up the reserve
-                * block pool so that the used block count in the superblock on
-                * disk is correct at the end of the remount. Stash the current
-                * reserve pool size so that if we get remounted rw, we can
-                * return it to the same size.
-                */
-               xfs_save_resvblks(mp);
-
-               xfs_quiesce_attr(mp);
-               mp->m_flags |= XFS_MOUNT_RDONLY;
-       }
-
-       return 0;
-}
-
 /*
  * Second stage of a freeze. The data is already frozen so we only
  * need to take care of the metadata. Once that's done sync the superblock
@@ -1409,15 +916,6 @@ xfs_fs_unfreeze(
        return 0;
 }
 
-STATIC int
-xfs_fs_show_options(
-       struct seq_file         *m,
-       struct dentry           *root)
-{
-       xfs_showargs(XFS_M(root->d_sb), m);
-       return 0;
-}
-
 /*
  * This function fills in xfs_mount_t fields based on mount args.
  * Note: the superblock _has_ now been read in.
@@ -1540,60 +1038,337 @@ xfs_destroy_percpu_counters(
        percpu_counter_destroy(&mp->m_delalloc_blks);
 }
 
-static struct xfs_mount *
-xfs_mount_alloc(
+static void
+xfs_fs_put_super(
        struct super_block      *sb)
 {
-       struct xfs_mount        *mp;
+       struct xfs_mount        *mp = XFS_M(sb);
 
-       mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL);
-       if (!mp)
-               return NULL;
+       /* if ->fill_super failed, we have no mount to tear down */
+       if (!sb->s_fs_info)
+               return;
 
-       mp->m_super = sb;
-       spin_lock_init(&mp->m_sb_lock);
-       spin_lock_init(&mp->m_agirotor_lock);
-       INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
-       spin_lock_init(&mp->m_perag_lock);
-       mutex_init(&mp->m_growlock);
-       atomic_set(&mp->m_active_trans, 0);
-       INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
-       INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
-       INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_worker);
-       mp->m_kobj.kobject.kset = xfs_kset;
-       /*
-        * We don't create the finobt per-ag space reservation until after log
-        * recovery, so we must set this to true so that an ifree transaction
-        * started during log recovery will not depend on space reservations
-        * for finobt expansion.
-        */
-       mp->m_finobt_nores = true;
-       return mp;
-}
+       xfs_notice(mp, "Unmounting Filesystem");
+       xfs_filestream_unmount(mp);
+       xfs_unmountfs(mp);
 
+       xfs_freesb(mp);
+       free_percpu(mp->m_stats.xs_stats);
+       xfs_destroy_percpu_counters(mp);
+       xfs_destroy_mount_workqueues(mp);
+       xfs_close_devices(mp);
 
-STATIC int
-xfs_fs_fill_super(
-       struct super_block      *sb,
-       void                    *data,
-       int                     silent)
-{
-       struct inode            *root;
-       struct xfs_mount        *mp = NULL;
-       int                     flags = 0, error = -ENOMEM;
+       sb->s_fs_info = NULL;
+       xfs_mount_free(mp);
+}
+
+static long
+xfs_fs_nr_cached_objects(
+       struct super_block      *sb,
+       struct shrink_control   *sc)
+{
+       /* Paranoia: catch incorrect calls during mount setup or teardown */
+       if (WARN_ON_ONCE(!sb->s_fs_info))
+               return 0;
+       return xfs_reclaim_inodes_count(XFS_M(sb));
+}
+
+static long
+xfs_fs_free_cached_objects(
+       struct super_block      *sb,
+       struct shrink_control   *sc)
+{
+       return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan);
+}
+
+static const struct super_operations xfs_super_operations = {
+       .alloc_inode            = xfs_fs_alloc_inode,
+       .destroy_inode          = xfs_fs_destroy_inode,
+       .dirty_inode            = xfs_fs_dirty_inode,
+       .drop_inode             = xfs_fs_drop_inode,
+       .put_super              = xfs_fs_put_super,
+       .sync_fs                = xfs_fs_sync_fs,
+       .freeze_fs              = xfs_fs_freeze,
+       .unfreeze_fs            = xfs_fs_unfreeze,
+       .statfs                 = xfs_fs_statfs,
+       .show_options           = xfs_fs_show_options,
+       .nr_cached_objects      = xfs_fs_nr_cached_objects,
+       .free_cached_objects    = xfs_fs_free_cached_objects,
+};
+
+static int
+suffix_kstrtoint(
+       const char      *s,
+       unsigned int    base,
+       int             *res)
+{
+       int             last, shift_left_factor = 0, _res;
+       char            *value;
+       int             ret = 0;
+
+       value = kstrdup(s, GFP_KERNEL);
+       if (!value)
+               return -ENOMEM;
 
+       last = strlen(value) - 1;
+       if (value[last] == 'K' || value[last] == 'k') {
+               shift_left_factor = 10;
+               value[last] = '\0';
+       }
+       if (value[last] == 'M' || value[last] == 'm') {
+               shift_left_factor = 20;
+               value[last] = '\0';
+       }
+       if (value[last] == 'G' || value[last] == 'g') {
+               shift_left_factor = 30;
+               value[last] = '\0';
+       }
+
+       if (kstrtoint(value, base, &_res))
+               ret = -EINVAL;
+       kfree(value);
+       *res = _res << shift_left_factor;
+       return ret;
+}
+
+/*
+ * Set mount state from a mount option.
+ *
+ * NOTE: mp->m_super is NULL here!
+ */
+static int
+xfs_fc_parse_param(
+       struct fs_context       *fc,
+       struct fs_parameter     *param)
+{
+       struct xfs_mount        *mp = fc->s_fs_info;
+       struct fs_parse_result  result;
+       int                     size = 0;
+       int                     opt;
+
+       opt = fs_parse(fc, &xfs_fs_parameters, param, &result);
+       if (opt < 0)
+               return opt;
+
+       switch (opt) {
+       case Opt_logbufs:
+               mp->m_logbufs = result.uint_32;
+               return 0;
+       case Opt_logbsize:
+               if (suffix_kstrtoint(param->string, 10, &mp->m_logbsize))
+                       return -EINVAL;
+               return 0;
+       case Opt_logdev:
+               kfree(mp->m_logname);
+               mp->m_logname = kstrdup(param->string, GFP_KERNEL);
+               if (!mp->m_logname)
+                       return -ENOMEM;
+               return 0;
+       case Opt_rtdev:
+               kfree(mp->m_rtname);
+               mp->m_rtname = kstrdup(param->string, GFP_KERNEL);
+               if (!mp->m_rtname)
+                       return -ENOMEM;
+               return 0;
+       case Opt_allocsize:
+               if (suffix_kstrtoint(param->string, 10, &size))
+                       return -EINVAL;
+               mp->m_allocsize_log = ffs(size) - 1;
+               mp->m_flags |= XFS_MOUNT_ALLOCSIZE;
+               return 0;
+       case Opt_grpid:
+       case Opt_bsdgroups:
+               mp->m_flags |= XFS_MOUNT_GRPID;
+               return 0;
+       case Opt_nogrpid:
+       case Opt_sysvgroups:
+               mp->m_flags &= ~XFS_MOUNT_GRPID;
+               return 0;
+       case Opt_wsync:
+               mp->m_flags |= XFS_MOUNT_WSYNC;
+               return 0;
+       case Opt_norecovery:
+               mp->m_flags |= XFS_MOUNT_NORECOVERY;
+               return 0;
+       case Opt_noalign:
+               mp->m_flags |= XFS_MOUNT_NOALIGN;
+               return 0;
+       case Opt_swalloc:
+               mp->m_flags |= XFS_MOUNT_SWALLOC;
+               return 0;
+       case Opt_sunit:
+               mp->m_dalign = result.uint_32;
+               return 0;
+       case Opt_swidth:
+               mp->m_swidth = result.uint_32;
+               return 0;
+       case Opt_inode32:
+               mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
+               return 0;
+       case Opt_inode64:
+               mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
+               return 0;
+       case Opt_nouuid:
+               mp->m_flags |= XFS_MOUNT_NOUUID;
+               return 0;
+       case Opt_ikeep:
+               mp->m_flags |= XFS_MOUNT_IKEEP;
+               return 0;
+       case Opt_noikeep:
+               mp->m_flags &= ~XFS_MOUNT_IKEEP;
+               return 0;
+       case Opt_largeio:
+               mp->m_flags |= XFS_MOUNT_LARGEIO;
+               return 0;
+       case Opt_nolargeio:
+               mp->m_flags &= ~XFS_MOUNT_LARGEIO;
+               return 0;
+       case Opt_attr2:
+               mp->m_flags |= XFS_MOUNT_ATTR2;
+               return 0;
+       case Opt_noattr2:
+               mp->m_flags &= ~XFS_MOUNT_ATTR2;
+               mp->m_flags |= XFS_MOUNT_NOATTR2;
+               return 0;
+       case Opt_filestreams:
+               mp->m_flags |= XFS_MOUNT_FILESTREAMS;
+               return 0;
+       case Opt_noquota:
+               mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT;
+               mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD;
+               mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE;
+               return 0;
+       case Opt_quota:
+       case Opt_uquota:
+       case Opt_usrquota:
+               mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
+                                XFS_UQUOTA_ENFD);
+               return 0;
+       case Opt_qnoenforce:
+       case Opt_uqnoenforce:
+               mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
+               mp->m_qflags &= ~XFS_UQUOTA_ENFD;
+               return 0;
+       case Opt_pquota:
+       case Opt_prjquota:
+               mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
+                                XFS_PQUOTA_ENFD);
+               return 0;
+       case Opt_pqnoenforce:
+               mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
+               mp->m_qflags &= ~XFS_PQUOTA_ENFD;
+               return 0;
+       case Opt_gquota:
+       case Opt_grpquota:
+               mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
+                                XFS_GQUOTA_ENFD);
+               return 0;
+       case Opt_gqnoenforce:
+               mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
+               mp->m_qflags &= ~XFS_GQUOTA_ENFD;
+               return 0;
+       case Opt_discard:
+               mp->m_flags |= XFS_MOUNT_DISCARD;
+               return 0;
+       case Opt_nodiscard:
+               mp->m_flags &= ~XFS_MOUNT_DISCARD;
+               return 0;
+#ifdef CONFIG_FS_DAX
+       case Opt_dax:
+               mp->m_flags |= XFS_MOUNT_DAX;
+               return 0;
+#endif
+       default:
+               xfs_warn(mp, "unknown mount option [%s].", param->key);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+xfs_fc_validate_params(
+       struct xfs_mount        *mp)
+{
        /*
-        * allocate mp and do all low-level struct initializations before we
-        * attach it to the super
+        * no recovery flag requires a read-only mount
         */
-       mp = xfs_mount_alloc(sb);
-       if (!mp)
-               goto out;
-       sb->s_fs_info = mp;
+       if ((mp->m_flags & XFS_MOUNT_NORECOVERY) &&
+           !(mp->m_flags & XFS_MOUNT_RDONLY)) {
+               xfs_warn(mp, "no-recovery mounts must be read-only.");
+               return -EINVAL;
+       }
+
+       if ((mp->m_flags & XFS_MOUNT_NOALIGN) &&
+           (mp->m_dalign || mp->m_swidth)) {
+               xfs_warn(mp,
+       "sunit and swidth options incompatible with the noalign option");
+               return -EINVAL;
+       }
+
+       if (!IS_ENABLED(CONFIG_XFS_QUOTA) && mp->m_qflags != 0) {
+               xfs_warn(mp, "quota support not available in this kernel.");
+               return -EINVAL;
+       }
+
+       if ((mp->m_dalign && !mp->m_swidth) ||
+           (!mp->m_dalign && mp->m_swidth)) {
+               xfs_warn(mp, "sunit and swidth must be specified together");
+               return -EINVAL;
+       }
+
+       if (mp->m_dalign && (mp->m_swidth % mp->m_dalign != 0)) {
+               xfs_warn(mp,
+       "stripe width (%d) must be a multiple of the stripe unit (%d)",
+                       mp->m_swidth, mp->m_dalign);
+               return -EINVAL;
+       }
+
+       if (mp->m_logbufs != -1 &&
+           mp->m_logbufs != 0 &&
+           (mp->m_logbufs < XLOG_MIN_ICLOGS ||
+            mp->m_logbufs > XLOG_MAX_ICLOGS)) {
+               xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
+                       mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS);
+               return -EINVAL;
+       }
+
+       if (mp->m_logbsize != -1 &&
+           mp->m_logbsize !=  0 &&
+           (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
+            mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
+            !is_power_of_2(mp->m_logbsize))) {
+               xfs_warn(mp,
+                       "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
+                       mp->m_logbsize);
+               return -EINVAL;
+       }
+
+       if ((mp->m_flags & XFS_MOUNT_ALLOCSIZE) &&
+           (mp->m_allocsize_log > XFS_MAX_IO_LOG ||
+            mp->m_allocsize_log < XFS_MIN_IO_LOG)) {
+               xfs_warn(mp, "invalid log iosize: %d [not %d-%d]",
+                       mp->m_allocsize_log, XFS_MIN_IO_LOG, XFS_MAX_IO_LOG);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+xfs_fc_fill_super(
+       struct super_block      *sb,
+       struct fs_context       *fc)
+{
+       struct xfs_mount        *mp = sb->s_fs_info;
+       struct inode            *root;
+       int                     flags = 0, error;
 
-       error = xfs_parseargs(mp, (char *)data);
+       mp->m_super = sb;
+
+       error = xfs_fc_validate_params(mp);
        if (error)
-               goto out_free_fsname;
+               goto out_free_names;
 
        sb_min_blocksize(sb, BBSIZE);
        sb->s_xattr = xfs_xattr_handlers;
@@ -1615,12 +1390,12 @@ xfs_fs_fill_super(
                msleep(xfs_globals.mount_delay * 1000);
        }
 
-       if (silent)
+       if (fc->sb_flags & SB_SILENT)
                flags |= XFS_MFSI_QUIET;
 
        error = xfs_open_devices(mp);
        if (error)
-               goto out_free_fsname;
+               goto out_free_names;
 
        error = xfs_init_mount_workqueues(mp);
        if (error)
@@ -1757,11 +1532,9 @@ xfs_fs_fill_super(
        xfs_destroy_mount_workqueues(mp);
  out_close_devices:
        xfs_close_devices(mp);
- out_free_fsname:
+ out_free_names:
        sb->s_fs_info = NULL;
-       xfs_free_fsname(mp);
-       kfree(mp);
- out:
+       xfs_mount_free(mp);
        return error;
 
  out_unmount:
@@ -1770,80 +1543,252 @@ xfs_fs_fill_super(
        goto out_free_sb;
 }
 
-STATIC void
-xfs_fs_put_super(
-       struct super_block      *sb)
+static int
+xfs_fc_get_tree(
+       struct fs_context       *fc)
 {
-       struct xfs_mount        *mp = XFS_M(sb);
+       return get_tree_bdev(fc, xfs_fc_fill_super);
+}
 
-       /* if ->fill_super failed, we have no mount to tear down */
-       if (!sb->s_fs_info)
-               return;
+static int
+xfs_remount_rw(
+       struct xfs_mount        *mp)
+{
+       struct xfs_sb           *sbp = &mp->m_sb;
+       int error;
 
-       xfs_notice(mp, "Unmounting Filesystem");
-       xfs_filestream_unmount(mp);
-       xfs_unmountfs(mp);
+       if (mp->m_flags & XFS_MOUNT_NORECOVERY) {
+               xfs_warn(mp,
+                       "ro->rw transition prohibited on norecovery mount");
+               return -EINVAL;
+       }
 
-       xfs_freesb(mp);
-       free_percpu(mp->m_stats.xs_stats);
-       xfs_destroy_percpu_counters(mp);
-       xfs_destroy_mount_workqueues(mp);
-       xfs_close_devices(mp);
+       if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+           xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
+               xfs_warn(mp,
+       "ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem",
+                       (sbp->sb_features_ro_compat &
+                               XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
+               return -EINVAL;
+       }
 
-       sb->s_fs_info = NULL;
-       xfs_free_fsname(mp);
-       kfree(mp);
+       mp->m_flags &= ~XFS_MOUNT_RDONLY;
+
+       /*
+        * If this is the first remount to writeable state we might have some
+        * superblock changes to update.
+        */
+       if (mp->m_update_sb) {
+               error = xfs_sync_sb(mp, false);
+               if (error) {
+                       xfs_warn(mp, "failed to write sb changes");
+                       return error;
+               }
+               mp->m_update_sb = false;
+       }
+
+       /*
+        * Fill out the reserve pool if it is empty. Use the stashed value if
+        * it is non-zero, otherwise go with the default.
+        */
+       xfs_restore_resvblks(mp);
+       xfs_log_work_queue(mp);
+
+       /* Recover any CoW blocks that never got remapped. */
+       error = xfs_reflink_recover_cow(mp);
+       if (error) {
+               xfs_err(mp,
+                       "Error %d recovering leftover CoW allocations.", error);
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+               return error;
+       }
+       xfs_start_block_reaping(mp);
+
+       /* Create the per-AG metadata reservation pool .*/
+       error = xfs_fs_reserve_ag_blocks(mp);
+       if (error && error != -ENOSPC)
+               return error;
+
+       return 0;
 }
 
-STATIC struct dentry *
-xfs_fs_mount(
-       struct file_system_type *fs_type,
-       int                     flags,
-       const char              *dev_name,
-       void                    *data)
+static int
+xfs_remount_ro(
+       struct xfs_mount        *mp)
 {
-       return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
+       int error;
+
+       /*
+        * Cancel background eofb scanning so it cannot race with the final
+        * log force+buftarg wait and deadlock the remount.
+        */
+       xfs_stop_block_reaping(mp);
+
+       /* Get rid of any leftover CoW reservations... */
+       error = xfs_icache_free_cowblocks(mp, NULL);
+       if (error) {
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+               return error;
+       }
+
+       /* Free the per-AG metadata reservation pool. */
+       error = xfs_fs_unreserve_ag_blocks(mp);
+       if (error) {
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+               return error;
+       }
+
+       /*
+        * Before we sync the metadata, we need to free up the reserve block
+        * pool so that the used block count in the superblock on disk is
+        * correct at the end of the remount. Stash the current* reserve pool
+        * size so that if we get remounted rw, we can return it to the same
+        * size.
+        */
+       xfs_save_resvblks(mp);
+
+       xfs_quiesce_attr(mp);
+       mp->m_flags |= XFS_MOUNT_RDONLY;
+
+       return 0;
 }
 
-static long
-xfs_fs_nr_cached_objects(
-       struct super_block      *sb,
-       struct shrink_control   *sc)
+/*
+ * Logically we would return an error here to prevent users from believing
+ * they might have changed mount options using remount which can't be changed.
+ *
+ * But unfortunately mount(8) adds all options from mtab and fstab to the mount
+ * arguments in some cases so we can't blindly reject options, but have to
+ * check for each specified option if it actually differs from the currently
+ * set option and only reject it if that's the case.
+ *
+ * Until that is implemented we return success for every remount request, and
+ * silently ignore all options that we can't actually change.
+ */
+static int
+xfs_fc_reconfigure(
+       struct fs_context *fc)
 {
-       /* Paranoia: catch incorrect calls during mount setup or teardown */
-       if (WARN_ON_ONCE(!sb->s_fs_info))
-               return 0;
-       return xfs_reclaim_inodes_count(XFS_M(sb));
+       struct xfs_mount        *mp = XFS_M(fc->root->d_sb);
+       struct xfs_mount        *new_mp = fc->s_fs_info;
+       xfs_sb_t                *sbp = &mp->m_sb;
+       int                     flags = fc->sb_flags;
+       int                     error;
+
+       error = xfs_fc_validate_params(new_mp);
+       if (error)
+               return error;
+
+       sync_filesystem(mp->m_super);
+
+       /* inode32 -> inode64 */
+       if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) &&
+           !(new_mp->m_flags & XFS_MOUNT_SMALL_INUMS)) {
+               mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
+               mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
+       }
+
+       /* inode64 -> inode32 */
+       if (!(mp->m_flags & XFS_MOUNT_SMALL_INUMS) &&
+           (new_mp->m_flags & XFS_MOUNT_SMALL_INUMS)) {
+               mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
+               mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
+       }
+
+       /* ro -> rw */
+       if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(flags & SB_RDONLY)) {
+               error = xfs_remount_rw(mp);
+               if (error)
+                       return error;
+       }
+
+       /* rw -> ro */
+       if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (flags & SB_RDONLY)) {
+               error = xfs_remount_ro(mp);
+               if (error)
+                       return error;
+       }
+
+       return 0;
 }
 
-static long
-xfs_fs_free_cached_objects(
-       struct super_block      *sb,
-       struct shrink_control   *sc)
+static void xfs_fc_free(
+       struct fs_context       *fc)
 {
-       return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan);
+       struct xfs_mount        *mp = fc->s_fs_info;
+
+       /*
+        * mp is stored in the fs_context when it is initialized.
+        * mp is transferred to the superblock on a successful mount,
+        * but if an error occurs before the transfer we have to free
+        * it here.
+        */
+       if (mp)
+               xfs_mount_free(mp);
 }
 
-static const struct super_operations xfs_super_operations = {
-       .alloc_inode            = xfs_fs_alloc_inode,
-       .destroy_inode          = xfs_fs_destroy_inode,
-       .dirty_inode            = xfs_fs_dirty_inode,
-       .drop_inode             = xfs_fs_drop_inode,
-       .put_super              = xfs_fs_put_super,
-       .sync_fs                = xfs_fs_sync_fs,
-       .freeze_fs              = xfs_fs_freeze,
-       .unfreeze_fs            = xfs_fs_unfreeze,
-       .statfs                 = xfs_fs_statfs,
-       .remount_fs             = xfs_fs_remount,
-       .show_options           = xfs_fs_show_options,
-       .nr_cached_objects      = xfs_fs_nr_cached_objects,
-       .free_cached_objects    = xfs_fs_free_cached_objects,
+static const struct fs_context_operations xfs_context_ops = {
+       .parse_param = xfs_fc_parse_param,
+       .get_tree    = xfs_fc_get_tree,
+       .reconfigure = xfs_fc_reconfigure,
+       .free        = xfs_fc_free,
 };
 
+static int xfs_init_fs_context(
+       struct fs_context       *fc)
+{
+       struct xfs_mount        *mp;
+
+       mp = kmem_alloc(sizeof(struct xfs_mount), KM_ZERO);
+       if (!mp)
+               return -ENOMEM;
+
+       spin_lock_init(&mp->m_sb_lock);
+       spin_lock_init(&mp->m_agirotor_lock);
+       INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
+       spin_lock_init(&mp->m_perag_lock);
+       mutex_init(&mp->m_growlock);
+       atomic_set(&mp->m_active_trans, 0);
+       INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
+       INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
+       INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_worker);
+       mp->m_kobj.kobject.kset = xfs_kset;
+       /*
+        * We don't create the finobt per-ag space reservation until after log
+        * recovery, so we must set this to true so that an ifree transaction
+        * started during log recovery will not depend on space reservations
+        * for finobt expansion.
+        */
+       mp->m_finobt_nores = true;
+
+       /*
+        * These can be overridden by the mount option parsing.
+        */
+       mp->m_logbufs = -1;
+       mp->m_logbsize = -1;
+       mp->m_allocsize_log = 16; /* 64k */
+
+       /*
+        * Copy binary VFS mount flags we are interested in.
+        */
+       if (fc->sb_flags & SB_RDONLY)
+               mp->m_flags |= XFS_MOUNT_RDONLY;
+       if (fc->sb_flags & SB_DIRSYNC)
+               mp->m_flags |= XFS_MOUNT_DIRSYNC;
+       if (fc->sb_flags & SB_SYNCHRONOUS)
+               mp->m_flags |= XFS_MOUNT_WSYNC;
+
+       fc->s_fs_info = mp;
+       fc->ops = &xfs_context_ops;
+
+       return 0;
+}
+
 static struct file_system_type xfs_fs_type = {
        .owner                  = THIS_MODULE,
        .name                   = "xfs",
-       .mount                  = xfs_fs_mount,
+       .init_fs_context        = xfs_init_fs_context,
+       .parameters             = &xfs_fs_parameters,
        .kill_sb                = kill_block_super,
        .fs_flags               = FS_REQUIRES_DEV,
 };
@@ -1852,32 +1797,39 @@ MODULE_ALIAS_FS("xfs");
 STATIC int __init
 xfs_init_zones(void)
 {
-       xfs_log_ticket_zone = kmem_zone_init(sizeof(xlog_ticket_t),
-                                               "xfs_log_ticket");
+       xfs_log_ticket_zone = kmem_cache_create("xfs_log_ticket",
+                                               sizeof(struct xlog_ticket),
+                                               0, 0, NULL);
        if (!xfs_log_ticket_zone)
                goto out;
 
-       xfs_bmap_free_item_zone = kmem_zone_init(
-                       sizeof(struct xfs_extent_free_item),
-                       "xfs_bmap_free_item");
+       xfs_bmap_free_item_zone = kmem_cache_create("xfs_bmap_free_item",
+                                       sizeof(struct xfs_extent_free_item),
+                                       0, 0, NULL);
        if (!xfs_bmap_free_item_zone)
                goto out_destroy_log_ticket_zone;
 
-       xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t),
-                                               "xfs_btree_cur");
+       xfs_btree_cur_zone = kmem_cache_create("xfs_btree_cur",
+                                              sizeof(struct xfs_btree_cur),
+                                              0, 0, NULL);
        if (!xfs_btree_cur_zone)
                goto out_destroy_bmap_free_item_zone;
 
-       xfs_da_state_zone = kmem_zone_init(sizeof(xfs_da_state_t),
-                                               "xfs_da_state");
+       xfs_da_state_zone = kmem_cache_create("xfs_da_state",
+                                             sizeof(struct xfs_da_state),
+                                             0, 0, NULL);
        if (!xfs_da_state_zone)
                goto out_destroy_btree_cur_zone;
 
-       xfs_ifork_zone = kmem_zone_init(sizeof(struct xfs_ifork), "xfs_ifork");
+       xfs_ifork_zone = kmem_cache_create("xfs_ifork",
+                                          sizeof(struct xfs_ifork),
+                                          0, 0, NULL);
        if (!xfs_ifork_zone)
                goto out_destroy_da_state_zone;
 
-       xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans");
+       xfs_trans_zone = kmem_cache_create("xf_trans",
+                                          sizeof(struct xfs_trans),
+                                          0, 0, NULL);
        if (!xfs_trans_zone)
                goto out_destroy_ifork_zone;
 
@@ -1887,109 +1839,121 @@ xfs_init_zones(void)
         * size possible under XFS.  This wastes a little bit of memory,
         * but it is much faster.
         */
-       xfs_buf_item_zone = kmem_zone_init(sizeof(struct xfs_buf_log_item),
-                                          "xfs_buf_item");
+       xfs_buf_item_zone = kmem_cache_create("xfs_buf_item",
+                                             sizeof(struct xfs_buf_log_item),
+                                             0, 0, NULL);
        if (!xfs_buf_item_zone)
                goto out_destroy_trans_zone;
 
-       xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) +
-                       ((XFS_EFD_MAX_FAST_EXTENTS - 1) *
-                                sizeof(xfs_extent_t))), "xfs_efd_item");
+       xfs_efd_zone = kmem_cache_create("xfs_efd_item",
+                                       (sizeof(struct xfs_efd_log_item) +
+                                       (XFS_EFD_MAX_FAST_EXTENTS - 1) *
+                                       sizeof(struct xfs_extent)),
+                                       0, 0, NULL);
        if (!xfs_efd_zone)
                goto out_destroy_buf_item_zone;
 
-       xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) +
-                       ((XFS_EFI_MAX_FAST_EXTENTS - 1) *
-                               sizeof(xfs_extent_t))), "xfs_efi_item");
+       xfs_efi_zone = kmem_cache_create("xfs_efi_item",
+                                        (sizeof(struct xfs_efi_log_item) +
+                                        (XFS_EFI_MAX_FAST_EXTENTS - 1) *
+                                        sizeof(struct xfs_extent)),
+                                        0, 0, NULL);
        if (!xfs_efi_zone)
                goto out_destroy_efd_zone;
 
-       xfs_inode_zone =
-               kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode",
-                       KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | KM_ZONE_SPREAD |
-                       KM_ZONE_ACCOUNT, xfs_fs_inode_init_once);
+       xfs_inode_zone = kmem_cache_create("xfs_inode",
+                                          sizeof(struct xfs_inode), 0,
+                                          (SLAB_HWCACHE_ALIGN |
+                                           SLAB_RECLAIM_ACCOUNT |
+                                           SLAB_MEM_SPREAD | SLAB_ACCOUNT),
+                                          xfs_fs_inode_init_once);
        if (!xfs_inode_zone)
                goto out_destroy_efi_zone;
 
-       xfs_ili_zone =
-               kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili",
-                                       KM_ZONE_SPREAD, NULL);
+       xfs_ili_zone = kmem_cache_create("xfs_ili",
+                                        sizeof(struct xfs_inode_log_item), 0,
+                                        SLAB_MEM_SPREAD, NULL);
        if (!xfs_ili_zone)
                goto out_destroy_inode_zone;
-       xfs_icreate_zone = kmem_zone_init(sizeof(struct xfs_icreate_item),
-                                       "xfs_icr");
+
+       xfs_icreate_zone = kmem_cache_create("xfs_icr",
+                                            sizeof(struct xfs_icreate_item),
+                                            0, 0, NULL);
        if (!xfs_icreate_zone)
                goto out_destroy_ili_zone;
 
-       xfs_rud_zone = kmem_zone_init(sizeof(struct xfs_rud_log_item),
-                       "xfs_rud_item");
+       xfs_rud_zone = kmem_cache_create("xfs_rud_item",
+                                        sizeof(struct xfs_rud_log_item),
+                                        0, 0, NULL);
        if (!xfs_rud_zone)
                goto out_destroy_icreate_zone;
 
-       xfs_rui_zone = kmem_zone_init(
+       xfs_rui_zone = kmem_cache_create("xfs_rui_item",
                        xfs_rui_log_item_sizeof(XFS_RUI_MAX_FAST_EXTENTS),
-                       "xfs_rui_item");
+                       0, 0, NULL);
        if (!xfs_rui_zone)
                goto out_destroy_rud_zone;
 
-       xfs_cud_zone = kmem_zone_init(sizeof(struct xfs_cud_log_item),
-                       "xfs_cud_item");
+       xfs_cud_zone = kmem_cache_create("xfs_cud_item",
+                                        sizeof(struct xfs_cud_log_item),
+                                        0, 0, NULL);
        if (!xfs_cud_zone)
                goto out_destroy_rui_zone;
 
-       xfs_cui_zone = kmem_zone_init(
+       xfs_cui_zone = kmem_cache_create("xfs_cui_item",
                        xfs_cui_log_item_sizeof(XFS_CUI_MAX_FAST_EXTENTS),
-                       "xfs_cui_item");
+                       0, 0, NULL);
        if (!xfs_cui_zone)
                goto out_destroy_cud_zone;
 
-       xfs_bud_zone = kmem_zone_init(sizeof(struct xfs_bud_log_item),
-                       "xfs_bud_item");
+       xfs_bud_zone = kmem_cache_create("xfs_bud_item",
+                                        sizeof(struct xfs_bud_log_item),
+                                        0, 0, NULL);
        if (!xfs_bud_zone)
                goto out_destroy_cui_zone;
 
-       xfs_bui_zone = kmem_zone_init(
+       xfs_bui_zone = kmem_cache_create("xfs_bui_item",
                        xfs_bui_log_item_sizeof(XFS_BUI_MAX_FAST_EXTENTS),
-                       "xfs_bui_item");
+                       0, 0, NULL);
        if (!xfs_bui_zone)
                goto out_destroy_bud_zone;
 
        return 0;
 
  out_destroy_bud_zone:
-       kmem_zone_destroy(xfs_bud_zone);
+       kmem_cache_destroy(xfs_bud_zone);
  out_destroy_cui_zone:
-       kmem_zone_destroy(xfs_cui_zone);
+       kmem_cache_destroy(xfs_cui_zone);
  out_destroy_cud_zone:
-       kmem_zone_destroy(xfs_cud_zone);
+       kmem_cache_destroy(xfs_cud_zone);
  out_destroy_rui_zone:
-       kmem_zone_destroy(xfs_rui_zone);
+       kmem_cache_destroy(xfs_rui_zone);
  out_destroy_rud_zone:
-       kmem_zone_destroy(xfs_rud_zone);
+       kmem_cache_destroy(xfs_rud_zone);
  out_destroy_icreate_zone:
-       kmem_zone_destroy(xfs_icreate_zone);
+       kmem_cache_destroy(xfs_icreate_zone);
  out_destroy_ili_zone:
-       kmem_zone_destroy(xfs_ili_zone);
+       kmem_cache_destroy(xfs_ili_zone);
  out_destroy_inode_zone:
-       kmem_zone_destroy(xfs_inode_zone);
+       kmem_cache_destroy(xfs_inode_zone);
  out_destroy_efi_zone:
-       kmem_zone_destroy(xfs_efi_zone);
+       kmem_cache_destroy(xfs_efi_zone);
  out_destroy_efd_zone:
-       kmem_zone_destroy(xfs_efd_zone);
+       kmem_cache_destroy(xfs_efd_zone);
  out_destroy_buf_item_zone:
-       kmem_zone_destroy(xfs_buf_item_zone);
+       kmem_cache_destroy(xfs_buf_item_zone);
  out_destroy_trans_zone:
-       kmem_zone_destroy(xfs_trans_zone);
+       kmem_cache_destroy(xfs_trans_zone);
  out_destroy_ifork_zone:
-       kmem_zone_destroy(xfs_ifork_zone);
+       kmem_cache_destroy(xfs_ifork_zone);
  out_destroy_da_state_zone:
-       kmem_zone_destroy(xfs_da_state_zone);
+       kmem_cache_destroy(xfs_da_state_zone);
  out_destroy_btree_cur_zone:
-       kmem_zone_destroy(xfs_btree_cur_zone);
+       kmem_cache_destroy(xfs_btree_cur_zone);
  out_destroy_bmap_free_item_zone:
-       kmem_zone_destroy(xfs_bmap_free_item_zone);
+       kmem_cache_destroy(xfs_bmap_free_item_zone);
  out_destroy_log_ticket_zone:
-       kmem_zone_destroy(xfs_log_ticket_zone);
+       kmem_cache_destroy(xfs_log_ticket_zone);
  out:
        return -ENOMEM;
 }
@@ -2002,24 +1966,24 @@ xfs_destroy_zones(void)
         * destroy caches.
         */
        rcu_barrier();
-       kmem_zone_destroy(xfs_bui_zone);
-       kmem_zone_destroy(xfs_bud_zone);
-       kmem_zone_destroy(xfs_cui_zone);
-       kmem_zone_destroy(xfs_cud_zone);
-       kmem_zone_destroy(xfs_rui_zone);
-       kmem_zone_destroy(xfs_rud_zone);
-       kmem_zone_destroy(xfs_icreate_zone);
-       kmem_zone_destroy(xfs_ili_zone);
-       kmem_zone_destroy(xfs_inode_zone);
-       kmem_zone_destroy(xfs_efi_zone);
-       kmem_zone_destroy(xfs_efd_zone);
-       kmem_zone_destroy(xfs_buf_item_zone);
-       kmem_zone_destroy(xfs_trans_zone);
-       kmem_zone_destroy(xfs_ifork_zone);
-       kmem_zone_destroy(xfs_da_state_zone);
-       kmem_zone_destroy(xfs_btree_cur_zone);
-       kmem_zone_destroy(xfs_bmap_free_item_zone);
-       kmem_zone_destroy(xfs_log_ticket_zone);
+       kmem_cache_destroy(xfs_bui_zone);
+       kmem_cache_destroy(xfs_bud_zone);
+       kmem_cache_destroy(xfs_cui_zone);
+       kmem_cache_destroy(xfs_cud_zone);
+       kmem_cache_destroy(xfs_rui_zone);
+       kmem_cache_destroy(xfs_rud_zone);
+       kmem_cache_destroy(xfs_icreate_zone);
+       kmem_cache_destroy(xfs_ili_zone);
+       kmem_cache_destroy(xfs_inode_zone);
+       kmem_cache_destroy(xfs_efi_zone);
+       kmem_cache_destroy(xfs_efd_zone);
+       kmem_cache_destroy(xfs_buf_item_zone);
+       kmem_cache_destroy(xfs_trans_zone);
+       kmem_cache_destroy(xfs_ifork_zone);
+       kmem_cache_destroy(xfs_da_state_zone);
+       kmem_cache_destroy(xfs_btree_cur_zone);
+       kmem_cache_destroy(xfs_bmap_free_item_zone);
+       kmem_cache_destroy(xfs_log_ticket_zone);
 }
 
 STATIC int __init
index 763e43d..b552cf6 100644 (file)
 #ifdef CONFIG_XFS_QUOTA
 extern int xfs_qm_init(void);
 extern void xfs_qm_exit(void);
+# define XFS_QUOTA_STRING      "quota, "
 #else
 # define xfs_qm_init() (0)
 # define xfs_qm_exit() do { } while (0)
+# define XFS_QUOTA_STRING
 #endif
 
 #ifdef CONFIG_XFS_POSIX_ACL
@@ -50,6 +52,12 @@ extern void xfs_qm_exit(void);
 # define XFS_WARN_STRING
 #endif
 
+#ifdef CONFIG_XFS_ASSERT_FATAL
+# define XFS_ASSERT_FATAL_STRING       "fatal assert, "
+#else
+# define XFS_ASSERT_FATAL_STRING
+#endif
+
 #ifdef DEBUG
 # define XFS_DBG_STRING                "debug"
 #else
@@ -63,6 +71,8 @@ extern void xfs_qm_exit(void);
                                XFS_SCRUB_STRING \
                                XFS_REPAIR_STRING \
                                XFS_WARN_STRING \
+                               XFS_QUOTA_STRING \
+                               XFS_ASSERT_FATAL_STRING \
                                XFS_DBG_STRING /* DBG must be last */
 
 struct xfs_inode;
index ed66fd2..a25502b 100644 (file)
@@ -17,6 +17,7 @@
 #include "xfs_bmap.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_quota.h"
+#include "xfs_symlink.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_trans.h"
index 9743d8c..b1fa091 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef __XFS_SYMLINK_H
 #define __XFS_SYMLINK_H 1
 
-/* Kernel only symlink defintions */
+/* Kernel only symlink definitions */
 
 int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
                const char *target_path, umode_t mode, struct xfs_inode **ipp);
index cbb23d7..c13bb36 100644 (file)
@@ -725,7 +725,7 @@ TRACE_EVENT(xfs_iomap_prealloc_size,
                __entry->writeio_blocks = writeio_blocks;
        ),
        TP_printk("dev %d:%d ino 0x%llx prealloc blocks %llu shift %d "
-                 "m_writeio_blocks %u",
+                 "m_allocsize_blocks %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino,
                  __entry->blocks, __entry->shift, __entry->writeio_blocks)
 )
@@ -1577,8 +1577,11 @@ DEFINE_ALLOC_EVENT(xfs_alloc_exact_notfound);
 DEFINE_ALLOC_EVENT(xfs_alloc_exact_error);
 DEFINE_ALLOC_EVENT(xfs_alloc_near_nominleft);
 DEFINE_ALLOC_EVENT(xfs_alloc_near_first);
-DEFINE_ALLOC_EVENT(xfs_alloc_near_greater);
-DEFINE_ALLOC_EVENT(xfs_alloc_near_lesser);
+DEFINE_ALLOC_EVENT(xfs_alloc_cur);
+DEFINE_ALLOC_EVENT(xfs_alloc_cur_right);
+DEFINE_ALLOC_EVENT(xfs_alloc_cur_left);
+DEFINE_ALLOC_EVENT(xfs_alloc_cur_lookup);
+DEFINE_ALLOC_EVENT(xfs_alloc_cur_lookup_done);
 DEFINE_ALLOC_EVENT(xfs_alloc_near_error);
 DEFINE_ALLOC_EVENT(xfs_alloc_near_noentry);
 DEFINE_ALLOC_EVENT(xfs_alloc_near_busy);
@@ -1598,6 +1601,32 @@ DEFINE_ALLOC_EVENT(xfs_alloc_vextent_noagbp);
 DEFINE_ALLOC_EVENT(xfs_alloc_vextent_loopfailed);
 DEFINE_ALLOC_EVENT(xfs_alloc_vextent_allfailed);
 
+TRACE_EVENT(xfs_alloc_cur_check,
+       TP_PROTO(struct xfs_mount *mp, xfs_btnum_t btnum, xfs_agblock_t bno,
+                xfs_extlen_t len, xfs_extlen_t diff, bool new),
+       TP_ARGS(mp, btnum, bno, len, diff, new),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_btnum_t, btnum)
+               __field(xfs_agblock_t, bno)
+               __field(xfs_extlen_t, len)
+               __field(xfs_extlen_t, diff)
+               __field(bool, new)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->btnum = btnum;
+               __entry->bno = bno;
+               __entry->len = len;
+               __entry->diff = diff;
+               __entry->new = new;
+       ),
+       TP_printk("dev %d:%d btree %s bno 0x%x len 0x%x diff 0x%x new %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __print_symbolic(__entry->btnum, XFS_BTNUM_STRINGS),
+                 __entry->bno, __entry->len, __entry->diff, __entry->new)
+)
+
 DECLARE_EVENT_CLASS(xfs_da_class,
        TP_PROTO(struct xfs_da_args *args),
        TP_ARGS(args),
index f4795fd..3b208f9 100644 (file)
@@ -71,7 +71,7 @@ xfs_trans_free(
        if (!(tp->t_flags & XFS_TRANS_NO_WRITECOUNT))
                sb_end_intwrite(tp->t_mountp->m_super);
        xfs_trans_free_dqinfo(tp);
-       kmem_zone_free(xfs_trans_zone, tp);
+       kmem_cache_free(xfs_trans_zone, tp);
 }
 
 /*
index 6ccfd75..00cc5b8 100644 (file)
@@ -427,15 +427,15 @@ xfsaild_push(
 
                case XFS_ITEM_FLUSHING:
                        /*
-                        * The item or its backing buffer is already beeing
+                        * The item or its backing buffer is already being
                         * flushed.  The typical reason for that is that an
                         * inode buffer is locked because we already pushed the
                         * updates to it as part of inode clustering.
                         *
                         * We do not want to to stop flushing just because lots
-                        * of items are already beeing flushed, but we need to
+                        * of items are already being flushed, but we need to
                         * re-try the flushing relatively soon if most of the
-                        * AIL is beeing flushed.
+                        * AIL is being flushed.
                         */
                        XFS_STATS_INC(mp, xs_push_ail_flushing);
                        trace_xfs_ail_flushing(lip);
@@ -612,7 +612,7 @@ xfsaild(
  * The push is run asynchronously in a workqueue, which means the caller needs
  * to handle waiting on the async flush for space to become available.
  * We don't want to interrupt any push that is in progress, hence we only queue
- * work if we set the pushing bit approriately.
+ * work if we set the pushing bit appropriately.
  *
  * We do this unlocked - we only need to know whether there is anything in the
  * AIL at the time we are called. We don't need to access the contents of
@@ -836,7 +836,7 @@ xfs_trans_ail_init(
        init_waitqueue_head(&ailp->ail_empty);
 
        ailp->ail_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
-                       ailp->ail_mount->m_fsname);
+                       ailp->ail_mount->m_super->s_id);
        if (IS_ERR(ailp->ail_task))
                goto out_free_ailp;
 
index 1645746..a6fe2d8 100644 (file)
@@ -25,8 +25,8 @@ STATIC void   xfs_trans_alloc_dqinfo(xfs_trans_t *);
  */
 void
 xfs_trans_dqjoin(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp)
+       struct xfs_trans        *tp,
+       struct xfs_dquot        *dqp)
 {
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
        ASSERT(dqp->q_logitem.qli_dquot == dqp);
@@ -49,8 +49,8 @@ xfs_trans_dqjoin(
  */
 void
 xfs_trans_log_dquot(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp)
+       struct xfs_trans        *tp,
+       struct xfs_dquot        *dqp)
 {
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
@@ -486,12 +486,12 @@ xfs_trans_apply_dquot_deltas(
  */
 void
 xfs_trans_unreserve_and_mod_dquots(
-       xfs_trans_t             *tp)
+       struct xfs_trans        *tp)
 {
        int                     i, j;
-       xfs_dquot_t             *dqp;
+       struct xfs_dquot        *dqp;
        struct xfs_dqtrx        *qtrx, *qa;
-       bool                    locked;
+       bool                    locked;
 
        if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY))
                return;
@@ -571,21 +571,21 @@ xfs_quota_warn(
  */
 STATIC int
 xfs_trans_dqresv(
-       xfs_trans_t     *tp,
-       xfs_mount_t     *mp,
-       xfs_dquot_t     *dqp,
-       int64_t         nblks,
-       long            ninos,
-       uint            flags)
+       struct xfs_trans        *tp,
+       struct xfs_mount        *mp,
+       struct xfs_dquot        *dqp,
+       int64_t                 nblks,
+       long                    ninos,
+       uint                    flags)
 {
-       xfs_qcnt_t      hardlimit;
-       xfs_qcnt_t      softlimit;
-       time_t          timer;
-       xfs_qwarncnt_t  warns;
-       xfs_qwarncnt_t  warnlimit;
-       xfs_qcnt_t      total_count;
-       xfs_qcnt_t      *resbcountp;
-       xfs_quotainfo_t *q = mp->m_quotainfo;
+       xfs_qcnt_t              hardlimit;
+       xfs_qcnt_t              softlimit;
+       time_t                  timer;
+       xfs_qwarncnt_t          warns;
+       xfs_qwarncnt_t          warnlimit;
+       xfs_qcnt_t              total_count;
+       xfs_qcnt_t              *resbcountp;
+       struct xfs_quotainfo    *q = mp->m_quotainfo;
        struct xfs_def_quota    *defq;
 
 
@@ -824,13 +824,13 @@ xfs_trans_reserve_quota_nblks(
 /*
  * This routine is called to allocate a quotaoff log item.
  */
-xfs_qoff_logitem_t *
+struct xfs_qoff_logitem *
 xfs_trans_get_qoff_item(
-       xfs_trans_t             *tp,
-       xfs_qoff_logitem_t      *startqoff,
+       struct xfs_trans        *tp,
+       struct xfs_qoff_logitem *startqoff,
        uint                    flags)
 {
-       xfs_qoff_logitem_t      *q;
+       struct xfs_qoff_logitem *q;
 
        ASSERT(tp != NULL);
 
@@ -852,8 +852,8 @@ xfs_trans_get_qoff_item(
  */
 void
 xfs_trans_log_quotaoff_item(
-       xfs_trans_t             *tp,
-       xfs_qoff_logitem_t      *qlp)
+       struct xfs_trans        *tp,
+       struct xfs_qoff_logitem *qlp)
 {
        tp->t_flags |= XFS_TRANS_DIRTY;
        set_bit(XFS_LI_DIRTY, &qlp->qql_item.li_flags);
@@ -872,6 +872,6 @@ xfs_trans_free_dqinfo(
 {
        if (!tp->t_dqinfo)
                return;
-       kmem_zone_free(xfs_qm_dqtrxzone, tp->t_dqinfo);
+       kmem_cache_free(xfs_qm_dqtrxzone, tp->t_dqinfo);
        tp->t_dqinfo = NULL;
 }
index cb895b1..383f020 100644 (file)
@@ -11,6 +11,7 @@
 #include "xfs_da_format.h"
 #include "xfs_inode.h"
 #include "xfs_attr.h"
+#include "xfs_acl.h"
 
 #include <linux/posix_acl_xattr.h>
 #include <linux/xattr.h>
diff --git a/include/Kbuild b/include/Kbuild
deleted file mode 100644 (file)
index 25edc43..0000000
+++ /dev/null
@@ -1,1187 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-# Add header-test-$(CONFIG_...) guard to headers that are only compiled
-# for particular architectures.
-#
-# Headers listed in header-test- are excluded from the test coverage.
-# Many headers are excluded for now because they fail to build. Please
-# consider to fix headers first before adding new ones to the blacklist.
-#
-# Sorted alphabetically.
-header-test-                   += acpi/acbuffer.h
-header-test-                   += acpi/acpi.h
-header-test-                   += acpi/acpi_bus.h
-header-test-                   += acpi/acpi_drivers.h
-header-test-                   += acpi/acpi_io.h
-header-test-                   += acpi/acpi_lpat.h
-header-test-                   += acpi/acpiosxf.h
-header-test-                   += acpi/acpixf.h
-header-test-                   += acpi/acrestyp.h
-header-test-                   += acpi/actbl.h
-header-test-                   += acpi/actbl1.h
-header-test-                   += acpi/actbl2.h
-header-test-                   += acpi/actbl3.h
-header-test-                   += acpi/actypes.h
-header-test-                   += acpi/battery.h
-header-test-                   += acpi/cppc_acpi.h
-header-test-                   += acpi/nfit.h
-header-test-                   += acpi/platform/acenv.h
-header-test-                   += acpi/platform/acenvex.h
-header-test-                   += acpi/platform/acintel.h
-header-test-                   += acpi/platform/aclinux.h
-header-test-                   += acpi/platform/aclinuxex.h
-header-test-                   += acpi/processor.h
-header-test-$(CONFIG_X86)      += clocksource/hyperv_timer.h
-header-test-                   += clocksource/timer-sp804.h
-header-test-                   += crypto/cast_common.h
-header-test-                   += crypto/internal/cryptouser.h
-header-test-                   += crypto/pkcs7.h
-header-test-                   += crypto/poly1305.h
-header-test-                   += crypto/sha3.h
-header-test-                   += drm/ati_pcigart.h
-header-test-                   += drm/bridge/dw_hdmi.h
-header-test-                   += drm/bridge/dw_mipi_dsi.h
-header-test-                   += drm/drm_audio_component.h
-header-test-                   += drm/drm_auth.h
-header-test-                   += drm/drm_debugfs.h
-header-test-                   += drm/drm_debugfs_crc.h
-header-test-                   += drm/drm_displayid.h
-header-test-                   += drm/drm_encoder_slave.h
-header-test-                   += drm/drm_fb_cma_helper.h
-header-test-                   += drm/drm_fb_helper.h
-header-test-                   += drm/drm_fixed.h
-header-test-                   += drm/drm_format_helper.h
-header-test-                   += drm/drm_lease.h
-header-test-                   += drm/drm_legacy.h
-header-test-                   += drm/drm_panel.h
-header-test-                   += drm/drm_plane_helper.h
-header-test-                   += drm/drm_rect.h
-header-test-                   += drm/i915_component.h
-header-test-                   += drm/intel-gtt.h
-header-test-                   += drm/tinydrm/tinydrm-helpers.h
-header-test-                   += drm/ttm/ttm_debug.h
-header-test-                   += keys/asymmetric-parser.h
-header-test-                   += keys/asymmetric-subtype.h
-header-test-                   += keys/asymmetric-type.h
-header-test-                   += keys/big_key-type.h
-header-test-                   += keys/request_key_auth-type.h
-header-test-                   += kvm/arm_arch_timer.h
-header-test-$(CONFIG_ARM)      += kvm/arm_hypercalls.h
-header-test-$(CONFIG_ARM64)    += kvm/arm_hypercalls.h
-header-test-                   += kvm/arm_pmu.h
-header-test-$(CONFIG_ARM)      += kvm/arm_psci.h
-header-test-$(CONFIG_ARM64)    += kvm/arm_psci.h
-header-test-                   += kvm/arm_vgic.h
-header-test-                   += linux/8250_pci.h
-header-test-                   += linux/a.out.h
-header-test-                   += linux/adxl.h
-header-test-                   += linux/agpgart.h
-header-test-                   += linux/alcor_pci.h
-header-test-                   += linux/amba/clcd.h
-header-test-                   += linux/amba/pl080.h
-header-test-                   += linux/amd-iommu.h
-header-test-$(CONFIG_ARM)      += linux/arm-cci.h
-header-test-$(CONFIG_ARM64)    += linux/arm-cci.h
-header-test-                   += linux/arm_sdei.h
-header-test-                   += linux/asn1_decoder.h
-header-test-                   += linux/ata_platform.h
-header-test-                   += linux/ath9k_platform.h
-header-test-                   += linux/atm_tcp.h
-header-test-                   += linux/atomic-fallback.h
-header-test-                   += linux/avf/virtchnl.h
-header-test-                   += linux/bcm47xx_sprom.h
-header-test-                   += linux/bcma/bcma_driver_gmac_cmn.h
-header-test-                   += linux/bcma/bcma_driver_mips.h
-header-test-                   += linux/bcma/bcma_driver_pci.h
-header-test-                   += linux/bcma/bcma_driver_pcie2.h
-header-test-                   += linux/bit_spinlock.h
-header-test-                   += linux/blk-mq-rdma.h
-header-test-                   += linux/blk-mq.h
-header-test-                   += linux/blktrace_api.h
-header-test-                   += linux/blockgroup_lock.h
-header-test-                   += linux/bma150.h
-header-test-                   += linux/bpf_lirc.h
-header-test-                   += linux/bpf_types.h
-header-test-                   += linux/bsg-lib.h
-header-test-                   += linux/bsg.h
-header-test-                   += linux/btf.h
-header-test-                   += linux/btree-128.h
-header-test-                   += linux/btree-type.h
-header-test-$(CONFIG_CPU_BIG_ENDIAN) += linux/byteorder/big_endian.h
-header-test-                   += linux/byteorder/generic.h
-header-test-$(CONFIG_CPU_LITTLE_ENDIAN) += linux/byteorder/little_endian.h
-header-test-                   += linux/c2port.h
-header-test-                   += linux/can/dev/peak_canfd.h
-header-test-                   += linux/can/platform/cc770.h
-header-test-                   += linux/can/platform/sja1000.h
-header-test-                   += linux/ceph/ceph_features.h
-header-test-                   += linux/ceph/ceph_frag.h
-header-test-                   += linux/ceph/ceph_fs.h
-header-test-                   += linux/ceph/debugfs.h
-header-test-                   += linux/ceph/msgr.h
-header-test-                   += linux/ceph/rados.h
-header-test-                   += linux/cgroup_subsys.h
-header-test-                   += linux/clk/sunxi-ng.h
-header-test-                   += linux/clk/ti.h
-header-test-                   += linux/cn_proc.h
-header-test-                   += linux/coda_psdev.h
-header-test-                   += linux/compaction.h
-header-test-                   += linux/console_struct.h
-header-test-                   += linux/count_zeros.h
-header-test-                   += linux/cs5535.h
-header-test-                   += linux/cuda.h
-header-test-                   += linux/cyclades.h
-header-test-                   += linux/dcookies.h
-header-test-                   += linux/delayacct.h
-header-test-                   += linux/delayed_call.h
-header-test-                   += linux/device-mapper.h
-header-test-                   += linux/devpts_fs.h
-header-test-                   += linux/dio.h
-header-test-                   += linux/dirent.h
-header-test-                   += linux/dlm_plock.h
-header-test-                   += linux/dm-dirty-log.h
-header-test-                   += linux/dm-region-hash.h
-header-test-                   += linux/dma-debug.h
-header-test-                   += linux/dma/mmp-pdma.h
-header-test-                   += linux/dma/sprd-dma.h
-header-test-                   += linux/dns_resolver.h
-header-test-                   += linux/drbd_genl.h
-header-test-                   += linux/drbd_genl_api.h
-header-test-                   += linux/dw_apb_timer.h
-header-test-                   += linux/dynamic_debug.h
-header-test-                   += linux/dynamic_queue_limits.h
-header-test-                   += linux/ecryptfs.h
-header-test-                   += linux/edma.h
-header-test-                   += linux/eeprom_93cx6.h
-header-test-                   += linux/efs_vh.h
-header-test-                   += linux/elevator.h
-header-test-                   += linux/elfcore-compat.h
-header-test-                   += linux/error-injection.h
-header-test-                   += linux/errseq.h
-header-test-                   += linux/eventpoll.h
-header-test-                   += linux/ext2_fs.h
-header-test-                   += linux/f75375s.h
-header-test-                   += linux/falloc.h
-header-test-                   += linux/fault-inject.h
-header-test-                   += linux/fbcon.h
-header-test-                   += linux/firmware/intel/stratix10-svc-client.h
-header-test-                   += linux/firmware/meson/meson_sm.h
-header-test-                   += linux/firmware/trusted_foundations.h
-header-test-                   += linux/firmware/xlnx-zynqmp.h
-header-test-                   += linux/fixp-arith.h
-header-test-                   += linux/flat.h
-header-test-                   += linux/fs_types.h
-header-test-                   += linux/fs_uart_pd.h
-header-test-                   += linux/fsi-occ.h
-header-test-                   += linux/fsi-sbefifo.h
-header-test-                   += linux/fsl/bestcomm/ata.h
-header-test-                   += linux/fsl/bestcomm/bestcomm.h
-header-test-                   += linux/fsl/bestcomm/bestcomm_priv.h
-header-test-                   += linux/fsl/bestcomm/fec.h
-header-test-                   += linux/fsl/bestcomm/gen_bd.h
-header-test-                   += linux/fsl/bestcomm/sram.h
-header-test-                   += linux/fsl_hypervisor.h
-header-test-                   += linux/fsldma.h
-header-test-                   += linux/ftrace_irq.h
-header-test-                   += linux/gameport.h
-header-test-                   += linux/genl_magic_func.h
-header-test-                   += linux/genl_magic_struct.h
-header-test-                   += linux/gpio/aspeed.h
-header-test-                   += linux/gpio/gpio-reg.h
-header-test-                   += linux/hid-debug.h
-header-test-                   += linux/hiddev.h
-header-test-                   += linux/hippidevice.h
-header-test-                   += linux/hmm.h
-header-test-                   += linux/hp_sdc.h
-header-test-                   += linux/huge_mm.h
-header-test-                   += linux/hugetlb_cgroup.h
-header-test-                   += linux/hugetlb_inline.h
-header-test-                   += linux/hwmon-vid.h
-header-test-                   += linux/hyperv.h
-header-test-                   += linux/i2c-algo-pca.h
-header-test-                   += linux/i2c-algo-pcf.h
-header-test-                   += linux/i3c/ccc.h
-header-test-                   += linux/i3c/device.h
-header-test-                   += linux/i3c/master.h
-header-test-                   += linux/i8042.h
-header-test-                   += linux/ide.h
-header-test-                   += linux/idle_inject.h
-header-test-                   += linux/if_frad.h
-header-test-                   += linux/if_rmnet.h
-header-test-                   += linux/if_tap.h
-header-test-                   += linux/iio/accel/kxcjk_1013.h
-header-test-                   += linux/iio/adc/ad_sigma_delta.h
-header-test-                   += linux/iio/buffer-dma.h
-header-test-                   += linux/iio/buffer_impl.h
-header-test-                   += linux/iio/common/st_sensors.h
-header-test-                   += linux/iio/common/st_sensors_i2c.h
-header-test-                   += linux/iio/common/st_sensors_spi.h
-header-test-                   += linux/iio/dac/ad5421.h
-header-test-                   += linux/iio/dac/ad5504.h
-header-test-                   += linux/iio/dac/ad5791.h
-header-test-                   += linux/iio/dac/max517.h
-header-test-                   += linux/iio/dac/mcp4725.h
-header-test-                   += linux/iio/frequency/ad9523.h
-header-test-                   += linux/iio/frequency/adf4350.h
-header-test-                   += linux/iio/hw-consumer.h
-header-test-                   += linux/iio/imu/adis.h
-header-test-                   += linux/iio/sysfs.h
-header-test-                   += linux/iio/timer/stm32-timer-trigger.h
-header-test-                   += linux/iio/trigger.h
-header-test-                   += linux/iio/triggered_event.h
-header-test-                   += linux/imx-media.h
-header-test-                   += linux/inet_diag.h
-header-test-                   += linux/init_ohci1394_dma.h
-header-test-                   += linux/initrd.h
-header-test-                   += linux/input/adp5589.h
-header-test-                   += linux/input/bu21013.h
-header-test-                   += linux/input/cma3000.h
-header-test-                   += linux/input/kxtj9.h
-header-test-                   += linux/input/lm8333.h
-header-test-                   += linux/input/sparse-keymap.h
-header-test-                   += linux/input/touchscreen.h
-header-test-                   += linux/input/tps6507x-ts.h
-header-test-$(CONFIG_X86)      += linux/intel-iommu.h
-header-test-                   += linux/intel-ish-client-if.h
-header-test-                   += linux/intel-pti.h
-header-test-                   += linux/intel-svm.h
-header-test-                   += linux/interconnect-provider.h
-header-test-                   += linux/ioc3.h
-header-test-$(CONFIG_BLOCK)    += linux/iomap.h
-header-test-                   += linux/ipack.h
-header-test-                   += linux/irq_cpustat.h
-header-test-                   += linux/irq_poll.h
-header-test-                   += linux/irqchip/arm-gic-v3.h
-header-test-                   += linux/irqchip/arm-gic-v4.h
-header-test-                   += linux/irqchip/irq-madera.h
-header-test-                   += linux/irqchip/irq-sa11x0.h
-header-test-                   += linux/irqchip/mxs.h
-header-test-                   += linux/irqchip/versatile-fpga.h
-header-test-                   += linux/irqdesc.h
-header-test-                   += linux/irqflags.h
-header-test-                   += linux/iscsi_boot_sysfs.h
-header-test-                   += linux/isdn/capiutil.h
-header-test-                   += linux/isdn/hdlc.h
-header-test-                   += linux/isdn_ppp.h
-header-test-                   += linux/jbd2.h
-header-test-                   += linux/jump_label.h
-header-test-                   += linux/jump_label_ratelimit.h
-header-test-                   += linux/jz4740-adc.h
-header-test-                   += linux/kasan.h
-header-test-                   += linux/kcore.h
-header-test-                   += linux/kdev_t.h
-header-test-                   += linux/kernelcapi.h
-header-test-                   += linux/khugepaged.h
-header-test-                   += linux/kobj_map.h
-header-test-                   += linux/kobject_ns.h
-header-test-                   += linux/kvm_host.h
-header-test-                   += linux/kvm_irqfd.h
-header-test-                   += linux/kvm_para.h
-header-test-                   += linux/lantiq.h
-header-test-                   += linux/lapb.h
-header-test-                   += linux/latencytop.h
-header-test-                   += linux/led-lm3530.h
-header-test-                   += linux/leds-bd2802.h
-header-test-                   += linux/leds-lp3944.h
-header-test-                   += linux/leds-lp3952.h
-header-test-                   += linux/leds_pwm.h
-header-test-                   += linux/libata.h
-header-test-                   += linux/license.h
-header-test-                   += linux/lightnvm.h
-header-test-                   += linux/lis3lv02d.h
-header-test-                   += linux/list_bl.h
-header-test-                   += linux/list_lru.h
-header-test-                   += linux/list_nulls.h
-header-test-                   += linux/lockd/share.h
-header-test-                   += linux/lzo.h
-header-test-                   += linux/mailbox/zynqmp-ipi-message.h
-header-test-                   += linux/maple.h
-header-test-                   += linux/mbcache.h
-header-test-                   += linux/mbus.h
-header-test-                   += linux/mc146818rtc.h
-header-test-                   += linux/mc6821.h
-header-test-                   += linux/mdev.h
-header-test-                   += linux/mem_encrypt.h
-header-test-                   += linux/memfd.h
-header-test-                   += linux/mfd/88pm80x.h
-header-test-                   += linux/mfd/88pm860x.h
-header-test-                   += linux/mfd/abx500/ab8500-bm.h
-header-test-                   += linux/mfd/abx500/ab8500-gpadc.h
-header-test-                   += linux/mfd/adp5520.h
-header-test-                   += linux/mfd/arizona/pdata.h
-header-test-                   += linux/mfd/as3711.h
-header-test-                   += linux/mfd/as3722.h
-header-test-                   += linux/mfd/da903x.h
-header-test-                   += linux/mfd/da9055/pdata.h
-header-test-                   += linux/mfd/db8500-prcmu.h
-header-test-                   += linux/mfd/dbx500-prcmu.h
-header-test-                   += linux/mfd/dln2.h
-header-test-                   += linux/mfd/dm355evm_msp.h
-header-test-                   += linux/mfd/ds1wm.h
-header-test-                   += linux/mfd/ezx-pcap.h
-header-test-                   += linux/mfd/intel_msic.h
-header-test-                   += linux/mfd/janz.h
-header-test-                   += linux/mfd/kempld.h
-header-test-                   += linux/mfd/lm3533.h
-header-test-                   += linux/mfd/lp8788-isink.h
-header-test-                   += linux/mfd/lpc_ich.h
-header-test-                   += linux/mfd/max77693.h
-header-test-                   += linux/mfd/max8998-private.h
-header-test-                   += linux/mfd/menelaus.h
-header-test-                   += linux/mfd/mt6397/core.h
-header-test-                   += linux/mfd/palmas.h
-header-test-                   += linux/mfd/pcf50633/backlight.h
-header-test-                   += linux/mfd/rc5t583.h
-header-test-                   += linux/mfd/retu.h
-header-test-                   += linux/mfd/samsung/core.h
-header-test-                   += linux/mfd/si476x-platform.h
-header-test-                   += linux/mfd/si476x-reports.h
-header-test-                   += linux/mfd/sky81452.h
-header-test-                   += linux/mfd/smsc.h
-header-test-                   += linux/mfd/sta2x11-mfd.h
-header-test-                   += linux/mfd/stmfx.h
-header-test-                   += linux/mfd/tc3589x.h
-header-test-                   += linux/mfd/tc6387xb.h
-header-test-                   += linux/mfd/tc6393xb.h
-header-test-                   += linux/mfd/tps65090.h
-header-test-                   += linux/mfd/tps6586x.h
-header-test-                   += linux/mfd/tps65910.h
-header-test-                   += linux/mfd/tps80031.h
-header-test-                   += linux/mfd/ucb1x00.h
-header-test-                   += linux/mfd/viperboard.h
-header-test-                   += linux/mfd/wm831x/core.h
-header-test-                   += linux/mfd/wm831x/otp.h
-header-test-                   += linux/mfd/wm831x/pdata.h
-header-test-                   += linux/mfd/wm8994/core.h
-header-test-                   += linux/mfd/wm8994/pdata.h
-header-test-                   += linux/mlx4/doorbell.h
-header-test-                   += linux/mlx4/srq.h
-header-test-                   += linux/mlx5/doorbell.h
-header-test-                   += linux/mlx5/eq.h
-header-test-                   += linux/mlx5/fs_helpers.h
-header-test-                   += linux/mlx5/mlx5_ifc.h
-header-test-                   += linux/mlx5/mlx5_ifc_fpga.h
-header-test-                   += linux/mm-arch-hooks.h
-header-test-                   += linux/mm_inline.h
-header-test-                   += linux/mmu_context.h
-header-test-                   += linux/mpage.h
-header-test-                   += linux/mtd/bbm.h
-header-test-                   += linux/mtd/cfi.h
-header-test-                   += linux/mtd/doc2000.h
-header-test-                   += linux/mtd/flashchip.h
-header-test-                   += linux/mtd/ftl.h
-header-test-                   += linux/mtd/gen_probe.h
-header-test-                   += linux/mtd/jedec.h
-header-test-                   += linux/mtd/nand_bch.h
-header-test-                   += linux/mtd/nand_ecc.h
-header-test-                   += linux/mtd/ndfc.h
-header-test-                   += linux/mtd/onenand.h
-header-test-                   += linux/mtd/pismo.h
-header-test-                   += linux/mtd/plat-ram.h
-header-test-                   += linux/mtd/spi-nor.h
-header-test-                   += linux/mv643xx.h
-header-test-                   += linux/mv643xx_eth.h
-header-test-                   += linux/mvebu-pmsu.h
-header-test-                   += linux/mxm-wmi.h
-header-test-                   += linux/n_r3964.h
-header-test-                   += linux/ndctl.h
-header-test-                   += linux/nfs.h
-header-test-                   += linux/nfs_fs_i.h
-header-test-                   += linux/nfs_fs_sb.h
-header-test-                   += linux/nfs_page.h
-header-test-                   += linux/nfs_xdr.h
-header-test-                   += linux/nfsacl.h
-header-test-                   += linux/nl802154.h
-header-test-                   += linux/ns_common.h
-header-test-                   += linux/nsc_gpio.h
-header-test-                   += linux/ntb_transport.h
-header-test-                   += linux/nubus.h
-header-test-                   += linux/nvme-fc-driver.h
-header-test-                   += linux/nvme-fc.h
-header-test-                   += linux/nvme-rdma.h
-header-test-                   += linux/nvram.h
-header-test-                   += linux/objagg.h
-header-test-                   += linux/of_clk.h
-header-test-                   += linux/of_net.h
-header-test-                   += linux/of_pdt.h
-header-test-                   += linux/olpc-ec.h
-header-test-                   += linux/omap-dma.h
-header-test-                   += linux/omap-dmaengine.h
-header-test-                   += linux/omap-gpmc.h
-header-test-                   += linux/omap-iommu.h
-header-test-                   += linux/omap-mailbox.h
-header-test-                   += linux/once.h
-header-test-                   += linux/osq_lock.h
-header-test-                   += linux/overflow.h
-header-test-                   += linux/page-flags-layout.h
-header-test-                   += linux/page-isolation.h
-header-test-                   += linux/page_ext.h
-header-test-                   += linux/page_owner.h
-header-test-                   += linux/parport_pc.h
-header-test-                   += linux/parser.h
-header-test-                   += linux/pci-acpi.h
-header-test-                   += linux/pci-dma-compat.h
-header-test-                   += linux/pci_hotplug.h
-header-test-                   += linux/pda_power.h
-header-test-                   += linux/perf/arm_pmu.h
-header-test-                   += linux/perf_regs.h
-header-test-                   += linux/phy/omap_control_phy.h
-header-test-                   += linux/phy/tegra/xusb.h
-header-test-                   += linux/phy/ulpi_phy.h
-header-test-                   += linux/phy_fixed.h
-header-test-                   += linux/pipe_fs_i.h
-header-test-                   += linux/pktcdvd.h
-header-test-                   += linux/pl320-ipc.h
-header-test-                   += linux/pl353-smc.h
-header-test-                   += linux/platform_data/ad5449.h
-header-test-                   += linux/platform_data/ad5755.h
-header-test-                   += linux/platform_data/ad7266.h
-header-test-                   += linux/platform_data/ad7291.h
-header-test-                   += linux/platform_data/ad7298.h
-header-test-                   += linux/platform_data/ad7303.h
-header-test-                   += linux/platform_data/ad7791.h
-header-test-                   += linux/platform_data/ad7793.h
-header-test-                   += linux/platform_data/ad7887.h
-header-test-                   += linux/platform_data/adau17x1.h
-header-test-                   += linux/platform_data/adp8870.h
-header-test-                   += linux/platform_data/ads1015.h
-header-test-                   += linux/platform_data/ads7828.h
-header-test-                   += linux/platform_data/apds990x.h
-header-test-                   += linux/platform_data/arm-ux500-pm.h
-header-test-                   += linux/platform_data/asoc-s3c.h
-header-test-                   += linux/platform_data/at91_adc.h
-header-test-                   += linux/platform_data/ata-pxa.h
-header-test-                   += linux/platform_data/atmel.h
-header-test-                   += linux/platform_data/bh1770glc.h
-header-test-                   += linux/platform_data/brcmfmac.h
-header-test-                   += linux/platform_data/cros_ec_commands.h
-header-test-                   += linux/platform_data/clk-u300.h
-header-test-                   += linux/platform_data/cyttsp4.h
-header-test-                   += linux/platform_data/dma-coh901318.h
-header-test-                   += linux/platform_data/dma-imx-sdma.h
-header-test-                   += linux/platform_data/dma-mcf-edma.h
-header-test-                   += linux/platform_data/dma-s3c24xx.h
-header-test-                   += linux/platform_data/dmtimer-omap.h
-header-test-                   += linux/platform_data/dsa.h
-header-test-                   += linux/platform_data/edma.h
-header-test-                   += linux/platform_data/elm.h
-header-test-                   += linux/platform_data/emif_plat.h
-header-test-                   += linux/platform_data/fsa9480.h
-header-test-                   += linux/platform_data/g762.h
-header-test-                   += linux/platform_data/gpio-ath79.h
-header-test-                   += linux/platform_data/gpio-davinci.h
-header-test-                   += linux/platform_data/gpio-dwapb.h
-header-test-                   += linux/platform_data/gpio-htc-egpio.h
-header-test-                   += linux/platform_data/gpmc-omap.h
-header-test-                   += linux/platform_data/hsmmc-omap.h
-header-test-                   += linux/platform_data/hwmon-s3c.h
-header-test-                   += linux/platform_data/i2c-davinci.h
-header-test-                   += linux/platform_data/i2c-imx.h
-header-test-                   += linux/platform_data/i2c-mux-reg.h
-header-test-                   += linux/platform_data/i2c-ocores.h
-header-test-                   += linux/platform_data/i2c-xiic.h
-header-test-                   += linux/platform_data/intel-spi.h
-header-test-                   += linux/platform_data/invensense_mpu6050.h
-header-test-                   += linux/platform_data/irda-pxaficp.h
-header-test-                   += linux/platform_data/irda-sa11x0.h
-header-test-                   += linux/platform_data/itco_wdt.h
-header-test-                   += linux/platform_data/jz4740/jz4740_nand.h
-header-test-                   += linux/platform_data/keyboard-pxa930_rotary.h
-header-test-                   += linux/platform_data/keypad-omap.h
-header-test-                   += linux/platform_data/leds-lp55xx.h
-header-test-                   += linux/platform_data/leds-omap.h
-header-test-                   += linux/platform_data/lp855x.h
-header-test-                   += linux/platform_data/lp8727.h
-header-test-                   += linux/platform_data/max197.h
-header-test-                   += linux/platform_data/max3421-hcd.h
-header-test-                   += linux/platform_data/max732x.h
-header-test-                   += linux/platform_data/mcs.h
-header-test-                   += linux/platform_data/mdio-bcm-unimac.h
-header-test-                   += linux/platform_data/mdio-gpio.h
-header-test-                   += linux/platform_data/media/si4713.h
-header-test-                   += linux/platform_data/mlxreg.h
-header-test-                   += linux/platform_data/mmc-omap.h
-header-test-                   += linux/platform_data/mmc-sdhci-s3c.h
-header-test-                   += linux/platform_data/mmp_audio.h
-header-test-                   += linux/platform_data/mtd-orion_nand.h
-header-test-                   += linux/platform_data/mv88e6xxx.h
-header-test-                   += linux/platform_data/net-cw1200.h
-header-test-                   += linux/platform_data/omap-twl4030.h
-header-test-                   += linux/platform_data/omapdss.h
-header-test-                   += linux/platform_data/pcf857x.h
-header-test-                   += linux/platform_data/pixcir_i2c_ts.h
-header-test-                   += linux/platform_data/pwm_omap_dmtimer.h
-header-test-                   += linux/platform_data/pxa2xx_udc.h
-header-test-                   += linux/platform_data/pxa_sdhci.h
-header-test-                   += linux/platform_data/remoteproc-omap.h
-header-test-                   += linux/platform_data/sa11x0-serial.h
-header-test-                   += linux/platform_data/sc18is602.h
-header-test-                   += linux/platform_data/sdhci-pic32.h
-header-test-                   += linux/platform_data/serial-sccnxp.h
-header-test-                   += linux/platform_data/sht3x.h
-header-test-                   += linux/platform_data/shtc1.h
-header-test-                   += linux/platform_data/si5351.h
-header-test-                   += linux/platform_data/sky81452-backlight.h
-header-test-                   += linux/platform_data/spi-davinci.h
-header-test-                   += linux/platform_data/spi-ep93xx.h
-header-test-                   += linux/platform_data/spi-mt65xx.h
-header-test-                   += linux/platform_data/st_sensors_pdata.h
-header-test-                   += linux/platform_data/ti-sysc.h
-header-test-                   += linux/platform_data/timer-ixp4xx.h
-header-test-                   += linux/platform_data/touchscreen-s3c2410.h
-header-test-                   += linux/platform_data/tsc2007.h
-header-test-                   += linux/platform_data/tsl2772.h
-header-test-                   += linux/platform_data/uio_pruss.h
-header-test-                   += linux/platform_data/usb-davinci.h
-header-test-                   += linux/platform_data/usb-ehci-mxc.h
-header-test-                   += linux/platform_data/usb-ehci-orion.h
-header-test-                   += linux/platform_data/usb-mx2.h
-header-test-                   += linux/platform_data/usb-ohci-s3c2410.h
-header-test-                   += linux/platform_data/usb-omap.h
-header-test-                   += linux/platform_data/usb-s3c2410_udc.h
-header-test-                   += linux/platform_data/usb3503.h
-header-test-                   += linux/platform_data/ux500_wdt.h
-header-test-                   += linux/platform_data/video-clcd-versatile.h
-header-test-                   += linux/platform_data/video-imxfb.h
-header-test-                   += linux/platform_data/video-pxafb.h
-header-test-                   += linux/platform_data/video_s3c.h
-header-test-                   += linux/platform_data/voltage-omap.h
-header-test-                   += linux/platform_data/x86/apple.h
-header-test-                   += linux/platform_data/x86/clk-pmc-atom.h
-header-test-                   += linux/platform_data/x86/pmc_atom.h
-header-test-                   += linux/platform_data/xtalk-bridge.h
-header-test-                   += linux/pm2301_charger.h
-header-test-                   += linux/pm_wakeirq.h
-header-test-                   += linux/pm_wakeup.h
-header-test-                   += linux/pmbus.h
-header-test-                   += linux/pmu.h
-header-test-                   += linux/posix_acl.h
-header-test-                   += linux/posix_acl_xattr.h
-header-test-                   += linux/power/ab8500.h
-header-test-                   += linux/power/bq27xxx_battery.h
-header-test-                   += linux/power/generic-adc-battery.h
-header-test-                   += linux/power/jz4740-battery.h
-header-test-                   += linux/power/max17042_battery.h
-header-test-                   += linux/power/max8903_charger.h
-header-test-                   += linux/ppp-comp.h
-header-test-                   += linux/pps-gpio.h
-header-test-                   += linux/pr.h
-header-test-                   += linux/proc_ns.h
-header-test-                   += linux/processor.h
-header-test-                   += linux/psi.h
-header-test-                   += linux/psp-sev.h
-header-test-                   += linux/pstore.h
-header-test-                   += linux/ptr_ring.h
-header-test-                   += linux/ptrace.h
-header-test-                   += linux/qcom-geni-se.h
-header-test-                   += linux/qed/eth_common.h
-header-test-                   += linux/qed/fcoe_common.h
-header-test-                   += linux/qed/iscsi_common.h
-header-test-                   += linux/qed/iwarp_common.h
-header-test-                   += linux/qed/qed_eth_if.h
-header-test-                   += linux/qed/qed_fcoe_if.h
-header-test-                   += linux/qed/rdma_common.h
-header-test-                   += linux/qed/storage_common.h
-header-test-                   += linux/qed/tcp_common.h
-header-test-                   += linux/qnx6_fs.h
-header-test-                   += linux/quicklist.h
-header-test-                   += linux/ramfs.h
-header-test-                   += linux/range.h
-header-test-                   += linux/rcu_node_tree.h
-header-test-                   += linux/rculist_bl.h
-header-test-                   += linux/rculist_nulls.h
-header-test-                   += linux/rcutiny.h
-header-test-                   += linux/rcutree.h
-header-test-                   += linux/reboot-mode.h
-header-test-                   += linux/regulator/fixed.h
-header-test-                   += linux/regulator/gpio-regulator.h
-header-test-                   += linux/regulator/max8973-regulator.h
-header-test-                   += linux/regulator/of_regulator.h
-header-test-                   += linux/regulator/tps51632-regulator.h
-header-test-                   += linux/regulator/tps62360.h
-header-test-                   += linux/regulator/tps6507x.h
-header-test-                   += linux/regulator/userspace-consumer.h
-header-test-                   += linux/remoteproc/st_slim_rproc.h
-header-test-                   += linux/reset/socfpga.h
-header-test-                   += linux/reset/sunxi.h
-header-test-                   += linux/rtc/m48t59.h
-header-test-                   += linux/rtc/rtc-omap.h
-header-test-                   += linux/rtc/sirfsoc_rtciobrg.h
-header-test-                   += linux/rwlock.h
-header-test-                   += linux/rwlock_types.h
-header-test-                   += linux/scc.h
-header-test-                   += linux/sched/deadline.h
-header-test-                   += linux/sched/smt.h
-header-test-                   += linux/sched/sysctl.h
-header-test-                   += linux/sched_clock.h
-header-test-                   += linux/scpi_protocol.h
-header-test-                   += linux/scx200_gpio.h
-header-test-                   += linux/seccomp.h
-header-test-                   += linux/sed-opal.h
-header-test-                   += linux/seg6_iptunnel.h
-header-test-                   += linux/selection.h
-header-test-                   += linux/set_memory.h
-header-test-                   += linux/shrinker.h
-header-test-                   += linux/sirfsoc_dma.h
-header-test-                   += linux/skb_array.h
-header-test-                   += linux/slab_def.h
-header-test-                   += linux/slub_def.h
-header-test-                   += linux/sm501.h
-header-test-                   += linux/smc91x.h
-header-test-                   += linux/static_key.h
-header-test-                   += linux/soc/actions/owl-sps.h
-header-test-                   += linux/soc/amlogic/meson-canvas.h
-header-test-                   += linux/soc/brcmstb/brcmstb.h
-header-test-                   += linux/soc/ixp4xx/npe.h
-header-test-                   += linux/soc/mediatek/infracfg.h
-header-test-                   += linux/soc/qcom/smd-rpm.h
-header-test-                   += linux/soc/qcom/smem.h
-header-test-                   += linux/soc/qcom/smem_state.h
-header-test-                   += linux/soc/qcom/wcnss_ctrl.h
-header-test-                   += linux/soc/renesas/rcar-rst.h
-header-test-                   += linux/soc/samsung/exynos-pmu.h
-header-test-                   += linux/soc/sunxi/sunxi_sram.h
-header-test-                   += linux/soc/ti/ti-msgmgr.h
-header-test-                   += linux/soc/ti/ti_sci_inta_msi.h
-header-test-                   += linux/soc/ti/ti_sci_protocol.h
-header-test-                   += linux/soundwire/sdw.h
-header-test-                   += linux/soundwire/sdw_intel.h
-header-test-                   += linux/soundwire/sdw_type.h
-header-test-                   += linux/spi/ad7877.h
-header-test-                   += linux/spi/ads7846.h
-header-test-                   += linux/spi/at86rf230.h
-header-test-                   += linux/spi/ds1305.h
-header-test-                   += linux/spi/libertas_spi.h
-header-test-                   += linux/spi/lms283gf05.h
-header-test-                   += linux/spi/max7301.h
-header-test-                   += linux/spi/mcp23s08.h
-header-test-                   += linux/spi/rspi.h
-header-test-                   += linux/spi/s3c24xx.h
-header-test-                   += linux/spi/sh_msiof.h
-header-test-                   += linux/spi/spi-fsl-dspi.h
-header-test-                   += linux/spi/spi_bitbang.h
-header-test-                   += linux/spi/spi_gpio.h
-header-test-                   += linux/spi/xilinx_spi.h
-header-test-                   += linux/spinlock_api_smp.h
-header-test-                   += linux/spinlock_api_up.h
-header-test-                   += linux/spinlock_types.h
-header-test-                   += linux/splice.h
-header-test-                   += linux/sram.h
-header-test-                   += linux/srcutiny.h
-header-test-                   += linux/srcutree.h
-header-test-                   += linux/ssb/ssb_driver_chipcommon.h
-header-test-                   += linux/ssb/ssb_driver_extif.h
-header-test-                   += linux/ssb/ssb_driver_mips.h
-header-test-                   += linux/ssb/ssb_driver_pci.h
-header-test-                   += linux/ssbi.h
-header-test-                   += linux/stackdepot.h
-header-test-                   += linux/stmp3xxx_rtc_wdt.h
-header-test-                   += linux/string_helpers.h
-header-test-                   += linux/sungem_phy.h
-header-test-                   += linux/sunrpc/msg_prot.h
-header-test-                   += linux/sunrpc/rpc_pipe_fs.h
-header-test-                   += linux/sunrpc/xprtmultipath.h
-header-test-                   += linux/sunrpc/xprtsock.h
-header-test-                   += linux/sunxi-rsb.h
-header-test-                   += linux/svga.h
-header-test-                   += linux/sw842.h
-header-test-                   += linux/swapfile.h
-header-test-                   += linux/swapops.h
-header-test-                   += linux/swiotlb.h
-header-test-                   += linux/sysv_fs.h
-header-test-                   += linux/t10-pi.h
-header-test-                   += linux/task_io_accounting.h
-header-test-                   += linux/tick.h
-header-test-                   += linux/timb_dma.h
-header-test-                   += linux/timekeeping.h
-header-test-                   += linux/timekeeping32.h
-header-test-                   += linux/ts-nbus.h
-header-test-                   += linux/tsacct_kern.h
-header-test-                   += linux/tty_flip.h
-header-test-                   += linux/tty_ldisc.h
-header-test-                   += linux/ucb1400.h
-header-test-                   += linux/usb/association.h
-header-test-                   += linux/usb/cdc-wdm.h
-header-test-                   += linux/usb/cdc_ncm.h
-header-test-                   += linux/usb/ezusb.h
-header-test-                   += linux/usb/gadget_configfs.h
-header-test-                   += linux/usb/gpio_vbus.h
-header-test-                   += linux/usb/hcd.h
-header-test-                   += linux/usb/iowarrior.h
-header-test-                   += linux/usb/irda.h
-header-test-                   += linux/usb/isp116x.h
-header-test-                   += linux/usb/isp1362.h
-header-test-                   += linux/usb/musb.h
-header-test-                   += linux/usb/net2280.h
-header-test-                   += linux/usb/ohci_pdriver.h
-header-test-                   += linux/usb/otg-fsm.h
-header-test-                   += linux/usb/pd_ado.h
-header-test-                   += linux/usb/r8a66597.h
-header-test-                   += linux/usb/rndis_host.h
-header-test-                   += linux/usb/serial.h
-header-test-                   += linux/usb/sl811.h
-header-test-                   += linux/usb/storage.h
-header-test-                   += linux/usb/uas.h
-header-test-                   += linux/usb/usb338x.h
-header-test-                   += linux/usb/usbnet.h
-header-test-                   += linux/usb/wusb-wa.h
-header-test-                   += linux/usb/xhci-dbgp.h
-header-test-                   += linux/usb_usual.h
-header-test-                   += linux/user-return-notifier.h
-header-test-                   += linux/userfaultfd_k.h
-header-test-                   += linux/verification.h
-header-test-                   += linux/vgaarb.h
-header-test-                   += linux/via_core.h
-header-test-                   += linux/via_i2c.h
-header-test-                   += linux/virtio_byteorder.h
-header-test-                   += linux/virtio_ring.h
-header-test-                   += linux/visorbus.h
-header-test-                   += linux/vme.h
-header-test-                   += linux/vmstat.h
-header-test-                   += linux/vmw_vmci_api.h
-header-test-                   += linux/vmw_vmci_defs.h
-header-test-                   += linux/vringh.h
-header-test-                   += linux/vt_buffer.h
-header-test-                   += linux/zorro.h
-header-test-                   += linux/zpool.h
-header-test-                   += math-emu/double.h
-header-test-                   += math-emu/op-common.h
-header-test-                   += math-emu/quad.h
-header-test-                   += math-emu/single.h
-header-test-                   += math-emu/soft-fp.h
-header-test-                   += media/davinci/dm355_ccdc.h
-header-test-                   += media/davinci/dm644x_ccdc.h
-header-test-                   += media/davinci/isif.h
-header-test-                   += media/davinci/vpbe_osd.h
-header-test-                   += media/davinci/vpbe_types.h
-header-test-                   += media/davinci/vpif_types.h
-header-test-                   += media/demux.h
-header-test-                   += media/drv-intf/soc_mediabus.h
-header-test-                   += media/dvb_net.h
-header-test-                   += media/fwht-ctrls.h
-header-test-                   += media/i2c/ad9389b.h
-header-test-                   += media/i2c/adv7343.h
-header-test-                   += media/i2c/adv7511.h
-header-test-                   += media/i2c/adv7842.h
-header-test-                   += media/i2c/m5mols.h
-header-test-                   += media/i2c/mt9m032.h
-header-test-                   += media/i2c/mt9t112.h
-header-test-                   += media/i2c/mt9v032.h
-header-test-                   += media/i2c/ov2659.h
-header-test-                   += media/i2c/ov7670.h
-header-test-                   += media/i2c/rj54n1cb0c.h
-header-test-                   += media/i2c/saa6588.h
-header-test-                   += media/i2c/saa7115.h
-header-test-                   += media/i2c/sr030pc30.h
-header-test-                   += media/i2c/tc358743.h
-header-test-                   += media/i2c/tda1997x.h
-header-test-                   += media/i2c/ths7303.h
-header-test-                   += media/i2c/tvaudio.h
-header-test-                   += media/i2c/tvp514x.h
-header-test-                   += media/i2c/tvp7002.h
-header-test-                   += media/i2c/wm8775.h
-header-test-                   += media/imx.h
-header-test-                   += media/media-dev-allocator.h
-header-test-                   += media/mpeg2-ctrls.h
-header-test-                   += media/rcar-fcp.h
-header-test-                   += media/tuner-types.h
-header-test-                   += media/tveeprom.h
-header-test-                   += media/v4l2-flash-led-class.h
-header-test-                   += misc/altera.h
-header-test-                   += misc/cxl-base.h
-header-test-                   += misc/cxllib.h
-header-test-                   += net/9p/9p.h
-header-test-                   += net/9p/client.h
-header-test-                   += net/9p/transport.h
-header-test-                   += net/af_vsock.h
-header-test-                   += net/ax88796.h
-header-test-                   += net/bluetooth/hci.h
-header-test-                   += net/bluetooth/hci_core.h
-header-test-                   += net/bluetooth/hci_mon.h
-header-test-                   += net/bluetooth/hci_sock.h
-header-test-                   += net/bluetooth/l2cap.h
-header-test-                   += net/bluetooth/mgmt.h
-header-test-                   += net/bluetooth/rfcomm.h
-header-test-                   += net/bluetooth/sco.h
-header-test-                   += net/bond_options.h
-header-test-                   += net/caif/cfsrvl.h
-header-test-                   += net/codel_impl.h
-header-test-                   += net/codel_qdisc.h
-header-test-                   += net/compat.h
-header-test-                   += net/datalink.h
-header-test-                   += net/dcbevent.h
-header-test-                   += net/dcbnl.h
-header-test-                   += net/dn_dev.h
-header-test-                   += net/dn_fib.h
-header-test-                   += net/dn_neigh.h
-header-test-                   += net/dn_nsp.h
-header-test-                   += net/dn_route.h
-header-test-                   += net/erspan.h
-header-test-                   += net/esp.h
-header-test-                   += net/ethoc.h
-header-test-                   += net/firewire.h
-header-test-                   += net/flow_offload.h
-header-test-                   += net/fq.h
-header-test-                   += net/fq_impl.h
-header-test-                   += net/garp.h
-header-test-                   += net/gtp.h
-header-test-                   += net/gue.h
-header-test-                   += net/hwbm.h
-header-test-                   += net/ila.h
-header-test-                   += net/inet6_connection_sock.h
-header-test-                   += net/inet_common.h
-header-test-                   += net/inet_frag.h
-header-test-                   += net/ip6_route.h
-header-test-                   += net/ip_vs.h
-header-test-                   += net/ipcomp.h
-header-test-                   += net/ipconfig.h
-header-test-                   += net/iucv/af_iucv.h
-header-test-                   += net/iucv/iucv.h
-header-test-                   += net/lapb.h
-header-test-                   += net/llc_c_ac.h
-header-test-                   += net/llc_c_st.h
-header-test-                   += net/llc_s_ac.h
-header-test-                   += net/llc_s_ev.h
-header-test-                   += net/llc_s_st.h
-header-test-                   += net/mpls_iptunnel.h
-header-test-                   += net/mrp.h
-header-test-                   += net/ncsi.h
-header-test-                   += net/netevent.h
-header-test-                   += net/netns/can.h
-header-test-                   += net/netns/generic.h
-header-test-                   += net/netns/ieee802154_6lowpan.h
-header-test-                   += net/netns/ipv4.h
-header-test-                   += net/netns/ipv6.h
-header-test-                   += net/netns/mpls.h
-header-test-                   += net/netns/nftables.h
-header-test-                   += net/netns/sctp.h
-header-test-                   += net/netrom.h
-header-test-                   += net/p8022.h
-header-test-                   += net/phonet/pep.h
-header-test-                   += net/phonet/phonet.h
-header-test-                   += net/phonet/pn_dev.h
-header-test-                   += net/pptp.h
-header-test-                   += net/psample.h
-header-test-                   += net/psnap.h
-header-test-                   += net/regulatory.h
-header-test-                   += net/rose.h
-header-test-                   += net/sctp/auth.h
-header-test-                   += net/sctp/stream_interleave.h
-header-test-                   += net/sctp/stream_sched.h
-header-test-                   += net/sctp/tsnmap.h
-header-test-                   += net/sctp/ulpevent.h
-header-test-                   += net/sctp/ulpqueue.h
-header-test-                   += net/secure_seq.h
-header-test-                   += net/smc.h
-header-test-                   += net/stp.h
-header-test-                   += net/transp_v6.h
-header-test-                   += net/tun_proto.h
-header-test-                   += net/udplite.h
-header-test-                   += net/xdp.h
-header-test-                   += net/xdp_priv.h
-header-test-                   += pcmcia/cistpl.h
-header-test-                   += pcmcia/ds.h
-header-test-                   += rdma/tid_rdma_defs.h
-header-test-                   += scsi/fc/fc_encaps.h
-header-test-                   += scsi/fc/fc_fc2.h
-header-test-                   += scsi/fc/fc_fcoe.h
-header-test-                   += scsi/fc/fc_fip.h
-header-test-                   += scsi/fc_encode.h
-header-test-                   += scsi/fc_frame.h
-header-test-                   += scsi/iser.h
-header-test-                   += scsi/libfc.h
-header-test-                   += scsi/libfcoe.h
-header-test-                   += scsi/libsas.h
-header-test-                   += scsi/sas_ata.h
-header-test-                   += scsi/scsi_cmnd.h
-header-test-                   += scsi/scsi_dbg.h
-header-test-                   += scsi/scsi_device.h
-header-test-                   += scsi/scsi_dh.h
-header-test-                   += scsi/scsi_eh.h
-header-test-                   += scsi/scsi_host.h
-header-test-                   += scsi/scsi_ioctl.h
-header-test-                   += scsi/scsi_request.h
-header-test-                   += scsi/scsi_tcq.h
-header-test-                   += scsi/scsi_transport.h
-header-test-                   += scsi/scsi_transport_fc.h
-header-test-                   += scsi/scsi_transport_sas.h
-header-test-                   += scsi/scsi_transport_spi.h
-header-test-                   += scsi/scsi_transport_srp.h
-header-test-                   += scsi/scsicam.h
-header-test-                   += scsi/sg.h
-header-test-                   += soc/arc/aux.h
-header-test-                   += soc/arc/mcip.h
-header-test-                   += soc/arc/timers.h
-header-test-                   += soc/brcmstb/common.h
-header-test-                   += soc/fsl/bman.h
-header-test-                   += soc/fsl/qe/qe.h
-header-test-                   += soc/fsl/qe/qe_ic.h
-header-test-                   += soc/fsl/qe/qe_tdm.h
-header-test-                   += soc/fsl/qe/ucc.h
-header-test-                   += soc/fsl/qe/ucc_fast.h
-header-test-                   += soc/fsl/qe/ucc_slow.h
-header-test-                   += soc/fsl/qman.h
-header-test-                   += soc/nps/common.h
-header-test-$(CONFIG_ARC)      += soc/nps/mtm.h
-header-test-                   += soc/qcom/cmd-db.h
-header-test-                   += soc/qcom/rpmh.h
-header-test-                   += soc/qcom/tcs.h
-header-test-                   += soc/tegra/ahb.h
-header-test-                   += soc/tegra/bpmp-abi.h
-header-test-                   += soc/tegra/common.h
-header-test-                   += soc/tegra/flowctrl.h
-header-test-                   += soc/tegra/fuse.h
-header-test-                   += soc/tegra/mc.h
-header-test-                   += sound/ac97/compat.h
-header-test-                   += sound/aci.h
-header-test-                   += sound/ad1843.h
-header-test-                   += sound/adau1373.h
-header-test-                   += sound/ak4113.h
-header-test-                   += sound/ak4114.h
-header-test-                   += sound/ak4117.h
-header-test-                   += sound/cs35l33.h
-header-test-                   += sound/cs35l34.h
-header-test-                   += sound/cs35l35.h
-header-test-                   += sound/cs35l36.h
-header-test-                   += sound/cs4271.h
-header-test-                   += sound/cs42l52.h
-header-test-                   += sound/cs8427.h
-header-test-                   += sound/da7218.h
-header-test-                   += sound/da7219-aad.h
-header-test-                   += sound/da7219.h
-header-test-                   += sound/da9055.h
-header-test-                   += sound/emu8000.h
-header-test-                   += sound/emux_synth.h
-header-test-                   += sound/hda_component.h
-header-test-                   += sound/hda_hwdep.h
-header-test-                   += sound/hda_i915.h
-header-test-                   += sound/hwdep.h
-header-test-                   += sound/i2c.h
-header-test-                   += sound/l3.h
-header-test-                   += sound/max98088.h
-header-test-                   += sound/max98095.h
-header-test-                   += sound/mixer_oss.h
-header-test-                   += sound/omap-hdmi-audio.h
-header-test-                   += sound/pcm_drm_eld.h
-header-test-                   += sound/pcm_iec958.h
-header-test-                   += sound/pcm_oss.h
-header-test-                   += sound/pxa2xx-lib.h
-header-test-                   += sound/rt286.h
-header-test-                   += sound/rt298.h
-header-test-                   += sound/rt5645.h
-header-test-                   += sound/rt5659.h
-header-test-                   += sound/rt5660.h
-header-test-                   += sound/rt5665.h
-header-test-                   += sound/rt5670.h
-header-test-                   += sound/s3c24xx_uda134x.h
-header-test-                   += sound/seq_device.h
-header-test-                   += sound/seq_kernel.h
-header-test-                   += sound/seq_midi_emul.h
-header-test-                   += sound/seq_oss.h
-header-test-                   += sound/soc-acpi-intel-match.h
-header-test-                   += sound/soc-dai.h
-header-test-                   += sound/soc-dapm.h
-header-test-                   += sound/soc-dpcm.h
-header-test-                   += sound/sof/control.h
-header-test-                   += sound/sof/dai-intel.h
-header-test-                   += sound/sof/dai.h
-header-test-                   += sound/sof/header.h
-header-test-                   += sound/sof/info.h
-header-test-                   += sound/sof/pm.h
-header-test-                   += sound/sof/stream.h
-header-test-                   += sound/sof/topology.h
-header-test-                   += sound/sof/trace.h
-header-test-                   += sound/sof/xtensa.h
-header-test-                   += sound/spear_spdif.h
-header-test-                   += sound/sta32x.h
-header-test-                   += sound/sta350.h
-header-test-                   += sound/tea6330t.h
-header-test-                   += sound/tlv320aic32x4.h
-header-test-                   += sound/tlv320dac33-plat.h
-header-test-                   += sound/uda134x.h
-header-test-                   += sound/wavefront.h
-header-test-                   += sound/wm8903.h
-header-test-                   += sound/wm8904.h
-header-test-                   += sound/wm8960.h
-header-test-                   += sound/wm8962.h
-header-test-                   += sound/wm8993.h
-header-test-                   += sound/wm8996.h
-header-test-                   += sound/wm9081.h
-header-test-                   += sound/wm9090.h
-header-test-                   += target/iscsi/iscsi_target_stat.h
-header-test-                   += trace/bpf_probe.h
-header-test-                   += trace/events/9p.h
-header-test-                   += trace/events/afs.h
-header-test-                   += trace/events/asoc.h
-header-test-                   += trace/events/bcache.h
-header-test-                   += trace/events/block.h
-header-test-                   += trace/events/cachefiles.h
-header-test-                   += trace/events/cgroup.h
-header-test-                   += trace/events/clk.h
-header-test-                   += trace/events/cma.h
-header-test-                   += trace/events/ext4.h
-header-test-                   += trace/events/f2fs.h
-header-test-                   += trace/events/fs_dax.h
-header-test-                   += trace/events/fscache.h
-header-test-                   += trace/events/fsi.h
-header-test-                   += trace/events/fsi_master_ast_cf.h
-header-test-                   += trace/events/fsi_master_gpio.h
-header-test-                   += trace/events/huge_memory.h
-header-test-                   += trace/events/ib_mad.h
-header-test-                   += trace/events/ib_umad.h
-header-test-                   += trace/events/io_uring.h
-header-test-                   += trace/events/iscsi.h
-header-test-                   += trace/events/jbd2.h
-header-test-                   += trace/events/kvm.h
-header-test-                   += trace/events/kyber.h
-header-test-                   += trace/events/libata.h
-header-test-                   += trace/events/mce.h
-header-test-                   += trace/events/mdio.h
-header-test-                   += trace/events/migrate.h
-header-test-                   += trace/events/mmflags.h
-header-test-                   += trace/events/nbd.h
-header-test-                   += trace/events/nilfs2.h
-header-test-                   += trace/events/pwc.h
-header-test-                   += trace/events/rdma.h
-header-test-                   += trace/events/rpcgss.h
-header-test-                   += trace/events/rpcrdma.h
-header-test-                   += trace/events/rxrpc.h
-header-test-                   += trace/events/scsi.h
-header-test-                   += trace/events/siox.h
-header-test-                   += trace/events/spi.h
-header-test-                   += trace/events/swiotlb.h
-header-test-                   += trace/events/syscalls.h
-header-test-                   += trace/events/target.h
-header-test-                   += trace/events/thermal_power_allocator.h
-header-test-                   += trace/events/timer.h
-header-test-                   += trace/events/wbt.h
-header-test-                   += trace/events/xen.h
-header-test-                   += trace/perf.h
-header-test-                   += trace/trace_events.h
-header-test-                   += uapi/drm/vmwgfx_drm.h
-header-test-                   += uapi/linux/a.out.h
-header-test-                   += uapi/linux/coda.h
-header-test-                   += uapi/linux/coda_psdev.h
-header-test-                   += uapi/linux/errqueue.h
-header-test-                   += uapi/linux/eventpoll.h
-header-test-                   += uapi/linux/hdlc/ioctl.h
-header-test-                   += uapi/linux/input.h
-header-test-                   += uapi/linux/kvm.h
-header-test-                   += uapi/linux/kvm_para.h
-header-test-                   += uapi/linux/lightnvm.h
-header-test-                   += uapi/linux/mic_common.h
-header-test-                   += uapi/linux/mman.h
-header-test-                   += uapi/linux/nilfs2_ondisk.h
-header-test-                   += uapi/linux/patchkey.h
-header-test-                   += uapi/linux/ptrace.h
-header-test-                   += uapi/linux/scc.h
-header-test-                   += uapi/linux/seg6_iptunnel.h
-header-test-                   += uapi/linux/smc_diag.h
-header-test-                   += uapi/linux/timex.h
-header-test-                   += uapi/linux/videodev2.h
-header-test-                   += uapi/scsi/scsi_bsg_fc.h
-header-test-                   += uapi/sound/asound.h
-header-test-                   += uapi/sound/sof/eq.h
-header-test-                   += uapi/sound/sof/fw.h
-header-test-                   += uapi/sound/sof/header.h
-header-test-                   += uapi/sound/sof/manifest.h
-header-test-                   += uapi/sound/sof/trace.h
-header-test-                   += uapi/xen/evtchn.h
-header-test-                   += uapi/xen/gntdev.h
-header-test-                   += uapi/xen/privcmd.h
-header-test-                   += vdso/vsyscall.h
-header-test-                   += video/broadsheetfb.h
-header-test-                   += video/cvisionppc.h
-header-test-                   += video/gbe.h
-header-test-                   += video/kyro.h
-header-test-                   += video/maxinefb.h
-header-test-                   += video/metronomefb.h
-header-test-                   += video/neomagic.h
-header-test-                   += video/of_display_timing.h
-header-test-                   += video/omapvrfb.h
-header-test-                   += video/s1d13xxxfb.h
-header-test-                   += video/sstfb.h
-header-test-                   += video/tgafb.h
-header-test-                   += video/udlfb.h
-header-test-                   += video/uvesafb.h
-header-test-                   += video/vga.h
-header-test-                   += video/w100fb.h
-header-test-                   += xen/acpi.h
-header-test-                   += xen/arm/hypercall.h
-header-test-                   += xen/arm/page-coherent.h
-header-test-                   += xen/arm/page.h
-header-test-                   += xen/balloon.h
-header-test-                   += xen/events.h
-header-test-                   += xen/features.h
-header-test-                   += xen/grant_table.h
-header-test-                   += xen/hvm.h
-header-test-                   += xen/interface/callback.h
-header-test-                   += xen/interface/event_channel.h
-header-test-                   += xen/interface/grant_table.h
-header-test-                   += xen/interface/hvm/dm_op.h
-header-test-                   += xen/interface/hvm/hvm_op.h
-header-test-                   += xen/interface/hvm/hvm_vcpu.h
-header-test-                   += xen/interface/hvm/params.h
-header-test-                   += xen/interface/hvm/start_info.h
-header-test-                   += xen/interface/io/9pfs.h
-header-test-                   += xen/interface/io/blkif.h
-header-test-                   += xen/interface/io/console.h
-header-test-                   += xen/interface/io/displif.h
-header-test-                   += xen/interface/io/fbif.h
-header-test-                   += xen/interface/io/kbdif.h
-header-test-                   += xen/interface/io/netif.h
-header-test-                   += xen/interface/io/pciif.h
-header-test-                   += xen/interface/io/protocols.h
-header-test-                   += xen/interface/io/pvcalls.h
-header-test-                   += xen/interface/io/ring.h
-header-test-                   += xen/interface/io/sndif.h
-header-test-                   += xen/interface/io/tpmif.h
-header-test-                   += xen/interface/io/vscsiif.h
-header-test-                   += xen/interface/io/xs_wire.h
-header-test-                   += xen/interface/memory.h
-header-test-                   += xen/interface/nmi.h
-header-test-                   += xen/interface/physdev.h
-header-test-                   += xen/interface/platform.h
-header-test-                   += xen/interface/sched.h
-header-test-                   += xen/interface/vcpu.h
-header-test-                   += xen/interface/version.h
-header-test-                   += xen/interface/xen-mca.h
-header-test-                   += xen/interface/xen.h
-header-test-                   += xen/interface/xenpmu.h
-header-test-                   += xen/mem-reservation.h
-header-test-                   += xen/page.h
-header-test-                   += xen/platform_pci.h
-header-test-                   += xen/swiotlb-xen.h
-header-test-                   += xen/xen-front-pgdir-shbuf.h
-header-test-                   += xen/xen-ops.h
-header-test-                   += xen/xen.h
-header-test-                   += xen/xenbus.h
-
-# Do not include directly
-header-test- += linux/compiler-clang.h
-header-test- += linux/compiler-gcc.h
-header-test- += linux/patchkey.h
-header-test- += linux/rwlock_api_smp.h
-header-test- += linux/spinlock_types_up.h
-header-test- += linux/spinlock_up.h
-header-test- += linux/wimax/debug.h
-header-test- += rdma/uverbs_named_ioctl.h
-
-# asm-generic/*.h is used by asm/*.h, and should not be included directly
-header-test- += asm-generic/% uapi/asm-generic/%
-
-# Timestamp files touched by Kconfig
-header-test- += config/%
-
-# Timestamp files touched by scripts/adjust_autoksyms.sh
-header-test- += ksym/%
-
-# You could compile-test these, but maybe not so useful...
-header-test- += dt-bindings/%
-
-# Do not test generated headers. Stale headers are often left over when you
-# traverse the git history without cleaning.
-header-test- += generated/%
-
-# The rest are compile-tested
-header-test-pattern-y += */*.h */*/*.h */*/*/*.h */*/*/*/*.h
diff --git a/include/asm-generic/4level-fixup.h b/include/asm-generic/4level-fixup.h
deleted file mode 100644 (file)
index e3667c9..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _4LEVEL_FIXUP_H
-#define _4LEVEL_FIXUP_H
-
-#define __ARCH_HAS_4LEVEL_HACK
-#define __PAGETABLE_PUD_FOLDED 1
-
-#define PUD_SHIFT                      PGDIR_SHIFT
-#define PUD_SIZE                       PGDIR_SIZE
-#define PUD_MASK                       PGDIR_MASK
-#define PTRS_PER_PUD                   1
-
-#define pud_t                          pgd_t
-
-#define pmd_alloc(mm, pud, address) \
-       ((unlikely(pgd_none(*(pud))) && __pmd_alloc(mm, pud, address))? \
-               NULL: pmd_offset(pud, address))
-
-#define pud_offset(pgd, start)         (pgd)
-#define pud_none(pud)                  0
-#define pud_bad(pud)                   0
-#define pud_present(pud)               1
-#define pud_ERROR(pud)                 do { } while (0)
-#define pud_clear(pud)                 pgd_clear(pud)
-#define pud_val(pud)                   pgd_val(pud)
-#define pud_populate(mm, pud, pmd)     pgd_populate(mm, pud, pmd)
-#define pud_page(pud)                  pgd_page(pud)
-#define pud_page_vaddr(pud)            pgd_page_vaddr(pud)
-
-#undef pud_free_tlb
-#define pud_free_tlb(tlb, x, addr)     do { } while (0)
-#define pud_free(mm, x)                        do { } while (0)
-#define __pud_free_tlb(tlb, x, addr)   do { } while (0)
-
-#undef  pud_addr_end
-#define pud_addr_end(addr, end)                (end)
-
-#include <asm-generic/5level-fixup.h>
-
-#endif
index f6947da..4c74b1c 100644 (file)
@@ -51,7 +51,6 @@ static inline int p4d_present(p4d_t p4d)
 #undef p4d_free_tlb
 #define p4d_free_tlb(tlb, x, addr)     do { } while (0)
 #define p4d_free(mm, x)                        do { } while (0)
-#define __p4d_free_tlb(tlb, x, addr)   do { } while (0)
 
 #undef  p4d_addr_end
 #define p4d_addr_end(addr, end)                (end)
index adff14f..ddfee1b 100644 (file)
@@ -4,4 +4,5 @@
 # (This file is not included when SRCARCH=um since UML borrows several
 # asm headers from the host architecutre.)
 
+mandatory-y += msi.h
 mandatory-y += simd.h
index 8a1ee10..9fdf213 100644 (file)
@@ -80,4 +80,21 @@ extern unsigned long find_first_zero_bit(const unsigned long *addr,
 
 #endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
 
+/**
+ * find_next_clump8 - find next 8-bit clump with set bits in a memory region
+ * @clump: location to store copy of found clump
+ * @addr: address to base the search on
+ * @size: bitmap size in number of bits
+ * @offset: bit offset at which to start searching
+ *
+ * Returns the bit offset for the next set clump; the found clump value is
+ * copied to the location pointed by @clump. If no bits are set, returns @size.
+ */
+extern unsigned long find_next_clump8(unsigned long *clump,
+                                     const unsigned long *addr,
+                                     unsigned long size, unsigned long offset);
+
+#define find_first_clump8(clump, bits, size) \
+       find_next_clump8((clump), (bits), (size), 0)
+
 #endif /*_ASM_GENERIC_BITOPS_FIND_H_ */
index fa57797..afddc54 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef __ASM_GENERIC_EXPORT_H
 #define __ASM_GENERIC_EXPORT_H
 
@@ -31,7 +32,6 @@
  */
 .macro ___EXPORT_SYMBOL name,val,sec
 #ifdef CONFIG_MODULES
-       .globl __ksymtab_\name
        .section ___ksymtab\sec+\name,"a"
        .balign KSYM_ALIGN
 __ksymtab_\name:
@@ -44,7 +44,6 @@ __kstrtab_\name:
 #ifdef CONFIG_MODVERSIONS
        .section ___kcrctab\sec+\name,"a"
        .balign KCRC_ALIGN
-__kcrctab_\name:
 #if defined(CONFIG_MODULE_REL_CRCS)
        .long __crc_\name - .
 #else
index aebab90..ce2cbb3 100644 (file)
@@ -50,7 +50,7 @@ static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
  */
 #define p4d_alloc_one(mm, address)             NULL
 #define p4d_free(mm, x)                                do { } while (0)
-#define __p4d_free_tlb(tlb, x, a)              do { } while (0)
+#define p4d_free_tlb(tlb, x, a)                        do { } while (0)
 
 #undef  p4d_addr_end
 #define p4d_addr_end(addr, end)                        (end)
index b85b827..0d9b28c 100644 (file)
@@ -60,7 +60,7 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
 }
-#define __pmd_free_tlb(tlb, x, a)              do { } while (0)
+#define pmd_free_tlb(tlb, x, a)                do { } while (0)
 
 #undef  pmd_addr_end
 #define pmd_addr_end(addr, end)                        (end)
index c77a1d3..d3776cb 100644 (file)
@@ -59,7 +59,7 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
  */
 #define pud_alloc_one(mm, address)             NULL
 #define pud_free(mm, x)                                do { } while (0)
-#define __pud_free_tlb(tlb, x, a)              do { } while (0)
+#define pud_free_tlb(tlb, x, a)                        do { } while (0)
 
 #undef  pud_addr_end
 #define pud_addr_end(addr, end)                        (end)
index 8186918..798ea36 100644 (file)
@@ -558,8 +558,19 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
  * Do the tests inline, but report and clear the bad entry in mm/memory.c.
  */
 void pgd_clear_bad(pgd_t *);
+
+#ifndef __PAGETABLE_P4D_FOLDED
 void p4d_clear_bad(p4d_t *);
+#else
+#define p4d_clear_bad(p4d)        do { } while (0)
+#endif
+
+#ifndef __PAGETABLE_PUD_FOLDED
 void pud_clear_bad(pud_t *);
+#else
+#define pud_clear_bad(p4d)        do { } while (0)
+#endif
+
 void pmd_clear_bad(pmd_t *);
 
 static inline int pgd_none_or_clear_bad(pgd_t *pgd)
@@ -903,6 +914,21 @@ static inline int pud_write(pud_t pud)
 }
 #endif /* pud_write */
 
+#if !defined(CONFIG_ARCH_HAS_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE)
+static inline int pmd_devmap(pmd_t pmd)
+{
+       return 0;
+}
+static inline int pud_devmap(pud_t pud)
+{
+       return 0;
+}
+static inline int pgd_devmap(pgd_t pgd)
+{
+       return 0;
+}
+#endif
+
 #if !defined(CONFIG_TRANSPARENT_HUGEPAGE) || \
        (defined(CONFIG_TRANSPARENT_HUGEPAGE) && \
         !defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD))
@@ -912,6 +938,31 @@ static inline int pud_trans_huge(pud_t pud)
 }
 #endif
 
+/* See pmd_none_or_trans_huge_or_clear_bad for discussion. */
+static inline int pud_none_or_trans_huge_or_dev_or_clear_bad(pud_t *pud)
+{
+       pud_t pudval = READ_ONCE(*pud);
+
+       if (pud_none(pudval) || pud_trans_huge(pudval) || pud_devmap(pudval))
+               return 1;
+       if (unlikely(pud_bad(pudval))) {
+               pud_clear_bad(pud);
+               return 1;
+       }
+       return 0;
+}
+
+/* See pmd_trans_unstable for discussion. */
+static inline int pud_trans_unstable(pud_t *pud)
+{
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) &&                    \
+       defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
+       return pud_none_or_trans_huge_or_dev_or_clear_bad(pud);
+#else
+       return 0;
+#endif
+}
+
 #ifndef pmd_read_atomic
 static inline pmd_t pmd_read_atomic(pmd_t *pmdp)
 {
index e649911..2b10036 100644 (file)
@@ -584,7 +584,6 @@ static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vm
        } while (0)
 #endif
 
-#ifndef __ARCH_HAS_4LEVEL_HACK
 #ifndef pud_free_tlb
 #define pud_free_tlb(tlb, pudp, address)                       \
        do {                                                    \
@@ -594,9 +593,7 @@ static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vm
                __pud_free_tlb(tlb, pudp, address);             \
        } while (0)
 #endif
-#endif
 
-#ifndef __ARCH_HAS_5LEVEL_HACK
 #ifndef p4d_free_tlb
 #define p4d_free_tlb(tlb, pudp, address)                       \
        do {                                                    \
@@ -605,7 +602,6 @@ static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vm
                __p4d_free_tlb(tlb, pudp, address);             \
        } while (0)
 #endif
-#endif
 
 #endif /* CONFIG_MMU */
 
diff --git a/include/dt-bindings/dma/x1000-dma.h b/include/dt-bindings/dma/x1000-dma.h
new file mode 100644 (file)
index 0000000..401e165
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * This header provides macros for X1000 DMA bindings.
+ *
+ * Copyright (c) 2019 Zhou Yanjie <zhouyanjie@zoho.com>
+ */
+
+#ifndef __DT_BINDINGS_DMA_X1000_DMA_H__
+#define __DT_BINDINGS_DMA_X1000_DMA_H__
+
+/*
+ * Request type numbers for the X1000 DMA controller (written to the DRTn
+ * register for the channel).
+ */
+#define X1000_DMA_DMIC_RX      0x5
+#define X1000_DMA_I2S0_TX      0x6
+#define X1000_DMA_I2S0_RX      0x7
+#define X1000_DMA_AUTO         0x8
+#define X1000_DMA_UART2_TX     0x10
+#define X1000_DMA_UART2_RX     0x11
+#define X1000_DMA_UART1_TX     0x12
+#define X1000_DMA_UART1_RX     0x13
+#define X1000_DMA_UART0_TX     0x14
+#define X1000_DMA_UART0_RX     0x15
+#define X1000_DMA_SSI0_TX      0x16
+#define X1000_DMA_SSI0_RX      0x17
+#define X1000_DMA_MSC0_TX      0x1a
+#define X1000_DMA_MSC0_RX      0x1b
+#define X1000_DMA_MSC1_TX      0x1c
+#define X1000_DMA_MSC1_RX      0x1d
+#define X1000_DMA_PCM0_TX      0x20
+#define X1000_DMA_PCM0_RX      0x21
+#define X1000_DMA_SMB0_TX      0x24
+#define X1000_DMA_SMB0_RX      0x25
+#define X1000_DMA_SMB1_TX      0x26
+#define X1000_DMA_SMB1_RX      0x27
+#define X1000_DMA_SMB2_TX      0x28
+#define X1000_DMA_SMB2_RX      0x29
+
+#endif /* __DT_BINDINGS_DMA_X1000_DMA_H__ */
index dc5c1c7..6d6bac1 100644 (file)
@@ -50,9 +50,9 @@
 #define RK_PD7         31
 
 #define RK_FUNC_GPIO   0
-#define RK_FUNC_1      1
-#define RK_FUNC_2      2
-#define RK_FUNC_3      3
-#define RK_FUNC_4      4
+#define RK_FUNC_1      1 /* deprecated */
+#define RK_FUNC_2      2 /* deprecated */
+#define RK_FUNC_3      3 /* deprecated */
+#define RK_FUNC_4      4 /* deprecated */
 
 #endif
index 93e36d0..f05f8b1 100644 (file)
 #define RPMH_REGULATOR_LEVEL_TURBO     384
 #define RPMH_REGULATOR_LEVEL_TURBO_L1  416
 
+/* MSM8976 Power Domain Indexes */
+#define MSM8976_VDDCX          0
+#define MSM8976_VDDCX_AO       1
+#define MSM8976_VDDCX_VFL      2
+#define MSM8976_VDDMX          3
+#define MSM8976_VDDMX_AO       4
+#define MSM8976_VDDMX_VFL      5
+
 /* MSM8996 Power Domain Indexes */
 #define MSM8996_VDDCX          0
 #define MSM8996_VDDCX_AO       1
@@ -68,6 +76,7 @@
 #define RPM_SMD_LEVEL_NOM_PLUS        320
 #define RPM_SMD_LEVEL_TURBO           384
 #define RPM_SMD_LEVEL_TURBO_NO_CPR    416
+#define RPM_SMD_LEVEL_TURBO_HIGH      448
 #define RPM_SMD_LEVEL_BINNING         512
 
 #endif
diff --git a/include/dt-bindings/reset/amlogic,meson-a1-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-reset.h
new file mode 100644 (file)
index 0000000..f1a3a79
--- /dev/null
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ *
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Xingyu Chen <xingyu.chen@amlogic.com>
+ *
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H
+#define _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H
+
+/*     RESET0                                  */
+/*                                     0       */
+#define RESET_AM2AXI_VAD               1
+/*                                     2-3     */
+#define RESET_PSRAM                    4
+#define RESET_PAD_CTRL                 5
+/*                                     6       */
+#define RESET_TEMP_SENSOR              7
+#define RESET_AM2AXI_DEV               8
+/*                                     9       */
+#define RESET_SPICC_A                  10
+#define RESET_MSR_CLK                  11
+#define RESET_AUDIO                    12
+#define RESET_ANALOG_CTRL              13
+#define RESET_SAR_ADC                  14
+#define RESET_AUDIO_VAD                        15
+#define RESET_CEC                      16
+#define RESET_PWM_EF                   17
+#define RESET_PWM_CD                   18
+#define RESET_PWM_AB                   19
+/*                                     20      */
+#define RESET_IR_CTRL                  21
+#define RESET_I2C_S_A                  22
+/*                                     23      */
+#define RESET_I2C_M_D                  24
+#define RESET_I2C_M_C                  25
+#define RESET_I2C_M_B                  26
+#define RESET_I2C_M_A                  27
+#define RESET_I2C_PROD_AHB             28
+#define RESET_I2C_PROD                 29
+/*                                     30-31   */
+
+/*     RESET1                                  */
+#define RESET_ACODEC                   32
+#define RESET_DMA                      33
+#define RESET_SD_EMMC_A                        34
+/*                                     35      */
+#define RESET_USBCTRL                  36
+/*                                     37      */
+#define RESET_USBPHY                   38
+/*                                     39-41   */
+#define RESET_RSA                      42
+#define RESET_DMC                      43
+/*                                     44      */
+#define RESET_IRQ_CTRL                 45
+/*                                     46      */
+#define RESET_NIC_VAD                  47
+#define RESET_NIC_AXI                  48
+#define RESET_RAMA                     49
+#define RESET_RAMB                     50
+/*                                     51-52   */
+#define RESET_ROM                      53
+#define RESET_SPIFC                    54
+#define RESET_GIC                      55
+#define RESET_UART_C                   56
+#define RESET_UART_B                   57
+#define RESET_UART_A                   58
+#define RESET_OSC_RING                 59
+/*                                     60-63   */
+
+/*     RESET2                                  */
+/*                                     64-95   */
+
+#endif
index 05c3636..1ef8078 100644 (file)
@@ -13,5 +13,7 @@
 #define AXG_ARB_FRDDR_A        3
 #define AXG_ARB_FRDDR_B        4
 #define AXG_ARB_FRDDR_C        5
+#define AXG_ARB_TODDR_D        6
+#define AXG_ARB_FRDDR_D        7
 
 #endif /* _DT_BINDINGS_AMLOGIC_MESON_AXG_AUDIO_ARB_H */
diff --git a/include/dt-bindings/reset/realtek,rtd1295.h b/include/dt-bindings/reset/realtek,rtd1295.h
new file mode 100644 (file)
index 0000000..2c0cb6a
--- /dev/null
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+/*
+ * Realtek RTD1295 reset controllers
+ *
+ * Copyright (c) 2017 Andreas Färber
+ */
+#ifndef DT_BINDINGS_RESET_RTD1295_H
+#define DT_BINDINGS_RESET_RTD1295_H
+
+/* soft reset 1 */
+#define RTD1295_RSTN_MISC              0
+#define RTD1295_RSTN_NAT               1
+#define RTD1295_RSTN_USB3_PHY0_POW     2
+#define RTD1295_RSTN_GSPI              3
+#define RTD1295_RSTN_USB3_P0_MDIO      4
+#define RTD1295_RSTN_SATA_0            5
+#define RTD1295_RSTN_USB               6
+#define RTD1295_RSTN_SATA_PHY_0                7
+#define RTD1295_RSTN_USB_PHY0          8
+#define RTD1295_RSTN_USB_PHY1          9
+#define RTD1295_RSTN_SATA_PHY_POW_0    10
+#define RTD1295_RSTN_SATA_FUNC_EXIST_0 11
+#define RTD1295_RSTN_HDMI              12
+#define RTD1295_RSTN_VE1               13
+#define RTD1295_RSTN_VE2               14
+#define RTD1295_RSTN_VE3               15
+#define RTD1295_RSTN_ETN               16
+#define RTD1295_RSTN_AIO               17
+#define RTD1295_RSTN_GPU               18
+#define RTD1295_RSTN_TVE               19
+#define RTD1295_RSTN_VO                        20
+#define RTD1295_RSTN_LVDS              21
+#define RTD1295_RSTN_SE                        22
+#define RTD1295_RSTN_DCU               23
+#define RTD1295_RSTN_DC_PHY            24
+#define RTD1295_RSTN_CP                        25
+#define RTD1295_RSTN_MD                        26
+#define RTD1295_RSTN_TP                        27
+#define RTD1295_RSTN_AE                        28
+#define RTD1295_RSTN_NF                        29
+#define RTD1295_RSTN_MIPI              30
+#define RTD1295_RSTN_RSA               31
+
+/* soft reset 2 */
+#define RTD1295_RSTN_ACPU              0
+#define RTD1295_RSTN_JPEG              1
+#define RTD1295_RSTN_USB_PHY3          2
+#define RTD1295_RSTN_USB_PHY2          3
+#define RTD1295_RSTN_USB3_PHY1_POW     4
+#define RTD1295_RSTN_USB3_P1_MDIO      5
+#define RTD1295_RSTN_PCIE0_STITCH      6
+#define RTD1295_RSTN_PCIE0_PHY         7
+#define RTD1295_RSTN_PCIE0             8
+#define RTD1295_RSTN_PCR_CNT           9
+#define RTD1295_RSTN_CR                        10
+#define RTD1295_RSTN_EMMC              11
+#define RTD1295_RSTN_SDIO              12
+#define RTD1295_RSTN_PCIE0_CORE                13
+#define RTD1295_RSTN_PCIE0_POWER       14
+#define RTD1295_RSTN_PCIE0_NONSTICH    15
+#define RTD1295_RSTN_PCIE1_PHY         16
+#define RTD1295_RSTN_PCIE1             17
+#define RTD1295_RSTN_I2C_5             18
+#define RTD1295_RSTN_PCIE1_STITCH      19
+#define RTD1295_RSTN_PCIE1_CORE                20
+#define RTD1295_RSTN_PCIE1_POWER       21
+#define RTD1295_RSTN_PCIE1_NONSTICH    22
+#define RTD1295_RSTN_I2C_4             23
+#define RTD1295_RSTN_I2C_3             24
+#define RTD1295_RSTN_I2C_2             25
+#define RTD1295_RSTN_I2C_1             26
+#define RTD1295_RSTN_UR2               27
+#define RTD1295_RSTN_UR1               28
+#define RTD1295_RSTN_MISC_SC           29
+#define RTD1295_RSTN_CBUS_TX           30
+#define RTD1295_RSTN_SDS_PHY           31
+
+/* soft reset 4 */
+#define RTD1295_RSTN_DCPHY_CRT         0
+#define RTD1295_RSTN_DCPHY_ALERT_RX    1
+#define RTD1295_RSTN_DCPHY_PTR         2
+#define RTD1295_RSTN_DCPHY_LDO         3
+#define RTD1295_RSTN_DCPHY_SSC_DIG     4
+#define RTD1295_RSTN_HDMIRX            5
+#define RTD1295_RSTN_CBUSRX            6
+#define RTD1295_RSTN_SATA_PHY_POW_1    7
+#define RTD1295_RSTN_SATA_FUNC_EXIST_1 8
+#define RTD1295_RSTN_SATA_PHY_1                9
+#define RTD1295_RSTN_SATA_1            10
+#define RTD1295_RSTN_FAN               11
+#define RTD1295_RSTN_HDMIRX_WRAP       12
+#define RTD1295_RSTN_PCIE0_PHY_MDIO    13
+#define RTD1295_RSTN_PCIE1_PHY_MDIO    14
+#define RTD1295_RSTN_DISP              15
+
+/* iso reset */
+#define RTD1295_ISO_RSTN_IR            1
+#define RTD1295_ISO_RSTN_CEC0          2
+#define RTD1295_ISO_RSTN_CEC1          3
+#define RTD1295_ISO_RSTN_DP            4
+#define RTD1295_ISO_RSTN_CBUSTX                5
+#define RTD1295_ISO_RSTN_CBUSRX                6
+#define RTD1295_ISO_RSTN_EFUSE         7
+#define RTD1295_ISO_RSTN_UR0           8
+#define RTD1295_ISO_RSTN_GMAC          9
+#define RTD1295_ISO_RSTN_GPHY          10
+#define RTD1295_ISO_RSTN_I2C_0         11
+#define RTD1295_ISO_RSTN_I2C_1         12
+#define RTD1295_ISO_RSTN_CBUS          13
+
+#endif
index 514bffa..fa19e01 100644 (file)
@@ -46,6 +46,8 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev);
 int pci_disable_pcie_error_reporting(struct pci_dev *dev);
 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
 int pci_cleanup_aer_error_status_regs(struct pci_dev *dev);
+void pci_save_aer_state(struct pci_dev *dev);
+void pci_restore_aer_state(struct pci_dev *dev);
 #else
 static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
 {
@@ -63,6 +65,8 @@ static inline int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
 {
        return -EINVAL;
 }
+static inline void pci_save_aer_state(struct pci_dev *dev) {}
+static inline void pci_restore_aer_state(struct pci_dev *dev) {}
 #endif
 
 void cper_print_aer(struct pci_dev *dev, int aer_severity,
index 29fc933..ff335b2 100644 (file)
@@ -53,6 +53,7 @@
  *  bitmap_find_next_zero_area_off(buf, len, pos, n, mask)  as above
  *  bitmap_shift_right(dst, src, n, nbits)      *dst = *src >> n
  *  bitmap_shift_left(dst, src, n, nbits)       *dst = *src << n
+ *  bitmap_replace(dst, old, new, mask, nbits)  *dst = (*old & ~(*mask)) | (*new & *mask)
  *  bitmap_remap(dst, src, old, new, nbits)     *dst = map(old, new)(src)
  *  bitmap_bitremap(oldbit, old, new, nbits)    newbit = map(old, new)(oldbit)
  *  bitmap_onto(dst, orig, relmap, nbits)       *dst = orig relative to relmap
@@ -66,6 +67,8 @@
  *  bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
  *  bitmap_from_arr32(dst, buf, nbits)          Copy nbits from u32[] buf to dst
  *  bitmap_to_arr32(buf, src, nbits)            Copy nbits from buf to u32[] dst
+ *  bitmap_get_value8(map, start)               Get 8bit value from map at start
+ *  bitmap_set_value8(map, value, start)        Set 8bit value to map at start
  *
  * Note, bitmap_zero() and bitmap_fill() operate over the region of
  * unsigned longs, that is, bits behind bitmap till the unsigned long
@@ -138,6 +141,9 @@ extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
                        const unsigned long *bitmap2, unsigned int nbits);
 extern int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
                        const unsigned long *bitmap2, unsigned int nbits);
+extern void __bitmap_replace(unsigned long *dst,
+                       const unsigned long *old, const unsigned long *new,
+                       const unsigned long *mask, unsigned int nbits);
 extern int __bitmap_intersects(const unsigned long *bitmap1,
                        const unsigned long *bitmap2, unsigned int nbits);
 extern int __bitmap_subset(const unsigned long *bitmap1,
@@ -432,6 +438,18 @@ static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *sr
                __bitmap_shift_left(dst, src, shift, nbits);
 }
 
+static inline void bitmap_replace(unsigned long *dst,
+                                 const unsigned long *old,
+                                 const unsigned long *new,
+                                 const unsigned long *mask,
+                                 unsigned int nbits)
+{
+       if (small_const_nbits(nbits))
+               *dst = (*old & ~(*mask)) | (*new & *mask);
+       else
+               __bitmap_replace(dst, old, new, mask, nbits);
+}
+
 static inline int bitmap_parse(const char *buf, unsigned int buflen,
                        unsigned long *maskp, int nmaskbits)
 {
@@ -489,6 +507,39 @@ static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
                dst[1] = mask >> 32;
 }
 
+/**
+ * bitmap_get_value8 - get an 8-bit value within a memory region
+ * @map: address to the bitmap memory region
+ * @start: bit offset of the 8-bit value; must be a multiple of 8
+ *
+ * Returns the 8-bit value located at the @start bit offset within the @src
+ * memory region.
+ */
+static inline unsigned long bitmap_get_value8(const unsigned long *map,
+                                             unsigned long start)
+{
+       const size_t index = BIT_WORD(start);
+       const unsigned long offset = start % BITS_PER_LONG;
+
+       return (map[index] >> offset) & 0xFF;
+}
+
+/**
+ * bitmap_set_value8 - set an 8-bit value within a memory region
+ * @map: address to the bitmap memory region
+ * @value: the 8-bit value; values wider than 8 bits may clobber bitmap
+ * @start: bit offset of the 8-bit value; must be a multiple of 8
+ */
+static inline void bitmap_set_value8(unsigned long *map, unsigned long value,
+                                    unsigned long start)
+{
+       const size_t index = BIT_WORD(start);
+       const unsigned long offset = start % BITS_PER_LONG;
+
+       map[index] &= ~(0xFFUL << offset);
+       map[index] |= value << offset;
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_BITMAP_H */
index c94a9ff..e479067 100644 (file)
@@ -47,6 +47,18 @@ extern unsigned long __sw_hweight64(__u64 w);
             (bit) < (size);                                    \
             (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
 
+/**
+ * for_each_set_clump8 - iterate over bitmap for each 8-bit clump with set bits
+ * @start: bit offset to start search and to store the current iteration offset
+ * @clump: location to store copy of current 8-bit clump
+ * @bits: bitmap address to base the search on
+ * @size: bitmap size in number of bits
+ */
+#define for_each_set_clump8(start, clump, bits, size) \
+       for ((start) = find_first_clump8(&(clump), (bits), (size)); \
+            (start) < (size); \
+            (start) = find_next_clump8(&(clump), (bits), (size), (start) + 8))
+
 static inline int get_bitmask_order(unsigned int count)
 {
        int order;
index 0fe5426..e3a0be2 100644 (file)
@@ -9,11 +9,11 @@
 #else /* __CHECKER__ */
 /*
  * Force a compilation error if condition is true, but also produce a
- * result (of value 0 and type size_t), so the expression can be used
+ * result (of value 0 and type int), so the expression can be used
  * e.g. in a structure initializer (or where-ever else comma expressions
  * aren't permitted).
  */
-#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); }))
+#define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))
 #endif /* __CHECKER__ */
 
 /* Force a compilation error if a constant expression is not a power of 2 */
index b9dbda1..8fe9b80 100644 (file)
@@ -280,10 +280,12 @@ extern const char *ceph_msg_type_name(int type);
 extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
 extern void *ceph_kvmalloc(size_t size, gfp_t flags);
 
-extern struct ceph_options *ceph_parse_options(char *options,
-                             const char *dev_name, const char *dev_name_end,
-                             int (*parse_extra_token)(char *c, void *private),
-                             void *private);
+struct fs_parameter;
+struct ceph_options *ceph_alloc_options(void);
+int ceph_parse_mon_ips(const char *buf, size_t len, struct ceph_options *opt,
+                      struct fs_context *fc);
+int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt,
+                    struct fs_context *fc);
 int ceph_print_client_options(struct seq_file *m, struct ceph_client *client,
                              bool show_all);
 extern void ceph_destroy_options(struct ceph_options *opt);
index bae54bb..b747325 100644 (file)
@@ -33,6 +33,13 @@ cpufreq_cooling_register(struct cpufreq_policy *policy);
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
 
+/**
+ * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
+ * @policy: cpufreq policy.
+ */
+struct thermal_cooling_device *
+of_cpufreq_cooling_register(struct cpufreq_policy *policy);
+
 #else /* !CONFIG_CPU_THERMAL */
 static inline struct thermal_cooling_device *
 cpufreq_cooling_register(struct cpufreq_policy *policy)
@@ -45,21 +52,12 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
        return;
 }
-#endif /* CONFIG_CPU_THERMAL */
 
-#if defined(CONFIG_THERMAL_OF) && defined(CONFIG_CPU_THERMAL)
-/**
- * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
- * @policy: cpufreq policy.
- */
-struct thermal_cooling_device *
-of_cpufreq_cooling_register(struct cpufreq_policy *policy);
-#else
 static inline struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct cpufreq_policy *policy)
 {
        return NULL;
 }
-#endif /* defined(CONFIG_THERMAL_OF) && defined(CONFIG_CPU_THERMAL) */
+#endif /* CONFIG_CPU_THERMAL */
 
 #endif /* __CPU_COOLING_H__ */
index 2dbe46b..1dabe36 100644 (file)
@@ -54,7 +54,6 @@ struct cpuidle_state {
        unsigned int    exit_latency; /* in US */
        int             power_usage; /* in mW */
        unsigned int    target_residency; /* in US */
-       bool            disabled; /* disabled on all CPUs */
 
        int (*enter)    (struct cpuidle_device *dev,
                        struct cpuidle_driver *drv,
@@ -77,6 +76,7 @@ struct cpuidle_state {
 #define CPUIDLE_FLAG_POLLING   BIT(0) /* polling state */
 #define CPUIDLE_FLAG_COUPLED   BIT(1) /* state applies to multiple cpus */
 #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
+#define CPUIDLE_FLAG_UNUSABLE  BIT(3) /* avoid using this state */
 
 struct cpuidle_device_kobj;
 struct cpuidle_state_kobj;
index 10090f1..c1488cc 100644 (file)
@@ -440,6 +440,11 @@ static inline bool d_is_negative(const struct dentry *dentry)
        return d_is_miss(dentry);
 }
 
+static inline bool d_flags_negative(unsigned flags)
+{
+       return (flags & DCACHE_ENTRY_TYPE) == DCACHE_MISS_TYPE;
+}
+
 static inline bool d_is_positive(const struct dentry *dentry)
 {
        return !d_is_negative(dentry);
index ab82df6..d09c6f6 100644 (file)
@@ -118,6 +118,9 @@ enum sprd_dma_int_type {
  * struct sprd_dma_linklist - DMA link-list address structure
  * @virt_addr: link-list virtual address to configure link-list node
  * @phy_addr: link-list physical address to link DMA transfer
+ * @wrap_addr: the wrap address for link-list mode, which means once the
+ * transfer address reaches the wrap address, the next transfer address
+ * will jump to the address specified by wrap_to register.
  *
  * The Spreadtrum DMA controller supports the link-list mode, that means slaves
  * can supply several groups configurations (each configuration represents one
@@ -181,6 +184,7 @@ enum sprd_dma_int_type {
 struct sprd_dma_linklist {
        unsigned long virt_addr;
        phys_addr_t phy_addr;
+       phys_addr_t wrap_addr;
 };
 
 #endif
index a7cf359..f64ca27 100644 (file)
@@ -129,6 +129,7 @@ static inline int dmar_res_noop(struct acpi_dmar_header *hdr, void *arg)
 #ifdef CONFIG_INTEL_IOMMU
 extern int iommu_detected, no_iommu;
 extern int intel_iommu_init(void);
+extern void intel_iommu_shutdown(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header, void *arg);
 extern int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg);
@@ -137,6 +138,7 @@ extern int dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert);
 extern int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
+static inline void intel_iommu_shutdown(void) { }
 
 #define        dmar_parse_one_rmrr             dmar_res_noop
 #define        dmar_parse_one_atsr             dmar_res_noop
index 8de8c4f..927f8a8 100644 (file)
@@ -113,6 +113,8 @@ extern int dmi_walk(void (*decode)(const struct dmi_header *, void *),
 extern bool dmi_match(enum dmi_field f, const char *str);
 extern void dmi_memdev_name(u16 handle, const char **bank, const char **device);
 extern u64 dmi_memdev_size(u16 handle);
+extern u8 dmi_memdev_type(u16 handle);
+extern u16 dmi_memdev_handle(int slot);
 
 #else
 
@@ -142,6 +144,8 @@ static inline bool dmi_match(enum dmi_field f, const char *str)
 static inline void dmi_memdev_name(u16 handle, const char **bank,
                const char **device) { }
 static inline u64 dmi_memdev_size(u16 handle) { return ~0ul; }
+static inline u8 dmi_memdev_type(u16 handle) { return 0x0; }
+static inline u16 dmi_memdev_handle(int slot) { return 0xffff; }
 static inline const struct dmi_system_id *
        dmi_first_match(const struct dmi_system_id *list) { return NULL; }
 
index 73f8c3c..d249b88 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/sched/topology.h>
 #include <linux/types.h>
 
-#ifdef CONFIG_ENERGY_MODEL
 /**
  * em_cap_state - Capacity state of a performance domain
  * @frequency: The CPU frequency in KHz, for consistency with CPUFreq
@@ -40,6 +39,7 @@ struct em_perf_domain {
        unsigned long cpus[0];
 };
 
+#ifdef CONFIG_ENERGY_MODEL
 #define EM_CPU_MAX_POWER 0xFFFF
 
 struct em_data_callback {
@@ -160,7 +160,6 @@ static inline int em_pd_nr_cap_states(struct em_perf_domain *pd)
 }
 
 #else
-struct em_perf_domain {};
 struct em_data_callback {};
 #define EM_DATA_CB(_active_power_cb) { }
 
index 941d075..6278414 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef _LINUX_EXPORT_H
 #define _LINUX_EXPORT_H
 
@@ -46,7 +47,7 @@ extern struct module __this_module;
  * absolute relocations that require runtime processing on relocatable
  * kernels.
  */
-#define __KSYMTAB_ENTRY_NS(sym, sec)                                   \
+#define __KSYMTAB_ENTRY(sym, sec)                                      \
        __ADDRESSABLE(sym)                                              \
        asm("   .section \"___ksymtab" sec "+" #sym "\", \"a\"  \n"     \
            "   .balign 4                                       \n"     \
@@ -56,33 +57,17 @@ extern struct module __this_module;
            "   .long   __kstrtabns_" #sym "- .                 \n"     \
            "   .previous                                       \n")
 
-#define __KSYMTAB_ENTRY(sym, sec)                                      \
-       __ADDRESSABLE(sym)                                              \
-       asm("   .section \"___ksymtab" sec "+" #sym "\", \"a\"  \n"     \
-           "   .balign 4                                       \n"     \
-           "__ksymtab_" #sym ":                                \n"     \
-           "   .long   " #sym "- .                             \n"     \
-           "   .long   __kstrtab_" #sym "- .                   \n"     \
-           "   .long   0                                       \n"     \
-           "   .previous                                       \n")
-
 struct kernel_symbol {
        int value_offset;
        int name_offset;
        int namespace_offset;
 };
 #else
-#define __KSYMTAB_ENTRY_NS(sym, sec)                                   \
-       static const struct kernel_symbol __ksymtab_##sym               \
-       __attribute__((section("___ksymtab" sec "+" #sym), used))       \
-       __aligned(sizeof(void *))                                       \
-       = { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }
-
 #define __KSYMTAB_ENTRY(sym, sec)                                      \
        static const struct kernel_symbol __ksymtab_##sym               \
        __attribute__((section("___ksymtab" sec "+" #sym), used))       \
        __aligned(sizeof(void *))                                       \
-       = { (unsigned long)&sym, __kstrtab_##sym, NULL }
+       = { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }
 
 struct kernel_symbol {
        unsigned long value;
@@ -93,28 +78,20 @@ struct kernel_symbol {
 
 #ifdef __GENKSYMS__
 
-#define ___EXPORT_SYMBOL(sym,sec)      __GENKSYMS_EXPORT_SYMBOL(sym)
-#define ___EXPORT_SYMBOL_NS(sym,sec,ns)        __GENKSYMS_EXPORT_SYMBOL(sym)
+#define ___EXPORT_SYMBOL(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym)
 
 #else
 
-#define ___export_symbol_common(sym, sec)                              \
+/* For every exported symbol, place a struct in the __ksymtab section */
+#define ___EXPORT_SYMBOL(sym, sec, ns)                                 \
        extern typeof(sym) sym;                                         \
        __CRC_SYMBOL(sym, sec);                                         \
        static const char __kstrtab_##sym[]                             \
        __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
-       = #sym                                                          \
-
-/* For every exported symbol, place a struct in the __ksymtab section */
-#define ___EXPORT_SYMBOL_NS(sym, sec, ns)                              \
-       ___export_symbol_common(sym, sec);                              \
+       = #sym;                                                         \
        static const char __kstrtabns_##sym[]                           \
        __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
-       = #ns;                                                          \
-       __KSYMTAB_ENTRY_NS(sym, sec)
-
-#define ___EXPORT_SYMBOL(sym, sec)                                     \
-       ___export_symbol_common(sym, sec);                              \
+       = ns;                                                           \
        __KSYMTAB_ENTRY(sym, sec)
 
 #endif
@@ -126,8 +103,7 @@ struct kernel_symbol {
  * be reused in other execution contexts such as the UEFI stub or the
  * decompressor.
  */
-#define __EXPORT_SYMBOL_NS(sym, sec, ns)
-#define __EXPORT_SYMBOL(sym, sec)
+#define __EXPORT_SYMBOL(sym, sec, ns)
 
 #elif defined(CONFIG_TRIM_UNUSED_KSYMS)
 
@@ -143,48 +119,38 @@ struct kernel_symbol {
 #define __ksym_marker(sym)     \
        static int __ksym_marker_##sym[0] __section(".discard.ksym") __used
 
-#define __EXPORT_SYMBOL(sym, sec)                              \
-       __ksym_marker(sym);                                     \
-       __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym))
-#define __cond_export_sym(sym, sec, conf)                      \
-       ___cond_export_sym(sym, sec, conf)
-#define ___cond_export_sym(sym, sec, enabled)                  \
-       __cond_export_sym_##enabled(sym, sec)
-#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
-#define __cond_export_sym_0(sym, sec) /* nothing */
-
-#define __EXPORT_SYMBOL_NS(sym, sec, ns)                               \
+#define __EXPORT_SYMBOL(sym, sec, ns)                                  \
        __ksym_marker(sym);                                             \
-       __cond_export_ns_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
-#define __cond_export_ns_sym(sym, sec, ns, conf)                       \
-       ___cond_export_ns_sym(sym, sec, ns, conf)
-#define ___cond_export_ns_sym(sym, sec, ns, enabled)                   \
-       __cond_export_ns_sym_##enabled(sym, sec, ns)
-#define __cond_export_ns_sym_1(sym, sec, ns) ___EXPORT_SYMBOL_NS(sym, sec, ns)
-#define __cond_export_ns_sym_0(sym, sec, ns) /* nothing */
+       __cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
+#define __cond_export_sym(sym, sec, ns, conf)                          \
+       ___cond_export_sym(sym, sec, ns, conf)
+#define ___cond_export_sym(sym, sec, ns, enabled)                      \
+       __cond_export_sym_##enabled(sym, sec, ns)
+#define __cond_export_sym_1(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns)
+#define __cond_export_sym_0(sym, sec, ns) /* nothing */
 
 #else
 
-#define __EXPORT_SYMBOL_NS(sym,sec,ns) ___EXPORT_SYMBOL_NS(sym,sec,ns)
-#define __EXPORT_SYMBOL(sym,sec)       ___EXPORT_SYMBOL(sym,sec)
+#define __EXPORT_SYMBOL(sym, sec, ns)  ___EXPORT_SYMBOL(sym, sec, ns)
 
 #endif /* CONFIG_MODULES */
 
 #ifdef DEFAULT_SYMBOL_NAMESPACE
-#undef __EXPORT_SYMBOL
-#define __EXPORT_SYMBOL(sym, sec)                              \
-       __EXPORT_SYMBOL_NS(sym, sec, DEFAULT_SYMBOL_NAMESPACE)
+#include <linux/stringify.h>
+#define _EXPORT_SYMBOL(sym, sec)       __EXPORT_SYMBOL(sym, sec, __stringify(DEFAULT_SYMBOL_NAMESPACE))
+#else
+#define _EXPORT_SYMBOL(sym, sec)       __EXPORT_SYMBOL(sym, sec, "")
 #endif
 
-#define EXPORT_SYMBOL(sym)             __EXPORT_SYMBOL(sym, "")
-#define EXPORT_SYMBOL_GPL(sym)         __EXPORT_SYMBOL(sym, "_gpl")
-#define EXPORT_SYMBOL_GPL_FUTURE(sym)  __EXPORT_SYMBOL(sym, "_gpl_future")
-#define EXPORT_SYMBOL_NS(sym, ns)      __EXPORT_SYMBOL_NS(sym, "", ns)
-#define EXPORT_SYMBOL_NS_GPL(sym, ns)  __EXPORT_SYMBOL_NS(sym, "_gpl", ns)
+#define EXPORT_SYMBOL(sym)             _EXPORT_SYMBOL(sym, "")
+#define EXPORT_SYMBOL_GPL(sym)         _EXPORT_SYMBOL(sym, "_gpl")
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)  _EXPORT_SYMBOL(sym, "_gpl_future")
+#define EXPORT_SYMBOL_NS(sym, ns)      __EXPORT_SYMBOL(sym, "", #ns)
+#define EXPORT_SYMBOL_NS_GPL(sym, ns)  __EXPORT_SYMBOL(sym, "_gpl", #ns)
 
 #ifdef CONFIG_UNUSED_SYMBOLS
-#define EXPORT_UNUSED_SYMBOL(sym)      __EXPORT_SYMBOL(sym, "_unused")
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)  __EXPORT_SYMBOL(sym, "_unused_gpl")
+#define EXPORT_UNUSED_SYMBOL(sym)      _EXPORT_SYMBOL(sym, "_unused")
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)  _EXPORT_SYMBOL(sym, "_unused_gpl")
 #else
 #define EXPORT_UNUSED_SYMBOL(sym)
 #define EXPORT_UNUSED_SYMBOL_GPL(sym)
index fc61fdb..8bf3d79 100644 (file)
@@ -20,7 +20,10 @@ struct space_resv {
 };
 
 #define FS_IOC_RESVSP          _IOW('X', 40, struct space_resv)
+#define FS_IOC_UNRESVSP                _IOW('X', 41, struct space_resv)
 #define FS_IOC_RESVSP64                _IOW('X', 42, struct space_resv)
+#define FS_IOC_UNRESVSP64      _IOW('X', 43, struct space_resv)
+#define FS_IOC_ZERO_RANGE      _IOW('X', 57, struct space_resv)
 
 #define        FALLOC_FL_SUPPORTED_MASK        (FALLOC_FL_KEEP_SIZE |          \
                                         FALLOC_FL_PUNCH_HOLE |         \
@@ -42,10 +45,13 @@ struct space_resv_32 {
        __s32           l_pad[4];       /* reserve area */
 };
 
-#define FS_IOC_RESVSP_32               _IOW ('X', 40, struct space_resv_32)
+#define FS_IOC_RESVSP_32       _IOW ('X', 40, struct space_resv_32)
+#define FS_IOC_UNRESVSP_32     _IOW ('X', 41, struct space_resv_32)
 #define FS_IOC_RESVSP64_32     _IOW ('X', 42, struct space_resv_32)
+#define FS_IOC_UNRESVSP64_32   _IOW ('X', 43, struct space_resv_32)
+#define FS_IOC_ZERO_RANGE_32   _IOW ('X', 57, struct space_resv_32)
 
-int compat_ioctl_preallocate(struct file *, struct space_resv_32 __user *);
+int compat_ioctl_preallocate(struct file *, int, struct space_resv_32 __user *);
 
 #endif
 
index 7613bf7..6669e2a 100644 (file)
@@ -16,11 +16,14 @@ enum {
 
 struct meson_sm_firmware;
 
-int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, u32 arg1,
-                 u32 arg2, u32 arg3, u32 arg4);
-int meson_sm_call_write(void *buffer, unsigned int b_size, unsigned int cmd_index,
-                       u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
-int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
-                      u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
+                 u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
+                       unsigned int b_size, unsigned int cmd_index, u32 arg0,
+                       u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
+                      unsigned int bsize, unsigned int cmd_index, u32 arg0,
+                      u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+struct meson_sm_firmware *meson_sm_get(struct device_node *firmware_node);
 
 #endif /* _MESON_SM_FW_H_ */
index df366f1..e41ad9e 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Xilinx Zynq MPSoC Firmware layer
  *
- *  Copyright (C) 2014-2018 Xilinx
+ *  Copyright (C) 2014-2019 Xilinx
  *
  *  Michal Simek <michal.simek@xilinx.com>
  *  Davorin Mista <davorin.mista@aggios.com>
@@ -46,6 +46,7 @@
 #define        ZYNQMP_PM_CAPABILITY_ACCESS     0x1U
 #define        ZYNQMP_PM_CAPABILITY_CONTEXT    0x2U
 #define        ZYNQMP_PM_CAPABILITY_WAKEUP     0x4U
+#define        ZYNQMP_PM_CAPABILITY_UNUSABLE   0x8U
 
 /*
  * Firmware FPGA Manager flags
index 670f96a..98e0349 100644 (file)
@@ -2554,7 +2554,7 @@ extern int finish_no_open(struct file *file, struct dentry *dentry);
 
 /* fs/ioctl.c */
 
-extern int ioctl_preallocate(struct file *filp, void __user *argp);
+extern int ioctl_preallocate(struct file *filp, int mode, void __user *argp);
 
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);
@@ -3156,7 +3156,6 @@ enum {
 };
 
 void dio_end_io(struct bio *bio);
-void dio_warn_stale_pagecache(struct file *filp);
 
 ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
                             struct block_device *bdev, struct iov_iter *iter,
@@ -3201,6 +3200,11 @@ static inline void inode_dio_end(struct inode *inode)
                wake_up_bit(&inode->i_state, __I_DIO_WAKEUP);
 }
 
+/*
+ * Warn about a page cache invalidation failure diring a direct I/O write.
+ */
+void dio_warn_stale_pagecache(struct file *filp);
+
 extern void inode_set_flags(struct inode *inode, unsigned int flags,
                            unsigned int mask);
 
index 4bd583b..5b14a0f 100644 (file)
@@ -206,7 +206,7 @@ extern struct gen_pool *devm_gen_pool_create(struct device *dev,
                int min_alloc_order, int nid, const char *name);
 extern struct gen_pool *gen_pool_get(struct device *dev, const char *name);
 
-bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start,
+extern bool gen_pool_has_addr(struct gen_pool *pool, unsigned long start,
                        size_t size);
 
 #ifdef CONFIG_OF
index 61f2f6f..e5b817c 100644 (file)
@@ -612,6 +612,8 @@ static inline bool pm_suspended_storage(void)
 /* 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 struct page *alloc_contig_pages(unsigned long nr_pages, gfp_t gfp_mask,
+                                      int nid, nodemask_t *nodemask);
 #endif
 void free_contig_range(unsigned long pfn, unsigned int nr_pages);
 
index 1b9a51a..1f98b52 100644 (file)
@@ -456,12 +456,18 @@ extern u64 hrtimer_next_event_without(const struct hrtimer *exclude);
 
 extern bool hrtimer_active(const struct hrtimer *timer);
 
-/*
- * Helper function to check, whether the timer is on one of the queues
+/**
+ * hrtimer_is_queued = check, whether the timer is on one of the queues
+ * @timer:     Timer to check
+ *
+ * Returns: True if the timer is queued, false otherwise
+ *
+ * The function can be used lockless, but it gives only a current snapshot.
  */
-static inline int hrtimer_is_queued(struct hrtimer *timer)
+static inline bool hrtimer_is_queued(struct hrtimer *timer)
 {
-       return timer->state & HRTIMER_STATE_ENQUEUED;
+       /* The READ_ONCE pairs with the update functions of timer->state */
+       return !!(READ_ONCE(timer->state) & HRTIMER_STATE_ENQUEUED);
 }
 
 /*
index 53fc34f..31d4920 100644 (file)
@@ -105,8 +105,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 address_space *mapping,
-                               pgoff_t idx, unsigned long address);
+u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx);
 
 pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
 
@@ -164,38 +163,130 @@ static inline void adjust_range_if_pmd_sharing_possible(
 {
 }
 
-#define follow_hugetlb_page(m,v,p,vs,a,b,i,w,n)        ({ BUG(); 0; })
-#define follow_huge_addr(mm, addr, write)      ERR_PTR(-EINVAL)
-#define copy_hugetlb_page_range(src, dst, vma) ({ BUG(); 0; })
+static inline long follow_hugetlb_page(struct mm_struct *mm,
+                       struct vm_area_struct *vma, struct page **pages,
+                       struct vm_area_struct **vmas, unsigned long *position,
+                       unsigned long *nr_pages, long i, unsigned int flags,
+                       int *nonblocking)
+{
+       BUG();
+       return 0;
+}
+
+static inline struct page *follow_huge_addr(struct mm_struct *mm,
+                                       unsigned long address, int write)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline int copy_hugetlb_page_range(struct mm_struct *dst,
+                       struct mm_struct *src, struct vm_area_struct *vma)
+{
+       BUG();
+       return 0;
+}
+
 static inline void hugetlb_report_meminfo(struct seq_file *m)
 {
 }
-#define hugetlb_report_node_meminfo(n, buf)    0
+
+static inline int hugetlb_report_node_meminfo(int nid, char *buf)
+{
+       return 0;
+}
+
 static inline void hugetlb_show_meminfo(void)
 {
 }
-#define follow_huge_pd(vma, addr, hpd, flags, pdshift) NULL
-#define follow_huge_pmd(mm, addr, pmd, flags)  NULL
-#define follow_huge_pud(mm, addr, pud, flags)  NULL
-#define follow_huge_pgd(mm, addr, pgd, flags)  NULL
-#define prepare_hugepage_range(file, addr, len)        (-EINVAL)
-#define pmd_huge(x)    0
-#define pud_huge(x)    0
-#define is_hugepage_only_range(mm, addr, len)  0
-#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
-#define hugetlb_mcopy_atomic_pte(dst_mm, dst_pte, dst_vma, dst_addr, \
-                               src_addr, pagep)        ({ BUG(); 0; })
-#define huge_pte_offset(mm, address, sz)       0
+
+static inline struct page *follow_huge_pd(struct vm_area_struct *vma,
+                               unsigned long address, hugepd_t hpd, int flags,
+                               int pdshift)
+{
+       return NULL;
+}
+
+static inline struct page *follow_huge_pmd(struct mm_struct *mm,
+                               unsigned long address, pmd_t *pmd, int flags)
+{
+       return NULL;
+}
+
+static inline struct page *follow_huge_pud(struct mm_struct *mm,
+                               unsigned long address, pud_t *pud, int flags)
+{
+       return NULL;
+}
+
+static inline struct page *follow_huge_pgd(struct mm_struct *mm,
+                               unsigned long address, pgd_t *pgd, int flags)
+{
+       return NULL;
+}
+
+static inline int prepare_hugepage_range(struct file *file,
+                               unsigned long addr, unsigned long len)
+{
+       return -EINVAL;
+}
+
+static inline int pmd_huge(pmd_t pmd)
+{
+       return 0;
+}
+
+static inline int pud_huge(pud_t pud)
+{
+       return 0;
+}
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+                                       unsigned long addr, unsigned long len)
+{
+       return 0;
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+                               unsigned long addr, unsigned long end,
+                               unsigned long floor, unsigned long ceiling)
+{
+       BUG();
+}
+
+static inline int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
+                                               pte_t *dst_pte,
+                                               struct vm_area_struct *dst_vma,
+                                               unsigned long dst_addr,
+                                               unsigned long src_addr,
+                                               struct page **pagep)
+{
+       BUG();
+       return 0;
+}
+
+static inline pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,
+                                       unsigned long sz)
+{
+       return NULL;
+}
 
 static inline bool isolate_huge_page(struct page *page, struct list_head *list)
 {
        return false;
 }
-#define putback_active_hugepage(p)     do {} while (0)
-#define move_hugetlb_state(old, new, reason)   do {} while (0)
 
-static inline unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
-               unsigned long address, unsigned long end, pgprot_t newprot)
+static inline void putback_active_hugepage(struct page *page)
+{
+}
+
+static inline void move_hugetlb_state(struct page *oldpage,
+                                       struct page *newpage, int reason)
+{
+}
+
+static inline unsigned long hugetlb_change_protection(
+                       struct vm_area_struct *vma, unsigned long address,
+                       unsigned long end, pgprot_t newprot)
 {
        return 0;
 }
@@ -213,9 +304,10 @@ static inline void __unmap_hugepage_range(struct mmu_gather *tlb,
 {
        BUG();
 }
+
 static inline vm_fault_t hugetlb_fault(struct mm_struct *mm,
-                               struct vm_area_struct *vma, unsigned long address,
-                               unsigned int flags)
+                       struct vm_area_struct *vma, unsigned long address,
+                       unsigned int flags)
 {
        BUG();
        return 0;
index 89fc59d..c5fe60e 100644 (file)
@@ -140,6 +140,19 @@ request_threaded_irq(unsigned int irq, irq_handler_t handler,
                     irq_handler_t thread_fn,
                     unsigned long flags, const char *name, void *dev);
 
+/**
+ * request_irq - Add a handler for an interrupt line
+ * @irq:       The interrupt line to allocate
+ * @handler:   Function to be called when the IRQ occurs.
+ *             Primary handler for threaded interrupts
+ *             If NULL, the default primary handler is installed
+ * @flags:     Handling flags
+ * @name:      Name of the device generating this interrupt
+ * @dev:       A cookie passed to the handler function
+ *
+ * This call allocates an interrupt and establishes a handler; see
+ * the documentation for request_threaded_irq() for details.
+ */
 static inline int __must_check
 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
            const char *name, void *dev)
@@ -520,8 +533,7 @@ enum
        IRQ_POLL_SOFTIRQ,
        TASKLET_SOFTIRQ,
        SCHED_SOFTIRQ,
-       HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the
-                           numbering. Sigh! */
+       HRTIMER_SOFTIRQ,
        RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
 
        NR_SOFTIRQS
index ec7a134..ee21eed 100644 (file)
@@ -102,7 +102,7 @@ struct io_pgtable_cfg {
                struct {
                        u64     ttbr[2];
                        u64     tcr;
-                       u64     mair[2];
+                       u64     mair;
                } arm_lpae_s1_cfg;
 
                struct {
diff --git a/include/linux/ioasid.h b/include/linux/ioasid.h
new file mode 100644 (file)
index 0000000..6f000d7
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_IOASID_H
+#define __LINUX_IOASID_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#define INVALID_IOASID ((ioasid_t)-1)
+typedef unsigned int ioasid_t;
+typedef ioasid_t (*ioasid_alloc_fn_t)(ioasid_t min, ioasid_t max, void *data);
+typedef void (*ioasid_free_fn_t)(ioasid_t ioasid, void *data);
+
+struct ioasid_set {
+       int dummy;
+};
+
+/**
+ * struct ioasid_allocator_ops - IOASID allocator helper functions and data
+ *
+ * @alloc:     helper function to allocate IOASID
+ * @free:      helper function to free IOASID
+ * @list:      for tracking ops that share helper functions but not data
+ * @pdata:     data belong to the allocator, provided when calling alloc()
+ */
+struct ioasid_allocator_ops {
+       ioasid_alloc_fn_t alloc;
+       ioasid_free_fn_t free;
+       struct list_head list;
+       void *pdata;
+};
+
+#define DECLARE_IOASID_SET(name) struct ioasid_set name = { 0 }
+
+#if IS_ENABLED(CONFIG_IOASID)
+ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
+                     void *private);
+void ioasid_free(ioasid_t ioasid);
+void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
+                 bool (*getter)(void *));
+int ioasid_register_allocator(struct ioasid_allocator_ops *allocator);
+void ioasid_unregister_allocator(struct ioasid_allocator_ops *allocator);
+int ioasid_set_data(ioasid_t ioasid, void *data);
+
+#else /* !CONFIG_IOASID */
+static inline ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min,
+                                   ioasid_t max, void *private)
+{
+       return INVALID_IOASID;
+}
+
+static inline void ioasid_free(ioasid_t ioasid)
+{
+}
+
+static inline void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
+                               bool (*getter)(void *))
+{
+       return NULL;
+}
+
+static inline int ioasid_register_allocator(struct ioasid_allocator_ops *allocator)
+{
+       return -ENOTSUPP;
+}
+
+static inline void ioasid_unregister_allocator(struct ioasid_allocator_ops *allocator)
+{
+}
+
+static inline int ioasid_set_data(ioasid_t ioasid, void *data)
+{
+       return -ENOTSUPP;
+}
+
+#endif /* CONFIG_IOASID */
+#endif /* __LINUX_IOASID_H */
index 29bac53..f2223cb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/ioasid.h>
 #include <uapi/linux/iommu.h>
 
 #define IOMMU_READ     (1 << 0)
  */
 #define IOMMU_PRIV     (1 << 5)
 /*
- * Non-coherent masters on few Qualcomm SoCs can use this page protection flag
- * to set correct cacheability attributes to use an outer level of cache -
- * last level cache, aka system cache.
+ * Non-coherent masters can use this page protection flag to set cacheable
+ * memory attributes for only a transparent outer level of cache, also known as
+ * the last-level or system cache.
  */
-#define IOMMU_QCOM_SYS_CACHE   (1 << 6)
+#define IOMMU_SYS_CACHE_ONLY   (1 << 6)
 
 struct iommu_ops;
 struct iommu_group;
@@ -244,7 +245,10 @@ struct iommu_iotlb_gather {
  * @sva_unbind: Unbind process address space from device
  * @sva_get_pasid: Get PASID associated to a SVA handle
  * @page_response: handle page request response
+ * @cache_invalidate: invalidate translation caches
  * @pgsize_bitmap: bitmap of all possible supported page sizes
+ * @sva_bind_gpasid: bind guest pasid and mm
+ * @sva_unbind_gpasid: unbind guest pasid and mm
  */
 struct iommu_ops {
        bool (*capable)(enum iommu_cap);
@@ -256,7 +260,7 @@ struct iommu_ops {
        int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
        void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
        int (*map)(struct iommu_domain *domain, unsigned long iova,
-                  phys_addr_t paddr, size_t size, int prot);
+                  phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
        size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
                     size_t size, struct iommu_iotlb_gather *iotlb_gather);
        void (*flush_iotlb_all)(struct iommu_domain *domain);
@@ -306,6 +310,12 @@ struct iommu_ops {
        int (*page_response)(struct device *dev,
                             struct iommu_fault_event *evt,
                             struct iommu_page_response *msg);
+       int (*cache_invalidate)(struct iommu_domain *domain, struct device *dev,
+                               struct iommu_cache_invalidate_info *inv_info);
+       int (*sva_bind_gpasid)(struct iommu_domain *domain,
+                       struct device *dev, struct iommu_gpasid_bind_data *data);
+
+       int (*sva_unbind_gpasid)(struct device *dev, int pasid);
 
        unsigned long pgsize_bitmap;
 };
@@ -417,10 +427,19 @@ extern int iommu_attach_device(struct iommu_domain *domain,
                               struct device *dev);
 extern void iommu_detach_device(struct iommu_domain *domain,
                                struct device *dev);
+extern int iommu_cache_invalidate(struct iommu_domain *domain,
+                                 struct device *dev,
+                                 struct iommu_cache_invalidate_info *inv_info);
+extern int iommu_sva_bind_gpasid(struct iommu_domain *domain,
+               struct device *dev, struct iommu_gpasid_bind_data *data);
+extern int iommu_sva_unbind_gpasid(struct iommu_domain *domain,
+                               struct device *dev, ioasid_t pasid);
 extern struct iommu_domain *iommu_get_domain_for_dev(struct device *dev);
 extern struct iommu_domain *iommu_get_dma_domain(struct device *dev);
 extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
                     phys_addr_t paddr, size_t size, int prot);
+extern int iommu_map_atomic(struct iommu_domain *domain, unsigned long iova,
+                           phys_addr_t paddr, size_t size, int prot);
 extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
                          size_t size);
 extern size_t iommu_unmap_fast(struct iommu_domain *domain,
@@ -428,6 +447,9 @@ extern size_t iommu_unmap_fast(struct iommu_domain *domain,
                               struct iommu_iotlb_gather *iotlb_gather);
 extern size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
                           struct scatterlist *sg,unsigned int nents, int prot);
+extern size_t iommu_map_sg_atomic(struct iommu_domain *domain,
+                                 unsigned long iova, struct scatterlist *sg,
+                                 unsigned int nents, int prot);
 extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova);
 extern void iommu_set_fault_handler(struct iommu_domain *domain,
                        iommu_fault_handler_t handler, void *token);
@@ -662,6 +684,13 @@ static inline int iommu_map(struct iommu_domain *domain, unsigned long iova,
        return -ENODEV;
 }
 
+static inline int iommu_map_atomic(struct iommu_domain *domain,
+                                  unsigned long iova, phys_addr_t paddr,
+                                  size_t size, int prot)
+{
+       return -ENODEV;
+}
+
 static inline size_t iommu_unmap(struct iommu_domain *domain,
                                 unsigned long iova, size_t size)
 {
@@ -682,6 +711,13 @@ static inline size_t iommu_map_sg(struct iommu_domain *domain,
        return 0;
 }
 
+static inline size_t iommu_map_sg_atomic(struct iommu_domain *domain,
+                                 unsigned long iova, struct scatterlist *sg,
+                                 unsigned int nents, int prot)
+{
+       return 0;
+}
+
 static inline void iommu_flush_tlb_all(struct iommu_domain *domain)
 {
 }
@@ -1005,6 +1041,25 @@ static inline int iommu_sva_get_pasid(struct iommu_sva *handle)
        return IOMMU_PASID_INVALID;
 }
 
+static inline int
+iommu_cache_invalidate(struct iommu_domain *domain,
+                      struct device *dev,
+                      struct iommu_cache_invalidate_info *inv_info)
+{
+       return -ENODEV;
+}
+static inline int iommu_sva_bind_gpasid(struct iommu_domain *domain,
+                               struct device *dev, struct iommu_gpasid_bind_data *data)
+{
+       return -ENODEV;
+}
+
+static inline int iommu_sva_unbind_gpasid(struct iommu_domain *domain,
+                                          struct device *dev, int pasid)
+{
+       return -ENODEV;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_DEBUGFS
index fb301cf..7853eb9 100644 (file)
@@ -610,6 +610,12 @@ extern int irq_chip_pm_put(struct irq_data *data);
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
 extern void handle_fasteoi_ack_irq(struct irq_desc *desc);
 extern void handle_fasteoi_mask_irq(struct irq_desc *desc);
+extern int irq_chip_set_parent_state(struct irq_data *data,
+                                    enum irqchip_irq_state which,
+                                    bool val);
+extern int irq_chip_get_parent_state(struct irq_data *data,
+                                    enum irqchip_irq_state which,
+                                    bool *state);
 extern void irq_chip_enable_parent(struct irq_data *data);
 extern void irq_chip_disable_parent(struct irq_data *data);
 extern void irq_chip_ack_parent(struct irq_data *data);
index b11fcdf..02da997 100644 (file)
@@ -22,7 +22,7 @@
 #define IRQ_WORK_CLAIMED       (IRQ_WORK_PENDING | IRQ_WORK_BUSY)
 
 struct irq_work {
-       unsigned long flags;
+       atomic_t flags;
        struct llist_node llnode;
        void (*func)(struct irq_work *);
 };
@@ -30,11 +30,15 @@ struct irq_work {
 static inline
 void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
 {
-       work->flags = 0;
+       atomic_set(&work->flags, 0);
        work->func = func;
 }
 
-#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), }
+#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = {     \
+               .flags = ATOMIC_INIT(0),                        \
+               .func  = (_f)                                   \
+}
+
 
 bool irq_work_queue(struct irq_work *work);
 bool irq_work_queue_on(struct irq_work *work, int cpu);
index a0bde9e..de991d6 100644 (file)
 #define GITS_TYPER_PLPIS               (1UL << 0)
 #define GITS_TYPER_VLPIS               (1UL << 1)
 #define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT        4
-#define GITS_TYPER_ITT_ENTRY_SIZE(r)   ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0xf) + 1)
+#define GITS_TYPER_ITT_ENTRY_SIZE      GENMASK_ULL(7, 4)
 #define GITS_TYPER_IDBITS_SHIFT                8
 #define GITS_TYPER_DEVBITS_SHIFT       13
-#define GITS_TYPER_DEVBITS(r)          ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
+#define GITS_TYPER_DEVBITS             GENMASK_ULL(17, 13)
 #define GITS_TYPER_PTA                 (1UL << 19)
 #define GITS_TYPER_HCC_SHIFT           24
 #define GITS_TYPER_HCC(r)              (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff)
diff --git a/include/linux/irqchip/ingenic.h b/include/linux/irqchip/ingenic.h
deleted file mode 100644 (file)
index 1465588..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- */
-
-#ifndef __LINUX_IRQCHIP_INGENIC_H__
-#define __LINUX_IRQCHIP_INGENIC_H__
-
-#include <linux/irq.h>
-
-extern void ingenic_intc_irq_suspend(struct irq_data *data);
-extern void ingenic_intc_irq_resume(struct irq_data *data);
-
-#endif
index 583e7ab..3c340db 100644 (file)
@@ -83,6 +83,7 @@ enum irq_domain_bus_token {
        DOMAIN_BUS_IPI,
        DOMAIN_BUS_FSL_MC_MSI,
        DOMAIN_BUS_TI_SCI_INTA_MSI,
+       DOMAIN_BUS_WAKEUP,
 };
 
 /**
index cc8a03c..4f404c5 100644 (file)
@@ -70,8 +70,18 @@ struct kasan_cache {
        int free_meta_offset;
 };
 
+/*
+ * These functions provide a special case to support backing module
+ * allocations with real shadow memory. With KASAN vmalloc, the special
+ * case is unnecessary, as the work is handled in the generic case.
+ */
+#ifndef CONFIG_KASAN_VMALLOC
 int kasan_module_alloc(void *addr, size_t size);
 void kasan_free_shadow(const struct vm_struct *vm);
+#else
+static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
+static inline void kasan_free_shadow(const struct vm_struct *vm) {}
+#endif
 
 int kasan_add_zero_shadow(void *start, unsigned long size);
 void kasan_remove_zero_shadow(void *start, unsigned long size);
@@ -194,4 +204,25 @@ static inline void *kasan_reset_tag(const void *addr)
 
 #endif /* CONFIG_KASAN_SW_TAGS */
 
+#ifdef CONFIG_KASAN_VMALLOC
+int kasan_populate_vmalloc(unsigned long requested_size,
+                          struct vm_struct *area);
+void kasan_poison_vmalloc(void *start, unsigned long size);
+void kasan_release_vmalloc(unsigned long start, unsigned long end,
+                          unsigned long free_region_start,
+                          unsigned long free_region_end);
+#else
+static inline int kasan_populate_vmalloc(unsigned long requested_size,
+                                        struct vm_struct *area)
+{
+       return 0;
+}
+
+static inline void kasan_poison_vmalloc(void *start, unsigned long size) {}
+static inline void kasan_release_vmalloc(unsigned long start,
+                                        unsigned long end,
+                                        unsigned long free_region_start,
+                                        unsigned long free_region_end) {}
+#endif
+
 #endif /* LINUX_KASAN_H */
index b76a180..a10e847 100644 (file)
@@ -37,12 +37,35 @@ do {                                                \
        (t)->kcov_mode &= ~KCOV_IN_CTXSW;       \
 } while (0)
 
+/* See Documentation/dev-tools/kcov.rst for usage details. */
+void kcov_remote_start(u64 handle);
+void kcov_remote_stop(void);
+u64 kcov_common_handle(void);
+
+static inline void kcov_remote_start_common(u64 id)
+{
+       kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, id));
+}
+
+static inline void kcov_remote_start_usb(u64 id)
+{
+       kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_USB, id));
+}
+
 #else
 
 static inline void kcov_task_init(struct task_struct *t) {}
 static inline void kcov_task_exit(struct task_struct *t) {}
 static inline void kcov_prepare_switch(struct task_struct *t) {}
 static inline void kcov_finish_switch(struct task_struct *t) {}
+static inline void kcov_remote_start(u64 handle) {}
+static inline void kcov_remote_stop(void) {}
+static inline u64 kcov_common_handle(void)
+{
+       return 0;
+}
+static inline void kcov_remote_start_common(u64 id) {}
+static inline void kcov_remote_start_usb(u64 id) {}
 
 #endif /* CONFIG_KCOV */
 #endif /* _LINUX_KCOV_H */
index 09f7592..3adcb39 100644 (file)
@@ -348,8 +348,7 @@ int __must_check kstrtoll(const char *s, unsigned int base, long long *res);
  * @res: Where to write the result of the conversion on success.
  *
  * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
+ * Used as a replacement for the simple_strtoull. Return code must be checked.
 */
 static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res)
 {
@@ -377,8 +376,7 @@ static inline int __must_check kstrtoul(const char *s, unsigned int base, unsign
  * @res: Where to write the result of the conversion on success.
  *
  * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
+ * Used as a replacement for the simple_strtoull. Return code must be checked.
  */
 static inline int __must_check kstrtol(const char *s, unsigned int base, long *res)
 {
@@ -454,7 +452,18 @@ static inline int __must_check kstrtos32_from_user(const char __user *s, size_t
        return kstrtoint_from_user(s, count, base, res);
 }
 
-/* Obsolete, do not use.  Use kstrto<foo> instead */
+/*
+ * Use kstrto<foo> instead.
+ *
+ * NOTE: simple_strto<foo> does not check for the range overflow and,
+ *      depending on the input, may give interesting results.
+ *
+ * Use these functions if and only if you cannot use kstrto<foo>, because
+ * the conversion ends on the first non-digit character, which may be far
+ * beyond the supported range. It might be useful to parse the strings like
+ * 10x50 or 12:21 without altering original string or temporary buffer in use.
+ * Keep in mind above caveat.
+ */
 
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
index edb0f0c..cea8574 100644 (file)
@@ -2,11 +2,14 @@
 #ifndef LIBFDT_ENV_H
 #define LIBFDT_ENV_H
 
-#include <linux/kernel.h>      /* For INT_MAX */
+#include <linux/limits.h>      /* For INT_MAX */
 #include <linux/string.h>
 
 #include <asm/byteorder.h>
 
+#define INT32_MAX      S32_MAX
+#define UINT32_MAX     U32_MAX
+
 typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
 typedef __be64 fdt64_t;
index decdbf4..7cce390 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef __LICENSE_H
 #define __LICENSE_H
 
index 88e1e63..54945aa 100644 (file)
@@ -108,10 +108,10 @@ void logic_outsl(unsigned long addr, const void *buffer, unsigned int count);
  * area by redefining the macro below.
  */
 #define PIO_INDIRECT_SIZE 0x4000
-#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
 #else
-#define MMIO_UPPER_LIMIT IO_SPACE_LIMIT
+#define PIO_INDIRECT_SIZE 0
 #endif /* CONFIG_INDIRECT_PIO */
+#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
 
 struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
 unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
index f491690..b38bbef 100644 (file)
@@ -358,6 +358,9 @@ static inline phys_addr_t memblock_phys_alloc(phys_addr_t size,
                                         MEMBLOCK_ALLOC_ACCESSIBLE);
 }
 
+void *memblock_alloc_exact_nid_raw(phys_addr_t size, phys_addr_t align,
+                                phys_addr_t min_addr, phys_addr_t max_addr,
+                                int nid);
 void *memblock_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align,
                                 phys_addr_t min_addr, phys_addr_t max_addr,
                                 int nid);
index ae703ea..a7a0a1a 100644 (file)
@@ -58,7 +58,6 @@ enum mem_cgroup_protection {
 
 struct mem_cgroup_reclaim_cookie {
        pg_data_t *pgdat;
-       int priority;
        unsigned int generation;
 };
 
@@ -81,7 +80,6 @@ struct mem_cgroup_id {
 enum mem_cgroup_events_target {
        MEM_CGROUP_TARGET_THRESH,
        MEM_CGROUP_TARGET_SOFTLIMIT,
-       MEM_CGROUP_TARGET_NUMAINFO,
        MEM_CGROUP_NTARGETS,
 };
 
@@ -112,7 +110,7 @@ struct memcg_shrinker_map {
 };
 
 /*
- * per-zone information in memory controller.
+ * per-node information in memory controller.
  */
 struct mem_cgroup_per_node {
        struct lruvec           lruvec;
@@ -126,7 +124,7 @@ struct mem_cgroup_per_node {
 
        unsigned long           lru_zone_size[MAX_NR_ZONES][NR_LRU_LISTS];
 
-       struct mem_cgroup_reclaim_iter  iter[DEF_PRIORITY + 1];
+       struct mem_cgroup_reclaim_iter  iter;
 
        struct memcg_shrinker_map __rcu *shrinker_map;
 
@@ -134,9 +132,6 @@ struct mem_cgroup_per_node {
        unsigned long           usage_in_excess;/* Set to the value by which */
                                                /* the soft limit is exceeded*/
        bool                    on_tree;
-       bool                    congested;      /* memcg has many dirty pages */
-                                               /* backed by a congested BDI */
-
        struct mem_cgroup       *memcg;         /* Back pointer, we cannot */
                                                /* use container_of        */
 };
@@ -313,13 +308,6 @@ struct mem_cgroup {
        struct list_head kmem_caches;
 #endif
 
-       int last_scanned_node;
-#if MAX_NUMNODES > 1
-       nodemask_t      scan_nodes;
-       atomic_t        numainfo_events;
-       atomic_t        numainfo_updating;
-#endif
-
 #ifdef CONFIG_CGROUP_WRITEBACK
        struct list_head cgwb_list;
        struct wb_domain cgwb_domain;
@@ -394,25 +382,27 @@ mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid)
 }
 
 /**
- * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone
- * @node: node of the wanted lruvec
+ * mem_cgroup_lruvec - get the lru list vector for a memcg & node
  * @memcg: memcg of the wanted lruvec
  *
- * Returns the lru list vector holding pages for a given @node or a given
- * @memcg and @zone. This can be the node lruvec, if the memory controller
- * is disabled.
+ * Returns the lru list vector holding pages for a given @memcg &
+ * @node combination. This can be the node lruvec, if the memory
+ * controller is disabled.
  */
-static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat,
-                               struct mem_cgroup *memcg)
+static inline struct lruvec *mem_cgroup_lruvec(struct mem_cgroup *memcg,
+                                              struct pglist_data *pgdat)
 {
        struct mem_cgroup_per_node *mz;
        struct lruvec *lruvec;
 
        if (mem_cgroup_disabled()) {
-               lruvec = node_lruvec(pgdat);
+               lruvec = &pgdat->__lruvec;
                goto out;
        }
 
+       if (!memcg)
+               memcg = root_mem_cgroup;
+
        mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
        lruvec = &mz->lruvec;
 out:
@@ -728,7 +718,7 @@ static inline void __mod_lruvec_page_state(struct page *page,
                return;
        }
 
-       lruvec = mem_cgroup_lruvec(pgdat, page->mem_cgroup);
+       lruvec = mem_cgroup_lruvec(page->mem_cgroup, pgdat);
        __mod_lruvec_state(lruvec, idx, val);
 }
 
@@ -899,16 +889,21 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new)
 {
 }
 
-static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat,
-                               struct mem_cgroup *memcg)
+static inline struct lruvec *mem_cgroup_lruvec(struct mem_cgroup *memcg,
+                                              struct pglist_data *pgdat)
 {
-       return node_lruvec(pgdat);
+       return &pgdat->__lruvec;
 }
 
 static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page,
                                                    struct pglist_data *pgdat)
 {
-       return &pgdat->lruvec;
+       return &pgdat->__lruvec;
+}
+
+static inline struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
+{
+       return NULL;
 }
 
 static inline bool mm_match_cgroup(struct mm_struct *mm,
index f46ea71..3a08ecd 100644 (file)
@@ -102,13 +102,10 @@ extern unsigned long __offline_isolated_pages(unsigned long start_pfn,
 
 typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
 
+extern void generic_online_page(struct page *page, unsigned int order);
 extern int set_online_page_callback(online_page_callback_t callback);
 extern int restore_online_page_callback(online_page_callback_t callback);
 
-extern void __online_page_set_limits(struct page *page);
-extern void __online_page_increment_counters(struct page *page);
-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,
@@ -229,9 +226,6 @@ void put_online_mems(void);
 void mem_hotplug_begin(void);
 void mem_hotplug_done(void);
 
-extern void set_zone_contiguous(struct zone *zone);
-extern void clear_zone_contiguous(struct zone *zone);
-
 #else /* ! CONFIG_MEMORY_HOTPLUG */
 #define pfn_to_online_page(pfn)                        \
 ({                                             \
@@ -339,6 +333,9 @@ static inline int remove_memory(int nid, u64 start, u64 size)
 static inline void __remove_memory(int nid, u64 start, u64 size) {}
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+extern void set_zone_contiguous(struct zone *zone);
+extern void clear_zone_contiguous(struct zone *zone);
+
 extern void __ref free_area_init_core_hotplug(int nid);
 extern int __add_memory(int nid, u64 start, u64 size);
 extern int add_memory(int nid, u64 start, u64 size);
index 067d146..f8db83a 100644 (file)
 #define TIM_CCER_CC4E  BIT(12) /* Capt/Comp 4  out Ena    */
 #define TIM_CCER_CC4P  BIT(13) /* Capt/Comp 4  Polarity   */
 #define TIM_CCER_CCXE  (BIT(0) | BIT(4) | BIT(8) | BIT(12))
-#define TIM_BDTR_BKE   BIT(12) /* Break input enable      */
-#define TIM_BDTR_BKP   BIT(13) /* Break input polarity    */
+#define TIM_BDTR_BKE(x)        BIT(12 + (x) * 12) /* Break input enable */
+#define TIM_BDTR_BKP(x)        BIT(13 + (x) * 12) /* Break input polarity */
 #define TIM_BDTR_AOE   BIT(14) /* Automatic Output Enable */
 #define TIM_BDTR_MOE   BIT(15) /* Main Output Enable      */
-#define TIM_BDTR_BKF   (BIT(16) | BIT(17) | BIT(18) | BIT(19))
-#define TIM_BDTR_BK2F  (BIT(20) | BIT(21) | BIT(22) | BIT(23))
-#define TIM_BDTR_BK2E  BIT(24) /* Break 2 input enable    */
-#define TIM_BDTR_BK2P  BIT(25) /* Break 2 input polarity  */
+#define TIM_BDTR_BKF(x)        (0xf << (16 + (x) * 4))
 #define TIM_DCR_DBA    GENMASK(4, 0)   /* DMA base addr */
 #define TIM_DCR_DBL    GENMASK(12, 8)  /* DMA burst len */
 
@@ -87,8 +84,7 @@
 #define TIM_CR2_MMS2_SHIFT     20
 #define TIM_SMCR_TS_SHIFT      4
 #define TIM_BDTR_BKF_MASK      0xF
-#define TIM_BDTR_BKF_SHIFT     16
-#define TIM_BDTR_BK2F_SHIFT    20
+#define TIM_BDTR_BKF_SHIFT(x)  (16 + (x) * 4)
 
 enum stm32_timers_dmas {
        STM32_TIMERS_DMA_CH1,
index f61cd12..20c2566 100644 (file)
 #define AT91_MATRIX_DDR_IOSR                   BIT(18)
 #define AT91_MATRIX_NFD0_SELECT                        BIT(24)
 #define AT91_MATRIX_DDR_MP_EN                  BIT(25)
-#define AT91_MATRIX_EBI_NUM_CS                 8
 
 #define AT91_MATRIX_USBPUCR_PUON               BIT(30)
 
index f6fb714..c97ea3b 100644 (file)
@@ -564,21 +564,6 @@ int vma_is_stack_for_current(struct vm_area_struct *vma);
 struct mmu_gather;
 struct inode;
 
-#if !defined(CONFIG_ARCH_HAS_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE)
-static inline int pmd_devmap(pmd_t pmd)
-{
-       return 0;
-}
-static inline int pud_devmap(pud_t pud)
-{
-       return 0;
-}
-static inline int pgd_devmap(pgd_t pgd)
-{
-       return 0;
-}
-#endif
-
 /*
  * FIXME: take this include out, include page-flags.h in
  * files which need it (119 of them)
@@ -1643,19 +1628,27 @@ static inline unsigned long get_mm_counter(struct mm_struct *mm, int member)
        return (unsigned long)val;
 }
 
+void mm_trace_rss_stat(struct mm_struct *mm, int member, long count);
+
 static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
 {
-       atomic_long_add(value, &mm->rss_stat.count[member]);
+       long count = atomic_long_add_return(value, &mm->rss_stat.count[member]);
+
+       mm_trace_rss_stat(mm, member, count);
 }
 
 static inline void inc_mm_counter(struct mm_struct *mm, int member)
 {
-       atomic_long_inc(&mm->rss_stat.count[member]);
+       long count = atomic_long_inc_return(&mm->rss_stat.count[member]);
+
+       mm_trace_rss_stat(mm, member, count);
 }
 
 static inline void dec_mm_counter(struct mm_struct *mm, int member)
 {
-       atomic_long_dec(&mm->rss_stat.count[member]);
+       long count = atomic_long_dec_return(&mm->rss_stat.count[member]);
+
+       mm_trace_rss_stat(mm, member, count);
 }
 
 /* Optimized variant when page is already known not to be PageAnon */
@@ -1845,12 +1838,12 @@ static inline void mm_dec_nr_ptes(struct mm_struct *mm) {}
 int __pte_alloc(struct mm_struct *mm, pmd_t *pmd);
 int __pte_alloc_kernel(pmd_t *pmd);
 
+#if defined(CONFIG_MMU)
+
 /*
- * The following ifdef needed to get the 4level-fixup.h header to work.
- * Remove it when 4level-fixup.h has been removed.
+ * The following ifdef needed to get the 5level-fixup.h header to work.
+ * Remove it when 5level-fixup.h has been removed.
  */
-#if defined(CONFIG_MMU) && !defined(__ARCH_HAS_4LEVEL_HACK)
-
 #ifndef __ARCH_HAS_5LEVEL_HACK
 static inline p4d_t *p4d_alloc(struct mm_struct *mm, pgd_t *pgd,
                unsigned long address)
@@ -1872,7 +1865,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
        return (unlikely(pud_none(*pud)) && __pmd_alloc(mm, pud, address))?
                NULL: pmd_offset(pud, address);
 }
-#endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
+#endif /* CONFIG_MMU */
 
 #if USE_SPLIT_PTE_PTLOCKS
 #if ALLOC_SPLIT_PTLOCKS
@@ -2214,9 +2207,6 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...);
 
 extern void setup_per_cpu_pageset(void);
 
-extern void zone_pcp_update(struct zone *zone);
-extern void zone_pcp_reset(struct zone *zone);
-
 /* page_alloc.c */
 extern int min_free_kbytes;
 extern int watermark_boost_factor;
@@ -2780,7 +2770,7 @@ extern int sysctl_memory_failure_early_kill;
 extern int sysctl_memory_failure_recovery;
 extern void shake_page(struct page *p, int access);
 extern atomic_long_t num_poisoned_pages __read_mostly;
-extern int soft_offline_page(struct page *page, int flags);
+extern int soft_offline_page(unsigned long pfn, int flags);
 
 
 /*
index b0a36d1..89d8ff0 100644 (file)
@@ -273,12 +273,12 @@ enum lru_list {
 
 #define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_ACTIVE_FILE; lru++)
 
-static inline int is_file_lru(enum lru_list lru)
+static inline bool is_file_lru(enum lru_list lru)
 {
        return (lru == LRU_INACTIVE_FILE || lru == LRU_ACTIVE_FILE);
 }
 
-static inline int is_active_lru(enum lru_list lru)
+static inline bool is_active_lru(enum lru_list lru)
 {
        return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE);
 }
@@ -296,6 +296,12 @@ struct zone_reclaim_stat {
        unsigned long           recent_scanned[2];
 };
 
+enum lruvec_flags {
+       LRUVEC_CONGESTED,               /* lruvec has many dirty pages
+                                        * backed by a congested BDI
+                                        */
+};
+
 struct lruvec {
        struct list_head                lists[NR_LRU_LISTS];
        struct zone_reclaim_stat        reclaim_stat;
@@ -303,12 +309,14 @@ struct lruvec {
        atomic_long_t                   inactive_age;
        /* Refaults at the time of last reclaim cycle */
        unsigned long                   refaults;
+       /* Various lruvec state flags (enum lruvec_flags) */
+       unsigned long                   flags;
 #ifdef CONFIG_MEMCG
        struct pglist_data *pgdat;
 #endif
 };
 
-/* Isolate unmapped file */
+/* Isolate unmapped pages */
 #define ISOLATE_UNMAPPED       ((__force isolate_mode_t)0x2)
 /* Isolate for asynchronous migration */
 #define ISOLATE_ASYNC_MIGRATE  ((__force isolate_mode_t)0x4)
@@ -572,9 +580,6 @@ struct zone {
 } ____cacheline_internodealigned_in_smp;
 
 enum pgdat_flags {
-       PGDAT_CONGESTED,                /* pgdat has many dirty pages backed by
-                                        * a congested BDI
-                                        */
        PGDAT_DIRTY,                    /* reclaim scanning has recently found
                                         * many dirty file pages at the tail
                                         * of the LRU.
@@ -777,7 +782,13 @@ typedef struct pglist_data {
 #endif
 
        /* Fields commonly accessed by the page reclaim scanner */
-       struct lruvec           lruvec;
+
+       /*
+        * NOTE: THIS IS UNUSED IF MEMCG IS ENABLED.
+        *
+        * Use mem_cgroup_lruvec() to look up lruvecs.
+        */
+       struct lruvec           __lruvec;
 
        unsigned long           flags;
 
@@ -800,11 +811,6 @@ typedef struct pglist_data {
 #define node_start_pfn(nid)    (NODE_DATA(nid)->node_start_pfn)
 #define node_end_pfn(nid) pgdat_end_pfn(NODE_DATA(nid))
 
-static inline struct lruvec *node_lruvec(struct pglist_data *pgdat)
-{
-       return &pgdat->lruvec;
-}
-
 static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat)
 {
        return pgdat->node_start_pfn + pgdat->node_spanned_pages;
@@ -842,7 +848,7 @@ static inline struct pglist_data *lruvec_pgdat(struct lruvec *lruvec)
 #ifdef CONFIG_MEMCG
        return lruvec->pgdat;
 #else
-       return container_of(lruvec, struct pglist_data, lruvec);
+       return container_of(lruvec, struct pglist_data, __lruvec);
 #endif
 }
 
@@ -1079,7 +1085,7 @@ static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
 /**
  * for_each_zone_zonelist_nodemask - helper macro to iterate over valid zones in a zonelist at or below a given zone index and within a nodemask
  * @zone - The current zone in the iterator
- * @z - The current pointer within zonelist->zones being iterated
+ * @z - The current pointer within zonelist->_zonerefs being iterated
  * @zlist - The zonelist being iterated
  * @highidx - The zone index of the highest zone to return
  * @nodemask - Nodemask allowed by the allocator
index 6d20895..bd165ba 100644 (file)
@@ -1,11 +1,14 @@
-#ifndef _LINUX_MODULE_H
-#define _LINUX_MODULE_H
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Dynamic loading of modules into the kernel.
  *
  * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
  * Rewritten again by Rusty Russell, 2002
  */
+
+#ifndef _LINUX_MODULE_H
+#define _LINUX_MODULE_H
+
 #include <linux/list.h>
 #include <linux/stat.h>
 #include <linux/compiler.h>
index 5229c18..ca92aea 100644 (file)
@@ -91,7 +91,7 @@ void module_arch_cleanup(struct module *mod);
 /* Any cleanup before freeing mod->module_init */
 void module_arch_freeing_init(struct module *mod);
 
-#ifdef CONFIG_KASAN
+#if defined(CONFIG_KASAN) && !defined(CONFIG_KASAN_VMALLOC)
 #include <linux/kasan.h>
 #define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
 #else
index 5ba250d..e5c3e23 100644 (file)
@@ -100,11 +100,11 @@ struct kparam_array
 
 /**
  * module_param - typesafe helper for a module/cmdline parameter
- * @value: the variable to alter, and exposed parameter name.
+ * @name: the variable to alter, and exposed parameter name.
  * @type: the type of the parameter
  * @perm: visibility in sysfs.
  *
- * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
+ * @name becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
  * ".") the kernel commandline parameter.  Note that - is changed to _, so
  * the user can use "foo-bar=1" even for variable "foo_bar".
  *
index 397a08a..7fe7b87 100644 (file)
@@ -60,6 +60,7 @@ extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
 extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
+extern struct dentry *lookup_positive_unlocked(const char *, struct dentry *, int);
 
 extern int follow_down_one(struct path *);
 extern int follow_down(struct path *);
index 0096a05..0189476 100644 (file)
@@ -150,10 +150,6 @@ extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
 extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
                struct notifier_block *nb);
 
-extern int blocking_notifier_chain_cond_register(
-               struct blocking_notifier_head *nh,
-               struct notifier_block *nb);
-
 extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
                struct notifier_block *nb);
 extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
index 30e40fb..eac7ab1 100644 (file)
@@ -12,6 +12,7 @@ struct of_pci_range_parser {
        const __be32 *end;
        int np;
        int pna;
+       bool dma;
 };
 
 struct of_pci_range {
@@ -33,10 +34,6 @@ extern u64 of_translate_dma_address(struct device_node *dev,
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern int of_address_to_resource(struct device_node *dev, int index,
                                  struct resource *r);
-extern struct device_node *of_find_matching_node_by_address(
-                                       struct device_node *from,
-                                       const struct of_device_id *matches,
-                                       u64 base_address);
 extern void __iomem *of_iomap(struct device_node *device, int index);
 void __iomem *of_io_request_and_map(struct device_node *device,
                                    int index, const char *name);
@@ -55,8 +52,6 @@ extern int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
 extern struct of_pci_range *of_pci_range_parser_one(
                                        struct of_pci_range_parser *parser,
                                        struct of_pci_range *range);
-extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
-                               u64 *paddr, u64 *size);
 extern bool of_dma_is_coherent(struct device_node *np);
 #else /* CONFIG_OF_ADDRESS */
 static inline void __iomem *of_io_request_and_map(struct device_node *device,
@@ -71,14 +66,6 @@ static inline u64 of_translate_address(struct device_node *np,
        return OF_BAD_ADDR;
 }
 
-static inline struct device_node *of_find_matching_node_by_address(
-                                       struct device_node *from,
-                                       const struct of_device_id *matches,
-                                       u64 base_address)
-{
-       return NULL;
-}
-
 static inline const __be32 *of_get_address(struct device_node *dev, int index,
                                        u64 *size, unsigned int *flags)
 {
@@ -104,12 +91,6 @@ static inline struct of_pci_range *of_pci_range_parser_one(
        return NULL;
 }
 
-static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
-                               u64 *paddr, u64 *size)
-{
-       return -ENODEV;
-}
-
 static inline bool of_dma_is_coherent(struct device_node *np)
 {
        return false;
index 21a89c4..29658c0 100644 (file)
@@ -2,11 +2,10 @@
 #ifndef __OF_PCI_H
 #define __OF_PCI_H
 
-#include <linux/pci.h>
-#include <linux/msi.h>
+#include <linux/types.h>
+#include <linux/errno.h>
 
 struct pci_dev;
-struct of_phandle_args;
 struct device_node;
 
 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_PCI)
index 1099c2f..6861df7 100644 (file)
@@ -30,7 +30,7 @@ static inline bool is_migrate_isolate(int migratetype)
 }
 #endif
 
-#define SKIP_HWPOISON  0x1
+#define MEMORY_OFFLINE 0x1
 #define REPORT_FAILURE 0x2
 
 bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
@@ -58,7 +58,7 @@ undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
  * Test all pages in [start_pfn, end_pfn) are isolated or not.
  */
 int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
-                       bool skip_hwpoisoned_pages);
+                       int isol_flags);
 
 struct page *alloc_migrate_target(struct page *page, unsigned long private);
 
index 1ebb88e..5d62e78 100644 (file)
@@ -4,74 +4,39 @@
 
 #include <linux/pci.h>
 
-#ifdef CONFIG_PCI_PRI
+#ifdef CONFIG_PCI_ATS
+/* Address Translation Service */
+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 /* CONFIG_PCI_ATS */
+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 /* CONFIG_PCI_ATS */
 
+#ifdef CONFIG_PCI_PRI
 int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
 void pci_disable_pri(struct pci_dev *pdev);
-void pci_restore_pri_state(struct pci_dev *pdev);
 int pci_reset_pri(struct pci_dev *pdev);
-
-#else /* CONFIG_PCI_PRI */
-
-static inline int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
-{
-       return -ENODEV;
-}
-
-static inline void pci_disable_pri(struct pci_dev *pdev)
-{
-}
-
-static inline void pci_restore_pri_state(struct pci_dev *pdev)
-{
-}
-
-static inline int pci_reset_pri(struct pci_dev *pdev)
-{
-       return -ENODEV;
-}
-
+int pci_prg_resp_pasid_required(struct pci_dev *pdev);
 #endif /* CONFIG_PCI_PRI */
 
 #ifdef CONFIG_PCI_PASID
-
 int pci_enable_pasid(struct pci_dev *pdev, int features);
 void pci_disable_pasid(struct pci_dev *pdev);
-void pci_restore_pasid_state(struct pci_dev *pdev);
 int pci_pasid_features(struct pci_dev *pdev);
 int pci_max_pasids(struct pci_dev *pdev);
-int pci_prg_resp_pasid_required(struct pci_dev *pdev);
-
-#else  /* CONFIG_PCI_PASID */
-
-static inline int pci_enable_pasid(struct pci_dev *pdev, int features)
-{
-       return -EINVAL;
-}
-
-static inline void pci_disable_pasid(struct pci_dev *pdev)
-{
-}
-
-static inline void pci_restore_pasid_state(struct pci_dev *pdev)
-{
-}
-
+#else /* CONFIG_PCI_PASID */
 static inline int pci_pasid_features(struct pci_dev *pdev)
-{
-       return -EINVAL;
-}
-
+{ return -EINVAL; }
 static inline int pci_max_pasids(struct pci_dev *pdev)
-{
-       return -EINVAL;
-}
-
-static inline int pci_prg_resp_pasid_required(struct pci_dev *pdev)
-{
-       return 0;
-}
+{ return -EINVAL; }
 #endif /* CONFIG_PCI_PASID */
 
-
-#endif /* LINUX_PCI_ATS_H*/
+#endif /* LINUX_PCI_ATS_H */
index f641bad..56f1846 100644 (file)
@@ -117,7 +117,7 @@ struct pci_epc_features {
        unsigned int    msix_capable : 1;
        u8      reserved_bar;
        u8      bar_fixed_64bit;
-       u64     bar_fixed_size[BAR_5 + 1];
+       u64     bar_fixed_size[PCI_STD_NUM_BARS];
        size_t  align;
 };
 
index eb9f371..c393dff 100644 (file)
@@ -82,7 +82,7 @@ enum pci_mmap_state {
 enum {
        /* #0-5: standard PCI resources */
        PCI_STD_RESOURCES,
-       PCI_STD_RESOURCE_END = 5,
+       PCI_STD_RESOURCE_END = PCI_STD_RESOURCES + PCI_STD_NUM_BARS - 1,
 
        /* #6: expansion ROM resource */
        PCI_ROM_RESOURCE,
@@ -284,7 +284,6 @@ struct irq_affinity;
 struct pcie_link_state;
 struct pci_vpd;
 struct pci_sriov;
-struct pci_ats;
 struct pci_p2pdma;
 
 /* The pci_dev structure describes PCI devices */
@@ -452,12 +451,14 @@ struct pci_dev {
        };
        u16             ats_cap;        /* ATS Capability offset */
        u8              ats_stu;        /* ATS Smallest Translation Unit */
-       atomic_t        ats_ref_cnt;    /* Number of VFs with ATS enabled */
 #endif
 #ifdef CONFIG_PCI_PRI
+       u16             pri_cap;        /* PRI Capability offset */
        u32             pri_reqs_alloc; /* Number of PRI requests allocated */
+       unsigned int    pasid_required:1; /* PRG Response PASID Required */
 #endif
 #ifdef CONFIG_PCI_PASID
+       u16             pasid_cap;      /* PASID Capability offset */
        u16             pasid_features;
 #endif
 #ifdef CONFIG_PCI_P2PDMA
@@ -805,8 +806,6 @@ struct module;
  *             The remove function always gets called from process
  *             context, so it can sleep.
  * @suspend:   Put device into low power state.
- * @suspend_late: Put device into low power state.
- * @resume_early: Wake device from low power state.
  * @resume:    Wake device from low power state.
  *             (Please see Documentation/power/pci.rst for descriptions
  *             of PCI Power Management and the related functions.)
@@ -829,8 +828,6 @@ struct pci_driver {
        int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);     /* New device inserted */
        void (*remove)(struct pci_dev *dev);    /* Device removed (NULL if not a hot-plug capable driver) */
        int  (*suspend)(struct pci_dev *dev, pm_message_t state);       /* Device suspended */
-       int  (*suspend_late)(struct pci_dev *dev, pm_message_t state);
-       int  (*resume_early)(struct pci_dev *dev);
        int  (*resume)(struct pci_dev *dev);    /* Device woken up */
        void (*shutdown)(struct pci_dev *dev);
        int  (*sriov_configure)(struct pci_dev *dev, int num_vfs); /* On PF */
@@ -1232,7 +1229,7 @@ struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
 int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size);
 int pci_add_ext_cap_save_buffer(struct pci_dev *dev,
                                u16 cap, unsigned int size);
-int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
+int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state);
 int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
 bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
@@ -1454,7 +1451,6 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
 void pci_free_irq_vectors(struct pci_dev *dev);
 int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
 const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec);
-int pci_irq_get_node(struct pci_dev *pdev, int vec);
 
 #else
 static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
@@ -1497,11 +1493,6 @@ static inline const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev,
 {
        return cpu_possible_mask;
 }
-
-static inline int pci_irq_get_node(struct pci_dev *pdev, int vec)
-{
-       return first_online_node;
-}
 #endif
 
 /**
@@ -1544,9 +1535,13 @@ extern bool pcie_ports_native;
 #define pcie_ports_native      false
 #endif
 
-#define PCIE_LINK_STATE_L0S    1
-#define PCIE_LINK_STATE_L1     2
-#define PCIE_LINK_STATE_CLKPM  4
+#define PCIE_LINK_STATE_L0S            BIT(0)
+#define PCIE_LINK_STATE_L1             BIT(1)
+#define PCIE_LINK_STATE_CLKPM          BIT(2)
+#define PCIE_LINK_STATE_L1_1           BIT(3)
+#define PCIE_LINK_STATE_L1_2           BIT(4)
+#define PCIE_LINK_STATE_L1_1_PCIPM     BIT(5)
+#define PCIE_LINK_STATE_L1_2_PCIPM     BIT(6)
 
 #ifdef CONFIG_PCIEASPM
 int pci_disable_link_state(struct pci_dev *pdev, int state);
@@ -1777,19 +1772,6 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
                                              NULL);
 }
 
-#ifdef CONFIG_PCI_ATS
-/* Address Translation Service */
-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 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>
@@ -2279,6 +2261,7 @@ struct irq_domain;
 struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus);
 int pci_parse_request_of_pci_ranges(struct device *dev,
                                    struct list_head *resources,
+                                   struct list_head *ib_resources,
                                    struct resource **bus_range);
 
 /* Arch may override this (weak) */
@@ -2287,9 +2270,11 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus);
 #else  /* CONFIG_OF */
 static inline struct irq_domain *
 pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
-static inline int pci_parse_request_of_pci_ranges(struct device *dev,
-                                                 struct list_head *resources,
-                                                 struct resource **bus_range)
+static inline int
+pci_parse_request_of_pci_ranges(struct device *dev,
+                               struct list_head *resources,
+                               struct list_head *ib_resources,
+                               struct resource **bus_range)
 {
        return -EINVAL;
 }
@@ -2403,4 +2388,12 @@ void pci_uevent_ers(struct pci_dev *pdev, enum  pci_ers_result err_type);
 #define pci_info_ratelimited(pdev, fmt, arg...) \
        dev_info_ratelimited(&(pdev)->dev, fmt, ##arg)
 
+#define pci_WARN(pdev, condition, fmt, arg...) \
+       WARN(condition, "%s %s: " fmt, \
+            dev_driver_string(&(pdev)->dev), pci_name(pdev), ##arg)
+
+#define pci_WARN_ONCE(pdev, condition, fmt, arg...) \
+       WARN_ONCE(condition, "%s %s: " fmt, \
+                 dev_driver_string(&(pdev)->dev), pci_name(pdev), ##arg)
+
 #endif /* LINUX_PCI_H */
index 21a5724..2302d13 100644 (file)
 #define PCI_DEVICE_ID_INTEL_84460GX    0x84ea
 #define PCI_DEVICE_ID_INTEL_IXP4XX     0x8500
 #define PCI_DEVICE_ID_INTEL_IXP2800    0x9004
+#define PCI_DEVICE_ID_INTEL_VMD_9A0B   0x9a0b
 #define PCI_DEVICE_ID_INTEL_S21152BB   0xb152
 
 #define PCI_VENDOR_ID_SCALEMP          0x8686
index 7aef0ab..390031e 100644 (file)
@@ -186,14 +186,14 @@ static inline void percpu_ref_get_many(struct percpu_ref *ref, unsigned long nr)
 {
        unsigned long __percpu *percpu_count;
 
-       rcu_read_lock_sched();
+       rcu_read_lock();
 
        if (__ref_is_percpu(ref, &percpu_count))
                this_cpu_add(*percpu_count, nr);
        else
                atomic_long_add(nr, &ref->count);
 
-       rcu_read_unlock_sched();
+       rcu_read_unlock();
 }
 
 /**
@@ -223,7 +223,7 @@ static inline bool percpu_ref_tryget(struct percpu_ref *ref)
        unsigned long __percpu *percpu_count;
        bool ret;
 
-       rcu_read_lock_sched();
+       rcu_read_lock();
 
        if (__ref_is_percpu(ref, &percpu_count)) {
                this_cpu_inc(*percpu_count);
@@ -232,7 +232,7 @@ static inline bool percpu_ref_tryget(struct percpu_ref *ref)
                ret = atomic_long_inc_not_zero(&ref->count);
        }
 
-       rcu_read_unlock_sched();
+       rcu_read_unlock();
 
        return ret;
 }
@@ -257,7 +257,7 @@ static inline bool percpu_ref_tryget_live(struct percpu_ref *ref)
        unsigned long __percpu *percpu_count;
        bool ret = false;
 
-       rcu_read_lock_sched();
+       rcu_read_lock();
 
        if (__ref_is_percpu(ref, &percpu_count)) {
                this_cpu_inc(*percpu_count);
@@ -266,7 +266,7 @@ static inline bool percpu_ref_tryget_live(struct percpu_ref *ref)
                ret = atomic_long_inc_not_zero(&ref->count);
        }
 
-       rcu_read_unlock_sched();
+       rcu_read_unlock();
 
        return ret;
 }
@@ -285,14 +285,14 @@ static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr)
 {
        unsigned long __percpu *percpu_count;
 
-       rcu_read_lock_sched();
+       rcu_read_lock();
 
        if (__ref_is_percpu(ref, &percpu_count))
                this_cpu_sub(*percpu_count, nr);
        else if (unlikely(atomic_long_sub_and_test(nr, &ref->count)))
                ref->release(ref);
 
-       rcu_read_unlock_sched();
+       rcu_read_unlock();
 }
 
 /**
index eab7036..30098a5 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/notifier.h>
 
+#include <linux/mfd/cros_ec.h>
 #include <linux/platform_data/cros_ec_commands.h>
 
 #define CROS_EC_DEV_NAME       "cros_ec"
@@ -115,12 +116,16 @@ struct cros_ec_command {
  *            code.
  * @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.
+ * @mkbp_event_supported: 0 if MKBP not supported. Otherwise its value is
+ *                        the maximum supported version of the MKBP host event
+ *                        command + 1.
  * @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.
  * @host_event_wake_mask: Mask of host events that cause wake from suspend.
+ * @last_event_time: exact time from the hard irq when we got notified of
+ *     a new event.
  * @ec: The platform_device used by the mfd driver to interface with the
  *      main EC.
  * @pd: The platform_device used by the mfd driver to interface with the
@@ -153,7 +158,7 @@ struct cros_ec_device {
        int (*pkt_xfer)(struct cros_ec_device *ec,
                        struct cros_ec_command *msg);
        struct mutex lock;
-       bool mkbp_event_supported;
+       u8 mkbp_event_supported;
        bool host_sleep_v1;
        struct blocking_notifier_head event_notifier;
 
@@ -161,20 +166,13 @@ struct cros_ec_device {
        int event_size;
        u32 host_event_wake_mask;
        u32 last_resume_result;
+       ktime_t last_event_time;
 
        /* The platform devices used by the mfd driver */
        struct platform_device *ec;
        struct platform_device *pd;
 };
 
-/**
- * struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
- * @sensor_num: Id of the sensor, as reported by the EC.
- */
-struct cros_ec_sensor_platform {
-       u8 sensor_num;
-};
-
 /**
  * struct cros_ec_platform - ChromeOS EC platform information.
  * @ec_name: Name of EC device (e.g. 'cros-ec', 'cros-pd', ...)
@@ -187,133 +185,51 @@ struct cros_ec_platform {
        u16 cmd_offset;
 };
 
-/**
- * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
- * @ec_dev: Device to suspend.
- *
- * This can be called by drivers to handle a suspend event.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_suspend(struct cros_ec_device *ec_dev);
 
-/**
- * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
- * @ec_dev: Device to resume.
- *
- * This can be called by drivers to handle a resume event.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_resume(struct cros_ec_device *ec_dev);
 
-/**
- * cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
- * @ec_dev: Device to register.
- * @msg: Message to write.
- *
- * This is intended to be used by all ChromeOS EC drivers, but at present
- * only SPI uses it. Once LPC uses the same protocol it can start using it.
- * I2C could use it now, with a refactor of the existing code.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
                       struct cros_ec_command *msg);
 
-/**
- * cros_ec_check_result() - Check ec_msg->result.
- * @ec_dev: EC device.
- * @msg: Message to check.
- *
- * This is used by ChromeOS EC drivers to check the ec_msg->result for
- * errors and to warn about them.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_check_result(struct cros_ec_device *ec_dev,
                         struct cros_ec_command *msg);
 
-/**
- * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
- * @ec_dev: EC device.
- * @msg: Message to write.
- *
- * Call this to send a command to the ChromeOS EC.  This should be used
- * instead of calling the EC's cmd_xfer() callback directly.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
                     struct cros_ec_command *msg);
 
-/**
- * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
- * @ec_dev: EC device.
- * @msg: Message to write.
- *
- * This function is identical to cros_ec_cmd_xfer, except it returns success
- * status only if both the command was transmitted successfully and the EC
- * replied with success status. It's not necessary to check msg->result when
- * using this function.
- *
- * Return: The number of bytes transferred on success or negative error code.
- */
 int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
                            struct cros_ec_command *msg);
 
-/**
- * cros_ec_register() - Register a new ChromeOS EC, using the provided info.
- * @ec_dev: Device to register.
- *
- * Before calling this, allocate a pointer to a new device and then fill
- * in all the fields up to the --private-- marker.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_register(struct cros_ec_device *ec_dev);
 
-/**
- * cros_ec_unregister() - Remove a ChromeOS EC.
- * @ec_dev: Device to unregister.
- *
- * Call this to deregister a ChromeOS EC, then clean up any private data.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_unregister(struct cros_ec_device *ec_dev);
 
-/**
- * cros_ec_query_all() -  Query the protocol version supported by the
- *         ChromeOS EC.
- * @ec_dev: Device to register.
- *
- * Return: 0 on success or negative error code.
- */
 int cros_ec_query_all(struct cros_ec_device *ec_dev);
 
-/**
- * cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.
- * @ec_dev: Device to fetch event from.
- * @wake_event: Pointer to a bool set to true upon return if the event might be
- *              treated as a wake event. Ignored if null.
- *
- * Return: negative error code on errors; 0 for no data; or else number of
- * bytes received (i.e., an event was retrieved successfully). Event types are
- * written out to @ec_dev->event_data.event_type on success.
- */
-int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
+int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
+                          bool *wake_event,
+                          bool *has_more_events);
+
+u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
+
+int cros_ec_check_features(struct cros_ec_dev *ec, int feature);
+
+int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
+
+bool cros_ec_handle_event(struct cros_ec_device *ec_dev);
 
 /**
- * cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.
- * @ec_dev: Device to fetch event from.
+ * cros_ec_get_time_ns() - Return time in ns.
  *
- * When MKBP is supported, when the EC raises an interrupt, we collect the
- * events raised and call the functions in the ec notifier. This function
- * is a helper to know which events are raised.
+ * This is the function used to record the time for last_event_time in struct
+ * cros_ec_device during the hard irq.
  *
- * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
+ * Return: ktime_t format since boot.
  */
-u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
+static inline ktime_t cros_ec_get_time_ns(void)
+{
+       return ktime_get_boottime_ns();
+}
 
 #endif /* __LINUX_CROS_EC_PROTO_H */
diff --git a/include/linux/platform_data/cros_ec_sensorhub.h b/include/linux/platform_data/cros_ec_sensorhub.h
new file mode 100644 (file)
index 0000000..bef7ffc
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Chrome OS EC MEMS Sensor Hub driver.
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
+#define __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
+
+#include <linux/platform_data/cros_ec_commands.h>
+
+/**
+ * struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
+ * @sensor_num: Id of the sensor, as reported by the EC.
+ */
+struct cros_ec_sensor_platform {
+       u8 sensor_num;
+};
+
+/**
+ * struct cros_ec_sensorhub - Sensor Hub device data.
+ *
+ * @ec: Embedded Controller where the hub is located.
+ */
+struct cros_ec_sensorhub {
+       struct cros_ec_dev *ec;
+};
+
+#endif   /* __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H */
diff --git a/include/linux/platform_data/ti-prm.h b/include/linux/platform_data/ti-prm.h
new file mode 100644 (file)
index 0000000..28154c3
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * TI PRM (Power & Reset Manager) platform data
+ *
+ * Copyright (C) 2019 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ */
+
+#ifndef _LINUX_PLATFORM_DATA_TI_PRM_H
+#define _LINUX_PLATFORM_DATA_TI_PRM_H
+
+struct clockdomain;
+
+struct ti_prm_platform_data {
+       void (*clkdm_deny_idle)(struct clockdomain *clkdm);
+       void (*clkdm_allow_idle)(struct clockdomain *clkdm);
+       struct clockdomain * (*clkdm_lookup)(const char *name);
+};
+
+#endif /* _LINUX_PLATFORM_DATA_TI_PRM_H */
index ad03b58..afede15 100644 (file)
@@ -29,6 +29,7 @@
  * @data_size: Size of the data buffer used for EC communication.
  * @debugfs_pdev: The child platform_device used by the debugfs sub-driver.
  * @rtc_pdev: The child platform_device used by the RTC sub-driver.
+ * @charger_pdev: Child platform_device used by the charger config sub-driver.
  * @telem_pdev: The child platform_device used by the telemetry sub-driver.
  */
 struct wilco_ec_device {
@@ -41,6 +42,7 @@ struct wilco_ec_device {
        size_t data_size;
        struct platform_device *debugfs_pdev;
        struct platform_device *rtc_pdev;
+       struct platform_device *charger_pdev;
        struct platform_device *telem_pdev;
 };
 
@@ -120,6 +122,19 @@ struct wilco_ec_message {
  */
 int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg);
 
+/**
+ * wilco_keyboard_leds_init() - Set up the keyboard backlight LEDs.
+ * @ec: EC device to query.
+ *
+ * After this call, the keyboard backlight will be exposed through a an LED
+ * device at /sys/class/leds.
+ *
+ * This may sleep because it uses wilco_ec_mailbox().
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int wilco_keyboard_leds_init(struct wilco_ec_device *ec);
+
 /*
  * A Property is typically a data item that is stored to NVRAM
  * by the EC. Each of these data items has an index associated
index ebf5ef1..19eafca 100644 (file)
@@ -34,6 +34,8 @@ enum pm_qos_flags_status {
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT    PM_QOS_LATENCY_ANY
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
+#define PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE     0
+#define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE     FREQ_QOS_MAX_DEFAULT_VALUE
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
@@ -49,21 +51,6 @@ struct pm_qos_flags_request {
        s32 flags;      /* Do not change to 64 bit */
 };
 
-enum dev_pm_qos_req_type {
-       DEV_PM_QOS_RESUME_LATENCY = 1,
-       DEV_PM_QOS_LATENCY_TOLERANCE,
-       DEV_PM_QOS_FLAGS,
-};
-
-struct dev_pm_qos_request {
-       enum dev_pm_qos_req_type type;
-       union {
-               struct plist_node pnode;
-               struct pm_qos_flags_request flr;
-       } data;
-       struct device *dev;
-};
-
 enum pm_qos_type {
        PM_QOS_UNITIALIZED,
        PM_QOS_MAX,             /* return the largest value */
@@ -90,9 +77,51 @@ struct pm_qos_flags {
        s32 effective_flags;    /* Do not change to 64 bit */
 };
 
+
+#define FREQ_QOS_MIN_DEFAULT_VALUE     0
+#define FREQ_QOS_MAX_DEFAULT_VALUE     S32_MAX
+
+enum freq_qos_req_type {
+       FREQ_QOS_MIN = 1,
+       FREQ_QOS_MAX,
+};
+
+struct freq_constraints {
+       struct pm_qos_constraints min_freq;
+       struct blocking_notifier_head min_freq_notifiers;
+       struct pm_qos_constraints max_freq;
+       struct blocking_notifier_head max_freq_notifiers;
+};
+
+struct freq_qos_request {
+       enum freq_qos_req_type type;
+       struct plist_node pnode;
+       struct freq_constraints *qos;
+};
+
+
+enum dev_pm_qos_req_type {
+       DEV_PM_QOS_RESUME_LATENCY = 1,
+       DEV_PM_QOS_LATENCY_TOLERANCE,
+       DEV_PM_QOS_MIN_FREQUENCY,
+       DEV_PM_QOS_MAX_FREQUENCY,
+       DEV_PM_QOS_FLAGS,
+};
+
+struct dev_pm_qos_request {
+       enum dev_pm_qos_req_type type;
+       union {
+               struct plist_node pnode;
+               struct pm_qos_flags_request flr;
+               struct freq_qos_request freq;
+       } data;
+       struct device *dev;
+};
+
 struct dev_pm_qos {
        struct pm_qos_constraints resume_latency;
        struct pm_qos_constraints latency_tolerance;
+       struct freq_constraints freq;
        struct pm_qos_flags flags;
        struct dev_pm_qos_request *resume_latency_req;
        struct dev_pm_qos_request *latency_tolerance_req;
@@ -191,6 +220,10 @@ static inline s32 dev_pm_qos_read_value(struct device *dev,
        switch (type) {
        case DEV_PM_QOS_RESUME_LATENCY:
                return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
        default:
                WARN_ON(1);
                return 0;
@@ -255,27 +288,6 @@ static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
 }
 #endif
 
-#define FREQ_QOS_MIN_DEFAULT_VALUE     0
-#define FREQ_QOS_MAX_DEFAULT_VALUE     (-1)
-
-enum freq_qos_req_type {
-       FREQ_QOS_MIN = 1,
-       FREQ_QOS_MAX,
-};
-
-struct freq_constraints {
-       struct pm_qos_constraints min_freq;
-       struct blocking_notifier_head min_freq_notifiers;
-       struct pm_qos_constraints max_freq;
-       struct blocking_notifier_head max_freq_notifiers;
-};
-
-struct freq_qos_request {
-       enum freq_qos_req_type type;
-       struct plist_node pnode;
-       struct freq_constraints *qos;
-};
-
 static inline int freq_qos_request_active(struct freq_qos_request *req)
 {
        return !IS_ERR_OR_NULL(req->qos);
@@ -291,6 +303,8 @@ int freq_qos_add_request(struct freq_constraints *qos,
                         enum freq_qos_req_type type, s32 value);
 int freq_qos_update_request(struct freq_qos_request *req, s32 new_value);
 int freq_qos_remove_request(struct freq_qos_request *req);
+int freq_qos_apply(struct freq_qos_request *req,
+                  enum pm_qos_req_action action, s32 value);
 
 int freq_qos_add_notifier(struct freq_constraints *qos,
                          enum freq_qos_req_type type,
index 661efa0..aa3da66 100644 (file)
@@ -63,6 +63,11 @@ struct wakeup_source {
        bool                    autosleep_enabled:1;
 };
 
+#define for_each_wakeup_source(ws) \
+       for ((ws) = wakeup_sources_walk_start();        \
+            (ws);                                      \
+            (ws) = wakeup_sources_walk_next((ws)))
+
 #ifdef CONFIG_PM_SLEEP
 
 /*
@@ -92,6 +97,10 @@ extern void wakeup_source_remove(struct wakeup_source *ws);
 extern struct wakeup_source *wakeup_source_register(struct device *dev,
                                                    const char *name);
 extern void wakeup_source_unregister(struct wakeup_source *ws);
+extern int wakeup_sources_read_lock(void);
+extern void wakeup_sources_read_unlock(int idx);
+extern struct wakeup_source *wakeup_sources_walk_start(void);
+extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws);
 extern int device_wakeup_enable(struct device *dev);
 extern int device_wakeup_disable(struct device *dev);
 extern void device_set_wakeup_capable(struct device *dev, bool capable);
index a705aa2..0640be5 100644 (file)
@@ -58,8 +58,8 @@ extern int remove_proc_subtree(const char *, struct proc_dir_entry *);
 struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
                struct proc_dir_entry *parent, const struct seq_operations *ops,
                unsigned int state_size, void *data);
-#define proc_create_net(name, mode, parent, state_size, ops) \
-       proc_create_net_data(name, mode, parent, state_size, ops, NULL)
+#define proc_create_net(name, mode, parent, ops, state_size) \
+       proc_create_net_data(name, mode, parent, ops, state_size, NULL)
 struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
                struct proc_dir_entry *parent,
                int (*show)(struct seq_file *, void *), void *data);
index b2c9c46..0ef808d 100644 (file)
@@ -243,10 +243,7 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
  * @request: optional hook for requesting a PWM
  * @free: optional hook for freeing a PWM
  * @capture: capture and report PWM signal
- * @apply: atomically apply a new PWM config. The state argument
- *        should be adjusted with the real hardware config (if the
- *        approximate the period or duty_cycle value, state should
- *        reflect it)
+ * @apply: atomically apply a new PWM config
  * @get_state: get the current PWM state. This function is only
  *            called once per PWM device when the PWM chip is
  *            registered.
index 2d5eff5..ffd72b3 100644 (file)
@@ -58,6 +58,7 @@ extern int qcom_scm_set_remote_state(u32 state, u32 id);
 extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
 extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
 extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
+extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
 extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
 extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
 #else
@@ -97,6 +98,7 @@ qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
 static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
 static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
 static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
+static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; }
 static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; }
 static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; }
 #endif
index fdd421b..724b0d0 100644 (file)
@@ -283,14 +283,12 @@ __rb_erase_augmented(struct rb_node *node, struct rb_root *root,
                __rb_change_child(node, successor, tmp, root);
 
                if (child2) {
-                       successor->__rb_parent_color = pc;
                        rb_set_parent_color(child2, parent, RB_BLACK);
                        rebalance = NULL;
                } else {
-                       unsigned long pc2 = successor->__rb_parent_color;
-                       successor->__rb_parent_color = pc;
-                       rebalance = __rb_is_black(pc2) ? parent : NULL;
+                       rebalance = rb_is_black(successor) ? parent : NULL;
                }
+               successor->__rb_parent_color = pc;
                tmp = successor;
        }
 
index eaae6b4..ec35814 100644 (file)
@@ -62,7 +62,8 @@ struct reset_control_lookup {
  * @of_node: corresponding device tree node as phandle target
  * @of_reset_n_cells: number of cells in reset line specifiers
  * @of_xlate: translation function to translate from specifier as found in the
- *            device tree to id as given to the reset control ops
+ *            device tree to id as given to the reset control ops, defaults
+ *            to :c:func:`of_reset_simple_xlate`.
  * @nr_resets: number of reset controls in this reset controller device
  */
 struct reset_controller_dev {
index eb597e8..05aa9f4 100644 (file)
@@ -203,12 +203,34 @@ static inline struct reset_control *reset_control_get_shared(
        return __reset_control_get(dev, id, 0, true, false, false);
 }
 
+/**
+ * reset_control_get_optional_exclusive - optional reset_control_get_exclusive()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Optional variant of reset_control_get_exclusive(). If the requested reset
+ * is not specified in the device tree, this function returns NULL instead of
+ * an error.
+ *
+ * See reset_control_get_exclusive() for more information.
+ */
 static inline struct reset_control *reset_control_get_optional_exclusive(
                                        struct device *dev, const char *id)
 {
        return __reset_control_get(dev, id, 0, false, true, true);
 }
 
+/**
+ * reset_control_get_optional_shared - optional reset_control_get_shared()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Optional variant of reset_control_get_shared(). If the requested reset
+ * is not specified in the device tree, this function returns NULL instead of
+ * an error.
+ *
+ * See reset_control_get_shared() for more information.
+ */
 static inline struct reset_control *reset_control_get_optional_shared(
                                        struct device *dev, const char *id)
 {
@@ -354,12 +376,36 @@ static inline struct reset_control *devm_reset_control_get_shared(
        return __devm_reset_control_get(dev, id, 0, true, false, false);
 }
 
+/**
+ * devm_reset_control_get_optional_exclusive - resource managed
+ *                                             reset_control_get_optional_exclusive()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get_optional_exclusive(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_get_optional_exclusive() for more information.
+ */
 static inline struct reset_control *devm_reset_control_get_optional_exclusive(
                                        struct device *dev, const char *id)
 {
        return __devm_reset_control_get(dev, id, 0, false, true, true);
 }
 
+/**
+ * devm_reset_control_get_optional_shared - resource managed
+ *                                          reset_control_get_optional_shared()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get_optional_shared(). For reset controllers returned
+ * from this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_get_optional_shared() for more information.
+ */
 static inline struct reset_control *devm_reset_control_get_optional_shared(
                                        struct device *dev, const char *id)
 {
index 06da59b..ff0339d 100644 (file)
@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resource_entry *entry)
 #define resource_list_for_each_entry_safe(entry, tmp, list)    \
        list_for_each_entry_safe((entry), (tmp), (list), node)
 
+static inline struct resource_entry *
+resource_list_first_type(struct list_head *list, unsigned long type)
+{
+       struct resource_entry *entry;
+
+       resource_list_for_each_entry(entry, list) {
+               if (resource_type(entry->res) == type)
+                       return entry;
+       }
+       return NULL;
+}
+
 #endif /* _LINUX_RESOURCE_EXT_H */
index df666cf..4e9d3c7 100644 (file)
@@ -159,11 +159,16 @@ struct rtc_device {
 };
 #define to_rtc_device(d) container_of(d, struct rtc_device, dev)
 
+#define rtc_lock(d) mutex_lock(&d->ops_lock)
+#define rtc_unlock(d) mutex_unlock(&d->ops_lock)
+
 /* useful timestamps */
+#define RTC_TIMESTAMP_BEGIN_0000       -62167219200ULL /* 0000-01-01 00:00:00 */
 #define RTC_TIMESTAMP_BEGIN_1900       -2208988800LL /* 1900-01-01 00:00:00 */
 #define RTC_TIMESTAMP_BEGIN_2000       946684800LL /* 2000-01-01 00:00:00 */
 #define RTC_TIMESTAMP_END_2063         2966371199LL /* 2063-12-31 23:59:59 */
 #define RTC_TIMESTAMP_END_2099         4102444799LL /* 2099-12-31 23:59:59 */
+#define RTC_TIMESTAMP_END_2199         7258118399LL /* 2199-12-31 23:59:59 */
 #define RTC_TIMESTAMP_END_9999         253402300799LL /* 9999-12-31 23:59:59 */
 
 extern struct rtc_device *devm_rtc_device_register(struct device *dev,
index 43aec56..67ee9d2 100644 (file)
 struct ds1685_priv {
        struct rtc_device *dev;
        void __iomem *regs;
+       void __iomem *data;
        u32 regstep;
-       resource_size_t baseaddr;
-       size_t size;
        int irq_num;
        bool bcd_mode;
        bool no_irq;
-       bool uie_unsupported;
-       bool alloc_io_resources;
        u8 (*read)(struct ds1685_priv *, int);
        void (*write)(struct ds1685_priv *, int, u8);
        void (*prepare_poweroff)(void);
@@ -74,12 +71,13 @@ struct ds1685_rtc_platform_data {
        const bool bcd_mode;
        const bool no_irq;
        const bool uie_unsupported;
-       const bool alloc_io_resources;
-       u8 (*plat_read)(struct ds1685_priv *, int);
-       void (*plat_write)(struct ds1685_priv *, int, u8);
        void (*plat_prepare_poweroff)(void);
        void (*plat_wake_alarm)(void);
        void (*plat_post_ram_clear)(void);
+       enum {
+               ds1685_reg_direct,
+               ds1685_reg_indirect
+       } access_type;
 };
 
 
index 07e68d9..467d260 100644 (file)
@@ -862,7 +862,7 @@ struct task_struct {
        u64                             start_time;
 
        /* Boot based time in nsecs: */
-       u64                             real_start_time;
+       u64                             start_boottime;
 
        /* MM fault and swap info: this can arguably be seen as either mm-specific or thread-specific: */
        unsigned long                   min_flt;
@@ -1210,6 +1210,8 @@ struct task_struct {
 #endif /* CONFIG_TRACING */
 
 #ifdef CONFIG_KCOV
+       /* See kernel/kcov.c for more details. */
+
        /* Coverage collection mode enabled for this task (0 if disabled): */
        unsigned int                    kcov_mode;
 
@@ -1221,6 +1223,12 @@ struct task_struct {
 
        /* KCOV descriptor wired with this task or NULL: */
        struct kcov                     *kcov;
+
+       /* KCOV common handle for remote coverage collection: */
+       u64                             kcov_handle;
+
+       /* KCOV sequence number: */
+       int                             kcov_sequence;
 #endif
 
 #ifdef CONFIG_MEMCG
index 6cb077b..ef7031f 100644 (file)
@@ -14,6 +14,7 @@
 #include <net/strparser.h>
 
 #define MAX_MSG_FRAGS                  MAX_SKB_FRAGS
+#define NR_MSG_FRAG_IDS                        (MAX_MSG_FRAGS + 1)
 
 enum __sk_action {
        __SK_DROP = 0,
@@ -29,13 +30,15 @@ struct sk_msg_sg {
        u32                             size;
        u32                             copybreak;
        unsigned long                   copy;
-       /* The extra element is used for chaining the front and sections when
-        * the list becomes partitioned (e.g. end < start). The crypto APIs
-        * require the chaining.
+       /* The extra two elements:
+        * 1) used for chaining the front and sections when the list becomes
+        *    partitioned (e.g. end < start). The crypto APIs require the
+        *    chaining;
+        * 2) to chain tailer SG entries after the message.
         */
-       struct scatterlist              data[MAX_MSG_FRAGS + 1];
+       struct scatterlist              data[MAX_MSG_FRAGS + 2];
 };
-static_assert(BITS_PER_LONG >= MAX_MSG_FRAGS);
+static_assert(BITS_PER_LONG >= NR_MSG_FRAG_IDS);
 
 /* UAPI in filter.c depends on struct sk_msg_sg being first element. */
 struct sk_msg {
@@ -142,13 +145,13 @@ static inline void sk_msg_apply_bytes(struct sk_psock *psock, u32 bytes)
 
 static inline u32 sk_msg_iter_dist(u32 start, u32 end)
 {
-       return end >= start ? end - start : end + (MAX_MSG_FRAGS - start);
+       return end >= start ? end - start : end + (NR_MSG_FRAG_IDS - start);
 }
 
 #define sk_msg_iter_var_prev(var)                      \
        do {                                            \
                if (var == 0)                           \
-                       var = MAX_MSG_FRAGS - 1;        \
+                       var = NR_MSG_FRAG_IDS - 1;      \
                else                                    \
                        var--;                          \
        } while (0)
@@ -156,7 +159,7 @@ static inline u32 sk_msg_iter_dist(u32 start, u32 end)
 #define sk_msg_iter_var_next(var)                      \
        do {                                            \
                var++;                                  \
-               if (var == MAX_MSG_FRAGS)               \
+               if (var == NR_MSG_FRAG_IDS)             \
                        var = 0;                        \
        } while (0)
 
@@ -173,9 +176,9 @@ static inline void sk_msg_clear_meta(struct sk_msg *msg)
 
 static inline void sk_msg_init(struct sk_msg *msg)
 {
-       BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != MAX_MSG_FRAGS);
+       BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != NR_MSG_FRAG_IDS);
        memset(msg, 0, sizeof(*msg));
-       sg_init_marker(msg->sg.data, MAX_MSG_FRAGS);
+       sg_init_marker(msg->sg.data, NR_MSG_FRAG_IDS);
 }
 
 static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src,
@@ -196,14 +199,11 @@ static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src)
 
 static inline bool sk_msg_full(const struct sk_msg *msg)
 {
-       return (msg->sg.end == msg->sg.start) && msg->sg.size;
+       return sk_msg_iter_dist(msg->sg.start, msg->sg.end) == MAX_MSG_FRAGS;
 }
 
 static inline u32 sk_msg_elem_used(const struct sk_msg *msg)
 {
-       if (sk_msg_full(msg))
-               return MAX_MSG_FRAGS;
-
        return sk_msg_iter_dist(msg->sg.start, msg->sg.end);
 }
 
index 4d2a2fa..877a95c 100644 (file)
@@ -561,26 +561,6 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
        return __kmalloc(size, flags);
 }
 
-/*
- * Determine size used for the nth kmalloc cache.
- * return size or 0 if a kmalloc cache for that
- * size does not exist
- */
-static __always_inline unsigned int kmalloc_size(unsigned int n)
-{
-#ifndef CONFIG_SLOB
-       if (n > 2)
-               return 1U << n;
-
-       if (n == 1 && KMALLOC_MIN_SIZE <= 32)
-               return 96;
-
-       if (n == 2 && KMALLOC_MIN_SIZE <= 64)
-               return 192;
-#endif
-       return 0;
-}
-
 static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
 {
 #ifndef CONFIG_SLOB
diff --git a/include/linux/soc/mmp/cputype.h b/include/linux/soc/mmp/cputype.h
new file mode 100644 (file)
index 0000000..2217907
--- /dev/null
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MACH_CPUTYPE_H
+#define __ASM_MACH_CPUTYPE_H
+
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+#include <asm/cputype.h>
+#endif
+
+/*
+ *  CPU   Stepping   CPU_ID      CHIP_ID
+ *
+ * PXA168    S0    0x56158400   0x0000C910
+ * PXA168    A0    0x56158400   0x00A0A168
+ * PXA910    Y1    0x56158400   0x00F2C920
+ * PXA910    A0    0x56158400   0x00F2C910
+ * PXA910    A1    0x56158400   0x00A0C910
+ * PXA920    Y0    0x56158400   0x00F2C920
+ * PXA920    A0    0x56158400   0x00A0C920
+ * PXA920    A1    0x56158400   0x00A1C920
+ * MMP2             Z0    0x560f5811   0x00F00410
+ * MMP2      Z1    0x560f5811   0x00E00410
+ * MMP2      A0    0x560f5811   0x00A0A610
+ * MMP3      A0    0x562f5842   0x00A02128
+ * MMP3      B0    0x562f5842   0x00B02128
+ */
+
+extern unsigned int mmp_chip_id;
+
+#ifdef CONFIG_CPU_PXA168
+static inline int cpu_is_pxa168(void)
+{
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
+               ((mmp_chip_id & 0xfff) == 0x168);
+}
+#else
+#define cpu_is_pxa168()        (0)
+#endif
+
+/* cpu_is_pxa910() is shared on both pxa910 and pxa920 */
+#ifdef CONFIG_CPU_PXA910
+static inline int cpu_is_pxa910(void)
+{
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
+               (((mmp_chip_id & 0xfff) == 0x910) ||
+                ((mmp_chip_id & 0xfff) == 0x920));
+}
+#else
+#define cpu_is_pxa910()        (0)
+#endif
+
+#if defined(CONFIG_CPU_MMP2) || defined(CONFIG_MACH_MMP2_DT)
+static inline int cpu_is_mmp2(void)
+{
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x58) &&
+               (((mmp_chip_id & 0xfff) == 0x410) ||
+                ((mmp_chip_id & 0xfff) == 0x610));
+}
+#else
+#define cpu_is_mmp2()  (0)
+#endif
+
+#ifdef CONFIG_MACH_MMP3_DT
+static inline int cpu_is_mmp3(void)
+{
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x58) &&
+               ((mmp_chip_id & 0xffff) == 0x2128);
+}
+
+static inline int cpu_is_mmp3_a0(void)
+{
+       return (cpu_is_mmp3() &&
+               ((mmp_chip_id & 0x00ff0000) == 0x00a00000));
+}
+
+static inline int cpu_is_mmp3_b0(void)
+{
+       return (cpu_is_mmp3() &&
+               ((mmp_chip_id & 0x00ff0000) == 0x00b00000));
+}
+
+#else
+#define cpu_is_mmp3()          (0)
+#define cpu_is_mmp3_a0()       (0)
+#define cpu_is_mmp3_b0()       (0)
+#endif
+
+#endif /* __ASM_MACH_CPUTYPE_H */
diff --git a/include/linux/soc/qcom/irq.h b/include/linux/soc/qcom/irq.h
new file mode 100644 (file)
index 0000000..9e1ece5
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __QCOM_IRQ_H
+#define __QCOM_IRQ_H
+
+#include <linux/irqdomain.h>
+
+#define GPIO_NO_WAKE_IRQ       ~0U
+
+/**
+ * QCOM specific IRQ domain flags that distinguishes the handling of wakeup
+ * capable interrupts by different interrupt controllers.
+ *
+ * IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP: Line must be masked at TLMM and the
+ *                                  interrupt configuration is done at PDC
+ * IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP: Interrupt configuration is handled at TLMM
+ */
+#define IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP                (IRQ_DOMAIN_FLAG_NONCORE << 0)
+#define IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP                (IRQ_DOMAIN_FLAG_NONCORE << 1)
+
+/**
+ * irq_domain_qcom_handle_wakeup: Return if the domain handles interrupt
+ *                                configuration
+ * @d: irq domain
+ *
+ * This QCOM specific irq domain call returns if the interrupt controller
+ * requires the interrupt be masked at the child interrupt controller.
+ */
+static inline bool irq_domain_qcom_handle_wakeup(const struct irq_domain *d)
+{
+       return (d->flags & IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP);
+}
+
+#endif
index eb71a50..90b8646 100644 (file)
@@ -38,33 +38,27 @@ struct llcc_slice_desc {
 };
 
 /**
- * llcc_slice_config - Data associated with the llcc slice
- * @usecase_id: usecase id for which the llcc slice is used
- * @slice_id: llcc slice id assigned to each slice
- * @max_cap: maximum capacity of the llcc slice
- * @priority: priority of the llcc slice
- * @fixed_size: whether the llcc slice can grow beyond its size
- * @bonus_ways: bonus ways associated with llcc slice
- * @res_ways: reserved ways associated with llcc slice
- * @cache_mode: mode of the llcc slice
- * @probe_target_ways: Probe only reserved and bonus ways on a cache miss
- * @dis_cap_alloc: Disable capacity based allocation
- * @retain_on_pc: Retain through power collapse
- * @activate_on_init: activate the slice on init
+ * llcc_edac_reg_data - llcc edac registers data for each error type
+ * @name: Name of the error
+ * @synd_reg: Syndrome register address
+ * @count_status_reg: Status register address to read the error count
+ * @ways_status_reg: Status register address to read the error ways
+ * @reg_cnt: Number of registers
+ * @count_mask: Mask value to get the error count
+ * @ways_mask: Mask value to get the error ways
+ * @count_shift: Shift value to get the error count
+ * @ways_shift: Shift value to get the error ways
  */
-struct llcc_slice_config {
-       u32 usecase_id;
-       u32 slice_id;
-       u32 max_cap;
-       u32 priority;
-       bool fixed_size;
-       u32 bonus_ways;
-       u32 res_ways;
-       u32 cache_mode;
-       u32 probe_target_ways;
-       bool dis_cap_alloc;
-       bool retain_on_pc;
-       bool activate_on_init;
+struct llcc_edac_reg_data {
+       char *name;
+       u64 synd_reg;
+       u64 count_status_reg;
+       u64 ways_status_reg;
+       u32 reg_cnt;
+       u32 count_mask;
+       u32 ways_mask;
+       u8  count_shift;
+       u8  ways_shift;
 };
 
 /**
@@ -93,30 +87,6 @@ struct llcc_drv_data {
        int ecc_irq;
 };
 
-/**
- * llcc_edac_reg_data - llcc edac registers data for each error type
- * @name: Name of the error
- * @synd_reg: Syndrome register address
- * @count_status_reg: Status register address to read the error count
- * @ways_status_reg: Status register address to read the error ways
- * @reg_cnt: Number of registers
- * @count_mask: Mask value to get the error count
- * @ways_mask: Mask value to get the error ways
- * @count_shift: Shift value to get the error count
- * @ways_shift: Shift value to get the error ways
- */
-struct llcc_edac_reg_data {
-       char *name;
-       u64 synd_reg;
-       u64 count_status_reg;
-       u64 ways_status_reg;
-       u32 reg_cnt;
-       u32 count_mask;
-       u32 ways_mask;
-       u8  count_shift;
-       u8  ways_shift;
-};
-
 #if IS_ENABLED(CONFIG_QCOM_LLCC)
 /**
  * llcc_slice_getd - get llcc slice descriptor
@@ -154,20 +124,6 @@ int llcc_slice_activate(struct llcc_slice_desc *desc);
  */
 int llcc_slice_deactivate(struct llcc_slice_desc *desc);
 
-/**
- * qcom_llcc_probe - program the sct table
- * @pdev: platform device pointer
- * @table: soc sct table
- * @sz: Size of the config table
- */
-int qcom_llcc_probe(struct platform_device *pdev,
-                     const struct llcc_slice_config *table, u32 sz);
-
-/**
- * qcom_llcc_remove - remove the sct table
- * @pdev: Platform device pointer
- */
-int qcom_llcc_remove(struct platform_device *pdev);
 #else
 static inline struct llcc_slice_desc *llcc_slice_getd(u32 uid)
 {
@@ -197,16 +153,6 @@ static inline int llcc_slice_deactivate(struct llcc_slice_desc *desc)
 {
        return -EINVAL;
 }
-static inline int qcom_llcc_probe(struct platform_device *pdev,
-                     const struct llcc_slice_config *table, u32 sz)
-{
-       return -ENODEV;
-}
-
-static inline int qcom_llcc_remove(struct platform_device *pdev)
-{
-       return -ENODEV;
-}
 #endif
 
 #endif
index b6ccdc2..02894e4 100644 (file)
@@ -216,6 +216,8 @@ int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4);
 extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos,
                                       const void *from, size_t available);
 
+int ptr_to_hashval(const void *ptr, unsigned long *hashval_out);
+
 /**
  * strstarts - does @str start with @prefix?
  * @str: string to examine
index 063c0c1..1e99f7a 100644 (file)
@@ -307,7 +307,7 @@ struct vma_swap_readahead {
 };
 
 /* linux/mm/workingset.c */
-void *workingset_eviction(struct page *page);
+void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg);
 void workingset_refault(struct page *page, void *shadow);
 void workingset_activation(struct page *page);
 
index 6df4773..02fa844 100644 (file)
@@ -120,8 +120,7 @@ static inline void *proc_sys_poll_event(struct ctl_table_poll *poll)
        struct ctl_table_poll name = __CTL_TABLE_POLL_INITIALIZER(name)
 
 /* A sysctl table is an array of struct ctl_table: */
-struct ctl_table 
-{
+struct ctl_table {
        const char *procname;           /* Text ID for /proc/sys, or zero */
        void *data;
        int maxlen;
@@ -140,8 +139,7 @@ struct ctl_node {
 
 /* struct ctl_table_header is used to maintain dynamic lists of
    struct ctl_table trees. */
-struct ctl_table_header
-{
+struct ctl_table_header {
        union {
                struct {
                        struct ctl_table *ctl_table;
index e45659c..d9111ae 100644 (file)
@@ -544,15 +544,4 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
 { }
 #endif /* CONFIG_THERMAL */
 
-#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)
-extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
-                                               enum events event);
-#else
-static inline int thermal_generate_netlink_event(struct thermal_zone_device *tz,
-                                               enum events event)
-{
-       return 0;
-}
-#endif
-
 #endif /* __THERMAL_H__ */
index 659a440..e93e249 100644 (file)
@@ -147,6 +147,8 @@ check_copy_size(const void *addr, size_t bytes, bool is_source)
                        __bad_copy_to();
                return false;
        }
+       if (WARN_ON_ONCE(bytes > INT_MAX))
+               return false;
        check_object_size(addr, bytes, is_source);
        return true;
 }
index b4c58a1..a4b2411 100644 (file)
@@ -22,6 +22,18 @@ struct notifier_block;               /* in notifier.h */
 #define VM_UNINITIALIZED       0x00000020      /* vm_struct is not fully initialized */
 #define VM_NO_GUARD            0x00000040      /* don't add guard page */
 #define VM_KASAN               0x00000080      /* has allocated kasan shadow memory */
+
+/*
+ * VM_KASAN is used slighly differently depending on CONFIG_KASAN_VMALLOC.
+ *
+ * If IS_ENABLED(CONFIG_KASAN_VMALLOC), VM_KASAN is set on a vm_struct after
+ * shadow memory has been mapped. It's used to handle allocation errors so that
+ * we don't try to poision shadow on free if it was never allocated.
+ *
+ * Otherwise, VM_KASAN is set for kasan_module_alloc() allocations and used to
+ * determine which allocations need the module shadow freed.
+ */
+
 /*
  * Memory with VM_FLUSH_RESET_PERMS cannot be freed in an interrupt or with
  * vfree_atomic().
index bdeda4b..292485f 100644 (file)
@@ -31,6 +31,12 @@ struct reclaim_stat {
        unsigned nr_unmap_fail;
 };
 
+enum writeback_stat_item {
+       NR_DIRTY_THRESHOLD,
+       NR_DIRTY_BG_THRESHOLD,
+       NR_VM_WRITEBACK_STAT_ITEMS,
+};
+
 #ifdef CONFIG_VM_EVENT_COUNTERS
 /*
  * Light weight per cpu counter implementation.
@@ -381,4 +387,48 @@ static inline void __mod_zone_freepage_state(struct zone *zone, int nr_pages,
 
 extern const char * const vmstat_text[];
 
+static inline const char *zone_stat_name(enum zone_stat_item item)
+{
+       return vmstat_text[item];
+}
+
+#ifdef CONFIG_NUMA
+static inline const char *numa_stat_name(enum numa_stat_item item)
+{
+       return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
+                          item];
+}
+#endif /* CONFIG_NUMA */
+
+static inline const char *node_stat_name(enum node_stat_item item)
+{
+       return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
+                          NR_VM_NUMA_STAT_ITEMS +
+                          item];
+}
+
+static inline const char *lru_list_name(enum lru_list lru)
+{
+       return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
+}
+
+static inline const char *writeback_stat_name(enum writeback_stat_item item)
+{
+       return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
+                          NR_VM_NUMA_STAT_ITEMS +
+                          NR_VM_NODE_STAT_ITEMS +
+                          item];
+}
+
+#if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
+static inline const char *vm_event_name(enum vm_event_item item)
+{
+       return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
+                          NR_VM_NUMA_STAT_ITEMS +
+                          NR_VM_NODE_STAT_ITEMS +
+                          NR_VM_WRITEBACK_STAT_ITEMS +
+                          item];
+}
+#endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
+
 #endif /* _LINUX_VMSTAT_H */
index 6ed91e8..df630f5 100644 (file)
@@ -100,7 +100,6 @@ struct tls_rec {
        struct list_head list;
        int tx_ready;
        int tx_flags;
-       int inplace_crypto;
 
        struct sk_msg msg_plaintext;
        struct sk_msg msg_encrypted;
@@ -377,7 +376,7 @@ int tls_push_sg(struct sock *sk, struct tls_context *ctx,
                int flags);
 int tls_push_partial_record(struct sock *sk, struct tls_context *ctx,
                            int flags);
-bool tls_free_partial_record(struct sock *sk, struct tls_context *ctx);
+void tls_free_partial_record(struct sock *sk, struct tls_context *ctx);
 
 static inline struct tls_msg *tls_msg(struct sk_buff *skb)
 {
index b71b5c4..533f567 100644 (file)
@@ -627,6 +627,7 @@ struct iscsi_reject {
 #define ISCSI_REASON_BOOKMARK_INVALID  9
 #define ISCSI_REASON_BOOKMARK_NO_RESOURCES     10
 #define ISCSI_REASON_NEGOTIATION_RESET 11
+#define ISCSI_REASON_WAITING_FOR_LOGOUT        12
 
 /* Max. number of Key=Value pairs in a text message */
 #define MAX_KEY_VALUE_PAIRS    8192
index 91bd749..a2849bb 100644 (file)
@@ -63,6 +63,7 @@ struct scsi_pointer {
 
 /* for scmd->state */
 #define SCMD_STATE_COMPLETE    0
+#define SCMD_STATE_INFLIGHT    1
 
 struct scsi_cmnd {
        struct scsi_request req;
@@ -190,12 +191,12 @@ static inline unsigned scsi_bufflen(struct scsi_cmnd *cmd)
        return cmd->sdb.length;
 }
 
-static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
+static inline void scsi_set_resid(struct scsi_cmnd *cmd, unsigned int resid)
 {
        cmd->req.resid_len = resid;
 }
 
-static inline int scsi_get_resid(struct scsi_cmnd *cmd)
+static inline unsigned int scsi_get_resid(struct scsi_cmnd *cmd)
 {
        return cmd->req.resid_len;
 }
index 202f4d6..3ed836d 100644 (file)
@@ -140,8 +140,10 @@ struct scsi_device {
        const char * rev;               /* ... "nullnullnullnull" before scan */
 
 #define SCSI_VPD_PG_LEN                255
+       struct scsi_vpd __rcu *vpd_pg0;
        struct scsi_vpd __rcu *vpd_pg83;
        struct scsi_vpd __rcu *vpd_pg80;
+       struct scsi_vpd __rcu *vpd_pg89;
        unsigned char current_tag;      /* current tag */
        struct scsi_target      *sdev_target;   /* used only for single_lun */
 
@@ -199,7 +201,8 @@ struct scsi_device {
        unsigned broken_fua:1;          /* Don't set FUA bit */
        unsigned lun_in_cdb:1;          /* Store LUN bits in CDB[1] */
        unsigned unmap_limit_for_ws:1;  /* Use the UNMAP limit for WRITE SAME */
-
+       unsigned rpm_autosuspend:1;     /* Enable runtime autosuspend at device
+                                        * creation time */
        atomic_t disk_events_disable_depth; /* disable depth for disk events */
 
        DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
index 31e0d6c..f577647 100644 (file)
@@ -23,19 +23,6 @@ struct scsi_host_cmd_pool;
 struct scsi_transport_template;
 
 
-/*
- * The various choices mean:
- * NONE: Self evident. Host adapter is not capable of scatter-gather.
- * ALL:         Means that the host adapter module can do scatter-gather,
- *      and that there is no limit to the size of the table to which
- *      we scatter/gather data.  The value we set here is the maximum
- *      single element sglist.  To use chained sglists, the adapter
- *      has to set a value beyond ALL (and correctly use the chain
- *      handling API.
- * Anything else:  Indicates the maximum number of chains that can be
- *      used in one scatter-gather request.
- */
-#define SG_NONE 0
 #define SG_ALL SG_CHUNK_SIZE
 
 #define MODE_UNKNOWN 0x00
@@ -345,7 +332,7 @@ struct scsi_host_template {
        /*
         * This determines if we will use a non-interrupt driven
         * or an interrupt driven scheme.  It is set to the maximum number
-        * of simultaneous commands a given host adapter will accept.
+        * of simultaneous commands a single hw queue in HBA will accept.
         */
        int can_queue;
 
@@ -486,6 +473,9 @@ struct scsi_host_template {
         */
        unsigned int cmd_size;
        struct scsi_host_cmd_pool *cmd_pool;
+
+       /* Delay for runtime autosuspend */
+       int rpm_autosuspend_delay;
 };
 
 /*
@@ -551,7 +541,6 @@ struct Scsi_Host {
        /* Area to keep a shared tag map */
        struct blk_mq_tag_set   tag_set;
 
-       atomic_t host_busy;                /* commands actually active on low-level */
        atomic_t host_blocked;
 
        unsigned int host_failed;          /* commands that failed.
index 16e2c2f..1238e35 100644 (file)
@@ -181,7 +181,7 @@ struct tegra_mc {
        spinlock_t lock;
 };
 
-void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate);
+int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate);
 unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc);
 
 #endif /* __SOC_TEGRA_MC_H__ */
index 7c9716f..1728e88 100644 (file)
@@ -876,7 +876,6 @@ struct se_portal_group {
        /* Spinlock for adding/removing sessions */
        spinlock_t              session_lock;
        struct mutex            tpg_lun_mutex;
-       struct list_head        se_tpg_node;
        /* linked list for initiator ACL list */
        struct list_head        acl_node_list;
        struct hlist_head       tpg_lun_hlist;
index 69e8bb8..ad7e642 100644 (file)
@@ -316,6 +316,53 @@ TRACE_EVENT(mm_page_alloc_extfrag,
                __entry->change_ownership)
 );
 
+/*
+ * Required for uniquely and securely identifying mm in rss_stat tracepoint.
+ */
+#ifndef __PTR_TO_HASHVAL
+static unsigned int __maybe_unused mm_ptr_to_hash(const void *ptr)
+{
+       int ret;
+       unsigned long hashval;
+
+       ret = ptr_to_hashval(ptr, &hashval);
+       if (ret)
+               return 0;
+
+       /* The hashed value is only 32-bit */
+       return (unsigned int)hashval;
+}
+#define __PTR_TO_HASHVAL
+#endif
+
+TRACE_EVENT(rss_stat,
+
+       TP_PROTO(struct mm_struct *mm,
+               int member,
+               long count),
+
+       TP_ARGS(mm, member, count),
+
+       TP_STRUCT__entry(
+               __field(unsigned int, mm_id)
+               __field(unsigned int, curr)
+               __field(int, member)
+               __field(long, size)
+       ),
+
+       TP_fast_assign(
+               __entry->mm_id = mm_ptr_to_hash(mm);
+               __entry->curr = !!(current->mm == mm);
+               __entry->member = member;
+               __entry->size = (count << PAGE_SHIFT);
+       ),
+
+       TP_printk("mm_id=%u curr=%d member=%d size=%ldB",
+               __entry->mm_id,
+               __entry->curr,
+               __entry->member,
+               __entry->size)
+       );
 #endif /* _TRACE_KMEM_H */
 
 /* This part must be outside protection */
index 7089760..472b33d 100644 (file)
@@ -757,6 +757,7 @@ static inline void ftrace_test_probe_##call(void)                   \
 #undef __get_str
 #undef __get_bitmask
 #undef __print_array
+#undef __print_hex_dump
 
 #undef TP_printk
 #define TP_printk(fmt, args...) "\"" fmt "\", "  __stringify(args)
index 7d80dbd..41a01b4 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __ASM_GENERIC_IPCBUF_H
 #define __ASM_GENERIC_IPCBUF_H
 
+#include <linux/posix_types.h>
+
 /*
  * The generic ipc64_perm structure:
  * Note extra padding because this structure is passed back and forth
index af95aa8..6504d7b 100644 (file)
@@ -3,6 +3,8 @@
 #define __ASM_GENERIC_MSGBUF_H
 
 #include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
+
 /*
  * generic msqid64_ds structure.
  *
index 1376060..0e709bd 100644 (file)
@@ -3,6 +3,7 @@
 #define __ASM_GENERIC_SEMBUF_H
 
 #include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
 
 /*
  * The semid64_ds structure for x86 architecture.
index 689fc93..e1cad4c 100644 (file)
@@ -3,6 +3,9 @@
  * ioctl interface for the scsi media changer driver
  */
 
+#ifndef _UAPI_LINUX_CHIO_H
+#define _UAPI_LINUX_CHIO_H
+
 /* changer element types */
 #define CHET_MT   0    /* media transport element (robot) */
 #define CHET_ST   1    /* storage element (media slots) */
@@ -160,10 +163,4 @@ struct changer_set_voltag {
 #define CHIOSVOLTAG    _IOW('c',18,struct changer_set_voltag)
 #define CHIOGVPARAMS   _IOR('c',19,struct changer_vendor_params)
 
-/* ---------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#endif /* _UAPI_LINUX_CHIO_H */
index fc00c5d..4ad3496 100644 (file)
@@ -152,4 +152,173 @@ struct iommu_page_response {
        __u32   code;
 };
 
+/* defines the granularity of the invalidation */
+enum iommu_inv_granularity {
+       IOMMU_INV_GRANU_DOMAIN, /* domain-selective invalidation */
+       IOMMU_INV_GRANU_PASID,  /* PASID-selective invalidation */
+       IOMMU_INV_GRANU_ADDR,   /* page-selective invalidation */
+       IOMMU_INV_GRANU_NR,     /* number of invalidation granularities */
+};
+
+/**
+ * struct iommu_inv_addr_info - Address Selective Invalidation Structure
+ *
+ * @flags: indicates the granularity of the address-selective invalidation
+ * - If the PASID bit is set, the @pasid field is populated and the invalidation
+ *   relates to cache entries tagged with this PASID and matching the address
+ *   range.
+ * - If ARCHID bit is set, @archid is populated and the invalidation relates
+ *   to cache entries tagged with this architecture specific ID and matching
+ *   the address range.
+ * - Both PASID and ARCHID can be set as they may tag different caches.
+ * - If neither PASID or ARCHID is set, global addr invalidation applies.
+ * - The LEAF flag indicates whether only the leaf PTE caching needs to be
+ *   invalidated and other paging structure caches can be preserved.
+ * @pasid: process address space ID
+ * @archid: architecture-specific ID
+ * @addr: first stage/level input address
+ * @granule_size: page/block size of the mapping in bytes
+ * @nb_granules: number of contiguous granules to be invalidated
+ */
+struct iommu_inv_addr_info {
+#define IOMMU_INV_ADDR_FLAGS_PASID     (1 << 0)
+#define IOMMU_INV_ADDR_FLAGS_ARCHID    (1 << 1)
+#define IOMMU_INV_ADDR_FLAGS_LEAF      (1 << 2)
+       __u32   flags;
+       __u32   archid;
+       __u64   pasid;
+       __u64   addr;
+       __u64   granule_size;
+       __u64   nb_granules;
+};
+
+/**
+ * struct iommu_inv_pasid_info - PASID Selective Invalidation Structure
+ *
+ * @flags: indicates the granularity of the PASID-selective invalidation
+ * - If the PASID bit is set, the @pasid field is populated and the invalidation
+ *   relates to cache entries tagged with this PASID and matching the address
+ *   range.
+ * - If the ARCHID bit is set, the @archid is populated and the invalidation
+ *   relates to cache entries tagged with this architecture specific ID and
+ *   matching the address range.
+ * - Both PASID and ARCHID can be set as they may tag different caches.
+ * - At least one of PASID or ARCHID must be set.
+ * @pasid: process address space ID
+ * @archid: architecture-specific ID
+ */
+struct iommu_inv_pasid_info {
+#define IOMMU_INV_PASID_FLAGS_PASID    (1 << 0)
+#define IOMMU_INV_PASID_FLAGS_ARCHID   (1 << 1)
+       __u32   flags;
+       __u32   archid;
+       __u64   pasid;
+};
+
+/**
+ * struct iommu_cache_invalidate_info - First level/stage invalidation
+ *     information
+ * @version: API version of this structure
+ * @cache: bitfield that allows to select which caches to invalidate
+ * @granularity: defines the lowest granularity used for the invalidation:
+ *     domain > PASID > addr
+ * @padding: reserved for future use (should be zero)
+ * @pasid_info: invalidation data when @granularity is %IOMMU_INV_GRANU_PASID
+ * @addr_info: invalidation data when @granularity is %IOMMU_INV_GRANU_ADDR
+ *
+ * Not all the combinations of cache/granularity are valid:
+ *
+ * +--------------+---------------+---------------+---------------+
+ * | type /       |   DEV_IOTLB   |     IOTLB     |      PASID    |
+ * | granularity  |               |               |      cache    |
+ * +==============+===============+===============+===============+
+ * | DOMAIN       |       N/A     |       Y       |       Y       |
+ * +--------------+---------------+---------------+---------------+
+ * | PASID        |       Y       |       Y       |       Y       |
+ * +--------------+---------------+---------------+---------------+
+ * | ADDR         |       Y       |       Y       |       N/A     |
+ * +--------------+---------------+---------------+---------------+
+ *
+ * Invalidations by %IOMMU_INV_GRANU_DOMAIN don't take any argument other than
+ * @version and @cache.
+ *
+ * If multiple cache types are invalidated simultaneously, they all
+ * must support the used granularity.
+ */
+struct iommu_cache_invalidate_info {
+#define IOMMU_CACHE_INVALIDATE_INFO_VERSION_1 1
+       __u32   version;
+/* IOMMU paging structure cache */
+#define IOMMU_CACHE_INV_TYPE_IOTLB     (1 << 0) /* IOMMU IOTLB */
+#define IOMMU_CACHE_INV_TYPE_DEV_IOTLB (1 << 1) /* Device IOTLB */
+#define IOMMU_CACHE_INV_TYPE_PASID     (1 << 2) /* PASID cache */
+#define IOMMU_CACHE_INV_TYPE_NR                (3)
+       __u8    cache;
+       __u8    granularity;
+       __u8    padding[2];
+       union {
+               struct iommu_inv_pasid_info pasid_info;
+               struct iommu_inv_addr_info addr_info;
+       };
+};
+
+/**
+ * struct iommu_gpasid_bind_data_vtd - Intel VT-d specific data on device and guest
+ * SVA binding.
+ *
+ * @flags:     VT-d PASID table entry attributes
+ * @pat:       Page attribute table data to compute effective memory type
+ * @emt:       Extended memory type
+ *
+ * Only guest vIOMMU selectable and effective options are passed down to
+ * the host IOMMU.
+ */
+struct iommu_gpasid_bind_data_vtd {
+#define IOMMU_SVA_VTD_GPASID_SRE       (1 << 0) /* supervisor request */
+#define IOMMU_SVA_VTD_GPASID_EAFE      (1 << 1) /* extended access enable */
+#define IOMMU_SVA_VTD_GPASID_PCD       (1 << 2) /* page-level cache disable */
+#define IOMMU_SVA_VTD_GPASID_PWT       (1 << 3) /* page-level write through */
+#define IOMMU_SVA_VTD_GPASID_EMTE      (1 << 4) /* extended mem type enable */
+#define IOMMU_SVA_VTD_GPASID_CD                (1 << 5) /* PASID-level cache disable */
+       __u64 flags;
+       __u32 pat;
+       __u32 emt;
+};
+
+/**
+ * struct iommu_gpasid_bind_data - Information about device and guest PASID binding
+ * @version:   Version of this data structure
+ * @format:    PASID table entry format
+ * @flags:     Additional information on guest bind request
+ * @gpgd:      Guest page directory base of the guest mm to bind
+ * @hpasid:    Process address space ID used for the guest mm in host IOMMU
+ * @gpasid:    Process address space ID used for the guest mm in guest IOMMU
+ * @addr_width:        Guest virtual address width
+ * @padding:   Reserved for future use (should be zero)
+ * @vtd:       Intel VT-d specific data
+ *
+ * Guest to host PASID mapping can be an identity or non-identity, where guest
+ * has its own PASID space. For non-identify mapping, guest to host PASID lookup
+ * is needed when VM programs guest PASID into an assigned device. VMM may
+ * trap such PASID programming then request host IOMMU driver to convert guest
+ * PASID to host PASID based on this bind data.
+ */
+struct iommu_gpasid_bind_data {
+#define IOMMU_GPASID_BIND_VERSION_1    1
+       __u32 version;
+#define IOMMU_PASID_FORMAT_INTEL_VTD   1
+       __u32 format;
+#define IOMMU_SVA_GPASID_VAL   (1 << 0) /* guest PASID valid */
+       __u64 flags;
+       __u64 gpgd;
+       __u64 hpasid;
+       __u64 gpasid;
+       __u32 addr_width;
+       __u8  padding[12];
+       /* Vendor specific data */
+       union {
+               struct iommu_gpasid_bind_data_vtd vtd;
+       };
+};
+
 #endif /* _UAPI_IOMMU_H */
index 9529867..409d3ad 100644 (file)
@@ -4,9 +4,24 @@
 
 #include <linux/types.h>
 
+/*
+ * Argument for KCOV_REMOTE_ENABLE ioctl, see Documentation/dev-tools/kcov.rst
+ * and the comment before kcov_remote_start() for usage details.
+ */
+struct kcov_remote_arg {
+       unsigned int    trace_mode;     /* KCOV_TRACE_PC or KCOV_TRACE_CMP */
+       unsigned int    area_size;      /* Length of coverage buffer in words */
+       unsigned int    num_handles;    /* Size of handles array */
+       __u64           common_handle;
+       __u64           handles[0];
+};
+
+#define KCOV_REMOTE_MAX_HANDLES                0x100
+
 #define KCOV_INIT_TRACE                        _IOR('c', 1, unsigned long)
 #define KCOV_ENABLE                    _IO('c', 100)
 #define KCOV_DISABLE                   _IO('c', 101)
+#define KCOV_REMOTE_ENABLE             _IOW('c', 102, struct kcov_remote_arg)
 
 enum {
        /*
@@ -32,4 +47,17 @@ enum {
 #define KCOV_CMP_SIZE(n)        ((n) << 1)
 #define KCOV_CMP_MASK           KCOV_CMP_SIZE(3)
 
+#define KCOV_SUBSYSTEM_COMMON  (0x00ull << 56)
+#define KCOV_SUBSYSTEM_USB     (0x01ull << 56)
+
+#define KCOV_SUBSYSTEM_MASK    (0xffull << 56)
+#define KCOV_INSTANCE_MASK     (0xffffffffull)
+
+static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst)
+{
+       if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK)
+               return 0;
+       return subsys | inst;
+}
+
 #endif /* _LINUX_KCOV_IOCTLS_H */
index e6f17c8..f0a16b4 100644 (file)
@@ -1348,6 +1348,7 @@ struct kvm_s390_ucas_mapping {
 #define KVM_PPC_GET_CPU_CHAR     _IOR(KVMIO,  0xb1, struct kvm_ppc_cpu_char)
 /* Available with KVM_CAP_PMU_EVENT_FILTER */
 #define KVM_SET_PMU_EVENT_FILTER  _IOW(KVMIO,  0xb2, struct kvm_pmu_event_filter)
+#define KVM_PPC_SVM_OFF                  _IO(KVMIO,  0xb3)
 
 /* ioctl for vm fd */
 #define KVM_CREATE_DEVICE        _IOWR(KVMIO,  0xe0, struct kvm_create_device)
index 29d6e93..acb7d2b 100644 (file)
@@ -34,6 +34,7 @@
  * of which the first 64 bytes are standardized as follows:
  */
 #define PCI_STD_HEADER_SIZEOF  64
+#define PCI_STD_NUM_BARS       6       /* Number of standard BARs */
 #define PCI_VENDOR_ID          0x00    /* 16 bits */
 #define PCI_DEVICE_ID          0x02    /* 16 bits */
 #define PCI_COMMAND            0x04    /* 16 bits */
 #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_32_0GT    0x0005 /* Supported Speed 32GT/s */
+#define  PCI_EXP_LNKCTL2_ENTER_COMP    0x0010 /* Enter Compliance */
+#define  PCI_EXP_LNKCTL2_TX_MARGIN     0x0380 /* Transmit Margin */
 #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 */
index c5bc7f7..947edb1 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef _UAPI_SCC_H
 #define _UAPI_SCC_H
 
+#include <linux/sockios.h>
 
 /* selection of hardware types */
 
index e7fe550..8ec3dd7 100644 (file)
 /* Sunix UART */
 #define PORT_SUNIX     121
 
-/* Freescale Linflex UART */
+/* Freescale LINFlexD UART */
 #define PORT_LINFLEXUART       122
 
 #endif /* _UAPILINUX_SERIAL_CORE_H */
index 128b68a..a34064a 100644 (file)
@@ -104,29 +104,9 @@ config COMPILE_TEST
          here. If you are a user/distributor, say N here to exclude useless
          drivers to be distributed.
 
-config HEADER_TEST
-       bool "Compile test headers that should be standalone compilable"
-       help
-         Compile test headers listed in header-test-y target to ensure they are
-         self-contained, i.e. compilable as standalone units.
-
-         If you are a developer or tester and want to ensure the requested
-         headers are self-contained, say Y here. Otherwise, choose N.
-
-config KERNEL_HEADER_TEST
-       bool "Compile test kernel headers"
-       depends on HEADER_TEST
-       help
-         Headers in include/ are used to build external moduls.
-         Compile test them to ensure they are self-contained, i.e.
-         compilable as standalone units.
-
-         If you are a developer or tester and want to ensure the headers
-         in include/ are self-contained, say Y here. Otherwise, choose N.
-
 config UAPI_HEADER_TEST
        bool "Compile test UAPI headers"
-       depends on HEADER_TEST && HEADERS_INSTALL && CC_CAN_LINK
+       depends on HEADERS_INSTALL && CC_CAN_LINK
        help
          Compile test headers exported to user-space to ensure they are
          self-contained, i.e. compilable as standalone units.
@@ -166,13 +146,13 @@ config LOCALVERSION_AUTO
          which is done within the script "scripts/setlocalversion".)
 
 config BUILD_SALT
-       string "Build ID Salt"
-       default ""
-       help
-          The build ID is used to link binaries and their debug info. Setting
-          this option will use the value in the calculation of the build id.
-          This is mostly useful for distributions which want to ensure the
-          build is unique between builds. It's safe to leave the default.
+       string "Build ID Salt"
+       default ""
+       help
+         The build ID is used to link binaries and their debug info. Setting
+         this option will use the value in the calculation of the build id.
+         This is mostly useful for distributions which want to ensure the
+         build is unique between builds. It's safe to leave the default.
 
 config HAVE_KERNEL_GZIP
        bool
@@ -838,7 +818,7 @@ menuconfig CGROUPS
 if CGROUPS
 
 config PAGE_COUNTER
-       bool
+       bool
 
 config MEMCG
        bool "Memory controller"
@@ -1331,9 +1311,9 @@ menuconfig EXPERT
        select DEBUG_KERNEL
        help
          This option allows certain base kernel options and settings
-          to be disabled or tweaked. This is for specialized
-          environments which can tolerate a "non-standard" kernel.
-          Only use this if you really know what you are doing.
+         to be disabled or tweaked. This is for specialized
+         environments which can tolerate a "non-standard" kernel.
+         Only use this if you really know what you are doing.
 
 config UID16
        bool "Enable 16-bit UID system calls" if EXPERT
@@ -1426,11 +1406,11 @@ config BUG
        bool "BUG() support" if EXPERT
        default y
        help
-          Disabling this option eliminates support for BUG and WARN, reducing
-          the size of your kernel image and potentially quietly ignoring
-          numerous fatal conditions. You should only consider disabling this
-          option for embedded systems with no facilities for reporting errors.
-          Just say Y.
+         Disabling this option eliminates support for BUG and WARN, reducing
+         the size of your kernel image and potentially quietly ignoring
+         numerous fatal conditions. You should only consider disabling this
+         option for embedded systems with no facilities for reporting errors.
+         Just say Y.
 
 config ELF_CORE
        depends on COREDUMP
@@ -1446,8 +1426,8 @@ config PCSPKR_PLATFORM
        select I8253_LOCK
        default y
        help
-          This option allows to disable the internal PC-Speaker
-          support, saving some memory.
+         This option allows to disable the internal PC-Speaker
+         support, saving some memory.
 
 config BASE_FULL
        default y
@@ -1565,29 +1545,29 @@ config MEMBARRIER
          If unsure, say Y.
 
 config KALLSYMS
-        bool "Load all symbols for debugging/ksymoops" if EXPERT
-        default y
-        help
-          Say Y here to let the kernel print out symbolic crash information and
-          symbolic stack backtraces. This increases the size of the kernel
-          somewhat, as all symbols have to be loaded into the kernel image.
+       bool "Load all symbols for debugging/ksymoops" if EXPERT
+       default y
+       help
+         Say Y here to let the kernel print out symbolic crash information and
+         symbolic stack backtraces. This increases the size of the kernel
+         somewhat, as all symbols have to be loaded into the kernel image.
 
 config KALLSYMS_ALL
        bool "Include all symbols in kallsyms"
        depends on DEBUG_KERNEL && KALLSYMS
        help
-          Normally kallsyms only contains the symbols of functions for nicer
-          OOPS messages and backtraces (i.e., symbols from the text and inittext
-          sections). This is sufficient for most cases. And only in very rare
-          cases (e.g., when a debugger is used) all symbols are required (e.g.,
-          names of variables from the data sections, etc).
+         Normally kallsyms only contains the symbols of functions for nicer
+         OOPS messages and backtraces (i.e., symbols from the text and inittext
+         sections). This is sufficient for most cases. And only in very rare
+         cases (e.g., when a debugger is used) all symbols are required (e.g.,
+         names of variables from the data sections, etc).
 
-          This option makes sure that all symbols are loaded into the kernel
-          image (i.e., symbols from all sections) in cost of increased kernel
-          size (depending on the kernel configuration, it may be 300KiB or
-          something like this).
+         This option makes sure that all symbols are loaded into the kernel
+         image (i.e., symbols from all sections) in cost of increased kernel
+         size (depending on the kernel configuration, it may be 300KiB or
+         something like this).
 
-          Say N unless you really need all symbols.
+         Say N unless you really need all symbols.
 
 config KALLSYMS_ABSOLUTE_PERCPU
        bool
@@ -1730,12 +1710,12 @@ config DEBUG_PERF_USE_VMALLOC
        depends on PERF_EVENTS && DEBUG_KERNEL && !PPC
        select PERF_USE_VMALLOC
        help
-        Use vmalloc memory to back perf mmap() buffers.
+         Use vmalloc memory to back perf mmap() buffers.
 
-        Mostly useful for debugging the vmalloc code on platforms
-        that don't require it.
+         Mostly useful for debugging the vmalloc code on platforms
+         that don't require it.
 
-        Say N if unsure.
+         Say N if unsure.
 
 endmenu
 
index f0902a7..f2cc0d1 100644 (file)
@@ -130,7 +130,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 = $(BASH) $(srctree)/kernel/gen_kheaders.sh $@
+      cmd_genikh = $(CONFIG_SHELL) $(srctree)/kernel/gen_kheaders.sh $@
 $(obj)/kheaders_data.tar.xz: FORCE
        $(call cmd,genikh)
 
index caca752..3f958b9 100644 (file)
@@ -289,7 +289,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
 
        if (irqs_disabled()) {
                work = this_cpu_ptr(&up_read_work);
-               if (work->irq_work.flags & IRQ_WORK_BUSY)
+               if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY)
                        /* cannot queue more up_read, fallback */
                        irq_work_busy = true;
        }
index d47bd40..d14cbc8 100644 (file)
@@ -178,7 +178,7 @@ bool dma_in_atomic_pool(void *start, size_t size)
        if (unlikely(!atomic_pool))
                return false;
 
-       return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
+       return gen_pool_has_addr(atomic_pool, (unsigned long)start, size);
 }
 
 void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
index c747610..ece7e13 100644 (file)
@@ -1457,7 +1457,7 @@ static int xol_add_vma(struct mm_struct *mm, struct xol_area *area)
                /* Try to map as high as possible, this is only a hint. */
                area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE,
                                                PAGE_SIZE, 0, 0);
-               if (area->vaddr & ~PAGE_MASK) {
+               if (IS_ERR_VALUE(area->vaddr)) {
                        ret = area->vaddr;
                        goto fail;
                }
index 0f0bac8..2508a4f 100644 (file)
@@ -93,6 +93,7 @@
 #include <linux/livepatch.h>
 #include <linux/thread_info.h>
 #include <linux/stackleak.h>
+#include <linux/kasan.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -223,6 +224,9 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
                if (!s)
                        continue;
 
+               /* Clear the KASAN shadow of the stack. */
+               kasan_unpoison_shadow(s->addr, THREAD_SIZE);
+
                /* Clear stale pointers from reused stack. */
                memset(s->addr, 0, THREAD_SIZE);
 
@@ -2181,7 +2185,7 @@ static __latent_entropy struct task_struct *copy_process(
         */
 
        p->start_time = ktime_get_ns();
-       p->real_start_time = ktime_get_boottime_ns();
+       p->start_boottime = ktime_get_boottime_ns();
 
        /*
         * Make it visible to the rest of the system, but dont wake it up yet.
index 5a0fc0b..e13ca84 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
 
 # This script generates an archive consisting of kernel headers
@@ -21,30 +21,38 @@ arch/$SRCARCH/include/
 # Uncomment it for debugging.
 # if [ ! -f /tmp/iter ]; then iter=1; echo 1 > /tmp/iter;
 # else iter=$(($(cat /tmp/iter) + 1)); echo $iter > /tmp/iter; fi
-# find $src_file_list -name "*.h" | xargs ls -l > /tmp/src-ls-$iter
-# find $obj_file_list -name "*.h" | xargs ls -l > /tmp/obj-ls-$iter
+# find $all_dirs -name "*.h" | xargs ls -l > /tmp/ls-$iter
+
+all_dirs=
+if [ "$building_out_of_srctree" ]; then
+       for d in $dir_list; do
+               all_dirs="$all_dirs $srctree/$d"
+       done
+fi
+all_dirs="$all_dirs $dir_list"
 
 # include/generated/compile.h is ignored because it is touched even when none
-# of the source files changed. This causes pointless regeneration, so let us
-# ignore them for md5 calculation.
-pushd $srctree > /dev/null
-src_files_md5="$(find $dir_list -name "*.h"                       |
-               grep -v "include/generated/compile.h"              |
-               grep -v "include/generated/autoconf.h"             |
-               xargs ls -l | md5sum | cut -d ' ' -f1)"
-popd > /dev/null
-obj_files_md5="$(find $dir_list -name "*.h"                       |
-               grep -v "include/generated/compile.h"              |
-               grep -v "include/generated/autoconf.h"             |
+# of the source files changed.
+#
+# When Kconfig regenerates include/generated/autoconf.h, its timestamp is
+# updated, but the contents might be still the same. When any CONFIG option is
+# changed, Kconfig touches the corresponding timestamp file include/config/*.h.
+# Hence, the md5sum detects the configuration change anyway. We do not need to
+# check include/generated/autoconf.h explicitly.
+#
+# Ignore them for md5 calculation to avoid pointless regeneration.
+headers_md5="$(find $all_dirs -name "*.h"                      |
+               grep -v "include/generated/compile.h"   |
+               grep -v "include/generated/autoconf.h"  |
                xargs ls -l | md5sum | cut -d ' ' -f1)"
+
 # Any changes to this script will also cause a rebuild of the archive.
 this_file_md5="$(ls -l $sfile | md5sum | cut -d ' ' -f1)"
 if [ -f $tarfile ]; then tarfile_md5="$(md5sum $tarfile | cut -d ' ' -f1)"; fi
 if [ -f kernel/kheaders.md5 ] &&
-       [ "$(cat kernel/kheaders.md5|head -1)" == "$src_files_md5" ] &&
-       [ "$(cat kernel/kheaders.md5|head -2|tail -1)" == "$obj_files_md5" ] &&
-       [ "$(cat kernel/kheaders.md5|head -3|tail -1)" == "$this_file_md5" ] &&
-       [ "$(cat kernel/kheaders.md5|tail -1)" == "$tarfile_md5" ]; then
+       [ "$(head -n 1 kernel/kheaders.md5)" = "$headers_md5" ] &&
+       [ "$(head -n 2 kernel/kheaders.md5 | tail -n 1)" = "$this_file_md5" ] &&
+       [ "$(tail -n 1 kernel/kheaders.md5)" = "$tarfile_md5" ]; then
                exit
 fi
 
@@ -55,14 +63,17 @@ fi
 rm -rf $cpio_dir
 mkdir $cpio_dir
 
-pushd $srctree > /dev/null
-for f in $dir_list;
-       do find "$f" -name "*.h";
-done | cpio --quiet -pd $cpio_dir
-popd > /dev/null
+if [ "$building_out_of_srctree" ]; then
+       (
+               cd $srctree
+               for f in $dir_list
+                       do find "$f" -name "*.h";
+               done | cpio --quiet -pd $cpio_dir
+       )
+fi
 
-# The second CPIO can complain if files already exist which can
-# happen with out of tree builds. Just silence CPIO for now.
+# The second CPIO can complain if files already exist which can happen with out
+# of tree builds having stale headers in srctree. Just silence CPIO for now.
 for f in $dir_list;
        do find "$f" -name "*.h";
 done | cpio --quiet -pd $cpio_dir >/dev/null 2>&1
@@ -79,8 +90,7 @@ find $cpio_dir -printf "./%P\n" | LC_ALL=C sort | \
     --owner=0 --group=0 --numeric-owner --no-recursion \
     -Jcf $tarfile -C $cpio_dir/ -T - > /dev/null
 
-echo "$src_files_md5" >  kernel/kheaders.md5
-echo "$obj_files_md5" >> kernel/kheaders.md5
+echo $headers_md5 > kernel/kheaders.md5
 echo "$this_file_md5" >> kernel/kheaders.md5
 echo "$(md5sum $tarfile | cut -d ' ' -f1)" >> kernel/kheaders.md5
 
index b76703b..b3fa2d8 100644 (file)
@@ -1297,6 +1297,50 @@ EXPORT_SYMBOL_GPL(handle_fasteoi_mask_irq);
 
 #endif /* CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS */
 
+/**
+ * irq_chip_set_parent_state - set the state of a parent interrupt.
+ *
+ * @data: Pointer to interrupt specific data
+ * @which: State to be restored (one of IRQCHIP_STATE_*)
+ * @val: Value corresponding to @which
+ *
+ * Conditional success, if the underlying irqchip does not implement it.
+ */
+int irq_chip_set_parent_state(struct irq_data *data,
+                             enum irqchip_irq_state which,
+                             bool val)
+{
+       data = data->parent_data;
+
+       if (!data || !data->chip->irq_set_irqchip_state)
+               return 0;
+
+       return data->chip->irq_set_irqchip_state(data, which, val);
+}
+EXPORT_SYMBOL_GPL(irq_chip_set_parent_state);
+
+/**
+ * irq_chip_get_parent_state - get the state of a parent interrupt.
+ *
+ * @data: Pointer to interrupt specific data
+ * @which: one of IRQCHIP_STATE_* the caller wants to know
+ * @state: a pointer to a boolean where the state is to be stored
+ *
+ * Conditional success, if the underlying irqchip does not implement it.
+ */
+int irq_chip_get_parent_state(struct irq_data *data,
+                             enum irqchip_irq_state which,
+                             bool *state)
+{
+       data = data->parent_data;
+
+       if (!data || !data->chip->irq_get_irqchip_state)
+               return 0;
+
+       return data->chip->irq_get_irqchip_state(data, which, state);
+}
+EXPORT_SYMBOL_GPL(irq_chip_get_parent_state);
+
 /**
  * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
  * NULL)
index 9be995f..5b8fdd6 100644 (file)
@@ -750,7 +750,7 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
 EXPORT_SYMBOL_GPL(irq_free_descs);
 
 /**
- * irq_alloc_descs - allocate and initialize a range of irq descriptors
+ * __irq_alloc_descs - allocate and initialize a range of irq descriptors
  * @irq:       Allocate for specific irq number if irq >= 0
  * @from:      Start the search from this irq number
  * @cnt:       Number of consecutive irqs to allocate.
index d42acaf..828cc30 100644 (file)
@@ -29,24 +29,16 @@ static DEFINE_PER_CPU(struct llist_head, lazy_list);
  */
 static bool irq_work_claim(struct irq_work *work)
 {
-       unsigned long flags, oflags, nflags;
+       int oflags;
 
+       oflags = atomic_fetch_or(IRQ_WORK_CLAIMED, &work->flags);
        /*
-        * Start with our best wish as a premise but only trust any
-        * flag value after cmpxchg() result.
+        * If the work is already pending, no need to raise the IPI.
+        * The pairing atomic_fetch_andnot() in irq_work_run() makes sure
+        * everything we did before is visible.
         */
-       flags = work->flags & ~IRQ_WORK_PENDING;
-       for (;;) {
-               nflags = flags | IRQ_WORK_CLAIMED;
-               oflags = cmpxchg(&work->flags, flags, nflags);
-               if (oflags == flags)
-                       break;
-               if (oflags & IRQ_WORK_PENDING)
-                       return false;
-               flags = oflags;
-               cpu_relax();
-       }
-
+       if (oflags & IRQ_WORK_PENDING)
+               return false;
        return true;
 }
 
@@ -61,7 +53,7 @@ void __weak arch_irq_work_raise(void)
 static void __irq_work_queue_local(struct irq_work *work)
 {
        /* If the work is "lazy", handle it from next tick if any */
-       if (work->flags & IRQ_WORK_LAZY) {
+       if (atomic_read(&work->flags) & IRQ_WORK_LAZY) {
                if (llist_add(&work->llnode, this_cpu_ptr(&lazy_list)) &&
                    tick_nohz_tick_stopped())
                        arch_irq_work_raise();
@@ -143,7 +135,6 @@ static void irq_work_run_list(struct llist_head *list)
 {
        struct irq_work *work, *tmp;
        struct llist_node *llnode;
-       unsigned long flags;
 
        BUG_ON(!irqs_disabled());
 
@@ -152,6 +143,7 @@ static void irq_work_run_list(struct llist_head *list)
 
        llnode = llist_del_all(list);
        llist_for_each_entry_safe(work, tmp, llnode, llnode) {
+               int flags;
                /*
                 * Clear the PENDING bit, after this point the @work
                 * can be re-used.
@@ -159,15 +151,15 @@ static void irq_work_run_list(struct llist_head *list)
                 * to claim that work don't rely on us to handle their data
                 * while we are in the middle of the func.
                 */
-               flags = work->flags & ~IRQ_WORK_PENDING;
-               xchg(&work->flags, flags);
+               flags = atomic_fetch_andnot(IRQ_WORK_PENDING, &work->flags);
 
                work->func(work);
                /*
                 * Clear the BUSY bit and return to the free state if
                 * no-one else claimed it meanwhile.
                 */
-               (void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY);
+               flags &= ~IRQ_WORK_PENDING;
+               (void)atomic_cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY);
        }
 }
 
@@ -199,7 +191,7 @@ void irq_work_sync(struct irq_work *work)
 {
        lockdep_assert_irqs_enabled();
 
-       while (work->flags & IRQ_WORK_BUSY)
+       while (atomic_read(&work->flags) & IRQ_WORK_BUSY)
                cpu_relax();
 }
 EXPORT_SYMBOL_GPL(irq_work_sync);
index 2ee3872..f503542 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/hashtable.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/preempt.h>
 #include <linux/uaccess.h>
 #include <linux/kcov.h>
 #include <linux/refcount.h>
+#include <linux/log2.h>
 #include <asm/setup.h>
 
+#define kcov_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__)
+
 /* Number of 64-bit words written per one comparison: */
 #define KCOV_WORDS_PER_CMP 4
 
@@ -44,19 +48,100 @@ struct kcov {
         * Reference counter. We keep one for:
         *  - opened file descriptor
         *  - task with enabled coverage (we can't unwire it from another task)
+        *  - each code section for remote coverage collection
         */
        refcount_t              refcount;
        /* The lock protects mode, size, area and t. */
        spinlock_t              lock;
        enum kcov_mode          mode;
-       /* Size of arena (in long's for KCOV_MODE_TRACE). */
-       unsigned                size;
+       /* Size of arena (in long's). */
+       unsigned int            size;
        /* Coverage buffer shared with user space. */
        void                    *area;
        /* Task for which we collect coverage, or NULL. */
        struct task_struct      *t;
+       /* Collecting coverage from remote (background) threads. */
+       bool                    remote;
+       /* Size of remote area (in long's). */
+       unsigned int            remote_size;
+       /*
+        * Sequence is incremented each time kcov is reenabled, used by
+        * kcov_remote_stop(), see the comment there.
+        */
+       int                     sequence;
 };
 
+struct kcov_remote_area {
+       struct list_head        list;
+       unsigned int            size;
+};
+
+struct kcov_remote {
+       u64                     handle;
+       struct kcov             *kcov;
+       struct hlist_node       hnode;
+};
+
+static DEFINE_SPINLOCK(kcov_remote_lock);
+static DEFINE_HASHTABLE(kcov_remote_map, 4);
+static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas);
+
+/* Must be called with kcov_remote_lock locked. */
+static struct kcov_remote *kcov_remote_find(u64 handle)
+{
+       struct kcov_remote *remote;
+
+       hash_for_each_possible(kcov_remote_map, remote, hnode, handle) {
+               if (remote->handle == handle)
+                       return remote;
+       }
+       return NULL;
+}
+
+static struct kcov_remote *kcov_remote_add(struct kcov *kcov, u64 handle)
+{
+       struct kcov_remote *remote;
+
+       if (kcov_remote_find(handle))
+               return ERR_PTR(-EEXIST);
+       remote = kmalloc(sizeof(*remote), GFP_ATOMIC);
+       if (!remote)
+               return ERR_PTR(-ENOMEM);
+       remote->handle = handle;
+       remote->kcov = kcov;
+       hash_add(kcov_remote_map, &remote->hnode, handle);
+       return remote;
+}
+
+/* Must be called with kcov_remote_lock locked. */
+static struct kcov_remote_area *kcov_remote_area_get(unsigned int size)
+{
+       struct kcov_remote_area *area;
+       struct list_head *pos;
+
+       kcov_debug("size = %u\n", size);
+       list_for_each(pos, &kcov_remote_areas) {
+               area = list_entry(pos, struct kcov_remote_area, list);
+               if (area->size == size) {
+                       list_del(&area->list);
+                       kcov_debug("rv = %px\n", area);
+                       return area;
+               }
+       }
+       kcov_debug("rv = NULL\n");
+       return NULL;
+}
+
+/* Must be called with kcov_remote_lock locked. */
+static void kcov_remote_area_put(struct kcov_remote_area *area,
+                                       unsigned int size)
+{
+       kcov_debug("area = %px, size = %u\n", area, size);
+       INIT_LIST_HEAD(&area->list);
+       area->size = size;
+       list_add(&area->list, &kcov_remote_areas);
+}
+
 static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
 {
        unsigned int mode;
@@ -73,7 +158,7 @@ static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_stru
         * in_interrupt() returns false (e.g. preempt_schedule_irq()).
         * READ_ONCE()/barrier() effectively provides load-acquire wrt
         * interrupts, there are paired barrier()/WRITE_ONCE() in
-        * kcov_ioctl_locked().
+        * kcov_start().
         */
        barrier();
        return mode == needed_mode;
@@ -227,6 +312,78 @@ void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases)
 EXPORT_SYMBOL(__sanitizer_cov_trace_switch);
 #endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */
 
+static void kcov_start(struct task_struct *t, unsigned int size,
+                       void *area, enum kcov_mode mode, int sequence)
+{
+       kcov_debug("t = %px, size = %u, area = %px\n", t, size, area);
+       /* Cache in task struct for performance. */
+       t->kcov_size = size;
+       t->kcov_area = area;
+       /* See comment in check_kcov_mode(). */
+       barrier();
+       WRITE_ONCE(t->kcov_mode, mode);
+       t->kcov_sequence = sequence;
+}
+
+static void kcov_stop(struct task_struct *t)
+{
+       WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED);
+       barrier();
+       t->kcov_size = 0;
+       t->kcov_area = NULL;
+}
+
+static void kcov_task_reset(struct task_struct *t)
+{
+       kcov_stop(t);
+       t->kcov = NULL;
+       t->kcov_sequence = 0;
+       t->kcov_handle = 0;
+}
+
+void kcov_task_init(struct task_struct *t)
+{
+       kcov_task_reset(t);
+       t->kcov_handle = current->kcov_handle;
+}
+
+static void kcov_reset(struct kcov *kcov)
+{
+       kcov->t = NULL;
+       kcov->mode = KCOV_MODE_INIT;
+       kcov->remote = false;
+       kcov->remote_size = 0;
+       kcov->sequence++;
+}
+
+static void kcov_remote_reset(struct kcov *kcov)
+{
+       int bkt;
+       struct kcov_remote *remote;
+       struct hlist_node *tmp;
+
+       spin_lock(&kcov_remote_lock);
+       hash_for_each_safe(kcov_remote_map, bkt, tmp, remote, hnode) {
+               if (remote->kcov != kcov)
+                       continue;
+               kcov_debug("removing handle %llx\n", remote->handle);
+               hash_del(&remote->hnode);
+               kfree(remote);
+       }
+       /* Do reset before unlock to prevent races with kcov_remote_start(). */
+       kcov_reset(kcov);
+       spin_unlock(&kcov_remote_lock);
+}
+
+static void kcov_disable(struct task_struct *t, struct kcov *kcov)
+{
+       kcov_task_reset(t);
+       if (kcov->remote)
+               kcov_remote_reset(kcov);
+       else
+               kcov_reset(kcov);
+}
+
 static void kcov_get(struct kcov *kcov)
 {
        refcount_inc(&kcov->refcount);
@@ -235,20 +392,12 @@ static void kcov_get(struct kcov *kcov)
 static void kcov_put(struct kcov *kcov)
 {
        if (refcount_dec_and_test(&kcov->refcount)) {
+               kcov_remote_reset(kcov);
                vfree(kcov->area);
                kfree(kcov);
        }
 }
 
-void kcov_task_init(struct task_struct *t)
-{
-       WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED);
-       barrier();
-       t->kcov_size = 0;
-       t->kcov_area = NULL;
-       t->kcov = NULL;
-}
-
 void kcov_task_exit(struct task_struct *t)
 {
        struct kcov *kcov;
@@ -256,15 +405,36 @@ void kcov_task_exit(struct task_struct *t)
        kcov = t->kcov;
        if (kcov == NULL)
                return;
+
        spin_lock(&kcov->lock);
+       kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t);
+       /*
+        * For KCOV_ENABLE devices we want to make sure that t->kcov->t == t,
+        * which comes down to:
+        *        WARN_ON(!kcov->remote && kcov->t != t);
+        *
+        * For KCOV_REMOTE_ENABLE devices, the exiting task is either:
+        * 2. A remote task between kcov_remote_start() and kcov_remote_stop().
+        *    In this case we should print a warning right away, since a task
+        *    shouldn't be exiting when it's in a kcov coverage collection
+        *    section. Here t points to the task that is collecting remote
+        *    coverage, and t->kcov->t points to the thread that created the
+        *    kcov device. Which means that to detect this case we need to
+        *    check that t != t->kcov->t, and this gives us the following:
+        *        WARN_ON(kcov->remote && kcov->t != t);
+        *
+        * 2. The task that created kcov exiting without calling KCOV_DISABLE,
+        *    and then again we can make sure that t->kcov->t == t:
+        *        WARN_ON(kcov->remote && kcov->t != t);
+        *
+        * By combining all three checks into one we get:
+        */
        if (WARN_ON(kcov->t != t)) {
                spin_unlock(&kcov->lock);
                return;
        }
        /* Just to not leave dangling references behind. */
-       kcov_task_init(t);
-       kcov->t = NULL;
-       kcov->mode = KCOV_MODE_INIT;
+       kcov_disable(t, kcov);
        spin_unlock(&kcov->lock);
        kcov_put(kcov);
 }
@@ -313,6 +483,7 @@ static int kcov_open(struct inode *inode, struct file *filep)
        if (!kcov)
                return -ENOMEM;
        kcov->mode = KCOV_MODE_DISABLED;
+       kcov->sequence = 1;
        refcount_set(&kcov->refcount, 1);
        spin_lock_init(&kcov->lock);
        filep->private_data = kcov;
@@ -325,6 +496,20 @@ static int kcov_close(struct inode *inode, struct file *filep)
        return 0;
 }
 
+static int kcov_get_mode(unsigned long arg)
+{
+       if (arg == KCOV_TRACE_PC)
+               return KCOV_MODE_TRACE_PC;
+       else if (arg == KCOV_TRACE_CMP)
+#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
+               return KCOV_MODE_TRACE_CMP;
+#else
+               return -ENOTSUPP;
+#endif
+       else
+               return -EINVAL;
+}
+
 /*
  * Fault in a lazily-faulted vmalloc area before it can be used by
  * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the
@@ -340,14 +525,35 @@ static void kcov_fault_in_area(struct kcov *kcov)
                READ_ONCE(area[offset]);
 }
 
+static inline bool kcov_check_handle(u64 handle, bool common_valid,
+                               bool uncommon_valid, bool zero_valid)
+{
+       if (handle & ~(KCOV_SUBSYSTEM_MASK | KCOV_INSTANCE_MASK))
+               return false;
+       switch (handle & KCOV_SUBSYSTEM_MASK) {
+       case KCOV_SUBSYSTEM_COMMON:
+               return (handle & KCOV_INSTANCE_MASK) ?
+                       common_valid : zero_valid;
+       case KCOV_SUBSYSTEM_USB:
+               return uncommon_valid;
+       default:
+               return false;
+       }
+       return false;
+}
+
 static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
                             unsigned long arg)
 {
        struct task_struct *t;
        unsigned long size, unused;
+       int mode, i;
+       struct kcov_remote_arg *remote_arg;
+       struct kcov_remote *remote;
 
        switch (cmd) {
        case KCOV_INIT_TRACE:
+               kcov_debug("KCOV_INIT_TRACE\n");
                /*
                 * Enable kcov in trace mode and setup buffer size.
                 * Must happen before anything else.
@@ -366,6 +572,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
                kcov->mode = KCOV_MODE_INIT;
                return 0;
        case KCOV_ENABLE:
+               kcov_debug("KCOV_ENABLE\n");
                /*
                 * Enable coverage for the current task.
                 * At this point user must have been enabled trace mode,
@@ -378,29 +585,20 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
                t = current;
                if (kcov->t != NULL || t->kcov != NULL)
                        return -EBUSY;
-               if (arg == KCOV_TRACE_PC)
-                       kcov->mode = KCOV_MODE_TRACE_PC;
-               else if (arg == KCOV_TRACE_CMP)
-#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
-                       kcov->mode = KCOV_MODE_TRACE_CMP;
-#else
-               return -ENOTSUPP;
-#endif
-               else
-                       return -EINVAL;
+               mode = kcov_get_mode(arg);
+               if (mode < 0)
+                       return mode;
                kcov_fault_in_area(kcov);
-               /* Cache in task struct for performance. */
-               t->kcov_size = kcov->size;
-               t->kcov_area = kcov->area;
-               /* See comment in check_kcov_mode(). */
-               barrier();
-               WRITE_ONCE(t->kcov_mode, kcov->mode);
+               kcov->mode = mode;
+               kcov_start(t, kcov->size, kcov->area, kcov->mode,
+                               kcov->sequence);
                t->kcov = kcov;
                kcov->t = t;
-               /* This is put either in kcov_task_exit() or in KCOV_DISABLE. */
+               /* Put either in kcov_task_exit() or in KCOV_DISABLE. */
                kcov_get(kcov);
                return 0;
        case KCOV_DISABLE:
+               kcov_debug("KCOV_DISABLE\n");
                /* Disable coverage for the current task. */
                unused = arg;
                if (unused != 0 || current->kcov != kcov)
@@ -408,11 +606,65 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
                t = current;
                if (WARN_ON(kcov->t != t))
                        return -EINVAL;
-               kcov_task_init(t);
-               kcov->t = NULL;
-               kcov->mode = KCOV_MODE_INIT;
+               kcov_disable(t, kcov);
                kcov_put(kcov);
                return 0;
+       case KCOV_REMOTE_ENABLE:
+               kcov_debug("KCOV_REMOTE_ENABLE\n");
+               if (kcov->mode != KCOV_MODE_INIT || !kcov->area)
+                       return -EINVAL;
+               t = current;
+               if (kcov->t != NULL || t->kcov != NULL)
+                       return -EBUSY;
+               remote_arg = (struct kcov_remote_arg *)arg;
+               mode = kcov_get_mode(remote_arg->trace_mode);
+               if (mode < 0)
+                       return mode;
+               if (remote_arg->area_size > LONG_MAX / sizeof(unsigned long))
+                       return -EINVAL;
+               kcov->mode = mode;
+               t->kcov = kcov;
+               kcov->t = t;
+               kcov->remote = true;
+               kcov->remote_size = remote_arg->area_size;
+               spin_lock(&kcov_remote_lock);
+               for (i = 0; i < remote_arg->num_handles; i++) {
+                       kcov_debug("handle %llx\n", remote_arg->handles[i]);
+                       if (!kcov_check_handle(remote_arg->handles[i],
+                                               false, true, false)) {
+                               spin_unlock(&kcov_remote_lock);
+                               kcov_disable(t, kcov);
+                               return -EINVAL;
+                       }
+                       remote = kcov_remote_add(kcov, remote_arg->handles[i]);
+                       if (IS_ERR(remote)) {
+                               spin_unlock(&kcov_remote_lock);
+                               kcov_disable(t, kcov);
+                               return PTR_ERR(remote);
+                       }
+               }
+               if (remote_arg->common_handle) {
+                       kcov_debug("common handle %llx\n",
+                                       remote_arg->common_handle);
+                       if (!kcov_check_handle(remote_arg->common_handle,
+                                               true, false, false)) {
+                               spin_unlock(&kcov_remote_lock);
+                               kcov_disable(t, kcov);
+                               return -EINVAL;
+                       }
+                       remote = kcov_remote_add(kcov,
+                                       remote_arg->common_handle);
+                       if (IS_ERR(remote)) {
+                               spin_unlock(&kcov_remote_lock);
+                               kcov_disable(t, kcov);
+                               return PTR_ERR(remote);
+                       }
+                       t->kcov_handle = remote_arg->common_handle;
+               }
+               spin_unlock(&kcov_remote_lock);
+               /* Put either in kcov_task_exit() or in KCOV_DISABLE. */
+               kcov_get(kcov);
+               return 0;
        default:
                return -ENOTTY;
        }
@@ -422,11 +674,35 @@ static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        struct kcov *kcov;
        int res;
+       struct kcov_remote_arg *remote_arg = NULL;
+       unsigned int remote_num_handles;
+       unsigned long remote_arg_size;
+
+       if (cmd == KCOV_REMOTE_ENABLE) {
+               if (get_user(remote_num_handles, (unsigned __user *)(arg +
+                               offsetof(struct kcov_remote_arg, num_handles))))
+                       return -EFAULT;
+               if (remote_num_handles > KCOV_REMOTE_MAX_HANDLES)
+                       return -EINVAL;
+               remote_arg_size = struct_size(remote_arg, handles,
+                                       remote_num_handles);
+               remote_arg = memdup_user((void __user *)arg, remote_arg_size);
+               if (IS_ERR(remote_arg))
+                       return PTR_ERR(remote_arg);
+               if (remote_arg->num_handles != remote_num_handles) {
+                       kfree(remote_arg);
+                       return -EINVAL;
+               }
+               arg = (unsigned long)remote_arg;
+       }
 
        kcov = filep->private_data;
        spin_lock(&kcov->lock);
        res = kcov_ioctl_locked(kcov, cmd, arg);
        spin_unlock(&kcov->lock);
+
+       kfree(remote_arg);
+
        return res;
 }
 
@@ -438,6 +714,207 @@ static const struct file_operations kcov_fops = {
        .release        = kcov_close,
 };
 
+/*
+ * kcov_remote_start() and kcov_remote_stop() can be used to annotate a section
+ * of code in a kernel background thread to allow kcov to be used to collect
+ * coverage from that part of code.
+ *
+ * The handle argument of kcov_remote_start() identifies a code section that is
+ * used for coverage collection. A userspace process passes this handle to
+ * KCOV_REMOTE_ENABLE ioctl to make the used kcov device start collecting
+ * coverage for the code section identified by this handle.
+ *
+ * The usage of these annotations in the kernel code is different depending on
+ * the type of the kernel thread whose code is being annotated.
+ *
+ * For global kernel threads that are spawned in a limited number of instances
+ * (e.g. one USB hub_event() worker thread is spawned per USB HCD), each
+ * instance must be assigned a unique 4-byte instance id. The instance id is
+ * then combined with a 1-byte subsystem id to get a handle via
+ * kcov_remote_handle(subsystem_id, instance_id).
+ *
+ * For local kernel threads that are spawned from system calls handler when a
+ * user interacts with some kernel interface (e.g. vhost workers), a handle is
+ * passed from a userspace process as the common_handle field of the
+ * kcov_remote_arg struct (note, that the user must generate a handle by using
+ * kcov_remote_handle() with KCOV_SUBSYSTEM_COMMON as the subsystem id and an
+ * arbitrary 4-byte non-zero number as the instance id). This common handle
+ * then gets saved into the task_struct of the process that issued the
+ * KCOV_REMOTE_ENABLE ioctl. When this proccess issues system calls that spawn
+ * kernel threads, the common handle must be retrived via kcov_common_handle()
+ * and passed to the spawned threads via custom annotations. Those kernel
+ * threads must in turn be annotated with kcov_remote_start(common_handle) and
+ * kcov_remote_stop(). All of the threads that are spawned by the same process
+ * obtain the same handle, hence the name "common".
+ *
+ * See Documentation/dev-tools/kcov.rst for more details.
+ *
+ * Internally, this function looks up the kcov device associated with the
+ * provided handle, allocates an area for coverage collection, and saves the
+ * pointers to kcov and area into the current task_struct to allow coverage to
+ * be collected via __sanitizer_cov_trace_pc()
+ * In turns kcov_remote_stop() clears those pointers from task_struct to stop
+ * collecting coverage and copies all collected coverage into the kcov area.
+ */
+void kcov_remote_start(u64 handle)
+{
+       struct kcov_remote *remote;
+       void *area;
+       struct task_struct *t;
+       unsigned int size;
+       enum kcov_mode mode;
+       int sequence;
+
+       if (WARN_ON(!kcov_check_handle(handle, true, true, true)))
+               return;
+       if (WARN_ON(!in_task()))
+               return;
+       t = current;
+       /*
+        * Check that kcov_remote_start is not called twice
+        * nor called by user tasks (with enabled kcov).
+        */
+       if (WARN_ON(t->kcov))
+               return;
+
+       kcov_debug("handle = %llx\n", handle);
+
+       spin_lock(&kcov_remote_lock);
+       remote = kcov_remote_find(handle);
+       if (!remote) {
+               kcov_debug("no remote found");
+               spin_unlock(&kcov_remote_lock);
+               return;
+       }
+       /* Put in kcov_remote_stop(). */
+       kcov_get(remote->kcov);
+       t->kcov = remote->kcov;
+       /*
+        * Read kcov fields before unlock to prevent races with
+        * KCOV_DISABLE / kcov_remote_reset().
+        */
+       size = remote->kcov->remote_size;
+       mode = remote->kcov->mode;
+       sequence = remote->kcov->sequence;
+       area = kcov_remote_area_get(size);
+       spin_unlock(&kcov_remote_lock);
+
+       if (!area) {
+               area = vmalloc(size * sizeof(unsigned long));
+               if (!area) {
+                       t->kcov = NULL;
+                       kcov_put(remote->kcov);
+                       return;
+               }
+       }
+       /* Reset coverage size. */
+       *(u64 *)area = 0;
+
+       kcov_debug("area = %px, size = %u", area, size);
+
+       kcov_start(t, size, area, mode, sequence);
+
+}
+EXPORT_SYMBOL(kcov_remote_start);
+
+static void kcov_move_area(enum kcov_mode mode, void *dst_area,
+                               unsigned int dst_area_size, void *src_area)
+{
+       u64 word_size = sizeof(unsigned long);
+       u64 count_size, entry_size_log;
+       u64 dst_len, src_len;
+       void *dst_entries, *src_entries;
+       u64 dst_occupied, dst_free, bytes_to_move, entries_moved;
+
+       kcov_debug("%px %u <= %px %lu\n",
+               dst_area, dst_area_size, src_area, *(unsigned long *)src_area);
+
+       switch (mode) {
+       case KCOV_MODE_TRACE_PC:
+               dst_len = READ_ONCE(*(unsigned long *)dst_area);
+               src_len = *(unsigned long *)src_area;
+               count_size = sizeof(unsigned long);
+               entry_size_log = __ilog2_u64(sizeof(unsigned long));
+               break;
+       case KCOV_MODE_TRACE_CMP:
+               dst_len = READ_ONCE(*(u64 *)dst_area);
+               src_len = *(u64 *)src_area;
+               count_size = sizeof(u64);
+               BUILD_BUG_ON(!is_power_of_2(KCOV_WORDS_PER_CMP));
+               entry_size_log = __ilog2_u64(sizeof(u64) * KCOV_WORDS_PER_CMP);
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+
+       /* As arm can't divide u64 integers use log of entry size. */
+       if (dst_len > ((dst_area_size * word_size - count_size) >>
+                               entry_size_log))
+               return;
+       dst_occupied = count_size + (dst_len << entry_size_log);
+       dst_free = dst_area_size * word_size - dst_occupied;
+       bytes_to_move = min(dst_free, src_len << entry_size_log);
+       dst_entries = dst_area + dst_occupied;
+       src_entries = src_area + count_size;
+       memcpy(dst_entries, src_entries, bytes_to_move);
+       entries_moved = bytes_to_move >> entry_size_log;
+
+       switch (mode) {
+       case KCOV_MODE_TRACE_PC:
+               WRITE_ONCE(*(unsigned long *)dst_area, dst_len + entries_moved);
+               break;
+       case KCOV_MODE_TRACE_CMP:
+               WRITE_ONCE(*(u64 *)dst_area, dst_len + entries_moved);
+               break;
+       default:
+               break;
+       }
+}
+
+/* See the comment before kcov_remote_start() for usage details. */
+void kcov_remote_stop(void)
+{
+       struct task_struct *t = current;
+       struct kcov *kcov = t->kcov;
+       void *area = t->kcov_area;
+       unsigned int size = t->kcov_size;
+       int sequence = t->kcov_sequence;
+
+       if (!kcov) {
+               kcov_debug("no kcov found\n");
+               return;
+       }
+
+       kcov_stop(t);
+       t->kcov = NULL;
+
+       spin_lock(&kcov->lock);
+       /*
+        * KCOV_DISABLE could have been called between kcov_remote_start()
+        * and kcov_remote_stop(), hence the check.
+        */
+       kcov_debug("move if: %d == %d && %d\n",
+               sequence, kcov->sequence, (int)kcov->remote);
+       if (sequence == kcov->sequence && kcov->remote)
+               kcov_move_area(kcov->mode, kcov->area, kcov->size, area);
+       spin_unlock(&kcov->lock);
+
+       spin_lock(&kcov_remote_lock);
+       kcov_remote_area_put(area, size);
+       spin_unlock(&kcov_remote_lock);
+
+       kcov_put(kcov);
+}
+EXPORT_SYMBOL(kcov_remote_stop);
+
+/* See the comment before kcov_remote_start() for usage details. */
+u64 kcov_common_handle(void)
+{
+       return current->kcov_handle;
+}
+EXPORT_SYMBOL(kcov_common_handle);
+
 static int __init kcov_init(void)
 {
        /*
index 052a402..3a486f8 100644 (file)
@@ -1033,6 +1033,8 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
        strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
 
        free_module(mod);
+       /* someone could wait for the module in add_unformed_module() */
+       wake_up_all(&module_wq);
        return 0;
 out:
        mutex_unlock(&module_mutex);
@@ -1400,7 +1402,7 @@ static int verify_namespace_is_imported(const struct load_info *info,
        char *imported_namespace;
 
        namespace = kernel_symbol_namespace(sym);
-       if (namespace) {
+       if (namespace && namespace[0]) {
                imported_namespace = get_modinfo(info, "import_ns");
                while (imported_namespace) {
                        if (strcmp(namespace, imported_namespace) == 0)
index d9f5081..63d7501 100644 (file)
@@ -23,22 +23,10 @@ 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);
-       }
-       n->next = *nl;
-       rcu_assign_pointer(*nl, n);
-       return 0;
-}
-
-static int notifier_chain_cond_register(struct notifier_block **nl,
-               struct notifier_block *n)
-{
-       while ((*nl) != NULL) {
-               if ((*nl) == n)
+               if (unlikely((*nl) == n)) {
+                       WARN(1, "double register detected");
                        return 0;
+               }
                if (n->priority > (*nl)->priority)
                        break;
                nl = &((*nl)->next);
@@ -232,29 +220,6 @@ int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
 
-/**
- *     blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain
- *     @nh: Pointer to head of the blocking notifier chain
- *     @n: New entry in notifier chain
- *
- *     Adds a notifier to a blocking notifier chain, only if not already
- *     present in the chain.
- *     Must be called in process context.
- *
- *     Currently always returns zero.
- */
-int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh,
-               struct notifier_block *n)
-{
-       int ret;
-
-       down_write(&nh->rwsem);
-       ret = notifier_chain_cond_register(&nh->head, n);
-       up_write(&nh->rwsem);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register);
-
 /**
  *     blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
  *     @nh: Pointer to head of the blocking notifier chain
index a45cba7..83edf86 100644 (file)
@@ -714,8 +714,10 @@ s32 freq_qos_read_value(struct freq_constraints *qos,
  * @req: Constraint request to apply.
  * @action: Action to perform (add/update/remove).
  * @value: Value to assign to the QoS request.
+ *
+ * This is only meant to be called from inside pm_qos, not drivers.
  */
-static int freq_qos_apply(struct freq_qos_request *req,
+int freq_qos_apply(struct freq_qos_request *req,
                          enum pm_qos_req_action action, s32 value)
 {
        int ret;
index c8be5a0..1ef6f75 100644 (file)
@@ -2961,7 +2961,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
 
 static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
        .func = wake_up_klogd_work_func,
-       .flags = IRQ_WORK_LAZY,
+       .flags = ATOMIC_INIT(IRQ_WORK_LAZY),
 };
 
 void wake_up_klogd(void)
index af7c94b..4b144b0 100644 (file)
@@ -336,7 +336,7 @@ static int profile_dead_cpu(unsigned int cpu)
        struct page *page;
        int i;
 
-       if (prof_cpu_mask != NULL)
+       if (cpumask_available(prof_cpu_mask))
                cpumask_clear_cpu(cpu, prof_cpu_mask);
 
        for (i = 0; i < 2; i++) {
@@ -373,7 +373,7 @@ static int profile_prepare_cpu(unsigned int cpu)
 
 static int profile_online_cpu(unsigned int cpu)
 {
-       if (prof_cpu_mask != NULL)
+       if (cpumask_available(prof_cpu_mask))
                cpumask_set_cpu(cpu, prof_cpu_mask);
 
        return 0;
@@ -403,7 +403,7 @@ void profile_tick(int type)
 {
        struct pt_regs *regs = get_irq_regs();
 
-       if (!user_mode(regs) && prof_cpu_mask != NULL &&
+       if (!user_mode(regs) && cpumask_available(prof_cpu_mask) &&
            cpumask_test_cpu(smp_processor_id(), prof_cpu_mask))
                profile_hit(type, (void *)profile_pc(regs));
 }
index 86800b4..322ca88 100644 (file)
@@ -915,7 +915,7 @@ static int __init sugov_register(void)
 {
        return cpufreq_register_governor(&schedutil_gov);
 }
-fs_initcall(sugov_register);
+core_initcall(sugov_register);
 
 #ifdef CONFIG_ENERGY_MODEL
 extern bool sched_energy_update;
index d3aef31..a9331f1 100644 (file)
@@ -1279,11 +1279,13 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
 
 SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
 {
-       struct oldold_utsname tmp = {};
+       struct oldold_utsname tmp;
 
        if (!name)
                return -EFAULT;
 
+       memset(&tmp, 0, sizeof(tmp));
+
        down_read(&uts_sem);
        memcpy(&tmp.sysname, &utsname()->sysname, __OLD_UTS_LEN);
        memcpy(&tmp.nodename, &utsname()->nodename, __OLD_UTS_LEN);
index b6f2f35..7066593 100644 (file)
@@ -1466,7 +1466,7 @@ static struct ctl_table vm_table[] = {
                .procname       = "drop_caches",
                .data           = &sysctl_drop_caches,
                .maxlen         = sizeof(int),
-               .mode           = 0644,
+               .mode           = 0200,
                .proc_handler   = drop_caches_sysctl_handler,
                .extra1         = SYSCTL_ONE,
                .extra2         = &four,
index 9e20873..8de90ea 100644 (file)
@@ -966,7 +966,8 @@ static int enqueue_hrtimer(struct hrtimer *timer,
 
        base->cpu_base->active_bases |= 1 << base->index;
 
-       timer->state = HRTIMER_STATE_ENQUEUED;
+       /* Pairs with the lockless read in hrtimer_is_queued() */
+       WRITE_ONCE(timer->state, HRTIMER_STATE_ENQUEUED);
 
        return timerqueue_add(&base->active, &timer->node);
 }
@@ -988,7 +989,8 @@ static void __remove_hrtimer(struct hrtimer *timer,
        struct hrtimer_cpu_base *cpu_base = base->cpu_base;
        u8 state = timer->state;
 
-       timer->state = newstate;
+       /* Pairs with the lockless read in hrtimer_is_queued() */
+       WRITE_ONCE(timer->state, newstate);
        if (!(state & HRTIMER_STATE_ENQUEUED))
                return;
 
@@ -1013,8 +1015,9 @@ static void __remove_hrtimer(struct hrtimer *timer,
 static inline int
 remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart)
 {
-       if (hrtimer_is_queued(timer)) {
-               u8 state = timer->state;
+       u8 state = timer->state;
+
+       if (state & HRTIMER_STATE_ENQUEUED) {
                int reprogram;
 
                /*
index 58e312e..704ccd9 100644 (file)
@@ -179,7 +179,7 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz
                return error;
 
        if (tz) {
-               /* Verify we're witin the +-15 hrs range */
+               /* Verify we're within the +-15 hrs range */
                if (tz->tz_minuteswest > 15*60 || tz->tz_minuteswest < -15*60)
                        return -EINVAL;
 
@@ -548,18 +548,21 @@ EXPORT_SYMBOL(set_normalized_timespec64);
  */
 struct timespec64 ns_to_timespec64(const s64 nsec)
 {
-       struct timespec64 ts;
+       struct timespec64 ts = { 0, 0 };
        s32 rem;
 
-       if (!nsec)
-               return (struct timespec64) {0, 0};
-
-       ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
-       if (unlikely(rem < 0)) {
-               ts.tv_sec--;
-               rem += NSEC_PER_SEC;
+       if (likely(nsec > 0)) {
+               ts.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
+               ts.tv_nsec = rem;
+       } else if (nsec < 0) {
+               /*
+                * With negative times, tv_sec points to the earlier
+                * second, and tv_nsec counts the nanoseconds since
+                * then, so tv_nsec is always a positive number.
+                */
+               ts.tv_sec = -div_u64_rem(-nsec - 1, NSEC_PER_SEC, &rem) - 1;
+               ts.tv_nsec = NSEC_PER_SEC - rem - 1;
        }
-       ts.tv_nsec = rem;
 
        return ts;
 }
@@ -878,10 +881,11 @@ int get_timespec64(struct timespec64 *ts,
 
        ts->tv_sec = kts.tv_sec;
 
-       /* Zero out the padding for 32 bit systems or in compat mode */
+       /* Zero out the padding in compat mode */
        if (in_compat_syscall())
                kts.tv_nsec &= 0xFFFFFFFFUL;
 
+       /* In 32-bit mode, this drops the padding */
        ts->tv_nsec = kts.tv_nsec;
 
        return 0;
index cdf5afa..25a0fcf 100644 (file)
@@ -671,6 +671,15 @@ config HIST_TRIGGERS
          See Documentation/trace/histogram.rst.
          If in doubt, say N.
 
+config TRACE_EVENT_INJECT
+       bool "Trace event injection"
+       depends on TRACING
+       help
+         Allow user-space to inject a specific trace event into the ring
+         buffer. This is mainly used for testing purpose.
+
+         If unsure, say N.
+
 config MMIOTRACE_TEST
        tristate "Test module for mmiotrace"
        depends on MMIOTRACE && m
index c2b2148..0e63db6 100644 (file)
@@ -69,6 +69,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o
 endif
 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
 obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o
+obj-$(CONFIG_TRACE_EVENT_INJECT) += trace_events_inject.o
 obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o
 obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o
 obj-$(CONFIG_KPROBE_EVENTS) += trace_kprobe.o
index ffc91d4..e5ef4ae 100644 (file)
@@ -739,7 +739,7 @@ BPF_CALL_1(bpf_send_signal, u32, sig)
                        return -EINVAL;
 
                work = this_cpu_ptr(&send_signal_work);
-               if (work->irq_work.flags & IRQ_WORK_BUSY)
+               if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY)
                        return -EBUSY;
 
                /* Add the current task, which is the target of sending signal,
index 66358d6..4bf050f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/trace_seq.h>
 #include <linux/spinlock.h>
 #include <linux/irq_work.h>
+#include <linux/security.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
 #include <linux/kthread.h>     /* for self test */
@@ -5068,6 +5069,11 @@ static __init int test_ringbuffer(void)
        int cpu;
        int ret = 0;
 
+       if (security_locked_down(LOCKDOWN_TRACEFS)) {
+               pr_warning("Lockdown is enabled, skipping ring buffer tests\n");
+               return 0;
+       }
+
        pr_info("Running ring buffer tests...\n");
 
        buffer = ring_buffer_alloc(RB_TEST_BUFFER_SIZE, RB_FL_OVERWRITE);
index 02a23a6..23459d5 100644 (file)
@@ -1888,6 +1888,12 @@ int __init register_tracer(struct tracer *type)
                return -1;
        }
 
+       if (security_locked_down(LOCKDOWN_TRACEFS)) {
+               pr_warning("Can not register tracer %s due to lockdown\n",
+                          type->name);
+               return -EPERM;
+       }
+
        mutex_lock(&trace_types_lock);
 
        tracing_selftest_running = true;
@@ -8789,6 +8795,11 @@ struct dentry *tracing_init_dentry(void)
 {
        struct trace_array *tr = &global_trace;
 
+       if (security_locked_down(LOCKDOWN_TRACEFS)) {
+               pr_warning("Tracing disabled due to lockdown\n");
+               return ERR_PTR(-EPERM);
+       }
+
        /* The top level trace array uses  NULL as parent */
        if (tr->dir)
                return NULL;
@@ -9231,6 +9242,12 @@ __init static int tracer_alloc_buffers(void)
        int ring_buf_size;
        int ret = -ENOMEM;
 
+
+       if (security_locked_down(LOCKDOWN_TRACEFS)) {
+               pr_warning("Tracing disabled due to lockdown\n");
+               return -EPERM;
+       }
+
        /*
         * Make sure we don't accidently add more trace options
         * than we have bits for.
index ca7fcca..63bf60f 100644 (file)
@@ -1601,6 +1601,7 @@ extern struct list_head ftrace_events;
 
 extern const struct file_operations event_trigger_fops;
 extern const struct file_operations event_hist_fops;
+extern const struct file_operations event_inject_fops;
 
 #ifdef CONFIG_HIST_TRIGGERS
 extern int register_trigger_hist_cmd(void);
index 6b3a69e..c6de3ce 100644 (file)
@@ -2044,6 +2044,12 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
        trace_create_file("format", 0444, file->dir, call,
                          &ftrace_event_format_fops);
 
+#ifdef CONFIG_TRACE_EVENT_INJECT
+       if (call->event.type && call->class->reg)
+               trace_create_file("inject", 0200, file->dir, file,
+                                 &event_inject_fops);
+#endif
+
        return 0;
 }
 
diff --git a/kernel/trace/trace_events_inject.c b/kernel/trace/trace_events_inject.c
new file mode 100644 (file)
index 0000000..d437107
--- /dev/null
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * trace_events_inject - trace event injection
+ *
+ * Copyright (C) 2019 Cong Wang <cwang@twitter.com>
+ */
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/rculist.h>
+
+#include "trace.h"
+
+static int
+trace_inject_entry(struct trace_event_file *file, void *rec, int len)
+{
+       struct trace_event_buffer fbuffer;
+       struct ring_buffer *buffer;
+       int written = 0;
+       void *entry;
+
+       rcu_read_lock_sched();
+       buffer = file->tr->trace_buffer.buffer;
+       entry = trace_event_buffer_reserve(&fbuffer, file, len);
+       if (entry) {
+               memcpy(entry, rec, len);
+               written = len;
+               trace_event_buffer_commit(&fbuffer);
+       }
+       rcu_read_unlock_sched();
+
+       return written;
+}
+
+static int
+parse_field(char *str, struct trace_event_call *call,
+           struct ftrace_event_field **pf, u64 *pv)
+{
+       struct ftrace_event_field *field;
+       char *field_name;
+       int s, i = 0;
+       int len;
+       u64 val;
+
+       if (!str[i])
+               return 0;
+       /* First find the field to associate to */
+       while (isspace(str[i]))
+               i++;
+       s = i;
+       while (isalnum(str[i]) || str[i] == '_')
+               i++;
+       len = i - s;
+       if (!len)
+               return -EINVAL;
+
+       field_name = kmemdup_nul(str + s, len, GFP_KERNEL);
+       if (!field_name)
+               return -ENOMEM;
+       field = trace_find_event_field(call, field_name);
+       kfree(field_name);
+       if (!field)
+               return -ENOENT;
+
+       *pf = field;
+       while (isspace(str[i]))
+               i++;
+       if (str[i] != '=')
+               return -EINVAL;
+       i++;
+       while (isspace(str[i]))
+               i++;
+       s = i;
+       if (isdigit(str[i]) || str[i] == '-') {
+               char *num, c;
+               int ret;
+
+               /* Make sure the field is not a string */
+               if (is_string_field(field))
+                       return -EINVAL;
+
+               if (str[i] == '-')
+                       i++;
+
+               /* We allow 0xDEADBEEF */
+               while (isalnum(str[i]))
+                       i++;
+               num = str + s;
+               c = str[i];
+               if (c != '\0' && !isspace(c))
+                       return -EINVAL;
+               str[i] = '\0';
+               /* Make sure it is a value */
+               if (field->is_signed)
+                       ret = kstrtoll(num, 0, &val);
+               else
+                       ret = kstrtoull(num, 0, &val);
+               str[i] = c;
+               if (ret)
+                       return ret;
+
+               *pv = val;
+               return i;
+       } else if (str[i] == '\'' || str[i] == '"') {
+               char q = str[i];
+
+               /* Make sure the field is OK for strings */
+               if (!is_string_field(field))
+                       return -EINVAL;
+
+               for (i++; str[i]; i++) {
+                       if (str[i] == '\\' && str[i + 1]) {
+                               i++;
+                               continue;
+                       }
+                       if (str[i] == q)
+                               break;
+               }
+               if (!str[i])
+                       return -EINVAL;
+
+               /* Skip quotes */
+               s++;
+               len = i - s;
+               if (len >= MAX_FILTER_STR_VAL)
+                       return -EINVAL;
+
+               *pv = (unsigned long)(str + s);
+               str[i] = 0;
+               /* go past the last quote */
+               i++;
+               return i;
+       }
+
+       return -EINVAL;
+}
+
+static int trace_get_entry_size(struct trace_event_call *call)
+{
+       struct ftrace_event_field *field;
+       struct list_head *head;
+       int size = 0;
+
+       head = trace_get_fields(call);
+       list_for_each_entry(field, head, link) {
+               if (field->size + field->offset > size)
+                       size = field->size + field->offset;
+       }
+
+       return size;
+}
+
+static void *trace_alloc_entry(struct trace_event_call *call, int *size)
+{
+       int entry_size = trace_get_entry_size(call);
+       struct ftrace_event_field *field;
+       struct list_head *head;
+       void *entry = NULL;
+
+       /* We need an extra '\0' at the end. */
+       entry = kzalloc(entry_size + 1, GFP_KERNEL);
+       if (!entry)
+               return NULL;
+
+       head = trace_get_fields(call);
+       list_for_each_entry(field, head, link) {
+               if (!is_string_field(field))
+                       continue;
+               if (field->filter_type == FILTER_STATIC_STRING)
+                       continue;
+               if (field->filter_type == FILTER_DYN_STRING) {
+                       u32 *str_item;
+                       int str_loc = entry_size & 0xffff;
+
+                       str_item = (u32 *)(entry + field->offset);
+                       *str_item = str_loc; /* string length is 0. */
+               } else {
+                       char **paddr;
+
+                       paddr = (char **)(entry + field->offset);
+                       *paddr = "";
+               }
+       }
+
+       *size = entry_size + 1;
+       return entry;
+}
+
+#define INJECT_STRING "STATIC STRING CAN NOT BE INJECTED"
+
+/* Caller is responsible to free the *pentry. */
+static int parse_entry(char *str, struct trace_event_call *call, void **pentry)
+{
+       struct ftrace_event_field *field;
+       unsigned long irq_flags;
+       void *entry = NULL;
+       int entry_size;
+       u64 val;
+       int len;
+
+       entry = trace_alloc_entry(call, &entry_size);
+       *pentry = entry;
+       if (!entry)
+               return -ENOMEM;
+
+       local_save_flags(irq_flags);
+       tracing_generic_entry_update(entry, call->event.type, irq_flags,
+                                    preempt_count());
+
+       while ((len = parse_field(str, call, &field, &val)) > 0) {
+               if (is_function_field(field))
+                       return -EINVAL;
+
+               if (is_string_field(field)) {
+                       char *addr = (char *)(unsigned long) val;
+
+                       if (field->filter_type == FILTER_STATIC_STRING) {
+                               strlcpy(entry + field->offset, addr, field->size);
+                       } else if (field->filter_type == FILTER_DYN_STRING) {
+                               int str_len = strlen(addr) + 1;
+                               int str_loc = entry_size & 0xffff;
+                               u32 *str_item;
+
+                               entry_size += str_len;
+                               *pentry = krealloc(entry, entry_size, GFP_KERNEL);
+                               if (!*pentry) {
+                                       kfree(entry);
+                                       return -ENOMEM;
+                               }
+                               entry = *pentry;
+
+                               strlcpy(entry + (entry_size - str_len), addr, str_len);
+                               str_item = (u32 *)(entry + field->offset);
+                               *str_item = (str_len << 16) | str_loc;
+                       } else {
+                               char **paddr;
+
+                               paddr = (char **)(entry + field->offset);
+                               *paddr = INJECT_STRING;
+                       }
+               } else {
+                       switch (field->size) {
+                       case 1: {
+                               u8 tmp = (u8) val;
+
+                               memcpy(entry + field->offset, &tmp, 1);
+                               break;
+                       }
+                       case 2: {
+                               u16 tmp = (u16) val;
+
+                               memcpy(entry + field->offset, &tmp, 2);
+                               break;
+                       }
+                       case 4: {
+                               u32 tmp = (u32) val;
+
+                               memcpy(entry + field->offset, &tmp, 4);
+                               break;
+                       }
+                       case 8:
+                               memcpy(entry + field->offset, &val, 8);
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+
+               str += len;
+       }
+
+       if (len < 0)
+               return len;
+
+       return entry_size;
+}
+
+static ssize_t
+event_inject_write(struct file *filp, const char __user *ubuf, size_t cnt,
+                  loff_t *ppos)
+{
+       struct trace_event_call *call;
+       struct trace_event_file *file;
+       int err = -ENODEV, size;
+       void *entry = NULL;
+       char *buf;
+
+       if (cnt >= PAGE_SIZE)
+               return -EINVAL;
+
+       buf = memdup_user_nul(ubuf, cnt);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+       strim(buf);
+
+       mutex_lock(&event_mutex);
+       file = event_file_data(filp);
+       if (file) {
+               call = file->event_call;
+               size = parse_entry(buf, call, &entry);
+               if (size < 0)
+                       err = size;
+               else
+                       err = trace_inject_entry(file, entry, size);
+       }
+       mutex_unlock(&event_mutex);
+
+       kfree(entry);
+       kfree(buf);
+
+       if (err < 0)
+               return err;
+
+       *ppos += err;
+       return cnt;
+}
+
+static ssize_t
+event_inject_read(struct file *file, char __user *buf, size_t size,
+                 loff_t *ppos)
+{
+       return -EPERM;
+}
+
+const struct file_operations event_inject_fops = {
+       .open = tracing_open_generic,
+       .read = event_inject_read,
+       .write = event_inject_write,
+};
index ab9a8ef..2f6fb96 100644 (file)
@@ -308,17 +308,6 @@ config HEADERS_INSTALL
          user-space program samples. It is also needed by some features such
          as uapi header sanity checks.
 
-config HEADERS_CHECK
-       bool "Run sanity checks on uapi headers when building 'all'"
-       depends on HEADERS_INSTALL
-       help
-         This option will run basic sanity checks on uapi headers when
-         building the 'all' target, for example, ensure that they do not
-         attempt to include files which were not exported, etc.
-
-         If you're making modifications to header files which are
-         relevant for userspace, say 'Y'.
-
 config OPTIMIZE_INLINING
        def_bool y
        help
index 6c9682c..81f5464 100644 (file)
@@ -6,6 +6,9 @@ config HAVE_ARCH_KASAN
 config HAVE_ARCH_KASAN_SW_TAGS
        bool
 
+config HAVE_ARCH_KASAN_VMALLOC
+       bool
+
 config CC_HAS_KASAN_GENERIC
        def_bool $(cc-option, -fsanitize=kernel-address)
 
@@ -142,6 +145,19 @@ config KASAN_SW_TAGS_IDENTIFY
          (use-after-free or out-of-bounds) at the cost of increased
          memory consumption.
 
+config KASAN_VMALLOC
+       bool "Back mappings in vmalloc space with real shadow memory"
+       depends on KASAN && HAVE_ARCH_KASAN_VMALLOC
+       help
+         By default, the shadow region for vmalloc space is the read-only
+         zero page. This means that KASAN cannot detect errors involving
+         vmalloc space.
+
+         Enabling this option will hook in to vmap/vmalloc and back those
+         mappings with real shadow memory allocated on demand. This allows
+         for KASAN to detect more sorts of errors (and to support vmapped
+         stacks), but at the cost of higher memory usage.
+
 config TEST_KASAN
        tristate "Module for testing KASAN for bug detection"
        depends on m && KASAN
index c2f0e2a..93217d4 100644 (file)
@@ -109,7 +109,7 @@ obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
 
-obj-y += logic_pio.o
+lib-y += logic_pio.o
 
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
index f9e8348..4250519 100644 (file)
@@ -222,6 +222,18 @@ int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
 }
 EXPORT_SYMBOL(__bitmap_andnot);
 
+void __bitmap_replace(unsigned long *dst,
+                     const unsigned long *old, const unsigned long *new,
+                     const unsigned long *mask, unsigned int nbits)
+{
+       unsigned int k;
+       unsigned int nr = BITS_TO_LONGS(nbits);
+
+       for (k = 0; k < nr; k++)
+               dst[k] = (old[k] & ~mask[k]) | (new[k] & mask[k]);
+}
+EXPORT_SYMBOL(__bitmap_replace);
+
 int __bitmap_intersects(const unsigned long *bitmap1,
                        const unsigned long *bitmap2, unsigned int bits)
 {
index d6632c1..f56070c 100644 (file)
@@ -303,7 +303,7 @@ EXPORT_SYMBOL(devm_ioport_unmap);
 /*
  * PCI iomap devres
  */
-#define PCIM_IOMAP_MAX PCI_ROM_RESOURCE
+#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
 
 struct pcim_iomap_devres {
        void __iomem *table[PCIM_IOMAP_MAX];
index 5c51eb4..e35a76b 100644 (file)
@@ -214,3 +214,17 @@ EXPORT_SYMBOL(find_next_bit_le);
 #endif
 
 #endif /* __BIG_ENDIAN */
+
+unsigned long find_next_clump8(unsigned long *clump, const unsigned long *addr,
+                              unsigned long size, unsigned long offset)
+{
+       offset = find_next_bit(addr, size, offset);
+       if (offset == size)
+               return size;
+
+       offset = round_down(offset, 8);
+       *clump = bitmap_get_value8(addr, offset);
+
+       return offset;
+}
+EXPORT_SYMBOL(find_next_clump8);
index 9fc3129..7f1244b 100644 (file)
@@ -472,7 +472,7 @@ void *gen_pool_dma_zalloc_align(struct gen_pool *pool, size_t size,
 EXPORT_SYMBOL(gen_pool_dma_zalloc_align);
 
 /**
- * gen_pool_free - free allocated special memory back to the pool
+ * gen_pool_free_owner - free allocated special memory back to the pool
  * @pool: pool to free to
  * @addr: starting address of memory to free back to pool
  * @size: size in bytes of memory to free
@@ -540,7 +540,7 @@ void gen_pool_for_each_chunk(struct gen_pool *pool,
 EXPORT_SYMBOL(gen_pool_for_each_chunk);
 
 /**
- * addr_in_gen_pool - checks if an address falls within the range of a pool
+ * gen_pool_has_addr - checks if an address falls within the range of a pool
  * @pool:      the generic memory pool
  * @start:     start address
  * @size:      size of the region
@@ -548,7 +548,7 @@ EXPORT_SYMBOL(gen_pool_for_each_chunk);
  * Check if the range of addresses falls within the specified pool. Returns
  * true if the entire range is contained in the pool and false otherwise.
  */
-bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start,
+bool gen_pool_has_addr(struct gen_pool *pool, unsigned long start,
                        size_t size)
 {
        bool found = false;
@@ -567,6 +567,7 @@ bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start,
        rcu_read_unlock();
        return found;
 }
+EXPORT_SYMBOL(gen_pool_has_addr);
 
 /**
  * gen_pool_avail - get available free space of the pool
index 9050275..f511a99 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2017 HiSilicon Limited, All Rights Reserved.
  * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
  * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: John Garry <john.garry@huawei.com>
  */
 
 #define pr_fmt(fmt)    "LOGIC PIO: " fmt
@@ -39,7 +40,8 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
        resource_size_t iio_sz = MMIO_UPPER_LIMIT;
        int ret = 0;
 
-       if (!new_range || !new_range->fwnode || !new_range->size)
+       if (!new_range || !new_range->fwnode || !new_range->size ||
+           (new_range->flags == LOGIC_PIO_INDIRECT && !new_range->ops))
                return -EINVAL;
 
        start = new_range->hw_start;
@@ -237,7 +239,7 @@ type logic_in##bw(unsigned long addr)                                       \
        } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
                struct logic_pio_hwaddr *entry = find_io_range(addr);   \
                                                                        \
-               if (entry && entry->ops)                                \
+               if (entry)                                              \
                        ret = entry->ops->in(entry->hostdata,           \
                                        addr, sizeof(type));            \
                else                                                    \
@@ -253,7 +255,7 @@ void logic_out##bw(type value, unsigned long addr)                  \
        } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
                struct logic_pio_hwaddr *entry = find_io_range(addr);   \
                                                                        \
-               if (entry && entry->ops)                                \
+               if (entry)                                              \
                        entry->ops->out(entry->hostdata,                \
                                        addr, value, sizeof(type));     \
                else                                                    \
@@ -261,7 +263,7 @@ void logic_out##bw(type value, unsigned long addr)                  \
        }                                                               \
 }                                                                      \
                                                                        \
-void logic_ins##bw(unsigned long addr, void *buffer,           \
+void logic_ins##bw(unsigned long addr, void *buffer,                   \
                   unsigned int count)                                  \
 {                                                                      \
        if (addr < MMIO_UPPER_LIMIT) {                                  \
@@ -269,7 +271,7 @@ void logic_ins##bw(unsigned long addr, void *buffer,                \
        } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
                struct logic_pio_hwaddr *entry = find_io_range(addr);   \
                                                                        \
-               if (entry && entry->ops)                                \
+               if (entry)                                              \
                        entry->ops->ins(entry->hostdata,                \
                                addr, buffer, sizeof(type), count);     \
                else                                                    \
@@ -286,7 +288,7 @@ void logic_outs##bw(unsigned long addr, const void *buffer,         \
        } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
                struct logic_pio_hwaddr *entry = find_io_range(addr);   \
                                                                        \
-               if (entry && entry->ops)                                \
+               if (entry)                                              \
                        entry->ops->outs(entry->hostdata,               \
                                addr, buffer, sizeof(type), count);     \
                else                                                    \
index ba74436..31fb27d 100644 (file)
@@ -3,6 +3,7 @@
  * rational fractions
  *
  * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
+ * Copyright (C) 2019 Trent Piepho <tpiepho@gmail.com>
  *
  * helper functions when coping with rational numbers
  */
@@ -10,6 +11,7 @@
 #include <linux/rational.h>
 #include <linux/compiler.h>
 #include <linux/export.h>
+#include <linux/kernel.h>
 
 /*
  * calculate best rational approximation for a given fraction
@@ -33,30 +35,65 @@ void rational_best_approximation(
        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/d is the starting rational, which is continually
+        * decreased each iteration using the Euclidean algorithm.
+        *
+        * dp is the value of d from the prior iteration.
+        *
+        * n2/d2, n1/d1, and n0/d0 are our successively more accurate
+        * approximations of the rational.  They are, respectively,
+        * the current, previous, and two prior iterations of it.
+        *
+        * a is current term of the continued fraction.
+        */
+       unsigned long n, d, n0, d0, n1, d1, n2, d2;
        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;
-               }
+               unsigned long dp, a;
+
                if (d == 0)
                        break;
-               t = d;
+               /* Find next term in continued fraction, 'a', via
+                * Euclidean algorithm.
+                */
+               dp = d;
                a = n / d;
                d = n % d;
-               n = t;
-               t = n0 + a * n1;
+               n = dp;
+
+               /* Calculate the current rational approximation (aka
+                * convergent), n2/d2, using the term just found and
+                * the two prior approximations.
+                */
+               n2 = n0 + a * n1;
+               d2 = d0 + a * d1;
+
+               /* If the current convergent exceeds the maxes, then
+                * return either the previous convergent or the
+                * largest semi-convergent, the final term of which is
+                * found below as 't'.
+                */
+               if ((n2 > max_numerator) || (d2 > max_denominator)) {
+                       unsigned long t = min((max_numerator - n0) / n1,
+                                             (max_denominator - d0) / d1);
+
+                       /* This tests if the semi-convergent is closer
+                        * than the previous convergent.
+                        */
+                       if (2u * t > a || (2u * t == a && d0 * dp > d1 * d)) {
+                               n1 = n0 + t * n1;
+                               d1 = d0 + t * d1;
+                       }
+                       break;
+               }
                n0 = n1;
-               n1 = t;
-               t = d0 + a * d1;
+               n1 = n2;
                d0 = d1;
-               d1 = t;
+               d1 = d2;
        }
        *best_numerator = n1;
        *best_denominator = d1;
index 51a98f7..e14a15a 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Test cases for printf facility.
+ * Test cases for bitmap API.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -21,6 +21,39 @@ static unsigned failed_tests __initdata;
 
 static char pbl_buffer[PAGE_SIZE] __initdata;
 
+static const unsigned long exp1[] __initconst = {
+       BITMAP_FROM_U64(1),
+       BITMAP_FROM_U64(2),
+       BITMAP_FROM_U64(0x0000ffff),
+       BITMAP_FROM_U64(0xffff0000),
+       BITMAP_FROM_U64(0x55555555),
+       BITMAP_FROM_U64(0xaaaaaaaa),
+       BITMAP_FROM_U64(0x11111111),
+       BITMAP_FROM_U64(0x22222222),
+       BITMAP_FROM_U64(0xffffffff),
+       BITMAP_FROM_U64(0xfffffffe),
+       BITMAP_FROM_U64(0x3333333311111111ULL),
+       BITMAP_FROM_U64(0xffffffff77777777ULL),
+       BITMAP_FROM_U64(0),
+};
+
+static const unsigned long exp2[] __initconst = {
+       BITMAP_FROM_U64(0x3333333311111111ULL),
+       BITMAP_FROM_U64(0xffffffff77777777ULL),
+};
+
+/* Fibonacci sequence */
+static const unsigned long exp2_to_exp3_mask[] __initconst = {
+       BITMAP_FROM_U64(0x008000020020212eULL),
+};
+/* exp3_0_1 = (exp2[0] & ~exp2_to_exp3_mask) | (exp2[1] & exp2_to_exp3_mask) */
+static const unsigned long exp3_0_1[] __initconst = {
+       BITMAP_FROM_U64(0x33b3333311313137ULL),
+};
+/* exp3_1_0 = (exp2[1] & ~exp2_to_exp3_mask) | (exp2[0] & exp2_to_exp3_mask) */
+static const unsigned long exp3_1_0[] __initconst = {
+       BITMAP_FROM_U64(0xff7fffff77575751ULL),
+};
 
 static bool __init
 __check_eq_uint(const char *srcfile, unsigned int line,
@@ -92,6 +125,36 @@ __check_eq_u32_array(const char *srcfile, unsigned int line,
        return true;
 }
 
+static bool __init __check_eq_clump8(const char *srcfile, unsigned int line,
+                                   const unsigned int offset,
+                                   const unsigned int size,
+                                   const unsigned char *const clump_exp,
+                                   const unsigned long *const clump)
+{
+       unsigned long exp;
+
+       if (offset >= size) {
+               pr_warn("[%s:%u] bit offset for clump out-of-bounds: expected less than %u, got %u\n",
+                       srcfile, line, size, offset);
+               return false;
+       }
+
+       exp = clump_exp[offset / 8];
+       if (!exp) {
+               pr_warn("[%s:%u] bit offset for zero clump: expected nonzero clump, got bit offset %u with clump value 0",
+                       srcfile, line, offset);
+               return false;
+       }
+
+       if (*clump != exp) {
+               pr_warn("[%s:%u] expected clump value of 0x%lX, got clump value of 0x%lX",
+                       srcfile, line, exp, *clump);
+               return false;
+       }
+
+       return true;
+}
+
 #define __expect_eq(suffix, ...)                                       \
        ({                                                              \
                int result = 0;                                         \
@@ -108,6 +171,7 @@ __check_eq_u32_array(const char *srcfile, unsigned int line,
 #define expect_eq_bitmap(...)          __expect_eq(bitmap, ##__VA_ARGS__)
 #define expect_eq_pbl(...)             __expect_eq(pbl, ##__VA_ARGS__)
 #define expect_eq_u32_array(...)       __expect_eq(u32_array, ##__VA_ARGS__)
+#define expect_eq_clump8(...)          __expect_eq(clump8, ##__VA_ARGS__)
 
 static void __init test_zero_clear(void)
 {
@@ -206,6 +270,30 @@ static void __init test_copy(void)
        expect_eq_pbl("0-108,128-1023", bmap2, 1024);
 }
 
+#define EXP2_IN_BITS   (sizeof(exp2) * 8)
+
+static void __init test_replace(void)
+{
+       unsigned int nbits = 64;
+       DECLARE_BITMAP(bmap, 1024);
+
+       bitmap_zero(bmap, 1024);
+       bitmap_replace(bmap, &exp2[0], &exp2[1], exp2_to_exp3_mask, nbits);
+       expect_eq_bitmap(bmap, exp3_0_1, nbits);
+
+       bitmap_zero(bmap, 1024);
+       bitmap_replace(bmap, &exp2[1], &exp2[0], exp2_to_exp3_mask, nbits);
+       expect_eq_bitmap(bmap, exp3_1_0, nbits);
+
+       bitmap_fill(bmap, 1024);
+       bitmap_replace(bmap, &exp2[0], &exp2[1], exp2_to_exp3_mask, nbits);
+       expect_eq_bitmap(bmap, exp3_0_1, nbits);
+
+       bitmap_fill(bmap, 1024);
+       bitmap_replace(bmap, &exp2[1], &exp2[0], exp2_to_exp3_mask, nbits);
+       expect_eq_bitmap(bmap, exp3_1_0, nbits);
+}
+
 #define PARSE_TIME 0x1
 
 struct test_bitmap_parselist{
@@ -216,53 +304,32 @@ struct test_bitmap_parselist{
        const int flags;
 };
 
-static const unsigned long exp[] __initconst = {
-       BITMAP_FROM_U64(1),
-       BITMAP_FROM_U64(2),
-       BITMAP_FROM_U64(0x0000ffff),
-       BITMAP_FROM_U64(0xffff0000),
-       BITMAP_FROM_U64(0x55555555),
-       BITMAP_FROM_U64(0xaaaaaaaa),
-       BITMAP_FROM_U64(0x11111111),
-       BITMAP_FROM_U64(0x22222222),
-       BITMAP_FROM_U64(0xffffffff),
-       BITMAP_FROM_U64(0xfffffffe),
-       BITMAP_FROM_U64(0x3333333311111111ULL),
-       BITMAP_FROM_U64(0xffffffff77777777ULL),
-       BITMAP_FROM_U64(0),
-};
-
-static const unsigned long exp2[] __initconst = {
-       BITMAP_FROM_U64(0x3333333311111111ULL),
-       BITMAP_FROM_U64(0xffffffff77777777ULL)
-};
-
 static const struct test_bitmap_parselist parselist_tests[] __initconst = {
 #define step (sizeof(u64) / sizeof(unsigned long))
 
-       {0, "0",                        &exp[0], 8, 0},
-       {0, "1",                        &exp[1 * step], 8, 0},
-       {0, "0-15",                     &exp[2 * step], 32, 0},
-       {0, "16-31",                    &exp[3 * step], 32, 0},
-       {0, "0-31:1/2",                 &exp[4 * step], 32, 0},
-       {0, "1-31:1/2",                 &exp[5 * step], 32, 0},
-       {0, "0-31:1/4",                 &exp[6 * step], 32, 0},
-       {0, "1-31:1/4",                 &exp[7 * step], 32, 0},
-       {0, "0-31:4/4",                 &exp[8 * step], 32, 0},
-       {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",                        &exp1[0], 8, 0},
+       {0, "1",                        &exp1[1 * step], 8, 0},
+       {0, "0-15",                     &exp1[2 * step], 32, 0},
+       {0, "16-31",                    &exp1[3 * step], 32, 0},
+       {0, "0-31:1/2",                 &exp1[4 * step], 32, 0},
+       {0, "1-31:1/2",                 &exp1[5 * step], 32, 0},
+       {0, "0-31:1/4",                 &exp1[6 * step], 32, 0},
+       {0, "1-31:1/4",                 &exp1[7 * step], 32, 0},
+       {0, "0-31:4/4",                 &exp1[8 * step], 32, 0},
+       {0, "1-31:4/4",                 &exp1[9 * step], 32, 0},
+       {0, "0-31:1/4,32-63:2/4",       &exp1[10 * step], 64, 0},
+       {0, "0-31:3/4,32-63:4/4",       &exp1[11 * step], 64, 0},
+       {0, "  ,,  0-31:3/4  ,, 32-63:4/4  ,,  ",       &exp1[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},
+       {0, "",                         &exp1[12 * step], 8, 0},
+       {0, "\n",                       &exp1[12 * step], 8, 0},
+       {0, ",,  ,,  , ,  ,",           &exp1[12 * step], 8, 0},
+       {0, " ,  ,,  , ,   ",           &exp1[12 * step], 8, 0},
+       {0, " ,  ,,  , ,   \n",         &exp1[12 * step], 8, 0},
 
        {-EINVAL, "-1", NULL, 8, 0},
        {-EINVAL, "-0", NULL, 8, 0},
@@ -280,6 +347,8 @@ static const struct test_bitmap_parselist parselist_tests[] __initconst = {
        {-EINVAL, "a-31:10/1", NULL, 8, 0},
        {-EINVAL, "0-31:a/1", NULL, 8, 0},
        {-EINVAL, "0-\n", NULL, 8, 0},
+
+#undef step
 };
 
 static void __init __test_bitmap_parselist(int is_user)
@@ -299,7 +368,7 @@ static void __init __test_bitmap_parselist(int is_user)
 
                        set_fs(KERNEL_DS);
                        time = ktime_get();
-                       err = bitmap_parselist_user(ptest.in, len,
+                       err = bitmap_parselist_user((__force const char __user *)ptest.in, len,
                                                    bmap, ptest.nbits);
                        time = ktime_get() - time;
                        set_fs(orig_fs);
@@ -326,6 +395,8 @@ static void __init __test_bitmap_parselist(int is_user)
                if (ptest.flags & PARSE_TIME)
                        pr_err("parselist%s: %d: input is '%s' OK, Time: %llu\n",
                                        mode, i, ptest.in, time);
+
+#undef ptest
        }
 }
 
@@ -339,20 +410,20 @@ static void __init test_bitmap_parselist_user(void)
        __test_bitmap_parselist(1);
 }
 
-#define EXP_BYTES      (sizeof(exp) * 8)
+#define EXP1_IN_BITS   (sizeof(exp1) * 8)
 
 static void __init test_bitmap_arr32(void)
 {
        unsigned int nbits, next_bit;
-       u32 arr[sizeof(exp) / 4];
-       DECLARE_BITMAP(bmap2, EXP_BYTES);
+       u32 arr[EXP1_IN_BITS / 32];
+       DECLARE_BITMAP(bmap2, EXP1_IN_BITS);
 
        memset(arr, 0xa5, sizeof(arr));
 
-       for (nbits = 0; nbits < EXP_BYTES; ++nbits) {
-               bitmap_to_arr32(arr, exp, nbits);
+       for (nbits = 0; nbits < EXP1_IN_BITS; ++nbits) {
+               bitmap_to_arr32(arr, exp1, nbits);
                bitmap_from_arr32(bmap2, arr, nbits);
-               expect_eq_bitmap(bmap2, exp, nbits);
+               expect_eq_bitmap(bmap2, exp1, nbits);
 
                next_bit = find_next_bit(bmap2,
                                round_up(nbits, BITS_PER_LONG), nbits);
@@ -361,7 +432,7 @@ static void __init test_bitmap_arr32(void)
                                " tail is not safely cleared: %d\n",
                                nbits, next_bit);
 
-               if (nbits < EXP_BYTES - 32)
+               if (nbits < EXP1_IN_BITS - 32)
                        expect_eq_uint(arr[DIV_ROUND_UP(nbits, 32)],
                                                                0xa5a5a5a5);
        }
@@ -404,15 +475,50 @@ static void noinline __init test_mem_optimisations(void)
        }
 }
 
+static const unsigned char clump_exp[] __initconst = {
+       0x01,   /* 1 bit set */
+       0x02,   /* non-edge 1 bit set */
+       0x00,   /* zero bits set */
+       0x38,   /* 3 bits set across 4-bit boundary */
+       0x38,   /* Repeated clump */
+       0x0F,   /* 4 bits set */
+       0xFF,   /* all bits set */
+       0x05,   /* non-adjacent 2 bits set */
+};
+
+static void __init test_for_each_set_clump8(void)
+{
+#define CLUMP_EXP_NUMBITS 64
+       DECLARE_BITMAP(bits, CLUMP_EXP_NUMBITS);
+       unsigned int start;
+       unsigned long clump;
+
+       /* set bitmap to test case */
+       bitmap_zero(bits, CLUMP_EXP_NUMBITS);
+       bitmap_set(bits, 0, 1);         /* 0x01 */
+       bitmap_set(bits, 9, 1);         /* 0x02 */
+       bitmap_set(bits, 27, 3);        /* 0x28 */
+       bitmap_set(bits, 35, 3);        /* 0x28 */
+       bitmap_set(bits, 40, 4);        /* 0x0F */
+       bitmap_set(bits, 48, 8);        /* 0xFF */
+       bitmap_set(bits, 56, 1);        /* 0x05 - part 1 */
+       bitmap_set(bits, 58, 1);        /* 0x05 - part 2 */
+
+       for_each_set_clump8(start, clump, bits, CLUMP_EXP_NUMBITS)
+               expect_eq_clump8(start, CLUMP_EXP_NUMBITS, clump_exp, &clump);
+}
+
 static void __init selftest(void)
 {
        test_zero_clear();
        test_fill_set();
        test_copy();
+       test_replace();
        test_bitmap_arr32();
        test_bitmap_parselist();
        test_bitmap_parselist_user();
        test_mem_optimisations();
+       test_for_each_set_clump8();
 }
 
 KSTM_MODULE_LOADERS(test_bitmap);
index 49cc4d5..328d33b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/vmalloc.h>
 
 #include <asm/page.h>
 
@@ -748,6 +749,30 @@ static noinline void __init kmalloc_double_kzfree(void)
        kzfree(ptr);
 }
 
+#ifdef CONFIG_KASAN_VMALLOC
+static noinline void __init vmalloc_oob(void)
+{
+       void *area;
+
+       pr_info("vmalloc out-of-bounds\n");
+
+       /*
+        * We have to be careful not to hit the guard page.
+        * The MMU will catch that and crash us.
+        */
+       area = vmalloc(3000);
+       if (!area) {
+               pr_err("Allocation failed\n");
+               return;
+       }
+
+       ((volatile char *)area)[3100];
+       vfree(area);
+}
+#else
+static void __init vmalloc_oob(void) {}
+#endif
+
 static int __init kmalloc_tests_init(void)
 {
        /*
@@ -793,6 +818,7 @@ static int __init kmalloc_tests_init(void)
        kasan_strings();
        kasan_bitops();
        kmalloc_double_kzfree();
+       vmalloc_oob();
 
        kasan_restore_multi_shot(multishot);
 
index 9742e5c..e4f706a 100644 (file)
@@ -183,6 +183,9 @@ static bool __init check_buf(void *buf, int size, bool want_ctor,
        return fail;
 }
 
+#define BULK_SIZE 100
+static void *bulk_array[BULK_SIZE];
+
 /*
  * Test kmem_cache with given parameters:
  *  want_ctor - use a constructor;
@@ -203,9 +206,24 @@ static int __init do_kmem_cache_size(size_t size, bool want_ctor,
                              want_rcu ? SLAB_TYPESAFE_BY_RCU : 0,
                              want_ctor ? test_ctor : NULL);
        for (iter = 0; iter < 10; iter++) {
+               /* Do a test of bulk allocations */
+               if (!want_rcu && !want_ctor) {
+                       int ret;
+
+                       ret = kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE, bulk_array);
+                       if (!ret) {
+                               fail = true;
+                       } else {
+                               int i;
+                               for (i = 0; i < ret; i++)
+                                       fail |= check_buf(bulk_array[i], size, want_ctor, want_rcu, want_zero);
+                               kmem_cache_free_bulk(c, ret, bulk_array);
+                       }
+               }
+
                buf = kmem_cache_alloc(c, alloc_mask);
                /* Check that buf is zeroed, if it must be. */
-               fail = check_buf(buf, size, want_ctor, want_rcu, want_zero);
+               fail |= check_buf(buf, size, want_ctor, want_rcu, want_zero);
                fill_with_garbage_skip(buf, size, want_ctor ? CTOR_BYTES : 0);
 
                if (!want_rcu) {
index fc552d5..7b9b58a 100644 (file)
@@ -140,25 +140,21 @@ static void val_to_string(char *str, size_t size, struct type_descriptor *type,
        }
 }
 
-static DEFINE_SPINLOCK(report_lock);
-
-static void ubsan_prologue(struct source_location *location,
-                       unsigned long *flags)
+static void ubsan_prologue(struct source_location *location)
 {
        current->in_ubsan++;
-       spin_lock_irqsave(&report_lock, *flags);
 
        pr_err("========================================"
                "========================================\n");
        print_source_location("UBSAN: Undefined behaviour in", location);
 }
 
-static void ubsan_epilogue(unsigned long *flags)
+static void ubsan_epilogue(void)
 {
        dump_stack();
        pr_err("========================================"
                "========================================\n");
-       spin_unlock_irqrestore(&report_lock, *flags);
+
        current->in_ubsan--;
 }
 
@@ -167,14 +163,13 @@ static void handle_overflow(struct overflow_data *data, void *lhs,
 {
 
        struct type_descriptor *type = data->type;
-       unsigned long flags;
        char lhs_val_str[VALUE_LENGTH];
        char rhs_val_str[VALUE_LENGTH];
 
        if (suppress_report(&data->location))
                return;
 
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
 
        val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs);
        val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs);
@@ -186,7 +181,7 @@ static void handle_overflow(struct overflow_data *data, void *lhs,
                rhs_val_str,
                type->type_name);
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 
 void __ubsan_handle_add_overflow(struct overflow_data *data,
@@ -214,20 +209,19 @@ EXPORT_SYMBOL(__ubsan_handle_mul_overflow);
 void __ubsan_handle_negate_overflow(struct overflow_data *data,
                                void *old_val)
 {
-       unsigned long flags;
        char old_val_str[VALUE_LENGTH];
 
        if (suppress_report(&data->location))
                return;
 
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
 
        val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val);
 
        pr_err("negation of %s cannot be represented in type %s:\n",
                old_val_str, data->type->type_name);
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 EXPORT_SYMBOL(__ubsan_handle_negate_overflow);
 
@@ -235,13 +229,12 @@ EXPORT_SYMBOL(__ubsan_handle_negate_overflow);
 void __ubsan_handle_divrem_overflow(struct overflow_data *data,
                                void *lhs, void *rhs)
 {
-       unsigned long flags;
        char rhs_val_str[VALUE_LENGTH];
 
        if (suppress_report(&data->location))
                return;
 
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
 
        val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs);
 
@@ -251,58 +244,52 @@ void __ubsan_handle_divrem_overflow(struct overflow_data *data,
        else
                pr_err("division by zero\n");
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);
 
 static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
 {
-       unsigned long flags;
-
        if (suppress_report(data->location))
                return;
 
-       ubsan_prologue(data->location, &flags);
+       ubsan_prologue(data->location);
 
        pr_err("%s null pointer of type %s\n",
                type_check_kinds[data->type_check_kind],
                data->type->type_name);
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 
 static void handle_misaligned_access(struct type_mismatch_data_common *data,
                                unsigned long ptr)
 {
-       unsigned long flags;
-
        if (suppress_report(data->location))
                return;
 
-       ubsan_prologue(data->location, &flags);
+       ubsan_prologue(data->location);
 
        pr_err("%s misaligned address %p for type %s\n",
                type_check_kinds[data->type_check_kind],
                (void *)ptr, data->type->type_name);
        pr_err("which requires %ld byte alignment\n", data->alignment);
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 
 static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
                                        unsigned long ptr)
 {
-       unsigned long flags;
-
        if (suppress_report(data->location))
                return;
 
-       ubsan_prologue(data->location, &flags);
+       ubsan_prologue(data->location);
        pr_err("%s address %p with insufficient space\n",
                type_check_kinds[data->type_check_kind],
                (void *) ptr);
        pr_err("for an object of type %s\n", data->type->type_name);
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 
 static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
@@ -351,25 +338,23 @@ EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);
 
 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, void *index)
 {
-       unsigned long flags;
        char index_str[VALUE_LENGTH];
 
        if (suppress_report(&data->location))
                return;
 
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
 
        val_to_string(index_str, sizeof(index_str), data->index_type, index);
        pr_err("index %s is out of range for type %s\n", index_str,
                data->array_type->type_name);
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 EXPORT_SYMBOL(__ubsan_handle_out_of_bounds);
 
 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
                                        void *lhs, void *rhs)
 {
-       unsigned long flags;
        struct type_descriptor *rhs_type = data->rhs_type;
        struct type_descriptor *lhs_type = data->lhs_type;
        char rhs_str[VALUE_LENGTH];
@@ -379,7 +364,7 @@ void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
        if (suppress_report(&data->location))
                goto out;
 
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
 
        val_to_string(rhs_str, sizeof(rhs_str), rhs_type, rhs);
        val_to_string(lhs_str, sizeof(lhs_str), lhs_type, lhs);
@@ -402,7 +387,7 @@ void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
                        lhs_str, rhs_str,
                        lhs_type->type_name);
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 out:
        user_access_restore(ua_flags);
 }
@@ -411,11 +396,9 @@ EXPORT_SYMBOL(__ubsan_handle_shift_out_of_bounds);
 
 void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
 {
-       unsigned long flags;
-
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
        pr_err("calling __builtin_unreachable()\n");
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
        panic("can't return from __builtin_unreachable()");
 }
 EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable);
@@ -423,19 +406,18 @@ EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable);
 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
                                void *val)
 {
-       unsigned long flags;
        char val_str[VALUE_LENGTH];
 
        if (suppress_report(&data->location))
                return;
 
-       ubsan_prologue(&data->location, &flags);
+       ubsan_prologue(&data->location);
 
        val_to_string(val_str, sizeof(val_str), data->type, val);
 
        pr_err("load of value %s is not a valid value for type %s\n",
                val_str, data->type->type_name);
 
-       ubsan_epilogue(&flags);
+       ubsan_epilogue();
 }
 EXPORT_SYMBOL(__ubsan_handle_load_invalid_value);
index dee8fc4..7c488a1 100644 (file)
@@ -761,11 +761,38 @@ static int __init initialize_ptr_random(void)
 early_initcall(initialize_ptr_random);
 
 /* Maps a pointer to a 32 bit unique identifier. */
+static inline int __ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
+{
+       unsigned long hashval;
+
+       if (static_branch_unlikely(&not_filled_random_ptr_key))
+               return -EAGAIN;
+
+#ifdef CONFIG_64BIT
+       hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
+       /*
+        * Mask off the first 32 bits, this makes explicit that we have
+        * modified the address (and 32 bits is plenty for a unique ID).
+        */
+       hashval = hashval & 0xffffffff;
+#else
+       hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key);
+#endif
+       *hashval_out = hashval;
+       return 0;
+}
+
+int ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
+{
+       return __ptr_to_hashval(ptr, hashval_out);
+}
+
 static char *ptr_to_id(char *buf, char *end, const void *ptr,
                       struct printf_spec spec)
 {
        const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)";
        unsigned long hashval;
+       int ret;
 
        /* When debugging early boot use non-cryptographically secure hash. */
        if (unlikely(debug_boot_weak_hash)) {
@@ -773,22 +800,13 @@ static char *ptr_to_id(char *buf, char *end, const void *ptr,
                return pointer_string(buf, end, (const void *)hashval, spec);
        }
 
-       if (static_branch_unlikely(&not_filled_random_ptr_key)) {
+       ret = __ptr_to_hashval(ptr, &hashval);
+       if (ret) {
                spec.field_width = 2 * sizeof(ptr);
                /* string length must be less than default_width */
                return error_string(buf, end, str, spec);
        }
 
-#ifdef CONFIG_64BIT
-       hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
-       /*
-        * Mask off the first 32 bits, this makes explicit that we have
-        * modified the address (and 32 bits is plenty for a unique ID).
-        */
-       hashval = hashval & 0xffffffff;
-#else
-       hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key);
-#endif
        return pointer_string(buf, end, (const void *)hashval, spec);
 }
 
index f332efe..ab80933 100644 (file)
@@ -29,7 +29,7 @@ config FLATMEM_MANUAL
 
          For systems that have holes in their physical address
          spaces and for features like NUMA and memory hotplug,
-         choose "Sparse Memory"
+         choose "Sparse Memory".
 
          If unsure, choose this option (Flat Memory) over any other.
 
@@ -122,9 +122,9 @@ config SPARSEMEM_VMEMMAP
        depends on SPARSEMEM && SPARSEMEM_VMEMMAP_ENABLE
        default y
        help
-        SPARSEMEM_VMEMMAP uses a virtually mapped memmap to optimise
-        pfn_to_page and page_to_pfn operations.  This is the most
-        efficient option when sufficient kernel resources are available.
+         SPARSEMEM_VMEMMAP uses a virtually mapped memmap to optimise
+         pfn_to_page and page_to_pfn operations.  This is the most
+         efficient option when sufficient kernel resources are available.
 
 config HAVE_MEMBLOCK_NODE_MAP
        bool
@@ -160,9 +160,9 @@ config MEMORY_HOTPLUG_SPARSE
        depends on SPARSEMEM && MEMORY_HOTPLUG
 
 config MEMORY_HOTPLUG_DEFAULT_ONLINE
-        bool "Online the newly added memory blocks by default"
-        depends on MEMORY_HOTPLUG
-        help
+       bool "Online the newly added memory blocks by default"
+       depends on MEMORY_HOTPLUG
+       help
          This option sets the default policy setting for memory hotplug
          onlining policy (/sys/devices/system/memory/auto_online_blocks) which
          determines what happens to newly added memory regions. Policy setting
@@ -227,14 +227,14 @@ config COMPACTION
        select MIGRATION
        depends on MMU
        help
-          Compaction is the only memory management component to form
-          high order (larger physically contiguous) memory blocks
-          reliably. The page allocator relies on compaction heavily and
-          the lack of the feature can lead to unexpected OOM killer
-          invocations for high order memory requests. You shouldn't
-          disable this option unless there really is a strong reason for
-          it and then we would be really interested to hear about that at
-          linux-mm@kvack.org.
+         Compaction is the only memory management component to form
+         high order (larger physically contiguous) memory blocks
+         reliably. The page allocator relies on compaction heavily and
+         the lack of the feature can lead to unexpected OOM killer
+         invocations for high order memory requests. You shouldn't
+         disable this option unless there really is a strong reason for
+         it and then we would be really interested to hear about that at
+         linux-mm@kvack.org.
 
 #
 # support for page migration
@@ -258,7 +258,7 @@ config ARCH_ENABLE_THP_MIGRATION
        bool
 
 config CONTIG_ALLOC
-       def_bool (MEMORY_ISOLATION && COMPACTION) || CMA
+       def_bool (MEMORY_ISOLATION && COMPACTION) || CMA
 
 config PHYS_ADDR_T_64BIT
        def_bool 64BIT
@@ -302,10 +302,10 @@ config KSM
          root has set /sys/kernel/mm/ksm/run to 1 (if CONFIG_SYSFS is set).
 
 config DEFAULT_MMAP_MIN_ADDR
-        int "Low address space to protect from user allocation"
+       int "Low address space to protect from user allocation"
        depends on MMU
-        default 4096
-        help
+       default 4096
+       help
          This is the portion of low virtual memory which should be protected
          from userspace allocation.  Keeping a user from writing to low pages
          can help reduce the impact of kernel NULL pointer bugs.
@@ -408,7 +408,7 @@ choice
 endchoice
 
 config ARCH_WANTS_THP_SWAP
-       def_bool n
+       def_bool n
 
 config THP_SWAP
        def_bool y
index 7fe0b83..be55d19 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -95,13 +95,11 @@ static void cma_clear_bitmap(struct cma *cma, unsigned long pfn,
 
 static int __init cma_activate_area(struct cma *cma)
 {
-       int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);
        unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
        unsigned i = cma->count >> pageblock_order;
        struct zone *zone;
 
-       cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-
+       cma->bitmap = bitmap_zalloc(cma_bitmap_maxno(cma), GFP_KERNEL);
        if (!cma->bitmap) {
                cma->count = 0;
                return -ENOMEM;
@@ -139,7 +137,7 @@ static int __init cma_activate_area(struct cma *cma)
 
 not_in_zone:
        pr_err("CMA area %s could not be activated\n", cma->name);
-       kfree(cma->bitmap);
+       bitmap_free(cma->bitmap);
        cma->count = 0;
        return -EINVAL;
 }
index a7dd9e8..4e6cbe2 100644 (file)
@@ -29,7 +29,7 @@ static int cma_debugfs_get(void *data, u64 *val)
 
        return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
 
 static int cma_used_get(void *data, u64 *val)
 {
@@ -44,7 +44,7 @@ static int cma_used_get(void *data, u64 *val)
 
        return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n");
 
 static int cma_maxchunk_get(void *data, u64 *val)
 {
@@ -66,7 +66,7 @@ static int cma_maxchunk_get(void *data, u64 *val)
 
        return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n");
 
 static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
 {
@@ -126,7 +126,7 @@ static int cma_free_write(void *data, u64 val)
 
        return cma_free_mem(cma, pages);
 }
-DEFINE_SIMPLE_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");
 
 static int cma_alloc_mem(struct cma *cma, int count)
 {
@@ -158,7 +158,7 @@ static int cma_alloc_write(void *data, u64 val)
 
        return cma_alloc_mem(cma, pages);
 }
-DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
 
 static void cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)
 {
index 85b7d08..bf6aa30 100644 (file)
@@ -2329,27 +2329,6 @@ EXPORT_SYMBOL(generic_file_read_iter);
 
 #ifdef CONFIG_MMU
 #define MMAP_LOTSAMISS  (100)
-static struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf,
-                                            struct file *fpin)
-{
-       int flags = vmf->flags;
-
-       if (fpin)
-               return fpin;
-
-       /*
-        * FAULT_FLAG_RETRY_NOWAIT means we don't want to wait on page locks or
-        * anything, so we only pin the file and drop the mmap_sem if only
-        * FAULT_FLAG_ALLOW_RETRY is set.
-        */
-       if ((flags & (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT)) ==
-           FAULT_FLAG_ALLOW_RETRY) {
-               fpin = get_file(vmf->vma->vm_file);
-               up_read(&vmf->vma->vm_mm->mmap_sem);
-       }
-       return fpin;
-}
-
 /*
  * lock_page_maybe_drop_mmap - lock the page, possibly dropping the mmap_sem
  * @vmf - the vm_fault for this fault.
@@ -3161,6 +3140,27 @@ int pagecache_write_end(struct file *file, struct address_space *mapping,
 }
 EXPORT_SYMBOL(pagecache_write_end);
 
+/*
+ * Warn about a page cache invalidation failure during a direct I/O write.
+ */
+void dio_warn_stale_pagecache(struct file *filp)
+{
+       static DEFINE_RATELIMIT_STATE(_rs, 86400 * HZ, DEFAULT_RATELIMIT_BURST);
+       char pathname[128];
+       struct inode *inode = file_inode(filp);
+       char *path;
+
+       errseq_set(&inode->i_mapping->wb_err, -EIO);
+       if (__ratelimit(&_rs)) {
+               path = file_path(filp, pathname, sizeof(pathname));
+               if (IS_ERR(path))
+                       path = "(unknown)";
+               pr_crit("Page cache invalidation failure on direct I/O.  Possible data corruption due to collision with buffered I/O!\n");
+               pr_crit("File: %s PID: %d Comm: %.20s\n", path, current->pid,
+                       current->comm);
+       }
+}
+
 ssize_t
 generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
 {
@@ -3218,11 +3218,15 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
         * Most of the time we do not need this since dio_complete() will do
         * the invalidation for us. However there are some file systems that
         * do not end up with dio_complete() being called, so let's not break
-        * them by removing it completely
+        * them by removing it completely.
+        *
+        * Noticeable example is a blkdev_direct_IO().
+        *
+        * Skip invalidation for async writes or if mapping has no pages.
         */
-       if (mapping->nrpages)
-               invalidate_inode_pages2_range(mapping,
-                                       pos >> PAGE_SHIFT, end);
+       if (written > 0 && mapping->nrpages &&
+           invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT, end))
+               dio_warn_stale_pagecache(file);
 
        if (written > 0) {
                pos += written;
index 8f236a3..7646bf9 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -734,11 +734,17 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
  *             Or NULL if the caller does not require them.
  * @nonblocking: whether waiting for disk IO or mmap_sem contention
  *
- * Returns number of pages pinned. This may be fewer than the number
- * requested. If nr_pages is 0 or negative, returns 0. If no pages
- * were pinned, returns -errno. Each page returned must be released
- * with a put_page() call when it is finished with. vmas will only
- * remain valid while mmap_sem is held.
+ * Returns either number of pages pinned (which may be less than the
+ * number requested), or an error. Details about the return value:
+ *
+ * -- If nr_pages is 0, returns 0.
+ * -- If nr_pages is >0, but no pages were pinned, returns -errno.
+ * -- If nr_pages is >0, and some pages were pinned, returns the number of
+ *    pages pinned. Again, this may be less than nr_pages.
+ *
+ * The caller is responsible for releasing returned @pages, via put_page().
+ *
+ * @vmas are valid only as long as mmap_sem is held.
  *
  * Must be called with mmap_sem held.  It may be released.  See below.
  *
@@ -1107,11 +1113,17 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
  *             subsequently whether VM_FAULT_RETRY functionality can be
  *             utilised. Lock must initially be held.
  *
- * Returns number of pages pinned. This may be fewer than the number
- * requested. If nr_pages is 0 or negative, returns 0. If no pages
- * were pinned, returns -errno. Each page returned must be released
- * with a put_page() call when it is finished with. vmas will only
- * remain valid while mmap_sem is held.
+ * Returns either number of pages pinned (which may be less than the
+ * number requested), or an error. Details about the return value:
+ *
+ * -- If nr_pages is 0, returns 0.
+ * -- If nr_pages is >0, but no pages were pinned, returns -errno.
+ * -- If nr_pages is >0, and some pages were pinned, returns the number of
+ *    pages pinned. Again, this may be less than nr_pages.
+ *
+ * The caller is responsible for releasing returned @pages, via put_page().
+ *
+ * @vmas are valid only as long as mmap_sem is held.
  *
  * Must be called with mmap_sem held for read or write.
  *
@@ -1443,6 +1455,7 @@ static long check_and_migrate_cma_pages(struct task_struct *tsk,
        bool drain_allow = true;
        bool migrate_allow = true;
        LIST_HEAD(cma_page_list);
+       long ret = nr_pages;
 
 check_again:
        for (i = 0; i < nr_pages;) {
@@ -1504,17 +1517,18 @@ check_again:
                 * again migrating any new CMA pages which we failed to isolate
                 * earlier.
                 */
-               nr_pages = __get_user_pages_locked(tsk, mm, start, nr_pages,
+               ret = __get_user_pages_locked(tsk, mm, start, nr_pages,
                                                   pages, vmas, NULL,
                                                   gup_flags);
 
-               if ((nr_pages > 0) && migrate_allow) {
+               if ((ret > 0) && migrate_allow) {
+                       nr_pages = ret;
                        drain_allow = true;
                        goto check_again;
                }
        }
 
-       return nr_pages;
+       return ret;
 }
 #else
 static long check_and_migrate_cma_pages(struct task_struct *tsk,
index 13cc937..41a0fbd 100644 (file)
@@ -3003,7 +3003,7 @@ next:
 
        return 0;
 }
-DEFINE_SIMPLE_ATTRIBUTE(split_huge_pages_fops, NULL, split_huge_pages_set,
+DEFINE_DEBUGFS_ATTRIBUTE(split_huge_pages_fops, NULL, split_huge_pages_set,
                "%llu\n");
 
 static int __init split_huge_pages_debugfs(void)
index b45a953..ac65bb5 100644 (file)
@@ -244,16 +244,66 @@ struct file_region {
        long to;
 };
 
+/* Must be called with resv->lock held. Calling this with count_only == true
+ * will count the number of pages to be added but will not modify the linked
+ * list.
+ */
+static long add_reservation_in_range(struct resv_map *resv, long f, long t,
+                                    bool count_only)
+{
+       long chg = 0;
+       struct list_head *head = &resv->regions;
+       struct file_region *rg = NULL, *trg = NULL, *nrg = NULL;
+
+       /* Locate the region we are before or in. */
+       list_for_each_entry(rg, head, link)
+               if (f <= rg->to)
+                       break;
+
+       /* Round our left edge to the current segment if it encloses us. */
+       if (f > rg->from)
+               f = rg->from;
+
+       chg = t - f;
+
+       /* Check for and consume any regions we now overlap with. */
+       nrg = rg;
+       list_for_each_entry_safe(rg, trg, rg->link.prev, link) {
+               if (&rg->link == head)
+                       break;
+               if (rg->from > t)
+                       break;
+
+               /* We overlap with this area, if it extends further than
+                * us then we must extend ourselves.  Account for its
+                * existing reservation.
+                */
+               if (rg->to > t) {
+                       chg += rg->to - t;
+                       t = rg->to;
+               }
+               chg -= rg->to - rg->from;
+
+               if (!count_only && rg != nrg) {
+                       list_del(&rg->link);
+                       kfree(rg);
+               }
+       }
+
+       if (!count_only) {
+               nrg->from = f;
+               nrg->to = t;
+       }
+
+       return chg;
+}
+
 /*
  * Add the huge page range represented by [f, t) to the reserve
- * map.  In the normal case, existing regions will be expanded
- * to accommodate the specified range.  Sufficient regions should
- * exist for expansion due to the previous call to region_chg
- * with the same range.  However, it is possible that region_del
- * could have been called after region_chg and modifed the map
- * in such a way that no region exists to be expanded.  In this
- * case, pull a region descriptor from the cache associated with
- * the map and use that for the new range.
+ * map.  Existing regions will be expanded to accommodate the specified
+ * range, or a region will be taken from the cache.  Sufficient regions
+ * must exist in the cache due to the previous call to region_chg with
+ * the same range.
  *
  * Return the number of new huge pages added to the map.  This
  * number is greater than or equal to zero.
@@ -261,7 +311,7 @@ struct file_region {
 static long region_add(struct resv_map *resv, long f, long t)
 {
        struct list_head *head = &resv->regions;
-       struct file_region *rg, *nrg, *trg;
+       struct file_region *rg, *nrg;
        long add = 0;
 
        spin_lock(&resv->lock);
@@ -272,9 +322,8 @@ static long region_add(struct resv_map *resv, long f, long t)
 
        /*
         * If no region exists which can be expanded to include the
-        * specified range, the list must have been modified by an
-        * interleving call to region_del().  Pull a region descriptor
-        * from the cache and use it for this range.
+        * specified range, pull a region descriptor from the cache
+        * and use it for this range.
         */
        if (&rg->link == head || t < rg->from) {
                VM_BUG_ON(resv->region_cache_count <= 0);
@@ -292,38 +341,7 @@ static long region_add(struct resv_map *resv, long f, long t)
                goto out_locked;
        }
 
-       /* Round our left edge to the current segment if it encloses us. */
-       if (f > rg->from)
-               f = rg->from;
-
-       /* Check for and consume any regions we now overlap with. */
-       nrg = rg;
-       list_for_each_entry_safe(rg, trg, rg->link.prev, link) {
-               if (&rg->link == head)
-                       break;
-               if (rg->from > t)
-                       break;
-
-               /* If this area reaches higher then extend our area to
-                * include it completely.  If this is not the first area
-                * which we intend to reuse, free it. */
-               if (rg->to > t)
-                       t = rg->to;
-               if (rg != nrg) {
-                       /* Decrement return value by the deleted range.
-                        * Another range will span this area so that by
-                        * end of routine add will be >= zero
-                        */
-                       add -= (rg->to - rg->from);
-                       list_del(&rg->link);
-                       kfree(rg);
-               }
-       }
-
-       add += (nrg->from - f);         /* Added to beginning of region */
-       nrg->from = f;
-       add += t - nrg->to;             /* Added to end of region */
-       nrg->to = t;
+       add = add_reservation_in_range(resv, f, t, false);
 
 out_locked:
        resv->adds_in_progress--;
@@ -339,15 +357,9 @@ out_locked:
  * call to region_add that will actually modify the reserve
  * map to add the specified range [f, t).  region_chg does
  * not change the number of huge pages represented by the
- * map.  However, if the existing regions in the map can not
- * be expanded to represent the new range, a new file_region
- * structure is added to the map as a placeholder.  This is
- * so that the subsequent region_add call will have all the
- * regions it needs and will not fail.
- *
- * Upon entry, region_chg will also examine the cache of region descriptors
- * associated with the map.  If there are not enough descriptors cached, one
- * will be allocated for the in progress add operation.
+ * map.  A new file_region structure is added to the cache
+ * as a placeholder, so that the subsequent region_add
+ * call will have all the regions it needs and will not fail.
  *
  * Returns the number of huge pages that need to be added to the existing
  * reservation map for the range [f, t).  This number is greater or equal to
@@ -356,11 +368,8 @@ out_locked:
  */
 static long region_chg(struct resv_map *resv, long f, long t)
 {
-       struct list_head *head = &resv->regions;
-       struct file_region *rg, *nrg = NULL;
        long chg = 0;
 
-retry:
        spin_lock(&resv->lock);
 retry_locked:
        resv->adds_in_progress++;
@@ -378,10 +387,8 @@ retry_locked:
                spin_unlock(&resv->lock);
 
                trg = kmalloc(sizeof(*trg), GFP_KERNEL);
-               if (!trg) {
-                       kfree(nrg);
+               if (!trg)
                        return -ENOMEM;
-               }
 
                spin_lock(&resv->lock);
                list_add(&trg->link, &resv->region_cache);
@@ -389,61 +396,8 @@ retry_locked:
                goto retry_locked;
        }
 
-       /* Locate the region we are before or in. */
-       list_for_each_entry(rg, head, link)
-               if (f <= rg->to)
-                       break;
+       chg = add_reservation_in_range(resv, f, t, true);
 
-       /* If we are below the current region then a new region is required.
-        * Subtle, allocate a new region at the position but make it zero
-        * size such that we can guarantee to record the reservation. */
-       if (&rg->link == head || t < rg->from) {
-               if (!nrg) {
-                       resv->adds_in_progress--;
-                       spin_unlock(&resv->lock);
-                       nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
-                       if (!nrg)
-                               return -ENOMEM;
-
-                       nrg->from = f;
-                       nrg->to   = f;
-                       INIT_LIST_HEAD(&nrg->link);
-                       goto retry;
-               }
-
-               list_add(&nrg->link, rg->link.prev);
-               chg = t - f;
-               goto out_nrg;
-       }
-
-       /* Round our left edge to the current segment if it encloses us. */
-       if (f > rg->from)
-               f = rg->from;
-       chg = t - f;
-
-       /* Check for and consume any regions we now overlap with. */
-       list_for_each_entry(rg, rg->link.prev, link) {
-               if (&rg->link == head)
-                       break;
-               if (rg->from > t)
-                       goto out;
-
-               /* We overlap with this area, if it extends further than
-                * us then we must extend ourselves.  Account for its
-                * existing reservation. */
-               if (rg->to > t) {
-                       chg += rg->to - t;
-                       t = rg->to;
-               }
-               chg -= rg->to - rg->from;
-       }
-
-out:
-       spin_unlock(&resv->lock);
-       /*  We already know we raced and no longer need the new region */
-       kfree(nrg);
-       return chg;
-out_nrg:
        spin_unlock(&resv->lock);
        return chg;
 }
@@ -1069,85 +1023,12 @@ static void free_gigantic_page(struct page *page, unsigned int order)
 }
 
 #ifdef CONFIG_CONTIG_ALLOC
-static int __alloc_gigantic_page(unsigned long start_pfn,
-                               unsigned long nr_pages, gfp_t gfp_mask)
-{
-       unsigned long end_pfn = start_pfn + nr_pages;
-       return alloc_contig_range(start_pfn, end_pfn, MIGRATE_MOVABLE,
-                                 gfp_mask);
-}
-
-static bool pfn_range_valid_gigantic(struct zone *z,
-                       unsigned long start_pfn, unsigned long nr_pages)
-{
-       unsigned long i, end_pfn = start_pfn + nr_pages;
-       struct page *page;
-
-       for (i = start_pfn; i < end_pfn; i++) {
-               page = pfn_to_online_page(i);
-               if (!page)
-                       return false;
-
-               if (page_zone(page) != z)
-                       return false;
-
-               if (PageReserved(page))
-                       return false;
-
-               if (page_count(page) > 0)
-                       return false;
-
-               if (PageHuge(page))
-                       return false;
-       }
-
-       return true;
-}
-
-static bool zone_spans_last_pfn(const struct zone *zone,
-                       unsigned long start_pfn, unsigned long nr_pages)
-{
-       unsigned long last_pfn = start_pfn + nr_pages - 1;
-       return zone_spans_pfn(zone, last_pfn);
-}
-
 static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask,
                int nid, nodemask_t *nodemask)
 {
-       unsigned int order = huge_page_order(h);
-       unsigned long nr_pages = 1 << order;
-       unsigned long ret, pfn, flags;
-       struct zonelist *zonelist;
-       struct zone *zone;
-       struct zoneref *z;
+       unsigned long nr_pages = 1UL << huge_page_order(h);
 
-       zonelist = node_zonelist(nid, gfp_mask);
-       for_each_zone_zonelist_nodemask(zone, z, zonelist, gfp_zone(gfp_mask), nodemask) {
-               spin_lock_irqsave(&zone->lock, flags);
-
-               pfn = ALIGN(zone->zone_start_pfn, nr_pages);
-               while (zone_spans_last_pfn(zone, pfn, nr_pages)) {
-                       if (pfn_range_valid_gigantic(zone, pfn, nr_pages)) {
-                               /*
-                                * We release the zone lock here because
-                                * alloc_contig_range() will also lock the zone
-                                * at some point. If there's an allocation
-                                * spinning on this lock, it may win the race
-                                * and cause alloc_contig_range() to fail...
-                                */
-                               spin_unlock_irqrestore(&zone->lock, flags);
-                               ret = __alloc_gigantic_page(pfn, nr_pages, gfp_mask);
-                               if (!ret)
-                                       return pfn_to_page(pfn);
-                               spin_lock_irqsave(&zone->lock, flags);
-                       }
-                       pfn += nr_pages;
-               }
-
-               spin_unlock_irqrestore(&zone->lock, flags);
-       }
-
-       return NULL;
+       return alloc_contig_pages(nr_pages, gfp_mask, nid, nodemask);
 }
 
 static void prep_new_huge_page(struct hstate *h, struct page *page, int nid);
@@ -3915,7 +3796,7 @@ retry:
                         * handling userfault.  Reacquire after handling
                         * fault to make calling code simpler.
                         */
-                       hash = hugetlb_fault_mutex_hash(h, mapping, idx, haddr);
+                       hash = hugetlb_fault_mutex_hash(mapping, idx);
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
                        ret = handle_userfault(&vmf, VM_UFFD_MISSING);
                        mutex_lock(&hugetlb_fault_mutex_table[hash]);
@@ -4042,8 +3923,7 @@ backout_unlocked:
 }
 
 #ifdef CONFIG_SMP
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
-                           pgoff_t idx, unsigned long address)
+u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx)
 {
        unsigned long key[2];
        u32 hash;
@@ -4051,7 +3931,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
        key[0] = (unsigned long) mapping;
        key[1] = idx;
 
-       hash = jhash2((u32 *)&key, sizeof(key)/sizeof(u32), 0);
+       hash = jhash2((u32 *)&key, sizeof(key)/(sizeof(u32)), 0);
 
        return hash & (num_fault_mutexes - 1);
 }
@@ -4060,8 +3940,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
  * 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 address_space *mapping,
-                           pgoff_t idx, unsigned long address)
+u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx)
 {
        return 0;
 }
@@ -4105,7 +3984,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, mapping, idx, haddr);
+       hash = hugetlb_fault_mutex_hash(mapping, idx);
        mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
        entry = huge_ptep_get(ptep);
@@ -4459,6 +4338,21 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                break;
                        }
                }
+
+               /*
+                * If subpage information not requested, update counters
+                * and skip the same_page loop below.
+                */
+               if (!pages && !vmas && !pfn_offset &&
+                   (vaddr + huge_page_size(h) < vma->vm_end) &&
+                   (remainder >= pages_per_huge_page(h))) {
+                       vaddr += huge_page_size(h);
+                       remainder -= pages_per_huge_page(h);
+                       i += pages_per_huge_page(h);
+                       spin_unlock(ptl);
+                       continue;
+               }
+
 same_page:
                if (pages) {
                        pages[i] = mem_map_offset(page, pfn_offset);
@@ -4842,7 +4736,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        if (!vma_shareable(vma, addr))
                return (pte_t *)pmd_alloc(mm, pud, addr);
 
-       i_mmap_lock_write(mapping);
+       i_mmap_lock_read(mapping);
        vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) {
                if (svma == vma)
                        continue;
@@ -4872,7 +4766,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        spin_unlock(ptl);
 out:
        pte = (pte_t *)pmd_alloc(mm, pud, addr);
-       i_mmap_unlock_write(mapping);
+       i_mmap_unlock_read(mapping);
        return pte;
 }
 
index 5b7430b..e488876 100644 (file)
@@ -67,8 +67,8 @@ static int hwpoison_unpoison(void *data, u64 val)
        return unpoison_memory(val);
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n");
-DEFINE_SIMPLE_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n");
+DEFINE_DEBUGFS_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n");
+DEFINE_DEBUGFS_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n");
 
 static void pfn_inject_exit(void)
 {
index 0d5f720..3cf20ab 100644 (file)
@@ -165,6 +165,9 @@ extern void post_alloc_hook(struct page *page, unsigned int order,
                                        gfp_t gfp_flags);
 extern int user_min_free_kbytes;
 
+extern void zone_pcp_update(struct zone *zone);
+extern void zone_pcp_reset(struct zone *zone);
+
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
 
 /*
@@ -290,7 +293,8 @@ static inline bool is_data_mapping(vm_flags_t flags)
 
 /* mm/util.c */
 void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
-               struct vm_area_struct *prev, struct rb_node *rb_parent);
+               struct vm_area_struct *prev);
+void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma);
 
 #ifdef CONFIG_MMU
 extern long populate_vma_page_range(struct vm_area_struct *vma,
@@ -362,6 +366,27 @@ vma_address(struct page *page, struct vm_area_struct *vma)
        return max(start, vma->vm_start);
 }
 
+static inline struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf,
+                                                   struct file *fpin)
+{
+       int flags = vmf->flags;
+
+       if (fpin)
+               return fpin;
+
+       /*
+        * FAULT_FLAG_RETRY_NOWAIT means we don't want to wait on page locks or
+        * anything, so we only pin the file and drop the mmap_sem if only
+        * FAULT_FLAG_ALLOW_RETRY is set.
+        */
+       if ((flags & (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT)) ==
+           FAULT_FLAG_ALLOW_RETRY) {
+               fpin = get_file(vmf->vma->vm_file);
+               up_read(&vmf->vma->vm_mm->mmap_sem);
+       }
+       return fpin;
+}
+
 #else /* !CONFIG_MMU */
 static inline void clear_page_mlock(struct page *page) { }
 static inline void mlock_vma_page(struct page *page) { }
index 6814d6d..2fa710b 100644 (file)
@@ -36,6 +36,9 @@
 #include <linux/bug.h>
 #include <linux/uaccess.h>
 
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
 #include "kasan.h"
 #include "../slab.h"
 
@@ -590,6 +593,7 @@ void kasan_kfree_large(void *ptr, unsigned long ip)
        /* The object will be poisoned by page_alloc. */
 }
 
+#ifndef CONFIG_KASAN_VMALLOC
 int kasan_module_alloc(void *addr, size_t size)
 {
        void *ret;
@@ -625,6 +629,7 @@ void kasan_free_shadow(const struct vm_struct *vm)
        if (vm->flags & VM_KASAN)
                vfree(kasan_mem_to_shadow(vm->addr));
 }
+#endif
 
 extern void __kasan_report(unsigned long addr, size_t size, bool is_write, unsigned long ip);
 
@@ -744,3 +749,232 @@ static int __init kasan_memhotplug_init(void)
 
 core_initcall(kasan_memhotplug_init);
 #endif
+
+#ifdef CONFIG_KASAN_VMALLOC
+static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr,
+                                     void *unused)
+{
+       unsigned long page;
+       pte_t pte;
+
+       if (likely(!pte_none(*ptep)))
+               return 0;
+
+       page = __get_free_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       memset((void *)page, KASAN_VMALLOC_INVALID, PAGE_SIZE);
+       pte = pfn_pte(PFN_DOWN(__pa(page)), PAGE_KERNEL);
+
+       spin_lock(&init_mm.page_table_lock);
+       if (likely(pte_none(*ptep))) {
+               set_pte_at(&init_mm, addr, ptep, pte);
+               page = 0;
+       }
+       spin_unlock(&init_mm.page_table_lock);
+       if (page)
+               free_page(page);
+       return 0;
+}
+
+int kasan_populate_vmalloc(unsigned long requested_size, struct vm_struct *area)
+{
+       unsigned long shadow_start, shadow_end;
+       int ret;
+
+       shadow_start = (unsigned long)kasan_mem_to_shadow(area->addr);
+       shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE);
+       shadow_end = (unsigned long)kasan_mem_to_shadow(area->addr +
+                                                       area->size);
+       shadow_end = ALIGN(shadow_end, PAGE_SIZE);
+
+       ret = apply_to_page_range(&init_mm, shadow_start,
+                                 shadow_end - shadow_start,
+                                 kasan_populate_vmalloc_pte, NULL);
+       if (ret)
+               return ret;
+
+       flush_cache_vmap(shadow_start, shadow_end);
+
+       kasan_unpoison_shadow(area->addr, requested_size);
+
+       area->flags |= VM_KASAN;
+
+       /*
+        * We need to be careful about inter-cpu effects here. Consider:
+        *
+        *   CPU#0                                CPU#1
+        * WRITE_ONCE(p, vmalloc(100));         while (x = READ_ONCE(p)) ;
+        *                                      p[99] = 1;
+        *
+        * With compiler instrumentation, that ends up looking like this:
+        *
+        *   CPU#0                                CPU#1
+        * // vmalloc() allocates memory
+        * // let a = area->addr
+        * // we reach kasan_populate_vmalloc
+        * // and call kasan_unpoison_shadow:
+        * STORE shadow(a), unpoison_val
+        * ...
+        * STORE shadow(a+99), unpoison_val     x = LOAD p
+        * // rest of vmalloc process           <data dependency>
+        * STORE p, a                           LOAD shadow(x+99)
+        *
+        * If there is no barrier between the end of unpoisioning the shadow
+        * and the store of the result to p, the stores could be committed
+        * in a different order by CPU#0, and CPU#1 could erroneously observe
+        * poison in the shadow.
+        *
+        * We need some sort of barrier between the stores.
+        *
+        * In the vmalloc() case, this is provided by a smp_wmb() in
+        * clear_vm_uninitialized_flag(). In the per-cpu allocator and in
+        * get_vm_area() and friends, the caller gets shadow allocated but
+        * doesn't have any pages mapped into the virtual address space that
+        * has been reserved. Mapping those pages in will involve taking and
+        * releasing a page-table lock, which will provide the barrier.
+        */
+
+       return 0;
+}
+
+/*
+ * Poison the shadow for a vmalloc region. Called as part of the
+ * freeing process at the time the region is freed.
+ */
+void kasan_poison_vmalloc(void *start, unsigned long size)
+{
+       size = round_up(size, KASAN_SHADOW_SCALE_SIZE);
+       kasan_poison_shadow(start, size, KASAN_VMALLOC_INVALID);
+}
+
+static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,
+                                       void *unused)
+{
+       unsigned long page;
+
+       page = (unsigned long)__va(pte_pfn(*ptep) << PAGE_SHIFT);
+
+       spin_lock(&init_mm.page_table_lock);
+
+       if (likely(!pte_none(*ptep))) {
+               pte_clear(&init_mm, addr, ptep);
+               free_page(page);
+       }
+       spin_unlock(&init_mm.page_table_lock);
+
+       return 0;
+}
+
+/*
+ * Release the backing for the vmalloc region [start, end), which
+ * lies within the free region [free_region_start, free_region_end).
+ *
+ * This can be run lazily, long after the region was freed. It runs
+ * under vmap_area_lock, so it's not safe to interact with the vmalloc/vmap
+ * infrastructure.
+ *
+ * How does this work?
+ * -------------------
+ *
+ * We have a region that is page aligned, labelled as A.
+ * That might not map onto the shadow in a way that is page-aligned:
+ *
+ *                    start                     end
+ *                    v                         v
+ * |????????|????????|AAAAAAAA|AA....AA|AAAAAAAA|????????| < vmalloc
+ *  -------- -------- --------          -------- --------
+ *      |        |       |                 |        |
+ *      |        |       |         /-------/        |
+ *      \-------\|/------/         |/---------------/
+ *              |||                ||
+ *             |??AAAAAA|AAAAAAAA|AA??????|                < shadow
+ *                 (1)      (2)      (3)
+ *
+ * First we align the start upwards and the end downwards, so that the
+ * shadow of the region aligns with shadow page boundaries. In the
+ * example, this gives us the shadow page (2). This is the shadow entirely
+ * covered by this allocation.
+ *
+ * Then we have the tricky bits. We want to know if we can free the
+ * partially covered shadow pages - (1) and (3) in the example. For this,
+ * we are given the start and end of the free region that contains this
+ * allocation. Extending our previous example, we could have:
+ *
+ *  free_region_start                                    free_region_end
+ *  |                 start                     end      |
+ *  v                 v                         v        v
+ * |FFFFFFFF|FFFFFFFF|AAAAAAAA|AA....AA|AAAAAAAA|FFFFFFFF| < vmalloc
+ *  -------- -------- --------          -------- --------
+ *      |        |       |                 |        |
+ *      |        |       |         /-------/        |
+ *      \-------\|/------/         |/---------------/
+ *              |||                ||
+ *             |FFAAAAAA|AAAAAAAA|AAF?????|                < shadow
+ *                 (1)      (2)      (3)
+ *
+ * Once again, we align the start of the free region up, and the end of
+ * the free region down so that the shadow is page aligned. So we can free
+ * page (1) - we know no allocation currently uses anything in that page,
+ * because all of it is in the vmalloc free region. But we cannot free
+ * page (3), because we can't be sure that the rest of it is unused.
+ *
+ * We only consider pages that contain part of the original region for
+ * freeing: we don't try to free other pages from the free region or we'd
+ * end up trying to free huge chunks of virtual address space.
+ *
+ * Concurrency
+ * -----------
+ *
+ * How do we know that we're not freeing a page that is simultaneously
+ * being used for a fresh allocation in kasan_populate_vmalloc(_pte)?
+ *
+ * We _can_ have kasan_release_vmalloc and kasan_populate_vmalloc running
+ * at the same time. While we run under free_vmap_area_lock, the population
+ * code does not.
+ *
+ * free_vmap_area_lock instead operates to ensure that the larger range
+ * [free_region_start, free_region_end) is safe: because __alloc_vmap_area and
+ * the per-cpu region-finding algorithm both run under free_vmap_area_lock,
+ * no space identified as free will become used while we are running. This
+ * means that so long as we are careful with alignment and only free shadow
+ * pages entirely covered by the free region, we will not run in to any
+ * trouble - any simultaneous allocations will be for disjoint regions.
+ */
+void kasan_release_vmalloc(unsigned long start, unsigned long end,
+                          unsigned long free_region_start,
+                          unsigned long free_region_end)
+{
+       void *shadow_start, *shadow_end;
+       unsigned long region_start, region_end;
+
+       region_start = ALIGN(start, PAGE_SIZE * KASAN_SHADOW_SCALE_SIZE);
+       region_end = ALIGN_DOWN(end, PAGE_SIZE * KASAN_SHADOW_SCALE_SIZE);
+
+       free_region_start = ALIGN(free_region_start,
+                                 PAGE_SIZE * KASAN_SHADOW_SCALE_SIZE);
+
+       if (start != region_start &&
+           free_region_start < region_start)
+               region_start -= PAGE_SIZE * KASAN_SHADOW_SCALE_SIZE;
+
+       free_region_end = ALIGN_DOWN(free_region_end,
+                                    PAGE_SIZE * KASAN_SHADOW_SCALE_SIZE);
+
+       if (end != region_end &&
+           free_region_end > region_end)
+               region_end += PAGE_SIZE * KASAN_SHADOW_SCALE_SIZE;
+
+       shadow_start = kasan_mem_to_shadow((void *)region_start);
+       shadow_end = kasan_mem_to_shadow((void *)region_end);
+
+       if (shadow_end > shadow_start) {
+               apply_to_page_range(&init_mm, (unsigned long)shadow_start,
+                                   (unsigned long)(shadow_end - shadow_start),
+                                   kasan_depopulate_vmalloc_pte, NULL);
+               flush_tlb_kernel_range((unsigned long)shadow_start,
+                                      (unsigned long)shadow_end);
+       }
+}
+#endif
index 36c6459..2d97efd 100644 (file)
@@ -86,6 +86,9 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info)
        case KASAN_ALLOCA_RIGHT:
                bug_type = "alloca-out-of-bounds";
                break;
+       case KASAN_VMALLOC_INVALID:
+               bug_type = "vmalloc-out-of-bounds";
+               break;
        }
 
        return bug_type;
index 35cff6b..3a08327 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 #define KASAN_GLOBAL_REDZONE    0xFA  /* redzone for global variable */
+#define KASAN_VMALLOC_INVALID   0xF9  /* unallocated space in vmapped page */
 
 /*
  * Stack redzone shadow values
index a8a57be..b679908 100644 (file)
@@ -1602,6 +1602,24 @@ static void collapse_file(struct mm_struct *mm,
                                        result = SCAN_FAIL;
                                        goto xa_unlocked;
                                }
+                       } else if (PageDirty(page)) {
+                               /*
+                                * khugepaged only works on read-only fd,
+                                * so this page is dirty because it hasn't
+                                * been flushed since first write. There
+                                * won't be new dirty pages.
+                                *
+                                * Trigger async flush here and hope the
+                                * writeback is done when khugepaged
+                                * revisits this page.
+                                *
+                                * This is a one-off situation. We are not
+                                * forcing writeback in loop.
+                                */
+                               xas_unlock_irq(&xas);
+                               filemap_flush(mapping);
+                               result = SCAN_FAIL;
+                               goto xa_unlocked;
                        } else if (trylock_page(page)) {
                                get_page(page);
                                xas_unlock_irq(&xas);
index 7905934..d17c7d5 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2478,6 +2478,7 @@ int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ksm_madvise);
 
 int __ksm_enter(struct mm_struct *mm)
 {
index 94c343b..bcdb6a0 100644 (file)
@@ -864,13 +864,13 @@ static int madvise_inject_error(int behavior,
 {
        struct page *page;
        struct zone *zone;
-       unsigned int order;
+       unsigned long size;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
 
-       for (; start < end; start += PAGE_SIZE << order) {
+       for (; start < end; start += size) {
                unsigned long pfn;
                int ret;
 
@@ -882,9 +882,9 @@ static int madvise_inject_error(int behavior,
                /*
                 * When soft offlining hugepages, after migrating the page
                 * we dissolve it, therefore in the second loop "page" will
-                * no longer be a compound page, and order will be 0.
+                * no longer be a compound page.
                 */
-               order = compound_order(compound_head(page));
+               size = page_size(compound_head(page));
 
                if (PageHWPoison(page)) {
                        put_page(page);
@@ -895,7 +895,7 @@ static int madvise_inject_error(int behavior,
                        pr_info("Soft offlining pfn %#lx at process virtual address %#lx\n",
                                        pfn, start);
 
-                       ret = soft_offline_page(page, MF_COUNT_INCREASED);
+                       ret = soft_offline_page(pfn, MF_COUNT_INCREASED);
                        if (ret)
                                return ret;
                        continue;
@@ -1059,9 +1059,9 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
        if (!madvise_behavior_valid(behavior))
                return error;
 
-       if (start & ~PAGE_MASK)
+       if (!PAGE_ALIGNED(start))
                return error;
-       len = (len_in + ~PAGE_MASK) & PAGE_MASK;
+       len = PAGE_ALIGN(len_in);
 
        /* Check to see whether len was rounded up from small -ve to zero */
        if (len_in && !len)
index c4b16ca..4bc2c7d 100644 (file)
  * at build time. The region arrays for the "memory" and "reserved"
  * types are initially sized to %INIT_MEMBLOCK_REGIONS and for the
  * "physmap" type to %INIT_PHYSMEM_REGIONS.
- * The :c:func:`memblock_allow_resize` enables automatic resizing of
- * the region arrays during addition of new regions. This feature
- * should be used with care so that memory allocated for the region
- * array will not overlap with areas that should be reserved, for
- * example initrd.
+ * The memblock_allow_resize() enables automatic resizing of the region
+ * arrays during addition of new regions. This feature should be used
+ * with care so that memory allocated for the region array will not
+ * overlap with areas that should be reserved, for example initrd.
  *
  * The early architecture setup should tell memblock what the physical
- * memory layout is by using :c:func:`memblock_add` or
- * :c:func:`memblock_add_node` functions. The first function does not
- * assign the region to a NUMA node and it is appropriate for UMA
- * systems. Yet, it is possible to use it on NUMA systems as well and
- * assign the region to a NUMA node later in the setup process using
- * :c:func:`memblock_set_node`. The :c:func:`memblock_add_node`
- * performs such an assignment directly.
+ * memory layout is by using memblock_add() or memblock_add_node()
+ * functions. The first function does not assign the region to a NUMA
+ * node and it is appropriate for UMA systems. Yet, it is possible to
+ * use it on NUMA systems as well and assign the region to a NUMA node
+ * later in the setup process using memblock_set_node(). The
+ * memblock_add_node() performs such an assignment directly.
  *
  * Once memblock is setup the memory can be allocated using one of the
  * API variants:
  *
- * * :c:func:`memblock_phys_alloc*` - these functions return the
- *   **physical** address of the allocated memory
- * * :c:func:`memblock_alloc*` - these functions return the **virtual**
- *   address of the allocated memory.
+ * * memblock_phys_alloc*() - these functions return the **physical**
+ *   address of the allocated memory
+ * * memblock_alloc*() - these functions return the **virtual** address
+ *   of the allocated memory.
  *
  * Note, that both API variants use implict assumptions about allowed
  * memory ranges and the fallback methods. Consult the documentation
- * of :c:func:`memblock_alloc_internal` and
- * :c:func:`memblock_alloc_range_nid` functions for more elaboarte
- * description.
+ * of memblock_alloc_internal() and memblock_alloc_range_nid()
+ * functions for more elaborate description.
  *
- * As the system boot progresses, the architecture specific
- * :c:func:`mem_init` function frees all the memory to the buddy page
- * allocator.
+ * As the system boot progresses, the architecture specific mem_init()
+ * function frees all the memory to the buddy page allocator.
  *
- * Unless an architecure enables %CONFIG_ARCH_KEEP_MEMBLOCK, the
+ * Unless an architecture enables %CONFIG_ARCH_KEEP_MEMBLOCK, the
  * memblock data structures will be discarded after the system
- * initialization compltes.
+ * initialization completes.
  */
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -1323,12 +1319,13 @@ __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
  * @start: the lower bound of the memory region to allocate (phys address)
  * @end: the upper bound of the memory region to allocate (phys address)
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
+ * @exact_nid: control the allocation fall back to other nodes
  *
  * The allocation is performed from memory region limited by
- * memblock.current_limit if @max_addr == %MEMBLOCK_ALLOC_ACCESSIBLE.
+ * memblock.current_limit if @end == %MEMBLOCK_ALLOC_ACCESSIBLE.
  *
- * If the specified node can not hold the requested memory the
- * allocation falls back to any node in the system
+ * If the specified node can not hold the requested memory and @exact_nid
+ * is false, the allocation falls back to any node in the system.
  *
  * For systems with memory mirroring, the allocation is attempted first
  * from the regions with mirroring enabled and then retried from any
@@ -1342,7 +1339,8 @@ __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
  */
 static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
                                        phys_addr_t align, phys_addr_t start,
-                                       phys_addr_t end, int nid)
+                                       phys_addr_t end, int nid,
+                                       bool exact_nid)
 {
        enum memblock_flags flags = choose_memblock_flags();
        phys_addr_t found;
@@ -1362,7 +1360,7 @@ again:
        if (found && !memblock_reserve(found, size))
                goto done;
 
-       if (nid != NUMA_NO_NODE) {
+       if (nid != NUMA_NO_NODE && !exact_nid) {
                found = memblock_find_in_range_node(size, align, start,
                                                    end, NUMA_NO_NODE,
                                                    flags);
@@ -1410,7 +1408,8 @@ phys_addr_t __init memblock_phys_alloc_range(phys_addr_t size,
                                             phys_addr_t start,
                                             phys_addr_t end)
 {
-       return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE);
+       return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE,
+                                       false);
 }
 
 /**
@@ -1429,7 +1428,7 @@ phys_addr_t __init memblock_phys_alloc_range(phys_addr_t size,
 phys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)
 {
        return memblock_alloc_range_nid(size, align, 0,
-                                       MEMBLOCK_ALLOC_ACCESSIBLE, nid);
+                                       MEMBLOCK_ALLOC_ACCESSIBLE, nid, false);
 }
 
 /**
@@ -1439,6 +1438,7 @@ phys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t ali
  * @min_addr: the lower bound of the memory region to allocate (phys address)
  * @max_addr: the upper bound of the memory region to allocate (phys address)
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
+ * @exact_nid: control the allocation fall back to other nodes
  *
  * Allocates memory block using memblock_alloc_range_nid() and
  * converts the returned physical address to virtual.
@@ -1454,7 +1454,7 @@ phys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t ali
 static void * __init memblock_alloc_internal(
                                phys_addr_t size, phys_addr_t align,
                                phys_addr_t min_addr, phys_addr_t max_addr,
-                               int nid)
+                               int nid, bool exact_nid)
 {
        phys_addr_t alloc;
 
@@ -1469,11 +1469,13 @@ static void * __init memblock_alloc_internal(
        if (max_addr > memblock.current_limit)
                max_addr = memblock.current_limit;
 
-       alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid);
+       alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid,
+                                       exact_nid);
 
        /* retry allocation without lower limit */
        if (!alloc && min_addr)
-               alloc = memblock_alloc_range_nid(size, align, 0, max_addr, nid);
+               alloc = memblock_alloc_range_nid(size, align, 0, max_addr, nid,
+                                               exact_nid);
 
        if (!alloc)
                return NULL;
@@ -1481,6 +1483,43 @@ static void * __init memblock_alloc_internal(
        return phys_to_virt(alloc);
 }
 
+/**
+ * memblock_alloc_exact_nid_raw - allocate boot memory block on the exact node
+ * without zeroing memory
+ * @size: size of memory block to be allocated in bytes
+ * @align: alignment of the region and block's size
+ * @min_addr: the lower bound of the memory region from where the allocation
+ *       is preferred (phys address)
+ * @max_addr: the upper bound of the memory region from where the allocation
+ *           is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to
+ *           allocate only from memory limited by memblock.current_limit value
+ * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
+ *
+ * Public function, provides additional debug information (including caller
+ * info), if enabled. Does not zero allocated memory.
+ *
+ * Return:
+ * Virtual address of allocated memory block on success, NULL on failure.
+ */
+void * __init memblock_alloc_exact_nid_raw(
+                       phys_addr_t size, phys_addr_t align,
+                       phys_addr_t min_addr, phys_addr_t max_addr,
+                       int nid)
+{
+       void *ptr;
+
+       memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n",
+                    __func__, (u64)size, (u64)align, nid, &min_addr,
+                    &max_addr, (void *)_RET_IP_);
+
+       ptr = memblock_alloc_internal(size, align,
+                                          min_addr, max_addr, nid, true);
+       if (ptr && size > 0)
+               page_init_poison(ptr, size);
+
+       return ptr;
+}
+
 /**
  * memblock_alloc_try_nid_raw - allocate boot memory block without zeroing
  * memory and without panicking
@@ -1512,7 +1551,7 @@ void * __init memblock_alloc_try_nid_raw(
                     &max_addr, (void *)_RET_IP_);
 
        ptr = memblock_alloc_internal(size, align,
-                                          min_addr, max_addr, nid);
+                                          min_addr, max_addr, nid, false);
        if (ptr && size > 0)
                page_init_poison(ptr, size);
 
@@ -1547,7 +1586,7 @@ void * __init memblock_alloc_try_nid(
                     __func__, (u64)size, (u64)align, nid, &min_addr,
                     &max_addr, (void *)_RET_IP_);
        ptr = memblock_alloc_internal(size, align,
-                                          min_addr, max_addr, nid);
+                                          min_addr, max_addr, nid, false);
        if (ptr)
                memset(ptr, 0, size);
 
index 01f3f8b..c5b5f74 100644 (file)
@@ -98,17 +98,8 @@ static bool do_memsw_account(void)
        return !cgroup_subsys_on_dfl(memory_cgrp_subsys) && do_swap_account;
 }
 
-static const char *const mem_cgroup_lru_names[] = {
-       "inactive_anon",
-       "active_anon",
-       "inactive_file",
-       "active_file",
-       "unevictable",
-};
-
 #define THRESHOLDS_EVENTS_TARGET 128
 #define SOFTLIMIT_EVENTS_TARGET 1024
-#define NUMAINFO_EVENTS_TARGET 1024
 
 /*
  * Cgroups above their limits are maintained in a RB-Tree, independent of
@@ -778,7 +769,7 @@ void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val)
        if (!memcg || memcg == root_mem_cgroup) {
                __mod_node_page_state(pgdat, idx, val);
        } else {
-               lruvec = mem_cgroup_lruvec(pgdat, memcg);
+               lruvec = mem_cgroup_lruvec(memcg, pgdat);
                __mod_lruvec_state(lruvec, idx, val);
        }
        rcu_read_unlock();
@@ -877,9 +868,6 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
                case MEM_CGROUP_TARGET_SOFTLIMIT:
                        next = val + SOFTLIMIT_EVENTS_TARGET;
                        break;
-               case MEM_CGROUP_TARGET_NUMAINFO:
-                       next = val + NUMAINFO_EVENTS_TARGET;
-                       break;
                default:
                        break;
                }
@@ -899,21 +887,12 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
        if (unlikely(mem_cgroup_event_ratelimit(memcg,
                                                MEM_CGROUP_TARGET_THRESH))) {
                bool do_softlimit;
-               bool do_numainfo __maybe_unused;
 
                do_softlimit = mem_cgroup_event_ratelimit(memcg,
                                                MEM_CGROUP_TARGET_SOFTLIMIT);
-#if MAX_NUMNODES > 1
-               do_numainfo = mem_cgroup_event_ratelimit(memcg,
-                                               MEM_CGROUP_TARGET_NUMAINFO);
-#endif
                mem_cgroup_threshold(memcg);
                if (unlikely(do_softlimit))
                        mem_cgroup_update_tree(memcg, page);
-#if MAX_NUMNODES > 1
-               if (unlikely(do_numainfo))
-                       atomic_inc(&memcg->numainfo_events);
-#endif
        }
 }
 
@@ -1052,7 +1031,7 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                struct mem_cgroup_per_node *mz;
 
                mz = mem_cgroup_nodeinfo(root, reclaim->pgdat->node_id);
-               iter = &mz->iter[reclaim->priority];
+               iter = &mz->iter;
 
                if (prev && reclaim->generation != iter->generation)
                        goto out_unlock;
@@ -1152,15 +1131,11 @@ static void __invalidate_reclaim_iterators(struct mem_cgroup *from,
        struct mem_cgroup_reclaim_iter *iter;
        struct mem_cgroup_per_node *mz;
        int nid;
-       int i;
 
        for_each_node(nid) {
                mz = mem_cgroup_nodeinfo(from, nid);
-               for (i = 0; i <= DEF_PRIORITY; i++) {
-                       iter = &mz->iter[i];
-                       cmpxchg(&iter->position,
-                               dead_memcg, NULL);
-               }
+               iter = &mz->iter;
+               cmpxchg(&iter->position, dead_memcg, NULL);
        }
 }
 
@@ -1238,7 +1213,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgd
        struct lruvec *lruvec;
 
        if (mem_cgroup_disabled()) {
-               lruvec = &pgdat->lruvec;
+               lruvec = &pgdat->__lruvec;
                goto out;
        }
 
@@ -1438,7 +1413,7 @@ static char *memory_stat_format(struct mem_cgroup *memcg)
                       PAGE_SIZE);
 
        for (i = 0; i < NR_LRU_LISTS; i++)
-               seq_buf_printf(&s, "%s %llu\n", mem_cgroup_lru_names[i],
+               seq_buf_printf(&s, "%s %llu\n", lru_list_name(i),
                               (u64)memcg_page_state(memcg, NR_LRU_BASE + i) *
                               PAGE_SIZE);
 
@@ -1451,8 +1426,10 @@ static char *memory_stat_format(struct mem_cgroup *memcg)
 
        /* Accumulated memory events */
 
-       seq_buf_printf(&s, "pgfault %lu\n", memcg_events(memcg, PGFAULT));
-       seq_buf_printf(&s, "pgmajfault %lu\n", memcg_events(memcg, PGMAJFAULT));
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGFAULT),
+                      memcg_events(memcg, PGFAULT));
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGMAJFAULT),
+                      memcg_events(memcg, PGMAJFAULT));
 
        seq_buf_printf(&s, "workingset_refault %lu\n",
                       memcg_page_state(memcg, WORKINGSET_REFAULT));
@@ -1461,22 +1438,27 @@ static char *memory_stat_format(struct mem_cgroup *memcg)
        seq_buf_printf(&s, "workingset_nodereclaim %lu\n",
                       memcg_page_state(memcg, WORKINGSET_NODERECLAIM));
 
-       seq_buf_printf(&s, "pgrefill %lu\n", memcg_events(memcg, PGREFILL));
+       seq_buf_printf(&s, "%s %lu\n",  vm_event_name(PGREFILL),
+                      memcg_events(memcg, PGREFILL));
        seq_buf_printf(&s, "pgscan %lu\n",
                       memcg_events(memcg, PGSCAN_KSWAPD) +
                       memcg_events(memcg, PGSCAN_DIRECT));
        seq_buf_printf(&s, "pgsteal %lu\n",
                       memcg_events(memcg, PGSTEAL_KSWAPD) +
                       memcg_events(memcg, PGSTEAL_DIRECT));
-       seq_buf_printf(&s, "pgactivate %lu\n", memcg_events(memcg, PGACTIVATE));
-       seq_buf_printf(&s, "pgdeactivate %lu\n", memcg_events(memcg, PGDEACTIVATE));
-       seq_buf_printf(&s, "pglazyfree %lu\n", memcg_events(memcg, PGLAZYFREE));
-       seq_buf_printf(&s, "pglazyfreed %lu\n", memcg_events(memcg, PGLAZYFREED));
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGACTIVATE),
+                      memcg_events(memcg, PGACTIVATE));
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGDEACTIVATE),
+                      memcg_events(memcg, PGDEACTIVATE));
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGLAZYFREE),
+                      memcg_events(memcg, PGLAZYFREE));
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGLAZYFREED),
+                      memcg_events(memcg, PGLAZYFREED));
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       seq_buf_printf(&s, "thp_fault_alloc %lu\n",
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(THP_FAULT_ALLOC),
                       memcg_events(memcg, THP_FAULT_ALLOC));
-       seq_buf_printf(&s, "thp_collapse_alloc %lu\n",
+       seq_buf_printf(&s, "%s %lu\n", vm_event_name(THP_COLLAPSE_ALLOC),
                       memcg_events(memcg, THP_COLLAPSE_ALLOC));
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
@@ -1595,104 +1577,6 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
        return ret;
 }
 
-#if MAX_NUMNODES > 1
-
-/**
- * test_mem_cgroup_node_reclaimable
- * @memcg: the target memcg
- * @nid: the node ID to be checked.
- * @noswap : specify true here if the user wants flle only information.
- *
- * This function returns whether the specified memcg contains any
- * reclaimable pages on a node. Returns true if there are any reclaimable
- * pages in the node.
- */
-static bool test_mem_cgroup_node_reclaimable(struct mem_cgroup *memcg,
-               int nid, bool noswap)
-{
-       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 (lruvec_page_state(lruvec, NR_INACTIVE_ANON) ||
-           lruvec_page_state(lruvec, NR_ACTIVE_ANON))
-               return true;
-       return false;
-
-}
-
-/*
- * Always updating the nodemask is not very good - even if we have an empty
- * list or the wrong list here, we can start from some node and traverse all
- * nodes based on the zonelist. So update the list loosely once per 10 secs.
- *
- */
-static void mem_cgroup_may_update_nodemask(struct mem_cgroup *memcg)
-{
-       int nid;
-       /*
-        * numainfo_events > 0 means there was at least NUMAINFO_EVENTS_TARGET
-        * pagein/pageout changes since the last update.
-        */
-       if (!atomic_read(&memcg->numainfo_events))
-               return;
-       if (atomic_inc_return(&memcg->numainfo_updating) > 1)
-               return;
-
-       /* make a nodemask where this memcg uses memory from */
-       memcg->scan_nodes = node_states[N_MEMORY];
-
-       for_each_node_mask(nid, node_states[N_MEMORY]) {
-
-               if (!test_mem_cgroup_node_reclaimable(memcg, nid, false))
-                       node_clear(nid, memcg->scan_nodes);
-       }
-
-       atomic_set(&memcg->numainfo_events, 0);
-       atomic_set(&memcg->numainfo_updating, 0);
-}
-
-/*
- * Selecting a node where we start reclaim from. Because what we need is just
- * reducing usage counter, start from anywhere is O,K. Considering
- * memory reclaim from current node, there are pros. and cons.
- *
- * Freeing memory from current node means freeing memory from a node which
- * we'll use or we've used. So, it may make LRU bad. And if several threads
- * hit limits, it will see a contention on a node. But freeing from remote
- * node means more costs for memory reclaim because of memory latency.
- *
- * Now, we use round-robin. Better algorithm is welcomed.
- */
-int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
-{
-       int node;
-
-       mem_cgroup_may_update_nodemask(memcg);
-       node = memcg->last_scanned_node;
-
-       node = next_node_in(node, memcg->scan_nodes);
-       /*
-        * mem_cgroup_may_update_nodemask might have seen no reclaimmable pages
-        * last time it really checked all the LRUs due to rate limiting.
-        * Fallback to the current node in that case for simplicity.
-        */
-       if (unlikely(node == MAX_NUMNODES))
-               node = numa_node_id();
-
-       memcg->last_scanned_node = node;
-       return node;
-}
-#else
-int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
-{
-       return 0;
-}
-#endif
-
 static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
                                   pg_data_t *pgdat,
                                   gfp_t gfp_mask,
@@ -1705,7 +1589,6 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
        unsigned long nr_scanned;
        struct mem_cgroup_reclaim_cookie reclaim = {
                .pgdat = pgdat,
-               .priority = 0,
        };
 
        excess = soft_limit_excess(root_memcg);
@@ -3750,7 +3633,7 @@ static int mem_cgroup_move_charge_write(struct cgroup_subsys_state *css,
 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);
+       struct lruvec *lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(nid));
        unsigned long nr = 0;
        enum lru_list lru;
 
@@ -3858,13 +3741,6 @@ static const unsigned int memcg1_events[] = {
        PGMAJFAULT,
 };
 
-static const char *const memcg1_event_names[] = {
-       "pgpgin",
-       "pgpgout",
-       "pgfault",
-       "pgmajfault",
-};
-
 static int memcg_stat_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
@@ -3873,7 +3749,6 @@ static int memcg_stat_show(struct seq_file *m, void *v)
        unsigned int i;
 
        BUILD_BUG_ON(ARRAY_SIZE(memcg1_stat_names) != ARRAY_SIZE(memcg1_stats));
-       BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS);
 
        for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
                if (memcg1_stats[i] == MEMCG_SWAP && !do_memsw_account())
@@ -3884,11 +3759,11 @@ static int memcg_stat_show(struct seq_file *m, void *v)
        }
 
        for (i = 0; i < ARRAY_SIZE(memcg1_events); i++)
-               seq_printf(m, "%s %lu\n", memcg1_event_names[i],
+               seq_printf(m, "%s %lu\n", vm_event_name(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],
+               seq_printf(m, "%s %lu\n", lru_list_name(i),
                           memcg_page_state_local(memcg, NR_LRU_BASE + i) *
                           PAGE_SIZE);
 
@@ -3913,11 +3788,12 @@ static int memcg_stat_show(struct seq_file *m, void *v)
        }
 
        for (i = 0; i < ARRAY_SIZE(memcg1_events); i++)
-               seq_printf(m, "total_%s %llu\n", memcg1_event_names[i],
+               seq_printf(m, "total_%s %llu\n",
+                          vm_event_name(memcg1_events[i]),
                           (u64)memcg_events(memcg, memcg1_events[i]));
 
        for (i = 0; i < NR_LRU_LISTS; i++)
-               seq_printf(m, "total_%s %llu\n", mem_cgroup_lru_names[i],
+               seq_printf(m, "total_%s %llu\n", lru_list_name(i),
                           (u64)memcg_page_state(memcg, NR_LRU_BASE + i) *
                           PAGE_SIZE);
 
@@ -5078,7 +4954,6 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
                goto fail;
 
        INIT_WORK(&memcg->high_work, high_work_func);
-       memcg->last_scanned_node = MAX_NUMNODES;
        INIT_LIST_HEAD(&memcg->oom_notify);
        mutex_init(&memcg->thresholds_lock);
        spin_lock_init(&memcg->move_lock);
@@ -5455,8 +5330,8 @@ static int mem_cgroup_move_account(struct page *page,
        anon = PageAnon(page);
 
        pgdat = page_pgdat(page);
-       from_vec = mem_cgroup_lruvec(pgdat, from);
-       to_vec = mem_cgroup_lruvec(pgdat, to);
+       from_vec = mem_cgroup_lruvec(from, pgdat);
+       to_vec = mem_cgroup_lruvec(to, pgdat);
 
        spin_lock_irqsave(&from->move_lock, flags);
 
@@ -6096,7 +5971,8 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
                                 char *buf, size_t nbytes, loff_t off)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
-       unsigned long nr_pages;
+       unsigned int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
+       bool drained = false;
        unsigned long high;
        int err;
 
@@ -6107,12 +5983,29 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
 
        memcg->high = high;
 
-       nr_pages = page_counter_read(&memcg->memory);
-       if (nr_pages > high)
-               try_to_free_mem_cgroup_pages(memcg, nr_pages - high,
-                                            GFP_KERNEL, true);
+       for (;;) {
+               unsigned long nr_pages = page_counter_read(&memcg->memory);
+               unsigned long reclaimed;
+
+               if (nr_pages <= high)
+                       break;
+
+               if (signal_pending(current))
+                       break;
+
+               if (!drained) {
+                       drain_all_stock(memcg);
+                       drained = true;
+                       continue;
+               }
+
+               reclaimed = try_to_free_mem_cgroup_pages(memcg, nr_pages - high,
+                                                        GFP_KERNEL, true);
+
+               if (!reclaimed && !nr_retries--)
+                       break;
+       }
 
-       memcg_wb_domain_size_changed(memcg);
        return nbytes;
 }
 
@@ -6144,10 +6037,8 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
                if (nr_pages <= max)
                        break;
 
-               if (signal_pending(current)) {
-                       err = -EINTR;
+               if (signal_pending(current))
                        break;
-               }
 
                if (!drained) {
                        drain_all_stock(memcg);
index 3151c87..41c634f 100644 (file)
@@ -303,30 +303,24 @@ static unsigned long dev_pagemap_mapping_shift(struct page *page,
 /*
  * Schedule a process for later kill.
  * Uses GFP_ATOMIC allocations to avoid potential recursions in the VM.
- * TBD would GFP_NOIO be enough?
  */
 static void add_to_kill(struct task_struct *tsk, struct page *p,
                       struct vm_area_struct *vma,
-                      struct list_head *to_kill,
-                      struct to_kill **tkc)
+                      struct list_head *to_kill)
 {
        struct to_kill *tk;
 
-       if (*tkc) {
-               tk = *tkc;
-               *tkc = NULL;
-       } else {
-               tk = kmalloc(sizeof(struct to_kill), GFP_ATOMIC);
-               if (!tk) {
-                       pr_err("Memory failure: Out of memory while machine check handling\n");
-                       return;
-               }
+       tk = kmalloc(sizeof(struct to_kill), GFP_ATOMIC);
+       if (!tk) {
+               pr_err("Memory failure: Out of memory while machine check handling\n");
+               return;
        }
+
        tk->addr = page_address_in_vma(p, vma);
        if (is_zone_device_page(p))
                tk->size_shift = dev_pagemap_mapping_shift(p, vma);
        else
-               tk->size_shift = compound_order(compound_head(p)) + PAGE_SHIFT;
+               tk->size_shift = page_shift(compound_head(p));
 
        /*
         * Send SIGKILL if "tk->addr == -EFAULT". Also, as
@@ -345,6 +339,7 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
                kfree(tk);
                return;
        }
+
        get_task_struct(tsk);
        tk->tsk = tsk;
        list_add_tail(&tk->nd, to_kill);
@@ -436,7 +431,7 @@ static struct task_struct *task_early_kill(struct task_struct *tsk,
  * Collect processes when the error hit an anonymous page.
  */
 static void collect_procs_anon(struct page *page, struct list_head *to_kill,
-                             struct to_kill **tkc, int force_early)
+                               int force_early)
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
@@ -461,7 +456,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
                        if (!page_mapped_in_vma(page, vma))
                                continue;
                        if (vma->vm_mm == t->mm)
-                               add_to_kill(t, page, vma, to_kill, tkc);
+                               add_to_kill(t, page, vma, to_kill);
                }
        }
        read_unlock(&tasklist_lock);
@@ -472,7 +467,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
  * Collect processes when the error hit a file mapped page.
  */
 static void collect_procs_file(struct page *page, struct list_head *to_kill,
-                             struct to_kill **tkc, int force_early)
+                               int force_early)
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
@@ -496,7 +491,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
                         * to be informed of all such data corruptions.
                         */
                        if (vma->vm_mm == t->mm)
-                               add_to_kill(t, page, vma, to_kill, tkc);
+                               add_to_kill(t, page, vma, to_kill);
                }
        }
        read_unlock(&tasklist_lock);
@@ -505,26 +500,17 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
 
 /*
  * Collect the processes who have the corrupted page mapped to kill.
- * This is done in two steps for locking reasons.
- * First preallocate one tokill structure outside the spin locks,
- * so that we can kill at least one process reasonably reliable.
  */
 static void collect_procs(struct page *page, struct list_head *tokill,
                                int force_early)
 {
-       struct to_kill *tk;
-
        if (!page->mapping)
                return;
 
-       tk = kmalloc(sizeof(struct to_kill), GFP_NOIO);
-       if (!tk)
-               return;
        if (PageAnon(page))
-               collect_procs_anon(page, tokill, &tk, force_early);
+               collect_procs_anon(page, tokill, force_early);
        else
-               collect_procs_file(page, tokill, &tk, force_early);
-       kfree(tk);
+               collect_procs_file(page, tokill, force_early);
 }
 
 static const char *action_name[] = {
@@ -1490,7 +1476,7 @@ static void memory_failure_work_func(struct work_struct *work)
                if (!gotten)
                        break;
                if (entry.flags & MF_SOFT_OFFLINE)
-                       soft_offline_page(pfn_to_page(entry.pfn), entry.flags);
+                       soft_offline_page(entry.pfn, entry.flags);
                else
                        memory_failure(entry.pfn, entry.flags);
        }
@@ -1871,7 +1857,7 @@ static int soft_offline_free_page(struct page *page)
 
 /**
  * soft_offline_page - Soft offline a page.
- * @page: page to offline
+ * @pfn: pfn to soft-offline
  * @flags: flags. Same as memory_failure().
  *
  * Returns 0 on success, otherwise negated errno.
@@ -1891,18 +1877,17 @@ static int soft_offline_free_page(struct page *page)
  * This is not a 100% solution for all memory, but tries to be
  * ``good enough'' for the majority of memory.
  */
-int soft_offline_page(struct page *page, int flags)
+int soft_offline_page(unsigned long pfn, int flags)
 {
        int ret;
-       unsigned long pfn = page_to_pfn(page);
+       struct page *page;
 
-       if (is_zone_device_page(page)) {
-               pr_debug_ratelimited("soft_offline: %#lx page is device page\n",
-                               pfn);
-               if (flags & MF_COUNT_INCREASED)
-                       put_page(page);
+       if (!pfn_valid(pfn))
+               return -ENXIO;
+       /* Only online pages can be soft-offlined (esp., not ZONE_DEVICE). */
+       page = pfn_to_online_page(pfn);
+       if (!page)
                return -EIO;
-       }
 
        if (PageHWPoison(page)) {
                pr_info("soft offline: %#lx page already poisoned\n", pfn);
index b6a5d6a..606da18 100644 (file)
@@ -72,6 +72,8 @@
 #include <linux/oom.h>
 #include <linux/numa.h>
 
+#include <trace/events/kmem.h>
+
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
@@ -152,6 +154,10 @@ static int __init init_zero_pfn(void)
 }
 core_initcall(init_zero_pfn);
 
+void mm_trace_rss_stat(struct mm_struct *mm, int member, long count)
+{
+       trace_rss_stat(mm, member, count);
+}
 
 #if defined(SPLIT_RSS_COUNTING)
 
@@ -666,7 +672,7 @@ struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
 
        if (pmd_devmap(pmd))
                return NULL;
-       if (is_zero_pfn(pfn))
+       if (is_huge_zero_pmd(pmd))
                return NULL;
        if (unlikely(pfn > highest_memmap_pfn))
                return NULL;
@@ -2289,10 +2295,11 @@ static vm_fault_t do_page_mkwrite(struct vm_fault *vmf)
  *
  * The function expects the page to be locked and unlocks it.
  */
-static void fault_dirty_shared_page(struct vm_area_struct *vma,
-                                   struct page *page)
+static vm_fault_t fault_dirty_shared_page(struct vm_fault *vmf)
 {
+       struct vm_area_struct *vma = vmf->vma;
        struct address_space *mapping;
+       struct page *page = vmf->page;
        bool dirtied;
        bool page_mkwrite = vma->vm_ops && vma->vm_ops->page_mkwrite;
 
@@ -2307,16 +2314,30 @@ static void fault_dirty_shared_page(struct vm_area_struct *vma,
        mapping = page_rmapping(page);
        unlock_page(page);
 
+       if (!page_mkwrite)
+               file_update_time(vma->vm_file);
+
+       /*
+        * Throttle page dirtying rate down to writeback speed.
+        *
+        * mapping may be NULL here because some device drivers do not
+        * set page.mapping but still dirty their pages
+        *
+        * Drop the mmap_sem before waiting on IO, if we can. The file
+        * is pinning the mapping, as per above.
+        */
        if ((dirtied || page_mkwrite) && mapping) {
-               /*
-                * Some device drivers do not set page.mapping
-                * but still dirty their pages
-                */
+               struct file *fpin;
+
+               fpin = maybe_unlock_mmap_for_io(vmf, NULL);
                balance_dirty_pages_ratelimited(mapping);
+               if (fpin) {
+                       fput(fpin);
+                       return VM_FAULT_RETRY;
+               }
        }
 
-       if (!page_mkwrite)
-               file_update_time(vma->vm_file);
+       return 0;
 }
 
 /*
@@ -2571,6 +2592,7 @@ static vm_fault_t wp_page_shared(struct vm_fault *vmf)
        __releases(vmf->ptl)
 {
        struct vm_area_struct *vma = vmf->vma;
+       vm_fault_t ret = VM_FAULT_WRITE;
 
        get_page(vmf->page);
 
@@ -2594,10 +2616,10 @@ static vm_fault_t wp_page_shared(struct vm_fault *vmf)
                wp_page_reuse(vmf);
                lock_page(vmf->page);
        }
-       fault_dirty_shared_page(vma, vmf->page);
+       ret |= fault_dirty_shared_page(vmf);
        put_page(vmf->page);
 
-       return VM_FAULT_WRITE;
+       return ret;
 }
 
 /*
@@ -3083,7 +3105,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
 
        /*
         * The memory barrier inside __SetPageUptodate makes sure that
-        * preceeding stores to the page contents become visible before
+        * preceding stores to the page contents become visible before
         * the set_pte_at() write.
         */
        __SetPageUptodate(page);
@@ -3641,7 +3663,7 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
                return ret;
        }
 
-       fault_dirty_shared_page(vma, vmf->page);
+       ret |= fault_dirty_shared_page(vmf);
        return ret;
 }
 
@@ -3988,6 +4010,7 @@ static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma,
        vmf.pud = pud_alloc(mm, p4d, address);
        if (!vmf.pud)
                return VM_FAULT_OOM;
+retry_pud:
        if (pud_none(*vmf.pud) && __transparent_hugepage_enabled(vma)) {
                ret = create_huge_pud(&vmf);
                if (!(ret & VM_FAULT_FALLBACK))
@@ -4014,6 +4037,11 @@ static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma,
        vmf.pmd = pmd_alloc(mm, vmf.pud, address);
        if (!vmf.pmd)
                return VM_FAULT_OOM;
+
+       /* Huge pud page fault raced with pmd_alloc? */
+       if (pud_trans_unstable(vmf.pud))
+               goto retry_pud;
+
        if (pmd_none(*vmf.pmd) && __transparent_hugepage_enabled(vma)) {
                ret = create_huge_pmd(&vmf);
                if (!(ret & VM_FAULT_FALLBACK))
@@ -4169,19 +4197,11 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
        smp_wmb(); /* See comment in __pte_alloc */
 
        ptl = pud_lock(mm, pud);
-#ifndef __ARCH_HAS_4LEVEL_HACK
        if (!pud_present(*pud)) {
                mm_inc_nr_pmds(mm);
                pud_populate(mm, pud, new);
        } else  /* Another has populated it */
                pmd_free(mm, new);
-#else
-       if (!pgd_present(*pud)) {
-               mm_inc_nr_pmds(mm);
-               pgd_populate(mm, pud, new);
-       } else /* Another has populated it */
-               pmd_free(mm, new);
-#endif /* __ARCH_HAS_4LEVEL_HACK */
        spin_unlock(ptl);
        return 0;
 }
index f307bd8..55ac23e 100644 (file)
@@ -49,8 +49,6 @@
  * and restore_online_page_callback() for generic callback restore.
  */
 
-static void generic_online_page(struct page *page, unsigned int order);
-
 static online_page_callback_t online_page_callback = generic_online_page;
 static DEFINE_MUTEX(online_page_callback_lock);
 
@@ -278,6 +276,22 @@ static int check_pfn_span(unsigned long pfn, unsigned long nr_pages,
        return 0;
 }
 
+static int check_hotplug_memory_addressable(unsigned long pfn,
+                                           unsigned long nr_pages)
+{
+       const u64 max_addr = PFN_PHYS(pfn + nr_pages) - 1;
+
+       if (max_addr >> MAX_PHYSMEM_BITS) {
+               const u64 max_allowed = (1ull << (MAX_PHYSMEM_BITS + 1)) - 1;
+               WARN(1,
+                    "Hotplugged memory exceeds maximum addressable address, range=%#llx-%#llx, maximum=%#llx\n",
+                    (u64)PFN_PHYS(pfn), max_addr, max_allowed);
+               return -E2BIG;
+       }
+
+       return 0;
+}
+
 /*
  * Reasonably generic function for adding memory.  It is
  * expected that archs that support memory hotplug will
@@ -291,6 +305,10 @@ int __ref __add_pages(int nid, unsigned long pfn, unsigned long nr_pages,
        unsigned long nr, start_sec, end_sec;
        struct vmem_altmap *altmap = restrictions->altmap;
 
+       err = check_hotplug_memory_addressable(pfn, nr_pages);
+       if (err)
+               return err;
+
        if (altmap) {
                /*
                 * Validate altmap is within bounds of the total request
@@ -580,24 +598,7 @@ int restore_online_page_callback(online_page_callback_t callback)
 }
 EXPORT_SYMBOL_GPL(restore_online_page_callback);
 
-void __online_page_set_limits(struct page *page)
-{
-}
-EXPORT_SYMBOL_GPL(__online_page_set_limits);
-
-void __online_page_increment_counters(struct page *page)
-{
-       adjust_managed_page_count(page, 1);
-}
-EXPORT_SYMBOL_GPL(__online_page_increment_counters);
-
-void __online_page_free(struct page *page)
-{
-       __free_reserved_page(page);
-}
-EXPORT_SYMBOL_GPL(__online_page_free);
-
-static void generic_online_page(struct page *page, unsigned int order)
+void generic_online_page(struct page *page, unsigned int order)
 {
        kernel_map_pages(page, 1 << order, 1);
        __free_pages_core(page, order);
@@ -607,6 +608,7 @@ static void generic_online_page(struct page *page, unsigned int order)
                totalhigh_pages_add(1UL << order);
 #endif
 }
+EXPORT_SYMBOL_GPL(generic_online_page);
 
 static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
                        void *arg)
@@ -1180,7 +1182,8 @@ static bool is_pageblock_removable_nolock(unsigned long pfn)
        if (!zone_spans_pfn(zone, pfn))
                return false;
 
-       return !has_unmovable_pages(zone, page, 0, MIGRATE_MOVABLE, SKIP_HWPOISON);
+       return !has_unmovable_pages(zone, page, 0, MIGRATE_MOVABLE,
+                                   MEMORY_OFFLINE);
 }
 
 /* Checks if this range of memory is likely to be hot-removable. */
@@ -1377,9 +1380,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
        return ret;
 }
 
-/*
- * remove from free_area[] and mark all as Reserved.
- */
+/* Mark all sections offline and remove all free pages from the buddy. */
 static int
 offline_isolated_pages_cb(unsigned long start, unsigned long nr_pages,
                        void *data)
@@ -1397,7 +1398,8 @@ static int
 check_pages_isolated_cb(unsigned long start_pfn, unsigned long nr_pages,
                        void *data)
 {
-       return test_pages_isolated(start_pfn, start_pfn + nr_pages, true);
+       return test_pages_isolated(start_pfn, start_pfn + nr_pages,
+                                  MEMORY_OFFLINE);
 }
 
 static int __init cmdline_parse_movable_node(char *p)
@@ -1478,10 +1480,19 @@ static void node_states_clear_node(int node, struct memory_notify *arg)
                node_clear_state(node, N_MEMORY);
 }
 
+static int count_system_ram_pages_cb(unsigned long start_pfn,
+                                    unsigned long nr_pages, void *data)
+{
+       unsigned long *nr_system_ram_pages = data;
+
+       *nr_system_ram_pages += nr_pages;
+       return 0;
+}
+
 static int __ref __offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn)
 {
-       unsigned long pfn, nr_pages;
+       unsigned long pfn, nr_pages = 0;
        unsigned long offlined_pages = 0;
        int ret, node, nr_isolate_pageblock;
        unsigned long flags;
@@ -1492,6 +1503,22 @@ static int __ref __offline_pages(unsigned long start_pfn,
 
        mem_hotplug_begin();
 
+       /*
+        * Don't allow to offline memory blocks that contain holes.
+        * Consequently, memory blocks with holes can never get onlined
+        * via the hotplug path - online_pages() - as hotplugged memory has
+        * no holes. This way, we e.g., don't have to worry about marking
+        * memory holes PG_reserved, don't need pfn_valid() checks, and can
+        * avoid using walk_system_ram_range() later.
+        */
+       walk_system_ram_range(start_pfn, end_pfn - start_pfn, &nr_pages,
+                             count_system_ram_pages_cb);
+       if (nr_pages != end_pfn - start_pfn) {
+               ret = -EINVAL;
+               reason = "memory holes";
+               goto failed_removal;
+       }
+
        /* This makes hotplug much easier...and readable.
           we assume this for now. .*/
        if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start,
@@ -1503,12 +1530,11 @@ static int __ref __offline_pages(unsigned long start_pfn,
 
        zone = page_zone(pfn_to_page(valid_start));
        node = zone_to_nid(zone);
-       nr_pages = end_pfn - start_pfn;
 
        /* set above range as isolated */
        ret = start_isolate_page_range(start_pfn, end_pfn,
                                       MIGRATE_MOVABLE,
-                                      SKIP_HWPOISON | REPORT_FAILURE);
+                                      MEMORY_OFFLINE | REPORT_FAILURE);
        if (ret < 0) {
                reason = "failure to isolate range";
                goto failed_removal;
@@ -1750,13 +1776,13 @@ static int __ref try_remove_memory(int nid, u64 start, u64 size)
 
        /* remove memmap entry */
        firmware_map_remove(start, start + size, "System RAM");
-       memblock_free(start, size);
-       memblock_remove(start, size);
 
        /* remove memory block devices before removing memory */
        remove_memory_block_devices(start, size);
 
        arch_remove_memory(nid, start, size, NULL);
+       memblock_free(start, size);
+       memblock_remove(start, size);
        __release_memory_resource(start, size);
 
        try_offline_node(nid);
index e08c941..067cf7d 100644 (file)
@@ -410,7 +410,9 @@ struct queue_pages {
        struct list_head *pagelist;
        unsigned long flags;
        nodemask_t *nmask;
-       struct vm_area_struct *prev;
+       unsigned long start;
+       unsigned long end;
+       struct vm_area_struct *first;
 };
 
 /*
@@ -618,6 +620,22 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
        unsigned long endvma = vma->vm_end;
        unsigned long flags = qp->flags;
 
+       /* range check first */
+       VM_BUG_ON((vma->vm_start > start) || (vma->vm_end < end));
+
+       if (!qp->first) {
+               qp->first = vma;
+               if (!(flags & MPOL_MF_DISCONTIG_OK) &&
+                       (qp->start < vma->vm_start))
+                       /* hole at head side of range */
+                       return -EFAULT;
+       }
+       if (!(flags & MPOL_MF_DISCONTIG_OK) &&
+               ((vma->vm_end < qp->end) &&
+               (!vma->vm_next || vma->vm_end < vma->vm_next->vm_start)))
+               /* hole at middle or tail of range */
+               return -EFAULT;
+
        /*
         * Need check MPOL_MF_STRICT to return -EIO if possible
         * regardless of vma_migratable
@@ -628,17 +646,6 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
 
        if (endvma > end)
                endvma = end;
-       if (vma->vm_start > start)
-               start = vma->vm_start;
-
-       if (!(flags & MPOL_MF_DISCONTIG_OK)) {
-               if (!vma->vm_next && vma->vm_end < end)
-                       return -EFAULT;
-               if (qp->prev && qp->prev->vm_end < vma->vm_start)
-                       return -EFAULT;
-       }
-
-       qp->prev = vma;
 
        if (flags & MPOL_MF_LAZY) {
                /* Similar to task_numa_work, skip inaccessible VMAs */
@@ -681,14 +688,23 @@ queue_pages_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                nodemask_t *nodes, unsigned long flags,
                struct list_head *pagelist)
 {
+       int err;
        struct queue_pages qp = {
                .pagelist = pagelist,
                .flags = flags,
                .nmask = nodes,
-               .prev = NULL,
+               .start = start,
+               .end = end,
+               .first = NULL,
        };
 
-       return walk_page_range(mm, start, end, &queue_pages_walk_ops, &qp);
+       err = walk_page_range(mm, start, end, &queue_pages_walk_ops, &qp);
+
+       if (!qp.first)
+               /* whole range in hole */
+               err = -EFAULT;
+
+       return err;
 }
 
 /*
@@ -740,8 +756,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
        unsigned long vmend;
 
        vma = find_vma(mm, start);
-       if (!vma || vma->vm_start > start)
-               return -EFAULT;
+       VM_BUG_ON(!vma);
 
        prev = vma->vm_prev;
        if (start > vma->vm_start)
index 4fe45d1..eae1565 100644 (file)
@@ -1168,15 +1168,11 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
                                   enum migrate_reason reason)
 {
        int rc = MIGRATEPAGE_SUCCESS;
-       struct page *newpage;
+       struct page *newpage = NULL;
 
        if (!thp_migration_supported() && PageTransHuge(page))
                return -ENOMEM;
 
-       newpage = get_new_page(page, private);
-       if (!newpage)
-               return -ENOMEM;
-
        if (page_count(page) == 1) {
                /* page was freed from under us. So we are done. */
                ClearPageActive(page);
@@ -1187,13 +1183,13 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
                                __ClearPageIsolated(page);
                        unlock_page(page);
                }
-               if (put_new_page)
-                       put_new_page(newpage, private);
-               else
-                       put_page(newpage);
                goto out;
        }
 
+       newpage = get_new_page(page, private);
+       if (!newpage)
+               return -ENOMEM;
+
        rc = __unmap_and_move(page, newpage, force, mode);
        if (rc == MIGRATEPAGE_SUCCESS)
                set_page_owner_migrate_reason(newpage, reason);
@@ -1863,7 +1859,7 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
                if (!zone_watermark_ok(zone, 0,
                                       high_wmark_pages(zone) +
                                       nr_migrate_pages,
-                                      0, 0))
+                                      ZONE_MOVABLE, 0))
                        continue;
                return true;
        }
index a7d8c84..9c64852 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -641,7 +641,7 @@ __vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
        struct vm_area_struct *prev, struct rb_node **rb_link,
        struct rb_node *rb_parent)
 {
-       __vma_link_list(mm, vma, prev, rb_parent);
+       __vma_link_list(mm, vma, prev);
        __vma_link_rb(mm, vma, rb_link, rb_parent);
 }
 
@@ -684,37 +684,14 @@ static void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
 
 static __always_inline void __vma_unlink_common(struct mm_struct *mm,
                                                struct vm_area_struct *vma,
-                                               struct vm_area_struct *prev,
-                                               bool has_prev,
                                                struct vm_area_struct *ignore)
 {
-       struct vm_area_struct *next;
-
        vma_rb_erase_ignore(vma, &mm->mm_rb, ignore);
-       next = vma->vm_next;
-       if (has_prev)
-               prev->vm_next = next;
-       else {
-               prev = vma->vm_prev;
-               if (prev)
-                       prev->vm_next = next;
-               else
-                       mm->mmap = next;
-       }
-       if (next)
-               next->vm_prev = prev;
-
+       __vma_unlink_list(mm, vma);
        /* Kill the cache */
        vmacache_invalidate(mm);
 }
 
-static inline void __vma_unlink_prev(struct mm_struct *mm,
-                                    struct vm_area_struct *vma,
-                                    struct vm_area_struct *prev)
-{
-       __vma_unlink_common(mm, vma, prev, true, vma);
-}
-
 /*
  * We cannot adjust vm_start, vm_end, vm_pgoff fields of a vma that
  * is already present in an i_mmap tree without adjusting the tree.
@@ -769,8 +746,6 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
                                remove_next = 1 + (end > next->vm_end);
                                VM_WARN_ON(remove_next == 2 &&
                                           end != next->vm_next->vm_end);
-                               VM_WARN_ON(remove_next == 1 &&
-                                          end != next->vm_end);
                                /* trim end to next, for case 6 first pass */
                                end = next->vm_end;
                        }
@@ -889,7 +864,7 @@ again:
                 * us to remove next before dropping the locks.
                 */
                if (remove_next != 3)
-                       __vma_unlink_prev(mm, next, vma);
+                       __vma_unlink_common(mm, next, next);
                else
                        /*
                         * vma is not before next if they've been
@@ -900,7 +875,7 @@ again:
                         * "next" (which is stored in post-swap()
                         * "vma").
                         */
-                       __vma_unlink_common(mm, next, NULL, false, vma);
+                       __vma_unlink_common(mm, next, vma);
                if (file)
                        __remove_shared_vm_struct(next, file, mapping);
        } else if (insert) {
@@ -1116,15 +1091,18 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
  * the area passed down from mprotect_fixup, never extending beyond one
  * vma, PPPPPP is the prev vma specified, and NNNNNN the next vma after:
  *
- *     AAAA             AAAA                AAAA          AAAA
- *    PPPPPPNNNNNN    PPPPPPNNNNNN    PPPPPPNNNNNN    PPPPNNNNXXXX
- *    cannot merge    might become    might become    might become
- *                    PPNNNNNNNNNN    PPPPPPPPPPNN    PPPPPPPPPPPP 6 or
- *    mmap, brk or    case 4 below    case 5 below    PPPPPPPPXXXX 7 or
- *    mremap move:                                    PPPPXXXXXXXX 8
- *        AAAA
- *    PPPP    NNNN    PPPPPPPPPPPP    PPPPPPPPNNNN    PPPPNNNNNNNN
- *    might become    case 1 below    case 2 below    case 3 below
+ *     AAAA             AAAA                   AAAA
+ *    PPPPPPNNNNNN    PPPPPPNNNNNN       PPPPPPNNNNNN
+ *    cannot merge    might become       might become
+ *                    PPNNNNNNNNNN       PPPPPPPPPPNN
+ *    mmap, brk or    case 4 below       case 5 below
+ *    mremap move:
+ *                        AAAA               AAAA
+ *                    PPPP    NNNN       PPPPNNNNXXXX
+ *                    might become       might become
+ *                    PPPPPPPPPPPP 1 or  PPPPPPPPPPPP 6 or
+ *                    PPPPPPPPNNNN 2 or  PPPPPPPPXXXX 7 or
+ *                    PPPPNNNNNNNN 3     PPPPXXXXXXXX 8
  *
  * It is important for case 8 that the vma NNNN overlapping the
  * region AAAA is never going to extended over XXXX. Instead XXXX must
@@ -1442,7 +1420,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
         * that it represents a valid section of the address space.
         */
        addr = get_unmapped_area(file, addr, len, pgoff, flags);
-       if (offset_in_page(addr))
+       if (IS_ERR_VALUE(addr))
                return addr;
 
        if (flags & MAP_FIXED_NOREPLACE) {
@@ -3006,15 +2984,16 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla
        struct rb_node **rb_link, *rb_parent;
        pgoff_t pgoff = addr >> PAGE_SHIFT;
        int error;
+       unsigned long mapped_addr;
 
        /* Until we need other flags, refuse anything except VM_EXEC. */
        if ((flags & (~VM_EXEC)) != 0)
                return -EINVAL;
        flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
 
-       error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
-       if (offset_in_page(error))
-               return error;
+       mapped_addr = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
+       if (IS_ERR_VALUE(mapped_addr))
+               return mapped_addr;
 
        error = mlock_future_check(mm, mm->def_flags, len);
        if (error)
index 7967825..7a8e84f 100644 (file)
@@ -80,6 +80,10 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                        if (prot_numa) {
                                struct page *page;
 
+                               /* Avoid TLB flush if possible */
+                               if (pte_protnone(oldpte))
+                                       continue;
+
                                page = vm_normal_page(vma, addr, oldpte);
                                if (!page || PageKsm(page))
                                        continue;
@@ -97,10 +101,6 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                                if (page_is_file_cache(page) && PageDirty(page))
                                        continue;
 
-                               /* Avoid TLB flush if possible */
-                               if (pte_protnone(oldpte))
-                                       continue;
-
                                /*
                                 * Don't mess with PTEs if page is already on the node
                                 * a single-threaded process is running on.
index 1fc8a29..122938d 100644 (file)
@@ -558,7 +558,7 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
        ret = get_unmapped_area(vma->vm_file, new_addr, new_len, vma->vm_pgoff +
                                ((addr - vma->vm_start) >> PAGE_SHIFT),
                                map_flags);
-       if (offset_in_page(ret))
+       if (IS_ERR_VALUE(ret))
                goto out1;
 
        ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, uf,
@@ -706,7 +706,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
                                        vma->vm_pgoff +
                                        ((addr - vma->vm_start) >> PAGE_SHIFT),
                                        map_flags);
-               if (offset_in_page(new_addr)) {
+               if (IS_ERR_VALUE(new_addr)) {
                        ret = new_addr;
                        goto out;
                }
index 7de5920..bd2b4e5 100644 (file)
@@ -648,7 +648,7 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
        if (rb_prev)
                prev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
 
-       __vma_link_list(mm, vma, prev, parent);
+       __vma_link_list(mm, vma, prev);
 }
 
 /*
@@ -684,13 +684,7 @@ static void delete_vma_from_mm(struct vm_area_struct *vma)
        /* remove from the MM's tree and list */
        rb_erase(&vma->vm_rb, &mm->mm_rb);
 
-       if (vma->vm_prev)
-               vma->vm_prev->vm_next = vma->vm_next;
-       else
-               mm->mmap = vma->vm_next;
-
-       if (vma->vm_next)
-               vma->vm_next->vm_prev = vma->vm_prev;
+       __vma_unlink_list(mm, vma);
 }
 
 /*
index f391c0c..4785a8a 100644 (file)
@@ -5354,6 +5354,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
                        " min:%lukB"
                        " low:%lukB"
                        " high:%lukB"
+                       " reserved_highatomic:%luKB"
                        " active_anon:%lukB"
                        " inactive_anon:%lukB"
                        " active_file:%lukB"
@@ -5375,6 +5376,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
                        K(min_wmark_pages(zone)),
                        K(low_wmark_pages(zone)),
                        K(high_wmark_pages(zone)),
+                       K(zone->nr_reserved_highatomic),
                        K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)),
                        K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)),
                        K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)),
@@ -6711,7 +6713,7 @@ static void __meminit pgdat_init_internals(struct pglist_data *pgdat)
 
        pgdat_page_ext_init(pgdat);
        spin_lock_init(&pgdat->lru_lock);
-       lruvec_init(node_lruvec(pgdat));
+       lruvec_init(&pgdat->__lruvec);
 }
 
 static void __meminit zone_init_internals(struct zone *zone, enum zone_type idx, int nid,
@@ -7988,6 +7990,15 @@ int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *table, int write,
        return 0;
 }
 
+static void __zone_pcp_update(struct zone *zone)
+{
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu)
+               pageset_set_high_and_batch(zone,
+                               per_cpu_ptr(zone->pageset, cpu));
+}
+
 /*
  * percpu_pagelist_fraction - changes the pcp->high for each zone on each
  * cpu.  It is the fraction of total pages in each zone that a hot per cpu
@@ -8019,13 +8030,8 @@ int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write,
        if (percpu_pagelist_fraction == old_percpu_pagelist_fraction)
                goto out;
 
-       for_each_populated_zone(zone) {
-               unsigned int cpu;
-
-               for_each_possible_cpu(cpu)
-                       pageset_set_high_and_batch(zone,
-                                       per_cpu_ptr(zone->pageset, cpu));
-       }
+       for_each_populated_zone(zone)
+               __zone_pcp_update(zone);
 out:
        mutex_unlock(&pcp_batch_high_lock);
        return ret;
@@ -8261,7 +8267,7 @@ bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
                 * The HWPoisoned page may be not in buddy system, and
                 * page_count() is not 0.
                 */
-               if ((flags & SKIP_HWPOISON) && PageHWPoison(page))
+               if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
                        continue;
 
                if (__PageMovable(page))
@@ -8477,7 +8483,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
        }
 
        /* Make sure the range is really isolated. */
-       if (test_pages_isolated(outer_start, end, false)) {
+       if (test_pages_isolated(outer_start, end, 0)) {
                pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
                        __func__, outer_start, end);
                ret = -EBUSY;
@@ -8502,6 +8508,107 @@ done:
                                pfn_max_align_up(end), migratetype);
        return ret;
 }
+
+static int __alloc_contig_pages(unsigned long start_pfn,
+                               unsigned long nr_pages, gfp_t gfp_mask)
+{
+       unsigned long end_pfn = start_pfn + nr_pages;
+
+       return alloc_contig_range(start_pfn, end_pfn, MIGRATE_MOVABLE,
+                                 gfp_mask);
+}
+
+static bool pfn_range_valid_contig(struct zone *z, unsigned long start_pfn,
+                                  unsigned long nr_pages)
+{
+       unsigned long i, end_pfn = start_pfn + nr_pages;
+       struct page *page;
+
+       for (i = start_pfn; i < end_pfn; i++) {
+               page = pfn_to_online_page(i);
+               if (!page)
+                       return false;
+
+               if (page_zone(page) != z)
+                       return false;
+
+               if (PageReserved(page))
+                       return false;
+
+               if (page_count(page) > 0)
+                       return false;
+
+               if (PageHuge(page))
+                       return false;
+       }
+       return true;
+}
+
+static bool zone_spans_last_pfn(const struct zone *zone,
+                               unsigned long start_pfn, unsigned long nr_pages)
+{
+       unsigned long last_pfn = start_pfn + nr_pages - 1;
+
+       return zone_spans_pfn(zone, last_pfn);
+}
+
+/**
+ * alloc_contig_pages() -- tries to find and allocate contiguous range of pages
+ * @nr_pages:  Number of contiguous pages to allocate
+ * @gfp_mask:  GFP mask to limit search and used during compaction
+ * @nid:       Target node
+ * @nodemask:  Mask for other possible nodes
+ *
+ * This routine is a wrapper around alloc_contig_range(). It scans over zones
+ * on an applicable zonelist to find a contiguous pfn range which can then be
+ * tried for allocation with alloc_contig_range(). This routine is intended
+ * for allocation requests which can not be fulfilled with the buddy allocator.
+ *
+ * The allocated memory is always aligned to a page boundary. If nr_pages is a
+ * power of two then the alignment is guaranteed to be to the given nr_pages
+ * (e.g. 1GB request would be aligned to 1GB).
+ *
+ * Allocated pages can be freed with free_contig_range() or by manually calling
+ * __free_page() on each allocated page.
+ *
+ * Return: pointer to contiguous pages on success, or NULL if not successful.
+ */
+struct page *alloc_contig_pages(unsigned long nr_pages, gfp_t gfp_mask,
+                               int nid, nodemask_t *nodemask)
+{
+       unsigned long ret, pfn, flags;
+       struct zonelist *zonelist;
+       struct zone *zone;
+       struct zoneref *z;
+
+       zonelist = node_zonelist(nid, gfp_mask);
+       for_each_zone_zonelist_nodemask(zone, z, zonelist,
+                                       gfp_zone(gfp_mask), nodemask) {
+               spin_lock_irqsave(&zone->lock, flags);
+
+               pfn = ALIGN(zone->zone_start_pfn, nr_pages);
+               while (zone_spans_last_pfn(zone, pfn, nr_pages)) {
+                       if (pfn_range_valid_contig(zone, pfn, nr_pages)) {
+                               /*
+                                * We release the zone lock here because
+                                * alloc_contig_range() will also lock the zone
+                                * at some point. If there's an allocation
+                                * spinning on this lock, it may win the race
+                                * and cause alloc_contig_range() to fail...
+                                */
+                               spin_unlock_irqrestore(&zone->lock, flags);
+                               ret = __alloc_contig_pages(pfn, nr_pages,
+                                                       gfp_mask);
+                               if (!ret)
+                                       return pfn_to_page(pfn);
+                               spin_lock_irqsave(&zone->lock, flags);
+                       }
+                       pfn += nr_pages;
+               }
+               spin_unlock_irqrestore(&zone->lock, flags);
+       }
+       return NULL;
+}
 #endif /* CONFIG_CONTIG_ALLOC */
 
 void free_contig_range(unsigned long pfn, unsigned int nr_pages)
@@ -8523,11 +8630,8 @@ void free_contig_range(unsigned long pfn, unsigned int nr_pages)
  */
 void __meminit zone_pcp_update(struct zone *zone)
 {
-       unsigned cpu;
        mutex_lock(&pcp_batch_high_lock);
-       for_each_possible_cpu(cpu)
-               pageset_set_high_and_batch(zone,
-                               per_cpu_ptr(zone->pageset, cpu));
+       __zone_pcp_update(zone);
        mutex_unlock(&pcp_batch_high_lock);
 }
 
@@ -8560,7 +8664,7 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
 {
        struct page *page;
        struct zone *zone;
-       unsigned int order, i;
+       unsigned int order;
        unsigned long pfn;
        unsigned long flags;
        unsigned long offlined_pages = 0;
@@ -8588,7 +8692,6 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                 */
                if (unlikely(!PageBuddy(page) && PageHWPoison(page))) {
                        pfn++;
-                       SetPageReserved(page);
                        offlined_pages++;
                        continue;
                }
@@ -8602,8 +8705,6 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                        pfn, 1 << order, end_pfn);
 #endif
                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);
index 60a66a5..3a198de 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/writeback.h>
 #include <linux/frontswap.h>
 #include <linux/blkdev.h>
+#include <linux/psi.h>
 #include <linux/uio.h>
 #include <linux/sched/task.h>
 #include <asm/pgtable.h>
@@ -354,10 +355,19 @@ int swap_readpage(struct page *page, bool synchronous)
        struct swap_info_struct *sis = page_swap_info(page);
        blk_qc_t qc;
        struct gendisk *disk;
+       unsigned long pflags;
 
        VM_BUG_ON_PAGE(!PageSwapCache(page) && !synchronous, page);
        VM_BUG_ON_PAGE(!PageLocked(page), page);
        VM_BUG_ON_PAGE(PageUptodate(page), page);
+
+       /*
+        * Count submission time as memory stall. When the device is congested,
+        * or the submitting cgroup IO-throttled, submission can be a
+        * significant part of overall IO time.
+        */
+       psi_memstall_enter(&pflags);
+
        if (frontswap_load(page) == 0) {
                SetPageUptodate(page);
                unlock_page(page);
@@ -371,7 +381,7 @@ int swap_readpage(struct page *page, bool synchronous)
                ret = mapping->a_ops->readpage(swap_file, page);
                if (!ret)
                        count_vm_event(PSWPIN);
-               return ret;
+               goto out;
        }
 
        ret = bdev_read_page(sis->bdev, swap_page_sector(page), page);
@@ -382,7 +392,7 @@ int swap_readpage(struct page *page, bool synchronous)
                }
 
                count_vm_event(PSWPIN);
-               return 0;
+               goto out;
        }
 
        ret = 0;
@@ -418,6 +428,7 @@ int swap_readpage(struct page *page, bool synchronous)
        bio_put(bio);
 
 out:
+       psi_memstall_leave(&pflags);
        return ret;
 }
 
index 89c19c0..04ee166 100644 (file)
@@ -168,7 +168,8 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  * @migratetype:       Migrate type to set in error recovery.
  * @flags:             The following flags are allowed (they can be combined in
  *                     a bit mask)
- *                     SKIP_HWPOISON - ignore hwpoison pages
+ *                     MEMORY_OFFLINE - isolate to offline (!allocate) memory
+ *                                      e.g., skip over PageHWPoison() pages
  *                     REPORT_FAILURE - report details about the failure to
  *                     isolate the range
  *
@@ -257,7 +258,7 @@ void undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
  */
 static unsigned long
 __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
-                                 bool skip_hwpoisoned_pages)
+                                 int flags)
 {
        struct page *page;
 
@@ -274,7 +275,7 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
                         * simple way to verify that as VM_BUG_ON(), though.
                         */
                        pfn += 1 << page_order(page);
-               else if (skip_hwpoisoned_pages && PageHWPoison(page))
+               else if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
                        /* A HWPoisoned page cannot be also PageBuddy */
                        pfn++;
                else
@@ -286,7 +287,7 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
 
 /* Caller should ensure that requested range is in a single zone */
 int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
-                       bool skip_hwpoisoned_pages)
+                       int isol_flags)
 {
        unsigned long pfn, flags;
        struct page *page;
@@ -308,8 +309,7 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
        /* Check all pages are free or marked as ISOLATED */
        zone = page_zone(page);
        spin_lock_irqsave(&zone->lock, flags);
-       pfn = __test_page_isolated_in_pageblock(start_pfn, end_pfn,
-                                               skip_hwpoisoned_pages);
+       pfn = __test_page_isolated_in_pageblock(start_pfn, end_pfn, isol_flags);
        spin_unlock_irqrestore(&zone->lock, flags);
 
        trace_test_pages_isolated(start_pfn, end_pfn, pfn);
index 532c292..3d7c01e 100644 (file)
@@ -24,18 +24,27 @@ void pgd_clear_bad(pgd_t *pgd)
        pgd_clear(pgd);
 }
 
+#ifndef __PAGETABLE_P4D_FOLDED
 void p4d_clear_bad(p4d_t *p4d)
 {
        p4d_ERROR(*p4d);
        p4d_clear(p4d);
 }
+#endif
 
+#ifndef __PAGETABLE_PUD_FOLDED
 void pud_clear_bad(pud_t *pud)
 {
        pud_ERROR(*pud);
        pud_clear(pud);
 }
+#endif
 
+/*
+ * Note that the pmd variant below can't be stub'ed out just as for p4d/pud
+ * above. pmd folding is special and typically pmd_* macros refer to upper
+ * level even when folded
+ */
 void pmd_clear_bad(pmd_t *pmd)
 {
        pmd_ERROR(*pmd);
index 0c7b2a9..b3e3819 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -251,18 +251,37 @@ static inline void unlock_anon_vma_root(struct anon_vma *root)
  * Attach the anon_vmas from src to dst.
  * Returns 0 on success, -ENOMEM on failure.
  *
- * If dst->anon_vma is NULL this function tries to find and reuse existing
- * anon_vma which has no vmas and only one child anon_vma. This prevents
- * degradation of anon_vma hierarchy to endless linear chain in case of
- * constantly forking task. On the other hand, an anon_vma with more than one
- * child isn't reused even if there was no alive vma, thus rmap walker has a
- * good chance of avoiding scanning the whole hierarchy when it searches where
- * page is mapped.
+ * anon_vma_clone() is called by __vma_split(), __split_vma(), copy_vma() and
+ * anon_vma_fork(). The first three want an exact copy of src, while the last
+ * one, anon_vma_fork(), may try to reuse an existing anon_vma to prevent
+ * endless growth of anon_vma. Since dst->anon_vma is set to NULL before call,
+ * we can identify this case by checking (!dst->anon_vma && src->anon_vma).
+ *
+ * If (!dst->anon_vma && src->anon_vma) is true, this function tries to find
+ * and reuse existing anon_vma which has no vmas and only one child anon_vma.
+ * This prevents degradation of anon_vma hierarchy to endless linear chain in
+ * case of constantly forking task. On the other hand, an anon_vma with more
+ * than one child isn't reused even if there was no alive vma, thus rmap
+ * walker has a good chance of avoiding scanning the whole hierarchy when it
+ * searches where page is mapped.
  */
 int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
 {
        struct anon_vma_chain *avc, *pavc;
        struct anon_vma *root = NULL;
+       struct vm_area_struct *prev = dst->vm_prev, *pprev = src->vm_prev;
+
+       /*
+        * If parent share anon_vma with its vm_prev, keep this sharing in in
+        * child.
+        *
+        * 1. Parent has vm_prev, which implies we have vm_prev.
+        * 2. Parent and its vm_prev have the same anon_vma.
+        */
+       if (!dst->anon_vma && src->anon_vma &&
+           pprev && pprev->anon_vma == src->anon_vma)
+               dst->anon_vma = prev->anon_vma;
+
 
        list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) {
                struct anon_vma *anon_vma;
@@ -287,8 +306,8 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
                 * will always reuse it. Root anon_vma is never reused:
                 * it has self-parent reference and at least one child.
                 */
-               if (!dst->anon_vma && anon_vma != src->anon_vma &&
-                               anon_vma->degree < 2)
+               if (!dst->anon_vma && src->anon_vma &&
+                   anon_vma != src->anon_vma && anon_vma->degree < 2)
                        dst->anon_vma = anon_vma;
        }
        if (dst->anon_vma)
@@ -458,9 +477,10 @@ void __init anon_vma_init(void)
  * chain and verify that the page in question is indeed mapped in it
  * [ something equivalent to page_mapped_in_vma() ].
  *
- * Since anon_vma's slab is DESTROY_BY_RCU and we know from page_remove_rmap()
- * that the anon_vma pointer from page->mapping is valid if there is a
- * mapcount, we can dereference the anon_vma after observing those.
+ * Since anon_vma's slab is SLAB_TYPESAFE_BY_RCU and we know from
+ * page_remove_rmap() that the anon_vma pointer from page->mapping is valid
+ * if there is a mapcount, we can dereference the anon_vma after observing
+ * those.
  */
 struct anon_vma *page_get_anon_vma(struct page *page)
 {
@@ -1055,7 +1075,6 @@ static void __page_set_anon_rmap(struct page *page,
 static void __page_check_anon_rmap(struct page *page,
        struct vm_area_struct *vma, unsigned long address)
 {
-#ifdef CONFIG_DEBUG_VM
        /*
         * The page's anon-rmap details (mapping and index) are guaranteed to
         * be set up correctly at this point.
@@ -1068,9 +1087,9 @@ static void __page_check_anon_rmap(struct page *page,
         * are initially only visible via the pagetables, and the pte is locked
         * over the call to page_add_new_anon_rmap.
         */
-       BUG_ON(page_anon_vma(page)->root != vma->anon_vma->root);
-       BUG_ON(page_to_pgoff(page) != linear_page_index(vma, address));
-#endif
+       VM_BUG_ON_PAGE(page_anon_vma(page)->root != vma->anon_vma->root, page);
+       VM_BUG_ON_PAGE(page_to_pgoff(page) != linear_page_index(vma, address),
+                      page);
 }
 
 /**
@@ -1273,12 +1292,20 @@ static void page_remove_anon_compound_rmap(struct page *page)
        if (TestClearPageDoubleMap(page)) {
                /*
                 * Subpages can be mapped with PTEs too. Check how many of
-                * themi are still mapped.
+                * them are still mapped.
                 */
                for (i = 0, nr = 0; i < HPAGE_PMD_NR; i++) {
                        if (atomic_add_negative(-1, &page[i]._mapcount))
                                nr++;
                }
+
+               /*
+                * Queue the page for deferred split if at least one small
+                * page of the compound page is unmapped, but at least one
+                * small page is still mapped.
+                */
+               if (nr && nr < HPAGE_PMD_NR)
+                       deferred_split_huge_page(page);
        } else {
                nr = HPAGE_PMD_NR;
        }
@@ -1286,10 +1313,8 @@ static void page_remove_anon_compound_rmap(struct page *page)
        if (unlikely(PageMlocked(page)))
                clear_page_mlock(page);
 
-       if (nr) {
+       if (nr)
                __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, -nr);
-               deferred_split_huge_page(page);
-       }
 }
 
 /**
index 220be9f..165fa63 100644 (file)
@@ -1369,7 +1369,8 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
        if (list_empty(&info->swaplist))
                list_add(&info->swaplist, &shmem_swaplist);
 
-       if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
+       if (add_to_swap_cache(page, swap,
+                       __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN) == 0) {
                spin_lock_irq(&info->lock);
                shmem_recalc_inode(inode);
                info->swapped++;
@@ -2022,16 +2023,14 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
                    shmem_falloc->waitq &&
                    vmf->pgoff >= shmem_falloc->start &&
                    vmf->pgoff < shmem_falloc->next) {
+                       struct file *fpin;
                        wait_queue_head_t *shmem_falloc_waitq;
                        DEFINE_WAIT_FUNC(shmem_fault_wait, synchronous_wake_function);
 
                        ret = VM_FAULT_NOPAGE;
-                       if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) &&
-                          !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
-                               /* It's polite to up mmap_sem if we can */
-                               up_read(&vma->vm_mm->mmap_sem);
+                       fpin = maybe_unlock_mmap_for_io(vmf, NULL);
+                       if (fpin)
                                ret = VM_FAULT_RETRY;
-                       }
 
                        shmem_falloc_waitq = shmem_falloc->waitq;
                        prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait,
@@ -2049,6 +2048,9 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
                        spin_lock(&inode->i_lock);
                        finish_wait(shmem_falloc_waitq, &shmem_fault_wait);
                        spin_unlock(&inode->i_lock);
+
+                       if (fpin)
+                               fput(fpin);
                        return ret;
                }
                spin_unlock(&inode->i_lock);
@@ -2213,11 +2215,14 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
                        return -EPERM;
 
                /*
-                * Since the F_SEAL_FUTURE_WRITE seals allow for a MAP_SHARED
-                * read-only mapping, take care to not allow mprotect to revert
-                * protections.
+                * Since an F_SEAL_FUTURE_WRITE sealed memfd can be mapped as
+                * MAP_SHARED and read-only, take care to not allow mprotect to
+                * revert protections on such mappings. Do this only for shared
+                * mappings. For private mappings, don't need to mask
+                * VM_MAYWRITE as we still want them to be COW-writable.
                 */
-               vma->vm_flags &= ~(VM_MAYWRITE);
+               if (vma->vm_flags & VM_SHARED)
+                       vma->vm_flags &= ~(VM_MAYWRITE);
        }
 
        file_accessed(file);
@@ -2742,7 +2747,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
                }
 
                shmem_falloc.waitq = &shmem_falloc_waitq;
-               shmem_falloc.start = unmap_start >> PAGE_SHIFT;
+               shmem_falloc.start = (u64)unmap_start >> PAGE_SHIFT;
                shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
                spin_lock(&inode->i_lock);
                inode->i_private = &shmem_falloc;
@@ -3928,7 +3933,7 @@ out2:
 static ssize_t shmem_enabled_show(struct kobject *kobj,
                struct kobj_attribute *attr, char *buf)
 {
-       int values[] = {
+       static const int values[] = {
                SHMEM_HUGE_ALWAYS,
                SHMEM_HUGE_WITHIN_SIZE,
                SHMEM_HUGE_ADVISE,
index 66e5d80..f1e1840 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1247,9 +1247,10 @@ void __init kmem_cache_init(void)
         * structures first.  Without this, further allocations will bug.
         */
        kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE] = create_kmalloc_cache(
-                               kmalloc_info[INDEX_NODE].name,
-                               kmalloc_size(INDEX_NODE), ARCH_KMALLOC_FLAGS,
-                               0, kmalloc_size(INDEX_NODE));
+                               kmalloc_info[INDEX_NODE].name[KMALLOC_NORMAL],
+                               kmalloc_info[INDEX_NODE].size,
+                               ARCH_KMALLOC_FLAGS, 0,
+                               kmalloc_info[INDEX_NODE].size);
        slab_state = PARTIAL_NODE;
        setup_kmalloc_cache_index_table();
 
index b2b0169..7e94700 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -139,7 +139,7 @@ extern struct kmem_cache *kmem_cache;
 
 /* A table of kmalloc cache names and sizes */
 extern const struct kmalloc_info_struct {
-       const char *name;
+       const char *name[NR_KMALLOC_TYPES];
        unsigned int size;
 } kmalloc_info[];
 
@@ -369,7 +369,7 @@ static __always_inline int memcg_charge_slab(struct page *page,
        if (ret)
                goto out;
 
-       lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
+       lruvec = mem_cgroup_lruvec(memcg, page_pgdat(page));
        mod_lruvec_state(lruvec, cache_vmstat_idx(s), 1 << order);
 
        /* transer try_charge() page references to kmem_cache */
@@ -393,7 +393,7 @@ static __always_inline void memcg_uncharge_slab(struct page *page, int order,
        rcu_read_lock();
        memcg = READ_ONCE(s->memcg_params.memcg);
        if (likely(!mem_cgroup_is_root(memcg))) {
-               lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
+               lruvec = mem_cgroup_lruvec(memcg, page_pgdat(page));
                mod_lruvec_state(lruvec, cache_vmstat_idx(s), -(1 << order));
                memcg_kmem_uncharge_memcg(page, order, memcg);
        } else {
index f9fb27b..f0ab6d4 100644 (file)
@@ -904,6 +904,18 @@ static void flush_memcg_workqueue(struct kmem_cache *s)
         * previous workitems on workqueue are processed.
         */
        flush_workqueue(memcg_kmem_cache_wq);
+
+       /*
+        * If we're racing with children kmem_cache deactivation, it might
+        * take another rcu grace period to complete their destruction.
+        * At this moment the corresponding percpu_ref_kill() call should be
+        * done, but it might take another rcu grace period to complete
+        * switching to the atomic mode.
+        * Please, note that we check without grabbing the slab_mutex. It's safe
+        * because at this moment the children list can't grow.
+        */
+       if (!list_empty(&s->memcg_params.children))
+               rcu_barrier();
 }
 #else
 static inline int shutdown_memcg_caches(struct kmem_cache *s)
@@ -1139,26 +1151,56 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
        return kmalloc_caches[kmalloc_type(flags)][index];
 }
 
+#ifdef CONFIG_ZONE_DMA
+#define INIT_KMALLOC_INFO(__size, __short_size)                        \
+{                                                              \
+       .name[KMALLOC_NORMAL]  = "kmalloc-" #__short_size,      \
+       .name[KMALLOC_RECLAIM] = "kmalloc-rcl-" #__short_size,  \
+       .name[KMALLOC_DMA]     = "dma-kmalloc-" #__short_size,  \
+       .size = __size,                                         \
+}
+#else
+#define INIT_KMALLOC_INFO(__size, __short_size)                        \
+{                                                              \
+       .name[KMALLOC_NORMAL]  = "kmalloc-" #__short_size,      \
+       .name[KMALLOC_RECLAIM] = "kmalloc-rcl-" #__short_size,  \
+       .size = __size,                                         \
+}
+#endif
+
 /*
  * kmalloc_info[] is to make slub_debug=,kmalloc-xx option work at boot time.
  * kmalloc_index() supports up to 2^26=64MB, so the final entry of the table is
  * kmalloc-67108864.
  */
 const struct kmalloc_info_struct kmalloc_info[] __initconst = {
-       {NULL,                      0},         {"kmalloc-96",             96},
-       {"kmalloc-192",           192},         {"kmalloc-8",               8},
-       {"kmalloc-16",             16},         {"kmalloc-32",             32},
-       {"kmalloc-64",             64},         {"kmalloc-128",           128},
-       {"kmalloc-256",           256},         {"kmalloc-512",           512},
-       {"kmalloc-1k",           1024},         {"kmalloc-2k",           2048},
-       {"kmalloc-4k",           4096},         {"kmalloc-8k",           8192},
-       {"kmalloc-16k",         16384},         {"kmalloc-32k",         32768},
-       {"kmalloc-64k",         65536},         {"kmalloc-128k",       131072},
-       {"kmalloc-256k",       262144},         {"kmalloc-512k",       524288},
-       {"kmalloc-1M",        1048576},         {"kmalloc-2M",        2097152},
-       {"kmalloc-4M",        4194304},         {"kmalloc-8M",        8388608},
-       {"kmalloc-16M",      16777216},         {"kmalloc-32M",      33554432},
-       {"kmalloc-64M",      67108864}
+       INIT_KMALLOC_INFO(0, 0),
+       INIT_KMALLOC_INFO(96, 96),
+       INIT_KMALLOC_INFO(192, 192),
+       INIT_KMALLOC_INFO(8, 8),
+       INIT_KMALLOC_INFO(16, 16),
+       INIT_KMALLOC_INFO(32, 32),
+       INIT_KMALLOC_INFO(64, 64),
+       INIT_KMALLOC_INFO(128, 128),
+       INIT_KMALLOC_INFO(256, 256),
+       INIT_KMALLOC_INFO(512, 512),
+       INIT_KMALLOC_INFO(1024, 1k),
+       INIT_KMALLOC_INFO(2048, 2k),
+       INIT_KMALLOC_INFO(4096, 4k),
+       INIT_KMALLOC_INFO(8192, 8k),
+       INIT_KMALLOC_INFO(16384, 16k),
+       INIT_KMALLOC_INFO(32768, 32k),
+       INIT_KMALLOC_INFO(65536, 64k),
+       INIT_KMALLOC_INFO(131072, 128k),
+       INIT_KMALLOC_INFO(262144, 256k),
+       INIT_KMALLOC_INFO(524288, 512k),
+       INIT_KMALLOC_INFO(1048576, 1M),
+       INIT_KMALLOC_INFO(2097152, 2M),
+       INIT_KMALLOC_INFO(4194304, 4M),
+       INIT_KMALLOC_INFO(8388608, 8M),
+       INIT_KMALLOC_INFO(16777216, 16M),
+       INIT_KMALLOC_INFO(33554432, 32M),
+       INIT_KMALLOC_INFO(67108864, 64M)
 };
 
 /*
@@ -1208,36 +1250,14 @@ void __init setup_kmalloc_cache_index_table(void)
        }
 }
 
-static const char *
-kmalloc_cache_name(const char *prefix, unsigned int size)
-{
-
-       static const char units[3] = "\0kM";
-       int idx = 0;
-
-       while (size >= 1024 && (size % 1024 == 0)) {
-               size /= 1024;
-               idx++;
-       }
-
-       return kasprintf(GFP_NOWAIT, "%s-%u%c", prefix, size, units[idx]);
-}
-
 static void __init
-new_kmalloc_cache(int idx, int type, slab_flags_t flags)
+new_kmalloc_cache(int idx, enum kmalloc_cache_type type, slab_flags_t flags)
 {
-       const char *name;
-
-       if (type == KMALLOC_RECLAIM) {
+       if (type == KMALLOC_RECLAIM)
                flags |= SLAB_RECLAIM_ACCOUNT;
-               name = kmalloc_cache_name("kmalloc-rcl",
-                                               kmalloc_info[idx].size);
-               BUG_ON(!name);
-       } else {
-               name = kmalloc_info[idx].name;
-       }
 
-       kmalloc_caches[type][idx] = create_kmalloc_cache(name,
+       kmalloc_caches[type][idx] = create_kmalloc_cache(
+                                       kmalloc_info[idx].name[type],
                                        kmalloc_info[idx].size, flags, 0,
                                        kmalloc_info[idx].size);
 }
@@ -1249,7 +1269,8 @@ new_kmalloc_cache(int idx, int type, slab_flags_t flags)
  */
 void __init create_kmalloc_caches(slab_flags_t flags)
 {
-       int i, type;
+       int i;
+       enum kmalloc_cache_type type;
 
        for (type = KMALLOC_NORMAL; type <= KMALLOC_RECLAIM; type++) {
                for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) {
@@ -1278,12 +1299,10 @@ void __init create_kmalloc_caches(slab_flags_t flags)
                struct kmem_cache *s = kmalloc_caches[KMALLOC_NORMAL][i];
 
                if (s) {
-                       unsigned int size = kmalloc_size(i);
-                       const char *n = kmalloc_cache_name("dma-kmalloc", size);
-
-                       BUG_ON(!n);
                        kmalloc_caches[KMALLOC_DMA][i] = create_kmalloc_cache(
-                               n, size, SLAB_CACHE_DMA | flags, 0, 0);
+                               kmalloc_info[i].name[KMALLOC_DMA],
+                               kmalloc_info[i].size,
+                               SLAB_CACHE_DMA | flags, 0, 0);
                }
        }
 #endif
index e72e802..d113897 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -93,9 +93,7 @@
  * minimal so we rely on the page allocators per cpu caches for
  * fast frees and allocs.
  *
- * Overloading of page flags that are otherwise used for LRU management.
- *
- * PageActive          The slab is frozen and exempt from list processing.
+ * page->frozen                The slab is frozen and exempt from list processing.
  *                     This means that the slab is dedicated to a purpose
  *                     such as satisfying allocations for a specific
  *                     processor. Objects may be freed in the slab while
  *                     free objects in addition to the regular freelist
  *                     that requires the slab lock.
  *
- * PageError           Slab requires special handling due to debug
+ * SLAB_DEBUG_FLAGS    Slab requires special handling due to debug
  *                     options set. This moves slab handling out of
  *                     the fast path and disables lockless freelists.
  */
@@ -736,6 +734,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
 {
        u8 *fault;
        u8 *end;
+       u8 *addr = page_address(page);
 
        metadata_access_enable();
        fault = memchr_inv(start, value, bytes);
@@ -748,8 +747,9 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
                end--;
 
        slab_bug(s, "%s overwritten", what);
-       pr_err("INFO: 0x%p-0x%p. First byte 0x%x instead of 0x%x\n",
-                                       fault, end - 1, fault[0], value);
+       pr_err("INFO: 0x%p-0x%p @offset=%tu. First byte 0x%x instead of 0x%x\n",
+                                       fault, end - 1, fault - addr,
+                                       fault[0], value);
        print_trailer(s, page, object);
 
        restore_bytes(s, what, value, fault, end);
@@ -844,7 +844,8 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
        while (end > fault && end[-1] == POISON_INUSE)
                end--;
 
-       slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1);
+       slab_err(s, page, "Padding overwritten. 0x%p-0x%p @offset=%tu",
+                       fault, end - 1, fault - start);
        print_section(KERN_ERR, "Padding ", pad, remainder);
 
        restore_bytes(s, "slab padding", POISON_INUSE, fault, end);
@@ -4383,31 +4384,26 @@ static int count_total(struct page *page)
 #endif
 
 #ifdef CONFIG_SLUB_DEBUG
-static int validate_slab(struct kmem_cache *s, struct page *page,
+static void validate_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
 {
        void *p;
        void *addr = page_address(page);
 
-       if (!check_slab(s, page) ||
-                       !on_freelist(s, page, NULL))
-               return 0;
+       if (!check_slab(s, page) || !on_freelist(s, page, NULL))
+               return;
 
        /* Now we know that a valid freelist exists */
        bitmap_zero(map, page->objects);
 
        get_map(s, page, map);
        for_each_object(p, s, addr, page->objects) {
-               if (test_bit(slab_index(p, s, addr), map))
-                       if (!check_object(s, page, p, SLUB_RED_INACTIVE))
-                               return 0;
-       }
+               u8 val = test_bit(slab_index(p, s, addr), map) ?
+                        SLUB_RED_INACTIVE : SLUB_RED_ACTIVE;
 
-       for_each_object(p, s, addr, page->objects)
-               if (!test_bit(slab_index(p, s, addr), map))
-                       if (!check_object(s, page, p, SLUB_RED_ACTIVE))
-                               return 0;
-       return 1;
+               if (!check_object(s, page, p, val))
+                       break;
+       }
 }
 
 static void validate_slab_slab(struct kmem_cache *s, struct page *page,
index f6891c1..b20ab7c 100644 (file)
@@ -458,8 +458,7 @@ struct page __init *__populate_section_memmap(unsigned long pfn,
        if (map)
                return map;
 
-       map = memblock_alloc_try_nid(size,
-                                         PAGE_SIZE, addr,
+       map = memblock_alloc_try_nid_raw(size, size, addr,
                                          MEMBLOCK_ALLOC_ACCESSIBLE, nid);
        if (!map)
                panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d from=%pa\n",
@@ -482,10 +481,13 @@ static void __init sparse_buffer_init(unsigned long size, int nid)
 {
        phys_addr_t addr = __pa(MAX_DMA_ADDRESS);
        WARN_ON(sparsemap_buf); /* forgot to call sparse_buffer_fini()? */
-       sparsemap_buf =
-               memblock_alloc_try_nid_raw(size, PAGE_SIZE,
-                                               addr,
-                                               MEMBLOCK_ALLOC_ACCESSIBLE, nid);
+       /*
+        * Pre-allocated buffer is mainly used by __populate_section_memmap
+        * and we want it to be properly aligned to the section size - this is
+        * especially the case for VMEMMAP which maps memmap to PMDs
+        */
+       sparsemap_buf = memblock_alloc_exact_nid_raw(size, section_map_size(),
+                                       addr, MEMBLOCK_ALLOC_ACCESSIBLE, nid);
        sparsemap_buf_end = sparsemap_buf + size;
 }
 
@@ -647,7 +649,7 @@ void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
 #endif
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-static struct page *populate_section_memmap(unsigned long pfn,
+static struct page * __meminit populate_section_memmap(unsigned long pfn,
                unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
        return __populate_section_memmap(pfn, nr_pages, nid, altmap);
@@ -669,7 +671,7 @@ static void free_map_bootmem(struct page *memmap)
        vmemmap_free(start, end, NULL);
 }
 #else
-struct page *populate_section_memmap(unsigned long pfn,
+struct page * __meminit populate_section_memmap(unsigned long pfn,
                unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
        struct page *page, *ret;
index 38c3fa4..5341ae9 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -373,9 +373,16 @@ static void __lru_cache_activate_page(struct page *page)
 void mark_page_accessed(struct page *page)
 {
        page = compound_head(page);
-       if (!PageActive(page) && !PageUnevictable(page) &&
-                       PageReferenced(page)) {
 
+       if (!PageReferenced(page)) {
+               SetPageReferenced(page);
+       } else if (PageUnevictable(page)) {
+               /*
+                * Unevictable pages are on the "LRU_UNEVICTABLE" list. But,
+                * this list is never rotated or maintained, so marking an
+                * evictable page accessed has no effect.
+                */
+       } else if (!PageActive(page)) {
                /*
                 * If the page is on the LRU, queue it for activation via
                 * activate_page_pvecs. Otherwise, assume the page is on a
@@ -389,8 +396,6 @@ void mark_page_accessed(struct page *page)
                ClearPageReferenced(page);
                if (page_is_file_cache(page))
                        workingset_activation(page);
-       } else if (!PageReferenced(page)) {
-               SetPageReferenced(page);
        }
        if (page_is_idle(page))
                clear_page_idle(page);
@@ -708,9 +713,10 @@ static void lru_add_drain_per_cpu(struct work_struct *dummy)
  */
 void lru_add_drain_all(void)
 {
+       static seqcount_t seqcount = SEQCNT_ZERO(seqcount);
        static DEFINE_MUTEX(lock);
        static struct cpumask has_work;
-       int cpu;
+       int cpu, seq;
 
        /*
         * Make sure nobody triggers this path before mm_percpu_wq is fully
@@ -719,7 +725,19 @@ void lru_add_drain_all(void)
        if (WARN_ON(!mm_percpu_wq))
                return;
 
+       seq = raw_read_seqcount_latch(&seqcount);
+
        mutex_lock(&lock);
+
+       /*
+        * Piggyback on drain started and finished while we waited for lock:
+        * all pages pended at the time of our enter were drained from vectors.
+        */
+       if (__read_seqcount_retry(&seqcount, seq))
+               goto done;
+
+       raw_write_seqcount_latch(&seqcount);
+
        cpumask_clear(&has_work);
 
        for_each_online_cpu(cpu) {
@@ -740,6 +758,7 @@ void lru_add_drain_all(void)
        for_each_cpu(cpu, &has_work)
                flush_work(&per_cpu(lru_add_drain_work, cpu));
 
+done:
        mutex_unlock(&lock);
 }
 #else
index dab4352..bb3261d 100644 (file)
@@ -2887,6 +2887,13 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
                error = set_blocksize(p->bdev, PAGE_SIZE);
                if (error < 0)
                        return error;
+               /*
+                * Zoned block devices contain zones that have a sequential
+                * write only restriction.  Hence zoned block devices are not
+                * suitable for swapping.  Disallow them here.
+                */
+               if (blk_queue_is_zoned(p->bdev->bd_queue))
+                       return -EINVAL;
                p->flags |= SWP_BLKDEV;
        } else if (S_ISREG(inode->i_mode)) {
                p->bdev = inode->i_sb->s_bdev;
index c7ae74c..1b0d7ab 100644 (file)
 #include <asm/tlbflush.h>
 #include "internal.h"
 
+static __always_inline
+struct vm_area_struct *find_dst_vma(struct mm_struct *dst_mm,
+                                   unsigned long dst_start,
+                                   unsigned long len)
+{
+       /*
+        * Make sure that the dst range is both valid and fully within a
+        * single existing vma.
+        */
+       struct vm_area_struct *dst_vma;
+
+       dst_vma = find_vma(dst_mm, dst_start);
+       if (!dst_vma)
+               return NULL;
+
+       if (dst_start < dst_vma->vm_start ||
+           dst_start + len > dst_vma->vm_end)
+               return NULL;
+
+       /*
+        * Check the vma is registered in uffd, this is required to
+        * enforce the VM_MAYWRITE check done at uffd registration
+        * time.
+        */
+       if (!dst_vma->vm_userfaultfd_ctx.ctx)
+               return NULL;
+
+       return dst_vma;
+}
+
 static int mcopy_atomic_pte(struct mm_struct *dst_mm,
                            pmd_t *dst_pmd,
                            struct vm_area_struct *dst_vma,
@@ -60,7 +90,7 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm,
 
        /*
         * The memory barrier inside __SetPageUptodate makes sure that
-        * preceeding stores to the page contents become visible before
+        * preceding stores to the page contents become visible before
         * the set_pte_at() write.
         */
        __SetPageUptodate(page);
@@ -184,7 +214,6 @@ static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
        unsigned long src_addr, dst_addr;
        long copied;
        struct page *page;
-       struct hstate *h;
        unsigned long vma_hpagesize;
        pgoff_t idx;
        u32 hash;
@@ -221,20 +250,9 @@ retry:
         */
        if (!dst_vma) {
                err = -ENOENT;
-               dst_vma = find_vma(dst_mm, dst_start);
+               dst_vma = find_dst_vma(dst_mm, dst_start, len);
                if (!dst_vma || !is_vm_hugetlb_page(dst_vma))
                        goto out_unlock;
-               /*
-                * Check the vma is registered in uffd, this is
-                * required to enforce the VM_MAYWRITE check done at
-                * uffd registration time.
-                */
-               if (!dst_vma->vm_userfaultfd_ctx.ctx)
-                       goto out_unlock;
-
-               if (dst_start < dst_vma->vm_start ||
-                   dst_start + len > dst_vma->vm_end)
-                       goto out_unlock;
 
                err = -EINVAL;
                if (vma_hpagesize != vma_kernel_pagesize(dst_vma))
@@ -243,10 +261,6 @@ retry:
                vm_shared = dst_vma->vm_flags & VM_SHARED;
        }
 
-       if (WARN_ON(dst_addr & (vma_hpagesize - 1) ||
-                   (len - copied) & (vma_hpagesize - 1)))
-               goto out_unlock;
-
        /*
         * If not shared, ensure the dst_vma has a anon_vma.
         */
@@ -256,24 +270,21 @@ retry:
                        goto out_unlock;
        }
 
-       h = hstate_vma(dst_vma);
-
        while (src_addr < src_start + len) {
                pte_t dst_pteval;
 
                BUG_ON(dst_addr >= dst_start + len);
-               VM_BUG_ON(dst_addr & ~huge_page_mask(h));
 
                /*
                 * Serialize via hugetlb_fault_mutex
                 */
                idx = linear_page_index(dst_vma, dst_addr);
                mapping = dst_vma->vm_file->f_mapping;
-               hash = hugetlb_fault_mutex_hash(h, mapping, idx, dst_addr);
+               hash = hugetlb_fault_mutex_hash(mapping, idx);
                mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                err = -ENOMEM;
-               dst_pte = huge_pte_alloc(dst_mm, dst_addr, huge_page_size(h));
+               dst_pte = huge_pte_alloc(dst_mm, dst_addr, vma_hpagesize);
                if (!dst_pte) {
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
                        goto out_unlock;
@@ -300,7 +311,8 @@ retry:
 
                        err = copy_huge_page_from_user(page,
                                                (const void __user *)src_addr,
-                                               pages_per_huge_page(h), true);
+                                               vma_hpagesize / PAGE_SIZE,
+                                               true);
                        if (unlikely(err)) {
                                err = -EFAULT;
                                goto out;
@@ -475,20 +487,9 @@ retry:
         * both valid and fully within a single existing vma.
         */
        err = -ENOENT;
-       dst_vma = find_vma(dst_mm, dst_start);
+       dst_vma = find_dst_vma(dst_mm, dst_start, len);
        if (!dst_vma)
                goto out_unlock;
-       /*
-        * Check the vma is registered in uffd, this is required to
-        * enforce the VM_MAYWRITE check done at uffd registration
-        * time.
-        */
-       if (!dst_vma->vm_userfaultfd_ctx.ctx)
-               goto out_unlock;
-
-       if (dst_start < dst_vma->vm_start ||
-           dst_start + len > dst_vma->vm_end)
-               goto out_unlock;
 
        err = -EINVAL;
        /*
index 3ad6db9..988d11e 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -271,7 +271,7 @@ void *memdup_user_nul(const void __user *src, size_t len)
 EXPORT_SYMBOL(memdup_user_nul);
 
 void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
-               struct vm_area_struct *prev, struct rb_node *rb_parent)
+               struct vm_area_struct *prev)
 {
        struct vm_area_struct *next;
 
@@ -280,18 +280,28 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
                next = prev->vm_next;
                prev->vm_next = vma;
        } else {
+               next = mm->mmap;
                mm->mmap = vma;
-               if (rb_parent)
-                       next = rb_entry(rb_parent,
-                                       struct vm_area_struct, vm_rb);
-               else
-                       next = NULL;
        }
        vma->vm_next = next;
        if (next)
                next->vm_prev = vma;
 }
 
+void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma)
+{
+       struct vm_area_struct *prev, *next;
+
+       next = vma->vm_next;
+       prev = vma->vm_prev;
+       if (prev)
+               prev->vm_next = next;
+       else
+               mm->mmap = next;
+       if (next)
+               next->vm_prev = prev;
+}
+
 /* Check if the vma is being used as a stack by this task */
 int vma_is_stack_for_current(struct vm_area_struct *vma)
 {
index 4a7d745..4d3b3d6 100644 (file)
@@ -331,6 +331,7 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
 
 
 static DEFINE_SPINLOCK(vmap_area_lock);
+static DEFINE_SPINLOCK(free_vmap_area_lock);
 /* Export for kexec only */
 LIST_HEAD(vmap_area_list);
 static LLIST_HEAD(vmap_purge_list);
@@ -682,7 +683,7 @@ insert_vmap_area_augment(struct vmap_area *va,
  * free area is inserted. If VA has been merged, it is
  * freed.
  */
-static __always_inline void
+static __always_inline struct vmap_area *
 merge_or_add_vmap_area(struct vmap_area *va,
        struct rb_root *root, struct list_head *head)
 {
@@ -749,7 +750,10 @@ merge_or_add_vmap_area(struct vmap_area *va,
 
                        /* Free vmap_area object. */
                        kmem_cache_free(vmap_area_cachep, va);
-                       return;
+
+                       /* Point to the new merged area. */
+                       va = sibling;
+                       merged = true;
                }
        }
 
@@ -758,6 +762,8 @@ insert:
                link_va(va, root, parent, link, head);
                augment_tree_propagate_from(va);
        }
+
+       return va;
 }
 
 static __always_inline bool
@@ -968,6 +974,19 @@ adjust_va_to_fit_type(struct vmap_area *va,
                         * There are a few exceptions though, as an example it is
                         * a first allocation (early boot up) when we have "one"
                         * big free space that has to be split.
+                        *
+                        * Also we can hit this path in case of regular "vmap"
+                        * allocations, if "this" current CPU was not preloaded.
+                        * See the comment in alloc_vmap_area() why. If so, then
+                        * GFP_NOWAIT is used instead to get an extra object for
+                        * split purpose. That is rare and most time does not
+                        * occur.
+                        *
+                        * What happens if an allocation gets failed. Basically,
+                        * an "overflow" path is triggered to purge lazily freed
+                        * areas to free some memory, then, the "retry" path is
+                        * triggered to repeat one more time. See more details
+                        * in alloc_vmap_area() function.
                         */
                        lva = kmem_cache_alloc(vmap_area_cachep, GFP_NOWAIT);
                        if (!lva)
@@ -1063,9 +1082,9 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
                return ERR_PTR(-EBUSY);
 
        might_sleep();
+       gfp_mask = gfp_mask & GFP_RECLAIM_MASK;
 
-       va = kmem_cache_alloc_node(vmap_area_cachep,
-                       gfp_mask & GFP_RECLAIM_MASK, node);
+       va = kmem_cache_alloc_node(vmap_area_cachep, gfp_mask, node);
        if (unlikely(!va))
                return ERR_PTR(-ENOMEM);
 
@@ -1073,49 +1092,55 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
         * Only scan the relevant parts containing pointers to other objects
         * to avoid false negatives.
         */
-       kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK);
+       kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask);
 
 retry:
        /*
-        * Preload this CPU with one extra vmap_area object to ensure
-        * that we have it available when fit type of free area is
-        * NE_FIT_TYPE.
+        * Preload this CPU with one extra vmap_area object. It is used
+        * when fit type of free area is NE_FIT_TYPE. Please note, it
+        * does not guarantee that an allocation occurs on a CPU that
+        * is preloaded, instead we minimize the case when it is not.
+        * It can happen because of cpu migration, because there is a
+        * race until the below spinlock is taken.
         *
         * The preload is done in non-atomic context, thus it allows us
         * to use more permissive allocation masks to be more stable under
-        * low memory condition and high memory pressure.
+        * low memory condition and high memory pressure. In rare case,
+        * if not preloaded, GFP_NOWAIT is used.
         *
-        * Even if it fails we do not really care about that. Just proceed
-        * as it is. "overflow" path will refill the cache we allocate from.
+        * Set "pva" to NULL here, because of "retry" path.
         */
-       preempt_disable();
-       if (!__this_cpu_read(ne_fit_preload_node)) {
-               preempt_enable();
-               pva = kmem_cache_alloc_node(vmap_area_cachep, GFP_KERNEL, node);
-               preempt_disable();
-
-               if (__this_cpu_cmpxchg(ne_fit_preload_node, NULL, pva)) {
-                       if (pva)
-                               kmem_cache_free(vmap_area_cachep, pva);
-               }
-       }
+       pva = NULL;
 
-       spin_lock(&vmap_area_lock);
-       preempt_enable();
+       if (!this_cpu_read(ne_fit_preload_node))
+               /*
+                * Even if it fails we do not really care about that.
+                * Just proceed as it is. If needed "overflow" path
+                * will refill the cache we allocate from.
+                */
+               pva = kmem_cache_alloc_node(vmap_area_cachep, gfp_mask, node);
+
+       spin_lock(&free_vmap_area_lock);
+
+       if (pva && __this_cpu_cmpxchg(ne_fit_preload_node, NULL, pva))
+               kmem_cache_free(vmap_area_cachep, pva);
 
        /*
         * If an allocation fails, the "vend" address is
         * returned. Therefore trigger the overflow path.
         */
        addr = __alloc_vmap_area(size, align, vstart, vend);
+       spin_unlock(&free_vmap_area_lock);
+
        if (unlikely(addr == vend))
                goto overflow;
 
        va->va_start = addr;
        va->va_end = addr + size;
        va->vm = NULL;
-       insert_vmap_area(va, &vmap_area_root, &vmap_area_list);
 
+       spin_lock(&vmap_area_lock);
+       insert_vmap_area(va, &vmap_area_root, &vmap_area_list);
        spin_unlock(&vmap_area_lock);
 
        BUG_ON(!IS_ALIGNED(va->va_start, align));
@@ -1125,7 +1150,6 @@ retry:
        return va;
 
 overflow:
-       spin_unlock(&vmap_area_lock);
        if (!purged) {
                purge_vmap_area_lazy();
                purged = 1;
@@ -1161,28 +1185,24 @@ int unregister_vmap_purge_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(unregister_vmap_purge_notifier);
 
-static void __free_vmap_area(struct vmap_area *va)
+/*
+ * Free a region of KVA allocated by alloc_vmap_area
+ */
+static void free_vmap_area(struct vmap_area *va)
 {
        /*
         * Remove from the busy tree/list.
         */
+       spin_lock(&vmap_area_lock);
        unlink_va(va, &vmap_area_root);
+       spin_unlock(&vmap_area_lock);
 
        /*
-        * Merge VA with its neighbors, otherwise just add it.
+        * Insert/Merge it back to the free tree/list.
         */
-       merge_or_add_vmap_area(va,
-               &free_vmap_area_root, &free_vmap_area_list);
-}
-
-/*
- * Free a region of KVA allocated by alloc_vmap_area
- */
-static void free_vmap_area(struct vmap_area *va)
-{
-       spin_lock(&vmap_area_lock);
-       __free_vmap_area(va);
-       spin_unlock(&vmap_area_lock);
+       spin_lock(&free_vmap_area_lock);
+       merge_or_add_vmap_area(va, &free_vmap_area_root, &free_vmap_area_list);
+       spin_unlock(&free_vmap_area_lock);
 }
 
 /*
@@ -1275,24 +1295,30 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
        flush_tlb_kernel_range(start, end);
        resched_threshold = lazy_max_pages() << 1;
 
-       spin_lock(&vmap_area_lock);
+       spin_lock(&free_vmap_area_lock);
        llist_for_each_entry_safe(va, n_va, valist, purge_list) {
                unsigned long nr = (va->va_end - va->va_start) >> PAGE_SHIFT;
+               unsigned long orig_start = va->va_start;
+               unsigned long orig_end = va->va_end;
 
                /*
                 * Finally insert or merge lazily-freed area. It is
                 * detached and there is no need to "unlink" it from
                 * anything.
                 */
-               merge_or_add_vmap_area(va,
-                       &free_vmap_area_root, &free_vmap_area_list);
+               va = merge_or_add_vmap_area(va, &free_vmap_area_root,
+                                           &free_vmap_area_list);
+
+               if (is_vmalloc_or_module_addr((void *)orig_start))
+                       kasan_release_vmalloc(orig_start, orig_end,
+                                             va->va_start, va->va_end);
 
                atomic_long_sub(nr, &vmap_lazy_nr);
 
                if (atomic_long_read(&vmap_lazy_nr) < resched_threshold)
-                       cond_resched_lock(&vmap_area_lock);
+                       cond_resched_lock(&free_vmap_area_lock);
        }
-       spin_unlock(&vmap_area_lock);
+       spin_unlock(&free_vmap_area_lock);
        return true;
 }
 
@@ -2014,15 +2040,21 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page **pages)
 }
 EXPORT_SYMBOL_GPL(map_vm_area);
 
-static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
-                             unsigned long flags, const void *caller)
+static inline void setup_vmalloc_vm_locked(struct vm_struct *vm,
+       struct vmap_area *va, unsigned long flags, const void *caller)
 {
-       spin_lock(&vmap_area_lock);
        vm->flags = flags;
        vm->addr = (void *)va->va_start;
        vm->size = va->va_end - va->va_start;
        vm->caller = caller;
        va->vm = vm;
+}
+
+static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
+                             unsigned long flags, const void *caller)
+{
+       spin_lock(&vmap_area_lock);
+       setup_vmalloc_vm_locked(vm, va, flags, caller);
        spin_unlock(&vmap_area_lock);
 }
 
@@ -2068,6 +2100,22 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
 
        setup_vmalloc_vm(area, va, flags, caller);
 
+       /*
+        * For KASAN, if we are in vmalloc space, we need to cover the shadow
+        * area with real memory. If we come here through VM_ALLOC, this is
+        * done by a higher level function that has access to the true size,
+        * which might not be a full page.
+        *
+        * We assume module space comes via VM_ALLOC path.
+        */
+       if (is_vmalloc_addr(area->addr) && !(area->flags & VM_ALLOC)) {
+               if (kasan_populate_vmalloc(area->size, area)) {
+                       unmap_vmap_area(va);
+                       kfree(area);
+                       return NULL;
+               }
+       }
+
        return area;
 }
 
@@ -2245,6 +2293,9 @@ static void __vunmap(const void *addr, int deallocate_pages)
        debug_check_no_locks_freed(area->addr, get_vm_area_size(area));
        debug_check_no_obj_freed(area->addr, get_vm_area_size(area));
 
+       if (area->flags & VM_KASAN)
+               kasan_poison_vmalloc(area->addr, area->size);
+
        vm_remove_mappings(area, deallocate_pages);
 
        if (deallocate_pages) {
@@ -2440,7 +2491,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
                        goto fail;
                }
                area->pages[i] = page;
-               if (gfpflags_allow_blocking(gfp_mask|highmem_mask))
+               if (gfpflags_allow_blocking(gfp_mask))
                        cond_resched();
        }
        atomic_long_add(area->nr_pages, &nr_vmalloc_pages);
@@ -2497,6 +2548,11 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
        if (!addr)
                return NULL;
 
+       if (is_vmalloc_or_module_addr(area->addr)) {
+               if (kasan_populate_vmalloc(real_size, area))
+                       return NULL;
+       }
+
        /*
         * In this function, newly allocated vm_struct has VM_UNINITIALIZED
         * flag. It means that vm_struct is not fully initialized.
@@ -3282,7 +3338,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
                        goto err_free;
        }
 retry:
-       spin_lock(&vmap_area_lock);
+       spin_lock(&free_vmap_area_lock);
 
        /* start scanning - we scan from the top, begin with the last area */
        area = term_area = last_area;
@@ -3364,29 +3420,44 @@ retry:
                va = vas[area];
                va->va_start = start;
                va->va_end = start + size;
-
-               insert_vmap_area(va, &vmap_area_root, &vmap_area_list);
        }
 
-       spin_unlock(&vmap_area_lock);
+       spin_unlock(&free_vmap_area_lock);
 
        /* insert all vm's */
-       for (area = 0; area < nr_vms; area++)
-               setup_vmalloc_vm(vms[area], vas[area], VM_ALLOC,
+       spin_lock(&vmap_area_lock);
+       for (area = 0; area < nr_vms; area++) {
+               insert_vmap_area(vas[area], &vmap_area_root, &vmap_area_list);
+
+               setup_vmalloc_vm_locked(vms[area], vas[area], VM_ALLOC,
                                 pcpu_get_vm_areas);
+       }
+       spin_unlock(&vmap_area_lock);
+
+       /* populate the shadow space outside of the lock */
+       for (area = 0; area < nr_vms; area++) {
+               /* assume success here */
+               kasan_populate_vmalloc(sizes[area], vms[area]);
+       }
 
        kfree(vas);
        return vms;
 
 recovery:
-       /* Remove previously inserted areas. */
+       /*
+        * Remove previously allocated areas. There is no
+        * need in removing these areas from the busy tree,
+        * because they are inserted only on the final step
+        * and when pcpu_get_vm_areas() is success.
+        */
        while (area--) {
-               __free_vmap_area(vas[area]);
+               merge_or_add_vmap_area(vas[area], &free_vmap_area_root,
+                                      &free_vmap_area_list);
                vas[area] = NULL;
        }
 
 overflow:
-       spin_unlock(&vmap_area_lock);
+       spin_unlock(&free_vmap_area_lock);
        if (!purged) {
                purge_vmap_area_lazy();
                purged = true;
@@ -3437,9 +3508,12 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
 
 #ifdef CONFIG_PROC_FS
 static void *s_start(struct seq_file *m, loff_t *pos)
+       __acquires(&vmap_purge_lock)
        __acquires(&vmap_area_lock)
 {
+       mutex_lock(&vmap_purge_lock);
        spin_lock(&vmap_area_lock);
+
        return seq_list_start(&vmap_area_list, *pos);
 }
 
@@ -3449,8 +3523,10 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 }
 
 static void s_stop(struct seq_file *m, void *p)
+       __releases(&vmap_purge_lock)
        __releases(&vmap_area_lock)
 {
+       mutex_unlock(&vmap_purge_lock);
        spin_unlock(&vmap_area_lock);
 }
 
index ee4eecc..74e8edc 100644 (file)
@@ -79,6 +79,13 @@ struct scan_control {
         */
        struct mem_cgroup *target_mem_cgroup;
 
+       /* Can active pages be deactivated as part of reclaim? */
+#define DEACTIVATE_ANON 1
+#define DEACTIVATE_FILE 2
+       unsigned int may_deactivate:2;
+       unsigned int force_deactivate:1;
+       unsigned int skipped_deactivate:1;
+
        /* Writepage batching in laptop mode; RECLAIM_WRITE */
        unsigned int may_writepage:1;
 
@@ -101,6 +108,12 @@ struct scan_control {
        /* One of the zones is ready for compaction */
        unsigned int compaction_ready:1;
 
+       /* There is easily reclaimable cold cache in the current node */
+       unsigned int cache_trim_mode:1;
+
+       /* The file pages on the current node are dangerously low */
+       unsigned int file_is_tiny:1;
+
        /* Allocation order */
        s8 order;
 
@@ -239,13 +252,13 @@ static void unregister_memcg_shrinker(struct shrinker *shrinker)
        up_write(&shrinker_rwsem);
 }
 
-static bool global_reclaim(struct scan_control *sc)
+static bool cgroup_reclaim(struct scan_control *sc)
 {
-       return !sc->target_mem_cgroup;
+       return sc->target_mem_cgroup;
 }
 
 /**
- * sane_reclaim - is the usual dirty throttling mechanism operational?
+ * writeback_throttling_sane - is the usual dirty throttling mechanism available?
  * @sc: scan_control in question
  *
  * The normal page dirty throttling mechanism in balance_dirty_pages() is
@@ -257,11 +270,9 @@ static bool global_reclaim(struct scan_control *sc)
  * This function tests whether the vmscan currently in progress can assume
  * that the normal dirty throttling mechanism is operational.
  */
-static bool sane_reclaim(struct scan_control *sc)
+static bool writeback_throttling_sane(struct scan_control *sc)
 {
-       struct mem_cgroup *memcg = sc->target_mem_cgroup;
-
-       if (!memcg)
+       if (!cgroup_reclaim(sc))
                return true;
 #ifdef CONFIG_CGROUP_WRITEBACK
        if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
@@ -269,29 +280,6 @@ static bool sane_reclaim(struct scan_control *sc)
 #endif
        return false;
 }
-
-static void set_memcg_congestion(pg_data_t *pgdat,
-                               struct mem_cgroup *memcg,
-                               bool congested)
-{
-       struct mem_cgroup_per_node *mn;
-
-       if (!memcg)
-               return;
-
-       mn = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
-       WRITE_ONCE(mn->congested, congested);
-}
-
-static bool memcg_congested(pg_data_t *pgdat,
-                       struct mem_cgroup *memcg)
-{
-       struct mem_cgroup_per_node *mn;
-
-       mn = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
-       return READ_ONCE(mn->congested);
-
-}
 #else
 static int prealloc_memcg_shrinker(struct shrinker *shrinker)
 {
@@ -302,27 +290,15 @@ static void unregister_memcg_shrinker(struct shrinker *shrinker)
 {
 }
 
-static bool global_reclaim(struct scan_control *sc)
+static bool cgroup_reclaim(struct scan_control *sc)
 {
-       return true;
+       return false;
 }
 
-static bool sane_reclaim(struct scan_control *sc)
+static bool writeback_throttling_sane(struct scan_control *sc)
 {
        return true;
 }
-
-static inline void set_memcg_congestion(struct pglist_data *pgdat,
-                               struct mem_cgroup *memcg, bool congested)
-{
-}
-
-static inline bool memcg_congested(struct pglist_data *pgdat,
-                       struct mem_cgroup *memcg)
-{
-       return false;
-
-}
 #endif
 
 /*
@@ -351,32 +327,21 @@ unsigned long zone_reclaimable_pages(struct zone *zone)
  */
 unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx)
 {
-       unsigned long lru_size = 0;
+       unsigned long size = 0;
        int zid;
 
-       if (!mem_cgroup_disabled()) {
-               for (zid = 0; zid < MAX_NR_ZONES; zid++)
-                       lru_size += mem_cgroup_get_zone_lru_size(lruvec, lru, zid);
-       } else
-               lru_size = node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
-
-       for (zid = zone_idx + 1; zid < MAX_NR_ZONES; zid++) {
+       for (zid = 0; zid <= zone_idx && zid < MAX_NR_ZONES; zid++) {
                struct zone *zone = &lruvec_pgdat(lruvec)->node_zones[zid];
-               unsigned long size;
 
                if (!managed_zone(zone))
                        continue;
 
                if (!mem_cgroup_disabled())
-                       size = mem_cgroup_get_zone_lru_size(lruvec, lru, zid);
+                       size += mem_cgroup_get_zone_lru_size(lruvec, lru, zid);
                else
-                       size = zone_page_state(&lruvec_pgdat(lruvec)->node_zones[zid],
-                                      NR_ZONE_LRU_BASE + lru);
-               lru_size -= min(size, lru_size);
+                       size += zone_page_state(zone, NR_ZONE_LRU_BASE + lru);
        }
-
-       return lru_size;
-
+       return size;
 }
 
 /*
@@ -775,7 +740,7 @@ static inline int is_page_cache_freeable(struct page *page)
        return page_count(page) - page_has_private(page) == 1 + page_cache_pins;
 }
 
-static int may_write_to_inode(struct inode *inode, struct scan_control *sc)
+static int may_write_to_inode(struct inode *inode)
 {
        if (current->flags & PF_SWAPWRITE)
                return 1;
@@ -823,8 +788,7 @@ typedef enum {
  * pageout is called by shrink_page_list() for each dirty page.
  * Calls ->writepage().
  */
-static pageout_t pageout(struct page *page, struct address_space *mapping,
-                        struct scan_control *sc)
+static pageout_t pageout(struct page *page, struct address_space *mapping)
 {
        /*
         * If the page is dirty, only perform writeback if that write
@@ -860,7 +824,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
        }
        if (mapping->a_ops->writepage == NULL)
                return PAGE_ACTIVATE;
-       if (!may_write_to_inode(mapping->host, sc))
+       if (!may_write_to_inode(mapping->host))
                return PAGE_KEEP;
 
        if (clear_page_dirty_for_io(page)) {
@@ -899,7 +863,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
  * gets returned with a refcount of 0.
  */
 static int __remove_mapping(struct address_space *mapping, struct page *page,
-                           bool reclaimed)
+                           bool reclaimed, struct mem_cgroup *target_memcg)
 {
        unsigned long flags;
        int refcount;
@@ -971,7 +935,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
                 */
                if (reclaimed && page_is_file_cache(page) &&
                    !mapping_exiting(mapping) && !dax_mapping(mapping))
-                       shadow = workingset_eviction(page);
+                       shadow = workingset_eviction(page, target_memcg);
                __delete_from_page_cache(page, shadow);
                xa_unlock_irqrestore(&mapping->i_pages, flags);
 
@@ -994,7 +958,7 @@ cannot_free:
  */
 int remove_mapping(struct address_space *mapping, struct page *page)
 {
-       if (__remove_mapping(mapping, page, false)) {
+       if (__remove_mapping(mapping, page, false, NULL)) {
                /*
                 * Unfreezing the refcount with 1 rather than 2 effectively
                 * drops the pagecache ref for us without requiring another
@@ -1239,7 +1203,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                goto activate_locked;
 
                        /* Case 2 above */
-                       } else if (sane_reclaim(sc) ||
+                       } else if (writeback_throttling_sane(sc) ||
                            !PageReclaim(page) || !may_enter_fs) {
                                /*
                                 * This is slightly racy - end_page_writeback()
@@ -1394,7 +1358,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                         * starts and then write it out here.
                         */
                        try_to_unmap_flush_dirty();
-                       switch (pageout(page, mapping, sc)) {
+                       switch (pageout(page, mapping)) {
                        case PAGE_KEEP:
                                goto keep_locked;
                        case PAGE_ACTIVATE:
@@ -1472,7 +1436,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 
                        count_vm_event(PGLAZYFREED);
                        count_memcg_page_event(page, PGLAZYFREED);
-               } else if (!mapping || !__remove_mapping(mapping, page, true))
+               } else if (!mapping || !__remove_mapping(mapping, page, true,
+                                                        sc->target_mem_cgroup))
                        goto keep_locked;
 
                unlock_page(page);
@@ -1820,7 +1785,7 @@ int isolate_lru_page(struct page *page)
 
 /*
  * A direct reclaimer may isolate SWAP_CLUSTER_MAX pages from the LRU list and
- * then get resheduled. When there are massive number of tasks doing page
+ * then get rescheduled. When there are massive number of tasks doing page
  * allocation, such sleeping direct reclaimers may keep piling up on each CPU,
  * the LRU list will go small and be scanned faster than necessary, leading to
  * unnecessary swapping, thrashing and OOM.
@@ -1833,7 +1798,7 @@ static int too_many_isolated(struct pglist_data *pgdat, int file,
        if (current_is_kswapd())
                return 0;
 
-       if (!sane_reclaim(sc))
+       if (!writeback_throttling_sane(sc))
                return 0;
 
        if (file) {
@@ -1983,7 +1948,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT;
-       if (global_reclaim(sc))
+       if (!cgroup_reclaim(sc))
                __count_vm_events(item, nr_scanned);
        __count_memcg_events(lruvec_memcg(lruvec), item, nr_scanned);
        spin_unlock_irq(&pgdat->lru_lock);
@@ -1997,7 +1962,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        spin_lock_irq(&pgdat->lru_lock);
 
        item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT;
-       if (global_reclaim(sc))
+       if (!cgroup_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];
@@ -2199,6 +2164,20 @@ unsigned long reclaim_pages(struct list_head *page_list)
        return nr_reclaimed;
 }
 
+static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
+                                struct lruvec *lruvec, struct scan_control *sc)
+{
+       if (is_active_lru(lru)) {
+               if (sc->may_deactivate & (1 << is_file_lru(lru)))
+                       shrink_active_list(nr_to_scan, lruvec, sc, lru);
+               else
+                       sc->skipped_deactivate = 1;
+               return 0;
+       }
+
+       return shrink_inactive_list(nr_to_scan, lruvec, sc, lru);
+}
+
 /*
  * The inactive anon list should be small enough that the VM never has
  * to do too much work.
@@ -2227,64 +2206,25 @@ unsigned long reclaim_pages(struct list_head *page_list)
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
-                                struct scan_control *sc, bool trace)
+static bool inactive_is_low(struct lruvec *lruvec, enum lru_list inactive_lru)
 {
-       enum lru_list active_lru = file * LRU_FILE + LRU_ACTIVE;
-       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
-       enum lru_list inactive_lru = file * LRU_FILE;
+       enum lru_list active_lru = inactive_lru + LRU_ACTIVE;
        unsigned long inactive, active;
        unsigned long inactive_ratio;
-       unsigned long refaults;
        unsigned long gb;
 
-       /*
-        * If we don't have swap space, anonymous page deactivation
-        * is pointless.
-        */
-       if (!file && !total_swap_pages)
-               return false;
-
-       inactive = lruvec_lru_size(lruvec, inactive_lru, sc->reclaim_idx);
-       active = lruvec_lru_size(lruvec, active_lru, sc->reclaim_idx);
-
-       /*
-        * When refaults are being observed, it means a new workingset
-        * is being established. Disable active list protection to get
-        * rid of the stale workingset quickly.
-        */
-       refaults = lruvec_page_state_local(lruvec, WORKINGSET_ACTIVATE);
-       if (file && lruvec->refaults != refaults) {
-               inactive_ratio = 0;
-       } else {
-               gb = (inactive + active) >> (30 - PAGE_SHIFT);
-               if (gb)
-                       inactive_ratio = int_sqrt(10 * gb);
-               else
-                       inactive_ratio = 1;
-       }
+       inactive = lruvec_page_state(lruvec, NR_LRU_BASE + inactive_lru);
+       active = lruvec_page_state(lruvec, NR_LRU_BASE + active_lru);
 
-       if (trace)
-               trace_mm_vmscan_inactive_list_is_low(pgdat->node_id, sc->reclaim_idx,
-                       lruvec_lru_size(lruvec, inactive_lru, MAX_NR_ZONES), inactive,
-                       lruvec_lru_size(lruvec, active_lru, MAX_NR_ZONES), active,
-                       inactive_ratio, file);
+       gb = (inactive + active) >> (30 - PAGE_SHIFT);
+       if (gb)
+               inactive_ratio = int_sqrt(10 * gb);
+       else
+               inactive_ratio = 1;
 
        return inactive * inactive_ratio < active;
 }
 
-static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
-                                struct lruvec *lruvec, struct scan_control *sc)
-{
-       if (is_active_lru(lru)) {
-               if (inactive_list_is_low(lruvec, is_file_lru(lru), sc, true))
-                       shrink_active_list(nr_to_scan, lruvec, sc, lru);
-               return 0;
-       }
-
-       return shrink_inactive_list(nr_to_scan, lruvec, sc, lru);
-}
-
 enum scan_balance {
        SCAN_EQUAL,
        SCAN_FRACT,
@@ -2301,10 +2241,10 @@ enum scan_balance {
  * nr[0] = anon inactive pages to scan; nr[1] = anon active pages to scan
  * nr[2] = file inactive pages to scan; nr[3] = file active pages to scan
  */
-static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
-                          struct scan_control *sc, unsigned long *nr,
-                          unsigned long *lru_pages)
+static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc,
+                          unsigned long *nr)
 {
+       struct mem_cgroup *memcg = lruvec_memcg(lruvec);
        int swappiness = mem_cgroup_swappiness(memcg);
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
        u64 fraction[2];
@@ -2329,7 +2269,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * using the memory controller's swap limit feature would be
         * too expensive.
         */
-       if (!global_reclaim(sc) && !swappiness) {
+       if (cgroup_reclaim(sc) && !swappiness) {
                scan_balance = SCAN_FILE;
                goto out;
        }
@@ -2345,58 +2285,18 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
        }
 
        /*
-        * Prevent the reclaimer from falling into the cache trap: as
-        * cache pages start out inactive, every cache fault will tip
-        * the scan balance towards the file LRU.  And as the file LRU
-        * shrinks, so does the window for rotation from references.
-        * This means we have a runaway feedback loop where a tiny
-        * thrashing file LRU becomes infinitely more attractive than
-        * anon pages.  Try to detect this based on file LRU size.
+        * If the system is almost out of file pages, force-scan anon.
         */
-       if (global_reclaim(sc)) {
-               unsigned long pgdatfile;
-               unsigned long pgdatfree;
-               int z;
-               unsigned long total_high_wmark = 0;
-
-               pgdatfree = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
-               pgdatfile = node_page_state(pgdat, NR_ACTIVE_FILE) +
-                          node_page_state(pgdat, NR_INACTIVE_FILE);
-
-               for (z = 0; z < MAX_NR_ZONES; z++) {
-                       struct zone *zone = &pgdat->node_zones[z];
-                       if (!managed_zone(zone))
-                               continue;
-
-                       total_high_wmark += high_wmark_pages(zone);
-               }
-
-               if (unlikely(pgdatfile + pgdatfree <= total_high_wmark)) {
-                       /*
-                        * Force SCAN_ANON if there are enough inactive
-                        * anonymous pages on the LRU in eligible zones.
-                        * Otherwise, the small LRU gets thrashed.
-                        */
-                       if (!inactive_list_is_low(lruvec, false, sc, false) &&
-                           lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, sc->reclaim_idx)
-                                       >> sc->priority) {
-                               scan_balance = SCAN_ANON;
-                               goto out;
-                       }
-               }
+       if (sc->file_is_tiny) {
+               scan_balance = SCAN_ANON;
+               goto out;
        }
 
        /*
-        * If there is enough inactive page cache, i.e. if the size of the
-        * inactive list is greater than that of the active list *and* the
-        * inactive list actually has some pages to scan on this priority, we
-        * do not reclaim anything from the anonymous working set right now.
-        * Without the second condition we could end up never scanning an
-        * lruvec even if it has plenty of old anonymous pages unless the
-        * system is under heavy pressure.
+        * If there is enough inactive page cache, we do not reclaim
+        * anything from the anonymous working right now.
         */
-       if (!inactive_list_is_low(lruvec, true, sc, false) &&
-           lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, sc->reclaim_idx) >> sc->priority) {
+       if (sc->cache_trim_mode) {
                scan_balance = SCAN_FILE;
                goto out;
        }
@@ -2454,7 +2354,6 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
        fraction[1] = fp;
        denominator = ap + fp + 1;
 out:
-       *lru_pages = 0;
        for_each_evictable_lru(lru) {
                int file = is_file_lru(lru);
                unsigned long lruvec_size;
@@ -2549,18 +2448,12 @@ out:
                        BUG();
                }
 
-               *lru_pages += lruvec_size;
                nr[lru] = scan;
        }
 }
 
-/*
- * This is a basic per-node page freer.  Used by both kswapd and direct reclaim.
- */
-static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memcg,
-                             struct scan_control *sc, unsigned long *lru_pages)
+static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
 {
-       struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg);
        unsigned long nr[NR_LRU_LISTS];
        unsigned long targets[NR_LRU_LISTS];
        unsigned long nr_to_scan;
@@ -2570,7 +2463,7 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
        struct blk_plug plug;
        bool scan_adjusted;
 
-       get_scan_count(lruvec, memcg, sc, nr, lru_pages);
+       get_scan_count(lruvec, sc, nr);
 
        /* Record the original scan target for proportional adjustments later */
        memcpy(targets, nr, sizeof(nr));
@@ -2586,7 +2479,7 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
         * abort proportional reclaim if either the file or anon lru has already
         * dropped to zero at the first pass.
         */
-       scan_adjusted = (global_reclaim(sc) && !current_is_kswapd() &&
+       scan_adjusted = (!cgroup_reclaim(sc) && !current_is_kswapd() &&
                         sc->priority == DEF_PRIORITY);
 
        blk_start_plug(&plug);
@@ -2668,7 +2561,7 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
         * Even if we did not try to evict anon pages at all, we want to
         * rebalance the anon lru active/inactive ratio.
         */
-       if (inactive_list_is_low(lruvec, false, sc, true))
+       if (total_swap_pages && inactive_is_low(lruvec, LRU_INACTIVE_ANON))
                shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
                                   sc, LRU_ACTIVE_ANON);
 }
@@ -2744,156 +2637,234 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
        return inactive_lru_pages > pages_for_compaction;
 }
 
-static bool pgdat_memcg_congested(pg_data_t *pgdat, struct mem_cgroup *memcg)
+static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc)
 {
-       return test_bit(PGDAT_CONGESTED, &pgdat->flags) ||
-               (memcg && memcg_congested(pgdat, memcg));
+       struct mem_cgroup *target_memcg = sc->target_mem_cgroup;
+       struct mem_cgroup *memcg;
+
+       memcg = mem_cgroup_iter(target_memcg, NULL, NULL);
+       do {
+               struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat);
+               unsigned long reclaimed;
+               unsigned long scanned;
+
+               switch (mem_cgroup_protected(target_memcg, memcg)) {
+               case MEMCG_PROT_MIN:
+                       /*
+                        * Hard protection.
+                        * If there is no reclaimable memory, OOM.
+                        */
+                       continue;
+               case MEMCG_PROT_LOW:
+                       /*
+                        * Soft protection.
+                        * Respect the protection only as long as
+                        * there is an unprotected supply
+                        * of reclaimable memory from other cgroups.
+                        */
+                       if (!sc->memcg_low_reclaim) {
+                               sc->memcg_low_skipped = 1;
+                               continue;
+                       }
+                       memcg_memory_event(memcg, MEMCG_LOW);
+                       break;
+               case MEMCG_PROT_NONE:
+                       /*
+                        * All protection thresholds breached. We may
+                        * still choose to vary the scan pressure
+                        * applied based on by how much the cgroup in
+                        * question has exceeded its protection
+                        * thresholds (see get_scan_count).
+                        */
+                       break;
+               }
+
+               reclaimed = sc->nr_reclaimed;
+               scanned = sc->nr_scanned;
+
+               shrink_lruvec(lruvec, sc);
+
+               shrink_slab(sc->gfp_mask, pgdat->node_id, memcg,
+                           sc->priority);
+
+               /* Record the group's reclaim efficiency */
+               vmpressure(sc->gfp_mask, memcg, false,
+                          sc->nr_scanned - scanned,
+                          sc->nr_reclaimed - reclaimed);
+
+       } while ((memcg = mem_cgroup_iter(target_memcg, memcg, NULL)));
 }
 
 static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc)
 {
        struct reclaim_state *reclaim_state = current->reclaim_state;
        unsigned long nr_reclaimed, nr_scanned;
+       struct lruvec *target_lruvec;
        bool reclaimable = false;
+       unsigned long file;
 
-       do {
-               struct mem_cgroup *root = sc->target_mem_cgroup;
-               unsigned long node_lru_pages = 0;
-               struct mem_cgroup *memcg;
+       target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat);
 
-               memset(&sc->nr, 0, sizeof(sc->nr));
+again:
+       memset(&sc->nr, 0, sizeof(sc->nr));
 
-               nr_reclaimed = sc->nr_reclaimed;
-               nr_scanned = sc->nr_scanned;
+       nr_reclaimed = sc->nr_reclaimed;
+       nr_scanned = sc->nr_scanned;
 
-               memcg = mem_cgroup_iter(root, NULL, NULL);
-               do {
-                       unsigned long lru_pages;
-                       unsigned long reclaimed;
-                       unsigned long scanned;
+       /*
+        * Target desirable inactive:active list ratios for the anon
+        * and file LRU lists.
+        */
+       if (!sc->force_deactivate) {
+               unsigned long refaults;
 
-                       switch (mem_cgroup_protected(root, memcg)) {
-                       case MEMCG_PROT_MIN:
-                               /*
-                                * Hard protection.
-                                * If there is no reclaimable memory, OOM.
-                                */
-                               continue;
-                       case MEMCG_PROT_LOW:
-                               /*
-                                * Soft protection.
-                                * Respect the protection only as long as
-                                * there is an unprotected supply
-                                * of reclaimable memory from other cgroups.
-                                */
-                               if (!sc->memcg_low_reclaim) {
-                                       sc->memcg_low_skipped = 1;
-                                       continue;
-                               }
-                               memcg_memory_event(memcg, MEMCG_LOW);
-                               break;
-                       case MEMCG_PROT_NONE:
-                               /*
-                                * All protection thresholds breached. We may
-                                * still choose to vary the scan pressure
-                                * applied based on by how much the cgroup in
-                                * question has exceeded its protection
-                                * thresholds (see get_scan_count).
-                                */
-                               break;
-                       }
+               if (inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
+                       sc->may_deactivate |= DEACTIVATE_ANON;
+               else
+                       sc->may_deactivate &= ~DEACTIVATE_ANON;
 
-                       reclaimed = sc->nr_reclaimed;
-                       scanned = sc->nr_scanned;
-                       shrink_node_memcg(pgdat, memcg, sc, &lru_pages);
-                       node_lru_pages += lru_pages;
+               /*
+                * When refaults are being observed, it means a new
+                * workingset is being established. Deactivate to get
+                * rid of any stale active pages quickly.
+                */
+               refaults = lruvec_page_state(target_lruvec,
+                                            WORKINGSET_ACTIVATE);
+               if (refaults != target_lruvec->refaults ||
+                   inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
+                       sc->may_deactivate |= DEACTIVATE_FILE;
+               else
+                       sc->may_deactivate &= ~DEACTIVATE_FILE;
+       } else
+               sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE;
 
-                       shrink_slab(sc->gfp_mask, pgdat->node_id, memcg,
-                                       sc->priority);
+       /*
+        * If we have plenty of inactive file pages that aren't
+        * thrashing, try to reclaim those first before touching
+        * anonymous pages.
+        */
+       file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE);
+       if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE))
+               sc->cache_trim_mode = 1;
+       else
+               sc->cache_trim_mode = 0;
+
+       /*
+        * Prevent the reclaimer from falling into the cache trap: as
+        * cache pages start out inactive, every cache fault will tip
+        * the scan balance towards the file LRU.  And as the file LRU
+        * shrinks, so does the window for rotation from references.
+        * This means we have a runaway feedback loop where a tiny
+        * thrashing file LRU becomes infinitely more attractive than
+        * anon pages.  Try to detect this based on file LRU size.
+        */
+       if (!cgroup_reclaim(sc)) {
+               unsigned long total_high_wmark = 0;
+               unsigned long free, anon;
+               int z;
 
-                       /* Record the group's reclaim efficiency */
-                       vmpressure(sc->gfp_mask, memcg, false,
-                                  sc->nr_scanned - scanned,
-                                  sc->nr_reclaimed - reclaimed);
+               free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
+               file = node_page_state(pgdat, NR_ACTIVE_FILE) +
+                          node_page_state(pgdat, NR_INACTIVE_FILE);
 
-               } while ((memcg = mem_cgroup_iter(root, memcg, NULL)));
+               for (z = 0; z < MAX_NR_ZONES; z++) {
+                       struct zone *zone = &pgdat->node_zones[z];
+                       if (!managed_zone(zone))
+                               continue;
 
-               if (reclaim_state) {
-                       sc->nr_reclaimed += reclaim_state->reclaimed_slab;
-                       reclaim_state->reclaimed_slab = 0;
+                       total_high_wmark += high_wmark_pages(zone);
                }
 
-               /* Record the subtree's reclaim efficiency */
-               vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
-                          sc->nr_scanned - nr_scanned,
-                          sc->nr_reclaimed - nr_reclaimed);
+               /*
+                * Consider anon: if that's low too, this isn't a
+                * runaway file reclaim problem, but rather just
+                * extreme pressure. Reclaim as per usual then.
+                */
+               anon = node_page_state(pgdat, NR_INACTIVE_ANON);
 
-               if (sc->nr_reclaimed - nr_reclaimed)
-                       reclaimable = true;
+               sc->file_is_tiny =
+                       file + free <= total_high_wmark &&
+                       !(sc->may_deactivate & DEACTIVATE_ANON) &&
+                       anon >> sc->priority;
+       }
 
-               if (current_is_kswapd()) {
-                       /*
-                        * If reclaim is isolating dirty pages under writeback,
-                        * it implies that the long-lived page allocation rate
-                        * is exceeding the page laundering rate. Either the
-                        * global limits are not being effective at throttling
-                        * processes due to the page distribution throughout
-                        * zones or there is heavy usage of a slow backing
-                        * device. The only option is to throttle from reclaim
-                        * context which is not ideal as there is no guarantee
-                        * the dirtying process is throttled in the same way
-                        * balance_dirty_pages() manages.
-                        *
-                        * Once a node is flagged PGDAT_WRITEBACK, kswapd will
-                        * count the number of pages under pages flagged for
-                        * immediate reclaim and stall if any are encountered
-                        * in the nr_immediate check below.
-                        */
-                       if (sc->nr.writeback && sc->nr.writeback == sc->nr.taken)
-                               set_bit(PGDAT_WRITEBACK, &pgdat->flags);
+       shrink_node_memcgs(pgdat, sc);
 
-                       /*
-                        * Tag a node as congested if all the dirty pages
-                        * scanned were backed by a congested BDI and
-                        * wait_iff_congested will stall.
-                        */
-                       if (sc->nr.dirty && sc->nr.dirty == sc->nr.congested)
-                               set_bit(PGDAT_CONGESTED, &pgdat->flags);
+       if (reclaim_state) {
+               sc->nr_reclaimed += reclaim_state->reclaimed_slab;
+               reclaim_state->reclaimed_slab = 0;
+       }
 
-                       /* Allow kswapd to start writing pages during reclaim.*/
-                       if (sc->nr.unqueued_dirty == sc->nr.file_taken)
-                               set_bit(PGDAT_DIRTY, &pgdat->flags);
+       /* Record the subtree's reclaim efficiency */
+       vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
+                  sc->nr_scanned - nr_scanned,
+                  sc->nr_reclaimed - nr_reclaimed);
 
-                       /*
-                        * If kswapd scans pages marked marked for immediate
-                        * reclaim and under writeback (nr_immediate), it
-                        * implies that pages are cycling through the LRU
-                        * faster than they are written so also forcibly stall.
-                        */
-                       if (sc->nr.immediate)
-                               congestion_wait(BLK_RW_ASYNC, HZ/10);
-               }
+       if (sc->nr_reclaimed - nr_reclaimed)
+               reclaimable = true;
 
+       if (current_is_kswapd()) {
                /*
-                * Legacy memcg will stall in page writeback so avoid forcibly
-                * stalling in wait_iff_congested().
+                * If reclaim is isolating dirty pages under writeback,
+                * it implies that the long-lived page allocation rate
+                * is exceeding the page laundering rate. Either the
+                * global limits are not being effective at throttling
+                * processes due to the page distribution throughout
+                * zones or there is heavy usage of a slow backing
+                * device. The only option is to throttle from reclaim
+                * context which is not ideal as there is no guarantee
+                * the dirtying process is throttled in the same way
+                * balance_dirty_pages() manages.
+                *
+                * Once a node is flagged PGDAT_WRITEBACK, kswapd will
+                * count the number of pages under pages flagged for
+                * immediate reclaim and stall if any are encountered
+                * in the nr_immediate check below.
                 */
-               if (!global_reclaim(sc) && sane_reclaim(sc) &&
-                   sc->nr.dirty && sc->nr.dirty == sc->nr.congested)
-                       set_memcg_congestion(pgdat, root, true);
+               if (sc->nr.writeback && sc->nr.writeback == sc->nr.taken)
+                       set_bit(PGDAT_WRITEBACK, &pgdat->flags);
+
+               /* Allow kswapd to start writing pages during reclaim.*/
+               if (sc->nr.unqueued_dirty == sc->nr.file_taken)
+                       set_bit(PGDAT_DIRTY, &pgdat->flags);
 
                /*
-                * Stall direct reclaim for IO completions if underlying BDIs
-                * and node is congested. Allow kswapd to continue until it
-                * starts encountering unqueued dirty pages or cycling through
-                * the LRU too quickly.
+                * If kswapd scans pages marked marked for immediate
+                * reclaim and under writeback (nr_immediate), it
+                * implies that pages are cycling through the LRU
+                * faster than they are written so also forcibly stall.
                 */
-               if (!sc->hibernation_mode && !current_is_kswapd() &&
-                  current_may_throttle() && pgdat_memcg_congested(pgdat, root))
-                       wait_iff_congested(BLK_RW_ASYNC, HZ/10);
+               if (sc->nr.immediate)
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
+       }
 
-       } while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
-                                        sc));
+       /*
+        * Tag a node/memcg as congested if all the dirty pages
+        * scanned were backed by a congested BDI and
+        * wait_iff_congested will stall.
+        *
+        * Legacy memcg will stall in page writeback so avoid forcibly
+        * stalling in wait_iff_congested().
+        */
+       if ((current_is_kswapd() ||
+            (cgroup_reclaim(sc) && writeback_throttling_sane(sc))) &&
+           sc->nr.dirty && sc->nr.dirty == sc->nr.congested)
+               set_bit(LRUVEC_CONGESTED, &target_lruvec->flags);
+
+       /*
+        * Stall direct reclaim for IO completions if underlying BDIs
+        * and node is congested. Allow kswapd to continue until it
+        * starts encountering unqueued dirty pages or cycling through
+        * the LRU too quickly.
+        */
+       if (!current_is_kswapd() && current_may_throttle() &&
+           !sc->hibernation_mode &&
+           test_bit(LRUVEC_CONGESTED, &target_lruvec->flags))
+               wait_iff_congested(BLK_RW_ASYNC, HZ/10);
+
+       if (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
+                                   sc))
+               goto again;
 
        /*
         * Kswapd gives up on balancing particular nodes after too
@@ -2973,7 +2944,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                 * Take care memory controller reclaiming has small influence
                 * to global LRU.
                 */
-               if (global_reclaim(sc)) {
+               if (!cgroup_reclaim(sc)) {
                        if (!cpuset_zone_allowed(zone,
                                                 GFP_KERNEL | __GFP_HARDWALL))
                                continue;
@@ -3032,19 +3003,14 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        sc->gfp_mask = orig_mask;
 }
 
-static void snapshot_refaults(struct mem_cgroup *root_memcg, pg_data_t *pgdat)
+static void snapshot_refaults(struct mem_cgroup *target_memcg, pg_data_t *pgdat)
 {
-       struct mem_cgroup *memcg;
-
-       memcg = mem_cgroup_iter(root_memcg, NULL, NULL);
-       do {
-               unsigned long refaults;
-               struct lruvec *lruvec;
+       struct lruvec *target_lruvec;
+       unsigned long refaults;
 
-               lruvec = mem_cgroup_lruvec(pgdat, memcg);
-               refaults = lruvec_page_state_local(lruvec, WORKINGSET_ACTIVATE);
-               lruvec->refaults = refaults;
-       } while ((memcg = mem_cgroup_iter(root_memcg, memcg, NULL)));
+       target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat);
+       refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE);
+       target_lruvec->refaults = refaults;
 }
 
 /*
@@ -3073,7 +3039,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
 retry:
        delayacct_freepages_start();
 
-       if (global_reclaim(sc))
+       if (!cgroup_reclaim(sc))
                __count_zid_vm_events(ALLOCSTALL, sc->reclaim_idx, 1);
 
        do {
@@ -3102,8 +3068,16 @@ retry:
                if (zone->zone_pgdat == last_pgdat)
                        continue;
                last_pgdat = zone->zone_pgdat;
+
                snapshot_refaults(sc->target_mem_cgroup, zone->zone_pgdat);
-               set_memcg_congestion(last_pgdat, sc->target_mem_cgroup, false);
+
+               if (cgroup_reclaim(sc)) {
+                       struct lruvec *lruvec;
+
+                       lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup,
+                                                  zone->zone_pgdat);
+                       clear_bit(LRUVEC_CONGESTED, &lruvec->flags);
+               }
        }
 
        delayacct_freepages_end();
@@ -3115,9 +3089,27 @@ retry:
        if (sc->compaction_ready)
                return 1;
 
+       /*
+        * We make inactive:active ratio decisions based on the node's
+        * composition of memory, but a restrictive reclaim_idx or a
+        * memory.low cgroup setting can exempt large amounts of
+        * memory from reclaim. Neither of which are very common, so
+        * instead of doing costly eligibility calculations of the
+        * entire cgroup subtree up front, we assume the estimates are
+        * good, and retry with forcible deactivation if that fails.
+        */
+       if (sc->skipped_deactivate) {
+               sc->priority = initial_priority;
+               sc->force_deactivate = 1;
+               sc->skipped_deactivate = 0;
+               goto retry;
+       }
+
        /* Untapped cgroup reserves?  Don't OOM, retry. */
        if (sc->memcg_low_skipped) {
                sc->priority = initial_priority;
+               sc->force_deactivate = 0;
+               sc->skipped_deactivate = 0;
                sc->memcg_low_reclaim = 1;
                sc->memcg_low_skipped = 0;
                goto retry;
@@ -3309,6 +3301,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                                                pg_data_t *pgdat,
                                                unsigned long *nr_scanned)
 {
+       struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat);
        struct scan_control sc = {
                .nr_to_reclaim = SWAP_CLUSTER_MAX,
                .target_mem_cgroup = memcg,
@@ -3317,7 +3310,6 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                .reclaim_idx = MAX_NR_ZONES - 1,
                .may_swap = !noswap,
        };
-       unsigned long lru_pages;
 
        WARN_ON_ONCE(!current->reclaim_state);
 
@@ -3334,7 +3326,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
         * will pick up pages from other mem cgroup's as well. We hack
         * the priority and make it zero.
         */
-       shrink_node_memcg(pgdat, memcg, &sc, &lru_pages);
+       shrink_lruvec(lruvec, &sc);
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
@@ -3348,10 +3340,8 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                           gfp_t gfp_mask,
                                           bool may_swap)
 {
-       struct zonelist *zonelist;
        unsigned long nr_reclaimed;
        unsigned long pflags;
-       int nid;
        unsigned int noreclaim_flag;
        struct scan_control sc = {
                .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
@@ -3364,16 +3354,14 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .may_unmap = 1,
                .may_swap = may_swap,
        };
-
-       set_task_reclaim_state(current, &sc.reclaim_state);
        /*
-        * Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
-        * take care of from where we get pages. So the node where we start the
-        * scan does not need to be the current node.
+        * Traverse the ZONELIST_FALLBACK zonelist of the current node to put
+        * equal pressure on all the nodes. This is based on the assumption that
+        * the reclaim does not bail out early.
         */
-       nid = mem_cgroup_select_victim_node(memcg);
+       struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
 
-       zonelist = &NODE_DATA(nid)->node_zonelists[ZONELIST_FALLBACK];
+       set_task_reclaim_state(current, &sc.reclaim_state);
 
        trace_mm_vmscan_memcg_reclaim_begin(0, sc.gfp_mask);
 
@@ -3396,18 +3384,20 @@ static void age_active_anon(struct pglist_data *pgdat,
                                struct scan_control *sc)
 {
        struct mem_cgroup *memcg;
+       struct lruvec *lruvec;
 
        if (!total_swap_pages)
                return;
 
+       lruvec = mem_cgroup_lruvec(NULL, pgdat);
+       if (!inactive_is_low(lruvec, LRU_INACTIVE_ANON))
+               return;
+
        memcg = mem_cgroup_iter(NULL, NULL, NULL);
        do {
-               struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg);
-
-               if (inactive_list_is_low(lruvec, false, sc, true))
-                       shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
-                                          sc, LRU_ACTIVE_ANON);
-
+               lruvec = mem_cgroup_lruvec(memcg, pgdat);
+               shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
+                                  sc, LRU_ACTIVE_ANON);
                memcg = mem_cgroup_iter(NULL, memcg, NULL);
        } while (memcg);
 }
@@ -3475,7 +3465,9 @@ static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
 /* Clear pgdat state for congested, dirty or under writeback. */
 static void clear_pgdat_congested(pg_data_t *pgdat)
 {
-       clear_bit(PGDAT_CONGESTED, &pgdat->flags);
+       struct lruvec *lruvec = mem_cgroup_lruvec(NULL, pgdat);
+
+       clear_bit(LRUVEC_CONGESTED, &lruvec->flags);
        clear_bit(PGDAT_DIRTY, &pgdat->flags);
        clear_bit(PGDAT_WRITEBACK, &pgdat->flags);
 }
index a822204..78d5337 100644 (file)
@@ -1084,7 +1084,8 @@ int fragmentation_index(struct zone *zone, unsigned int order)
 }
 #endif
 
-#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || defined(CONFIG_NUMA)
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || \
+    defined(CONFIG_NUMA) || defined(CONFIG_MEMCG)
 #ifdef CONFIG_ZONE_DMA
 #define TEXT_FOR_DMA(xx) xx "_dma",
 #else
@@ -1134,7 +1135,7 @@ const char * const vmstat_text[] = {
        "numa_other",
 #endif
 
-       /* Node-based counters */
+       /* enum node_stat_item counters */
        "nr_inactive_anon",
        "nr_active_anon",
        "nr_inactive_file",
@@ -1172,7 +1173,7 @@ const char * const vmstat_text[] = {
        "nr_dirty_threshold",
        "nr_dirty_background_threshold",
 
-#ifdef CONFIG_VM_EVENT_COUNTERS
+#if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
        /* enum vm_event_item counters */
        "pgpgin",
        "pgpgout",
@@ -1291,9 +1292,9 @@ const char * const vmstat_text[] = {
        "swap_ra",
        "swap_ra_hit",
 #endif
-#endif /* CONFIG_VM_EVENTS_COUNTERS */
+#endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
 };
-#endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA */
+#endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA || CONFIG_MEMCG */
 
 #if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \
      defined(CONFIG_PROC_FS)
@@ -1564,10 +1565,8 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
        if (is_zone_first_populated(pgdat, zone)) {
                seq_printf(m, "\n  per-node stats");
                for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
-                       seq_printf(m, "\n      %-12s %lu",
-                               vmstat_text[i + NR_VM_ZONE_STAT_ITEMS +
-                               NR_VM_NUMA_STAT_ITEMS],
-                               node_page_state(pgdat, i));
+                       seq_printf(m, "\n      %-12s %lu", node_stat_name(i),
+                                  node_page_state(pgdat, i));
                }
        }
        seq_printf(m,
@@ -1600,14 +1599,13 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
        }
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               seq_printf(m, "\n      %-12s %lu", vmstat_text[i],
-                               zone_page_state(zone, i));
+               seq_printf(m, "\n      %-12s %lu", zone_stat_name(i),
+                          zone_page_state(zone, i));
 
 #ifdef CONFIG_NUMA
        for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
-               seq_printf(m, "\n      %-12s %lu",
-                               vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
-                               zone_numa_state_snapshot(zone, i));
+               seq_printf(m, "\n      %-12s %lu", numa_stat_name(i),
+                          zone_numa_state_snapshot(zone, i));
 #endif
 
        seq_printf(m, "\n  pagesets");
@@ -1658,31 +1656,23 @@ static const struct seq_operations zoneinfo_op = {
        .show   = zoneinfo_show,
 };
 
-enum writeback_stat_item {
-       NR_DIRTY_THRESHOLD,
-       NR_DIRTY_BG_THRESHOLD,
-       NR_VM_WRITEBACK_STAT_ITEMS,
-};
+#define NR_VMSTAT_ITEMS (NR_VM_ZONE_STAT_ITEMS + \
+                        NR_VM_NUMA_STAT_ITEMS + \
+                        NR_VM_NODE_STAT_ITEMS + \
+                        NR_VM_WRITEBACK_STAT_ITEMS + \
+                        (IS_ENABLED(CONFIG_VM_EVENT_COUNTERS) ? \
+                         NR_VM_EVENT_ITEMS : 0))
 
 static void *vmstat_start(struct seq_file *m, loff_t *pos)
 {
        unsigned long *v;
-       int i, stat_items_size;
+       int i;
 
-       if (*pos >= ARRAY_SIZE(vmstat_text))
+       if (*pos >= NR_VMSTAT_ITEMS)
                return NULL;
-       stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +
-                         NR_VM_NUMA_STAT_ITEMS * sizeof(unsigned long) +
-                         NR_VM_NODE_STAT_ITEMS * sizeof(unsigned long) +
-                         NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long);
-
-#ifdef CONFIG_VM_EVENT_COUNTERS
-       stat_items_size += sizeof(struct vm_event_state);
-#endif
 
-       BUILD_BUG_ON(stat_items_size !=
-                    ARRAY_SIZE(vmstat_text) * sizeof(unsigned long));
-       v = kmalloc(stat_items_size, GFP_KERNEL);
+       BUILD_BUG_ON(ARRAY_SIZE(vmstat_text) < NR_VMSTAT_ITEMS);
+       v = kmalloc_array(NR_VMSTAT_ITEMS, sizeof(unsigned long), GFP_KERNEL);
        m->private = v;
        if (!v)
                return ERR_PTR(-ENOMEM);
@@ -1715,7 +1705,7 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
 static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
 {
        (*pos)++;
-       if (*pos >= ARRAY_SIZE(vmstat_text))
+       if (*pos >= NR_VMSTAT_ITEMS)
                return NULL;
        return (unsigned long *)m->private + *pos;
 }
@@ -1781,7 +1771,7 @@ int vmstat_refresh(struct ctl_table *table, int write,
                val = atomic_long_read(&vm_zone_stat[i]);
                if (val < 0) {
                        pr_warn("%s: %s %ld\n",
-                               __func__, vmstat_text[i], val);
+                               __func__, zone_stat_name(i), val);
                        err = -EINVAL;
                }
        }
@@ -1790,7 +1780,7 @@ int vmstat_refresh(struct ctl_table *table, int write,
                val = atomic_long_read(&vm_numa_stat[i]);
                if (val < 0) {
                        pr_warn("%s: %s %ld\n",
-                               __func__, vmstat_text[i + NR_VM_ZONE_STAT_ITEMS], val);
+                               __func__, numa_stat_name(i), val);
                        err = -EINVAL;
                }
        }
index c963831..474186b 100644 (file)
@@ -213,28 +213,53 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
        *workingsetp = workingset;
 }
 
+static void advance_inactive_age(struct mem_cgroup *memcg, pg_data_t *pgdat)
+{
+       /*
+        * Reclaiming a cgroup means reclaiming all its children in a
+        * round-robin fashion. That means that each cgroup has an LRU
+        * order that is composed of the LRU orders of its child
+        * cgroups; and every page has an LRU position not just in the
+        * cgroup that owns it, but in all of that group's ancestors.
+        *
+        * So when the physical inactive list of a leaf cgroup ages,
+        * the virtual inactive lists of all its parents, including
+        * the root cgroup's, age as well.
+        */
+       do {
+               struct lruvec *lruvec;
+
+               lruvec = mem_cgroup_lruvec(memcg, pgdat);
+               atomic_long_inc(&lruvec->inactive_age);
+       } while (memcg && (memcg = parent_mem_cgroup(memcg)));
+}
+
 /**
  * workingset_eviction - note the eviction of a page from memory
+ * @target_memcg: the cgroup that is causing the reclaim
  * @page: the page being evicted
  *
  * Returns a shadow entry to be stored in @page->mapping->i_pages in place
  * of the evicted @page so that a later refault can be detected.
  */
-void *workingset_eviction(struct page *page)
+void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg)
 {
        struct pglist_data *pgdat = page_pgdat(page);
-       struct mem_cgroup *memcg = page_memcg(page);
-       int memcgid = mem_cgroup_id(memcg);
        unsigned long eviction;
        struct lruvec *lruvec;
+       int memcgid;
 
        /* Page is fully exclusive and pins page->mem_cgroup */
        VM_BUG_ON_PAGE(PageLRU(page), page);
        VM_BUG_ON_PAGE(page_count(page), page);
        VM_BUG_ON_PAGE(!PageLocked(page), page);
 
-       lruvec = mem_cgroup_lruvec(pgdat, memcg);
-       eviction = atomic_long_inc_return(&lruvec->inactive_age);
+       advance_inactive_age(page_memcg(page), pgdat);
+
+       lruvec = mem_cgroup_lruvec(target_memcg, pgdat);
+       /* XXX: target_memcg can be NULL, go through lruvec */
+       memcgid = mem_cgroup_id(lruvec_memcg(lruvec));
+       eviction = atomic_long_read(&lruvec->inactive_age);
        return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page));
 }
 
@@ -244,10 +269,13 @@ void *workingset_eviction(struct page *page)
  * @shadow: shadow entry of the evicted page
  *
  * Calculates and evaluates the refault distance of the previously
- * evicted page in the context of the node it was allocated in.
+ * evicted page in the context of the node and the memcg whose memory
+ * pressure caused the eviction.
  */
 void workingset_refault(struct page *page, void *shadow)
 {
+       struct mem_cgroup *eviction_memcg;
+       struct lruvec *eviction_lruvec;
        unsigned long refault_distance;
        struct pglist_data *pgdat;
        unsigned long active_file;
@@ -277,12 +305,12 @@ void workingset_refault(struct page *page, void *shadow)
         * would be better if the root_mem_cgroup existed in all
         * configurations instead.
         */
-       memcg = mem_cgroup_from_id(memcgid);
-       if (!mem_cgroup_disabled() && !memcg)
+       eviction_memcg = mem_cgroup_from_id(memcgid);
+       if (!mem_cgroup_disabled() && !eviction_memcg)
                goto out;
-       lruvec = mem_cgroup_lruvec(pgdat, memcg);
-       refault = atomic_long_read(&lruvec->inactive_age);
-       active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES);
+       eviction_lruvec = mem_cgroup_lruvec(eviction_memcg, pgdat);
+       refault = atomic_long_read(&eviction_lruvec->inactive_age);
+       active_file = lruvec_page_state(eviction_lruvec, NR_ACTIVE_FILE);
 
        /*
         * Calculate the refault distance
@@ -302,6 +330,17 @@ void workingset_refault(struct page *page, void *shadow)
         */
        refault_distance = (refault - eviction) & EVICTION_MASK;
 
+       /*
+        * The activation decision for this page is made at the level
+        * where the eviction occurred, as that is where the LRU order
+        * during page reclaim is being determined.
+        *
+        * However, the cgroup that will own the page is the one that
+        * is actually experiencing the refault event.
+        */
+       memcg = page_memcg(page);
+       lruvec = mem_cgroup_lruvec(memcg, pgdat);
+
        inc_lruvec_state(lruvec, WORKINGSET_REFAULT);
 
        /*
@@ -313,7 +352,7 @@ void workingset_refault(struct page *page, void *shadow)
                goto out;
 
        SetPageActive(page);
-       atomic_long_inc(&lruvec->inactive_age);
+       advance_inactive_age(memcg, pgdat);
        inc_lruvec_state(lruvec, WORKINGSET_ACTIVATE);
 
        /* Page was active prior to eviction */
@@ -332,7 +371,6 @@ out:
 void workingset_activation(struct page *page)
 {
        struct mem_cgroup *memcg;
-       struct lruvec *lruvec;
 
        rcu_read_lock();
        /*
@@ -345,8 +383,7 @@ void workingset_activation(struct page *page)
        memcg = page_memcg_rcu(page);
        if (!mem_cgroup_disabled() && !memcg)
                goto out;
-       lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
-       atomic_long_inc(&lruvec->inactive_age);
+       advance_inactive_age(memcg, page_pgdat(page));
 out:
        rcu_read_unlock();
 }
@@ -426,7 +463,7 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
                struct lruvec *lruvec;
                int i;
 
-               lruvec = mem_cgroup_lruvec(NODE_DATA(sc->nid), sc->memcg);
+               lruvec = mem_cgroup_lruvec(sc->memcg, NODE_DATA(sc->nid));
                for (pages = 0, i = 0; i < NR_LRU_LISTS; i++)
                        pages += lruvec_page_state_local(lruvec,
                                                         NR_LRU_BASE + i);
index 6d3d3f6..43754d8 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/rwlock.h>
 #include <linux/zpool.h>
 #include <linux/magic.h>
 
@@ -90,6 +91,7 @@ struct z3fold_buddy_slots {
         */
        unsigned long slot[BUDDY_MASK + 1];
        unsigned long pool; /* back link + flags */
+       rwlock_t lock;
 };
 #define HANDLE_FLAG_MASK       (0x03)
 
@@ -124,6 +126,7 @@ struct z3fold_header {
        unsigned short start_middle;
        unsigned short first_num:2;
        unsigned short mapped_count:2;
+       unsigned short foreign_handles:2;
 };
 
 /**
@@ -178,6 +181,19 @@ enum z3fold_page_flags {
        PAGE_CLAIMED, /* by either reclaim or free */
 };
 
+/*
+ * handle flags, go under HANDLE_FLAG_MASK
+ */
+enum z3fold_handle_flags {
+       HANDLES_ORPHANED = 0,
+};
+
+/*
+ * Forward declarations
+ */
+static struct z3fold_header *__z3fold_alloc(struct z3fold_pool *, size_t, bool);
+static void compact_page_work(struct work_struct *w);
+
 /*****************
  * Helpers
 *****************/
@@ -191,8 +207,6 @@ static int size_to_chunks(size_t size)
 #define for_each_unbuddied_list(_iter, _begin) \
        for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++)
 
-static void compact_page_work(struct work_struct *w);
-
 static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool,
                                                        gfp_t gfp)
 {
@@ -204,6 +218,7 @@ static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool,
        if (slots) {
                memset(slots->slot, 0, sizeof(slots->slot));
                slots->pool = (unsigned long)pool;
+               rwlock_init(&slots->lock);
        }
 
        return slots;
@@ -219,25 +234,110 @@ static inline struct z3fold_buddy_slots *handle_to_slots(unsigned long handle)
        return (struct z3fold_buddy_slots *)(handle & ~(SLOTS_ALIGN - 1));
 }
 
+/* Lock a z3fold page */
+static inline void z3fold_page_lock(struct z3fold_header *zhdr)
+{
+       spin_lock(&zhdr->page_lock);
+}
+
+/* Try to lock a z3fold page */
+static inline int z3fold_page_trylock(struct z3fold_header *zhdr)
+{
+       return spin_trylock(&zhdr->page_lock);
+}
+
+/* Unlock a z3fold page */
+static inline void z3fold_page_unlock(struct z3fold_header *zhdr)
+{
+       spin_unlock(&zhdr->page_lock);
+}
+
+
+static inline struct z3fold_header *__get_z3fold_header(unsigned long handle,
+                                                       bool lock)
+{
+       struct z3fold_buddy_slots *slots;
+       struct z3fold_header *zhdr;
+       int locked = 0;
+
+       if (!(handle & (1 << PAGE_HEADLESS))) {
+               slots = handle_to_slots(handle);
+               do {
+                       unsigned long addr;
+
+                       read_lock(&slots->lock);
+                       addr = *(unsigned long *)handle;
+                       zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
+                       if (lock)
+                               locked = z3fold_page_trylock(zhdr);
+                       read_unlock(&slots->lock);
+                       if (locked)
+                               break;
+                       cpu_relax();
+               } while (lock);
+       } else {
+               zhdr = (struct z3fold_header *)(handle & PAGE_MASK);
+       }
+
+       return zhdr;
+}
+
+/* Returns the z3fold page where a given handle is stored */
+static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
+{
+       return __get_z3fold_header(h, false);
+}
+
+/* return locked z3fold page if it's not headless */
+static inline struct z3fold_header *get_z3fold_header(unsigned long h)
+{
+       return __get_z3fold_header(h, true);
+}
+
+static inline void put_z3fold_header(struct z3fold_header *zhdr)
+{
+       struct page *page = virt_to_page(zhdr);
+
+       if (!test_bit(PAGE_HEADLESS, &page->private))
+               z3fold_page_unlock(zhdr);
+}
+
 static inline void free_handle(unsigned long handle)
 {
        struct z3fold_buddy_slots *slots;
+       struct z3fold_header *zhdr;
        int i;
        bool is_free;
 
        if (handle & (1 << PAGE_HEADLESS))
                return;
 
-       WARN_ON(*(unsigned long *)handle == 0);
-       *(unsigned long *)handle = 0;
+       if (WARN_ON(*(unsigned long *)handle == 0))
+               return;
+
+       zhdr = handle_to_z3fold_header(handle);
        slots = handle_to_slots(handle);
+       write_lock(&slots->lock);
+       *(unsigned long *)handle = 0;
+       write_unlock(&slots->lock);
+       if (zhdr->slots == slots)
+               return; /* simple case, nothing else to do */
+
+       /* we are freeing a foreign handle if we are here */
+       zhdr->foreign_handles--;
        is_free = true;
+       read_lock(&slots->lock);
+       if (!test_bit(HANDLES_ORPHANED, &slots->pool)) {
+               read_unlock(&slots->lock);
+               return;
+       }
        for (i = 0; i <= BUDDY_MASK; i++) {
                if (slots->slot[i]) {
                        is_free = false;
                        break;
                }
        }
+       read_unlock(&slots->lock);
 
        if (is_free) {
                struct z3fold_pool *pool = slots_to_pool(slots);
@@ -322,6 +422,7 @@ static struct z3fold_header *init_z3fold_page(struct page *page, bool headless,
        zhdr->first_num = 0;
        zhdr->start_middle = 0;
        zhdr->cpu = -1;
+       zhdr->foreign_handles = 0;
        zhdr->slots = slots;
        zhdr->pool = pool;
        INIT_LIST_HEAD(&zhdr->buddy);
@@ -341,24 +442,6 @@ static void free_z3fold_page(struct page *page, bool headless)
        __free_page(page);
 }
 
-/* Lock a z3fold page */
-static inline void z3fold_page_lock(struct z3fold_header *zhdr)
-{
-       spin_lock(&zhdr->page_lock);
-}
-
-/* Try to lock a z3fold page */
-static inline int z3fold_page_trylock(struct z3fold_header *zhdr)
-{
-       return spin_trylock(&zhdr->page_lock);
-}
-
-/* Unlock a z3fold page */
-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)
 {
@@ -389,7 +472,9 @@ static unsigned long __encode_handle(struct z3fold_header *zhdr,
        if (bud == LAST)
                h |= (zhdr->last_chunks << BUDDY_SHIFT);
 
+       write_lock(&slots->lock);
        slots->slot[idx] = h;
+       write_unlock(&slots->lock);
        return (unsigned long)&slots->slot[idx];
 }
 
@@ -398,22 +483,15 @@ static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
        return __encode_handle(zhdr, zhdr->slots, bud);
 }
 
-/* Returns the z3fold page where a given handle is stored */
-static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
-{
-       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)
 {
-       unsigned long addr = *(unsigned long *)handle;
+       struct z3fold_buddy_slots *slots = handle_to_slots(handle);
+       unsigned long addr;
 
+       read_lock(&slots->lock);
+       addr = *(unsigned long *)handle;
+       read_unlock(&slots->lock);
        return (addr & ~PAGE_MASK) >> BUDDY_SHIFT;
 }
 
@@ -425,10 +503,13 @@ static unsigned short handle_to_chunks(unsigned long handle)
 static enum buddy handle_to_buddy(unsigned long handle)
 {
        struct z3fold_header *zhdr;
+       struct z3fold_buddy_slots *slots = handle_to_slots(handle);
        unsigned long addr;
 
+       read_lock(&slots->lock);
        WARN_ON(handle & (1 << PAGE_HEADLESS));
        addr = *(unsigned long *)handle;
+       read_unlock(&slots->lock);
        zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
        return (addr - zhdr->first_num) & BUDDY_MASK;
 }
@@ -442,6 +523,8 @@ static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
 {
        struct page *page = virt_to_page(zhdr);
        struct z3fold_pool *pool = zhdr_to_pool(zhdr);
+       bool is_free = true;
+       int i;
 
        WARN_ON(!list_empty(&zhdr->buddy));
        set_bit(PAGE_STALE, &page->private);
@@ -450,8 +533,25 @@ static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
        if (!list_empty(&page->lru))
                list_del_init(&page->lru);
        spin_unlock(&pool->lock);
+
+       /* If there are no foreign handles, free the handles array */
+       read_lock(&zhdr->slots->lock);
+       for (i = 0; i <= BUDDY_MASK; i++) {
+               if (zhdr->slots->slot[i]) {
+                       is_free = false;
+                       break;
+               }
+       }
+       if (!is_free)
+               set_bit(HANDLES_ORPHANED, &zhdr->slots->pool);
+       read_unlock(&zhdr->slots->lock);
+
+       if (is_free)
+               kmem_cache_free(pool->c_handle, zhdr->slots);
+
        if (locked)
                z3fold_page_unlock(zhdr);
+
        spin_lock(&pool->stale_lock);
        list_add(&zhdr->buddy, &pool->stale);
        queue_work(pool->release_wq, &pool->work);
@@ -479,6 +579,7 @@ static void release_z3fold_page_locked_list(struct kref *ref)
        struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
                                               refcount);
        struct z3fold_pool *pool = zhdr_to_pool(zhdr);
+
        spin_lock(&pool->lock);
        list_del_init(&zhdr->buddy);
        spin_unlock(&pool->lock);
@@ -559,6 +660,119 @@ static inline void *mchunk_memmove(struct z3fold_header *zhdr,
                       zhdr->middle_chunks << CHUNK_SHIFT);
 }
 
+static inline bool buddy_single(struct z3fold_header *zhdr)
+{
+       return !((zhdr->first_chunks && zhdr->middle_chunks) ||
+                       (zhdr->first_chunks && zhdr->last_chunks) ||
+                       (zhdr->middle_chunks && zhdr->last_chunks));
+}
+
+static struct z3fold_header *compact_single_buddy(struct z3fold_header *zhdr)
+{
+       struct z3fold_pool *pool = zhdr_to_pool(zhdr);
+       void *p = zhdr;
+       unsigned long old_handle = 0;
+       size_t sz = 0;
+       struct z3fold_header *new_zhdr = NULL;
+       int first_idx = __idx(zhdr, FIRST);
+       int middle_idx = __idx(zhdr, MIDDLE);
+       int last_idx = __idx(zhdr, LAST);
+       unsigned short *moved_chunks = NULL;
+
+       /*
+        * No need to protect slots here -- all the slots are "local" and
+        * the page lock is already taken
+        */
+       if (zhdr->first_chunks && zhdr->slots->slot[first_idx]) {
+               p += ZHDR_SIZE_ALIGNED;
+               sz = zhdr->first_chunks << CHUNK_SHIFT;
+               old_handle = (unsigned long)&zhdr->slots->slot[first_idx];
+               moved_chunks = &zhdr->first_chunks;
+       } else if (zhdr->middle_chunks && zhdr->slots->slot[middle_idx]) {
+               p += zhdr->start_middle << CHUNK_SHIFT;
+               sz = zhdr->middle_chunks << CHUNK_SHIFT;
+               old_handle = (unsigned long)&zhdr->slots->slot[middle_idx];
+               moved_chunks = &zhdr->middle_chunks;
+       } else if (zhdr->last_chunks && zhdr->slots->slot[last_idx]) {
+               p += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT);
+               sz = zhdr->last_chunks << CHUNK_SHIFT;
+               old_handle = (unsigned long)&zhdr->slots->slot[last_idx];
+               moved_chunks = &zhdr->last_chunks;
+       }
+
+       if (sz > 0) {
+               enum buddy new_bud = HEADLESS;
+               short chunks = size_to_chunks(sz);
+               void *q;
+
+               new_zhdr = __z3fold_alloc(pool, sz, false);
+               if (!new_zhdr)
+                       return NULL;
+
+               if (WARN_ON(new_zhdr == zhdr))
+                       goto out_fail;
+
+               if (new_zhdr->first_chunks == 0) {
+                       if (new_zhdr->middle_chunks != 0 &&
+                                       chunks >= new_zhdr->start_middle) {
+                               new_bud = LAST;
+                       } else {
+                               new_bud = FIRST;
+                       }
+               } else if (new_zhdr->last_chunks == 0) {
+                       new_bud = LAST;
+               } else if (new_zhdr->middle_chunks == 0) {
+                       new_bud = MIDDLE;
+               }
+               q = new_zhdr;
+               switch (new_bud) {
+               case FIRST:
+                       new_zhdr->first_chunks = chunks;
+                       q += ZHDR_SIZE_ALIGNED;
+                       break;
+               case MIDDLE:
+                       new_zhdr->middle_chunks = chunks;
+                       new_zhdr->start_middle =
+                               new_zhdr->first_chunks + ZHDR_CHUNKS;
+                       q += new_zhdr->start_middle << CHUNK_SHIFT;
+                       break;
+               case LAST:
+                       new_zhdr->last_chunks = chunks;
+                       q += PAGE_SIZE - (new_zhdr->last_chunks << CHUNK_SHIFT);
+                       break;
+               default:
+                       goto out_fail;
+               }
+               new_zhdr->foreign_handles++;
+               memcpy(q, p, sz);
+               write_lock(&zhdr->slots->lock);
+               *(unsigned long *)old_handle = (unsigned long)new_zhdr +
+                       __idx(new_zhdr, new_bud);
+               if (new_bud == LAST)
+                       *(unsigned long *)old_handle |=
+                                       (new_zhdr->last_chunks << BUDDY_SHIFT);
+               write_unlock(&zhdr->slots->lock);
+               add_to_unbuddied(pool, new_zhdr);
+               z3fold_page_unlock(new_zhdr);
+
+               *moved_chunks = 0;
+       }
+
+       return new_zhdr;
+
+out_fail:
+       if (new_zhdr) {
+               if (kref_put(&new_zhdr->refcount, release_z3fold_page_locked))
+                       atomic64_dec(&pool->pages_nr);
+               else {
+                       add_to_unbuddied(pool, new_zhdr);
+                       z3fold_page_unlock(new_zhdr);
+               }
+       }
+       return NULL;
+
+}
+
 #define BIG_CHUNK_GAP  3
 /* Has to be called with lock held */
 static int z3fold_compact_page(struct z3fold_header *zhdr)
@@ -638,6 +852,15 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked)
                return;
        }
 
+       if (!zhdr->foreign_handles && buddy_single(zhdr) &&
+           zhdr->mapped_count == 0 && compact_single_buddy(zhdr)) {
+               if (kref_put(&zhdr->refcount, release_z3fold_page_locked))
+                       atomic64_dec(&pool->pages_nr);
+               else
+                       z3fold_page_unlock(zhdr);
+               return;
+       }
+
        z3fold_compact_page(zhdr);
        add_to_unbuddied(pool, zhdr);
        z3fold_page_unlock(zhdr);
@@ -690,7 +913,8 @@ lookup:
                spin_unlock(&pool->lock);
 
                page = virt_to_page(zhdr);
-               if (test_bit(NEEDS_COMPACTING, &page->private)) {
+               if (test_bit(NEEDS_COMPACTING, &page->private) ||
+                   test_bit(PAGE_CLAIMED, &page->private)) {
                        z3fold_page_unlock(zhdr);
                        zhdr = NULL;
                        put_cpu_ptr(pool->unbuddied);
@@ -734,7 +958,8 @@ lookup:
                        spin_unlock(&pool->lock);
 
                        page = virt_to_page(zhdr);
-                       if (test_bit(NEEDS_COMPACTING, &page->private)) {
+                       if (test_bit(NEEDS_COMPACTING, &page->private) ||
+                           test_bit(PAGE_CLAIMED, &page->private)) {
                                z3fold_page_unlock(zhdr);
                                zhdr = NULL;
                                if (can_sleep)
@@ -1000,7 +1225,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
        enum buddy bud;
        bool page_claimed;
 
-       zhdr = handle_to_z3fold_header(handle);
+       zhdr = get_z3fold_header(handle);
        page = virt_to_page(zhdr);
        page_claimed = test_and_set_bit(PAGE_CLAIMED, &page->private);
 
@@ -1014,6 +1239,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
                        spin_lock(&pool->lock);
                        list_del(&page->lru);
                        spin_unlock(&pool->lock);
+                       put_z3fold_header(zhdr);
                        free_z3fold_page(page, true);
                        atomic64_dec(&pool->pages_nr);
                }
@@ -1021,7 +1247,6 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
        }
 
        /* Non-headless case */
-       z3fold_page_lock(zhdr);
        bud = handle_to_buddy(handle);
 
        switch (bud) {
@@ -1037,11 +1262,13 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
        default:
                pr_err("%s: unknown bud %d\n", __func__, bud);
                WARN_ON(1);
-               z3fold_page_unlock(zhdr);
+               put_z3fold_header(zhdr);
+               clear_bit(PAGE_CLAIMED, &page->private);
                return;
        }
 
-       free_handle(handle);
+       if (!page_claimed)
+               free_handle(handle);
        if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list)) {
                atomic64_dec(&pool->pages_nr);
                return;
@@ -1053,7 +1280,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
        }
        if (unlikely(PageIsolated(page)) ||
            test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
-               z3fold_page_unlock(zhdr);
+               put_z3fold_header(zhdr);
                clear_bit(PAGE_CLAIMED, &page->private);
                return;
        }
@@ -1063,14 +1290,14 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
                spin_unlock(&pool->lock);
                zhdr->cpu = -1;
                kref_get(&zhdr->refcount);
-               do_compact_page(zhdr, true);
                clear_bit(PAGE_CLAIMED, &page->private);
+               do_compact_page(zhdr, true);
                return;
        }
        kref_get(&zhdr->refcount);
-       queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work);
        clear_bit(PAGE_CLAIMED, &page->private);
-       z3fold_page_unlock(zhdr);
+       queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work);
+       put_z3fold_header(zhdr);
 }
 
 /**
@@ -1111,11 +1338,10 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
  */
 static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
 {
-       int i, ret = 0;
+       int i, ret = -1;
        struct z3fold_header *zhdr = NULL;
        struct page *page = NULL;
        struct list_head *pos;
-       struct z3fold_buddy_slots slots;
        unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
 
        spin_lock(&pool->lock);
@@ -1153,6 +1379,12 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
                                zhdr = NULL;
                                continue; /* can't evict at this point */
                        }
+                       if (zhdr->foreign_handles) {
+                               clear_bit(PAGE_CLAIMED, &page->private);
+                               z3fold_page_unlock(zhdr);
+                               zhdr = NULL;
+                               continue; /* can't evict such page */
+                       }
                        kref_get(&zhdr->refcount);
                        list_del_init(&zhdr->buddy);
                        zhdr->cpu = -1;
@@ -1176,39 +1408,38 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
                        last_handle = 0;
                        middle_handle = 0;
                        if (zhdr->first_chunks)
-                               first_handle = __encode_handle(zhdr, &slots,
-                                                               FIRST);
+                               first_handle = encode_handle(zhdr, FIRST);
                        if (zhdr->middle_chunks)
-                               middle_handle = __encode_handle(zhdr, &slots,
-                                                               MIDDLE);
+                               middle_handle = encode_handle(zhdr, MIDDLE);
                        if (zhdr->last_chunks)
-                               last_handle = __encode_handle(zhdr, &slots,
-                                                               LAST);
+                               last_handle = encode_handle(zhdr, LAST);
                        /*
                         * it's safe to unlock here because we hold a
                         * reference to this page
                         */
                        z3fold_page_unlock(zhdr);
                } else {
-                       first_handle = __encode_handle(zhdr, &slots, HEADLESS);
+                       first_handle = encode_handle(zhdr, HEADLESS);
                        last_handle = middle_handle = 0;
                }
-
                /* Issue the eviction callback(s) */
                if (middle_handle) {
                        ret = pool->ops->evict(pool, middle_handle);
                        if (ret)
                                goto next;
+                       free_handle(middle_handle);
                }
                if (first_handle) {
                        ret = pool->ops->evict(pool, first_handle);
                        if (ret)
                                goto next;
+                       free_handle(first_handle);
                }
                if (last_handle) {
                        ret = pool->ops->evict(pool, last_handle);
                        if (ret)
                                goto next;
+                       free_handle(last_handle);
                }
 next:
                if (test_bit(PAGE_HEADLESS, &page->private)) {
@@ -1264,14 +1495,13 @@ static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
        void *addr;
        enum buddy buddy;
 
-       zhdr = handle_to_z3fold_header(handle);
+       zhdr = get_z3fold_header(handle);
        addr = zhdr;
        page = virt_to_page(zhdr);
 
        if (test_bit(PAGE_HEADLESS, &page->private))
                goto out;
 
-       z3fold_page_lock(zhdr);
        buddy = handle_to_buddy(handle);
        switch (buddy) {
        case FIRST:
@@ -1293,8 +1523,8 @@ static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
 
        if (addr)
                zhdr->mapped_count++;
-       z3fold_page_unlock(zhdr);
 out:
+       put_z3fold_header(zhdr);
        return addr;
 }
 
@@ -1309,18 +1539,17 @@ static void z3fold_unmap(struct z3fold_pool *pool, unsigned long handle)
        struct page *page;
        enum buddy buddy;
 
-       zhdr = handle_to_z3fold_header(handle);
+       zhdr = get_z3fold_header(handle);
        page = virt_to_page(zhdr);
 
        if (test_bit(PAGE_HEADLESS, &page->private))
                return;
 
-       z3fold_page_lock(zhdr);
        buddy = handle_to_buddy(handle);
        if (buddy == MIDDLE)
                clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
        zhdr->mapped_count--;
-       z3fold_page_unlock(zhdr);
+       put_z3fold_header(zhdr);
 }
 
 /**
@@ -1352,19 +1581,21 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
            test_bit(PAGE_STALE, &page->private))
                goto out;
 
+       if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0)
+               goto out;
+
        pool = zhdr_to_pool(zhdr);
+       spin_lock(&pool->lock);
+       if (!list_empty(&zhdr->buddy))
+               list_del_init(&zhdr->buddy);
+       if (!list_empty(&page->lru))
+               list_del_init(&page->lru);
+       spin_unlock(&pool->lock);
+
+       kref_get(&zhdr->refcount);
+       z3fold_page_unlock(zhdr);
+       return true;
 
-       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;
@@ -1387,7 +1618,7 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
        if (!z3fold_page_trylock(zhdr)) {
                return -EAGAIN;
        }
-       if (zhdr->mapped_count != 0) {
+       if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0) {
                z3fold_page_unlock(zhdr);
                return -EBUSY;
        }
index 2d56824..a9d6c97 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/nsproxy.h>
-#include <linux/parser.h>
+#include <linux/fs_parser.h>
 #include <linux/sched.h>
 #include <linux/sched/mm.h>
 #include <linux/seq_file.h>
@@ -254,58 +254,77 @@ enum {
        Opt_mount_timeout,
        Opt_osd_idle_ttl,
        Opt_osd_request_timeout,
-       Opt_last_int,
        /* int args above */
        Opt_fsid,
        Opt_name,
        Opt_secret,
        Opt_key,
        Opt_ip,
-       Opt_last_string,
        /* string args above */
        Opt_share,
-       Opt_noshare,
        Opt_crc,
-       Opt_nocrc,
        Opt_cephx_require_signatures,
-       Opt_nocephx_require_signatures,
        Opt_cephx_sign_messages,
-       Opt_nocephx_sign_messages,
        Opt_tcp_nodelay,
-       Opt_notcp_nodelay,
        Opt_abort_on_full,
 };
 
-static match_table_t opt_tokens = {
-       {Opt_osdtimeout, "osdtimeout=%d"},
-       {Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
-       {Opt_mount_timeout, "mount_timeout=%d"},
-       {Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
-       {Opt_osd_request_timeout, "osd_request_timeout=%d"},
-       /* int args above */
-       {Opt_fsid, "fsid=%s"},
-       {Opt_name, "name=%s"},
-       {Opt_secret, "secret=%s"},
-       {Opt_key, "key=%s"},
-       {Opt_ip, "ip=%s"},
-       /* string args above */
-       {Opt_share, "share"},
-       {Opt_noshare, "noshare"},
-       {Opt_crc, "crc"},
-       {Opt_nocrc, "nocrc"},
-       {Opt_cephx_require_signatures, "cephx_require_signatures"},
-       {Opt_nocephx_require_signatures, "nocephx_require_signatures"},
-       {Opt_cephx_sign_messages, "cephx_sign_messages"},
-       {Opt_nocephx_sign_messages, "nocephx_sign_messages"},
-       {Opt_tcp_nodelay, "tcp_nodelay"},
-       {Opt_notcp_nodelay, "notcp_nodelay"},
-       {Opt_abort_on_full, "abort_on_full"},
-       {-1, NULL}
+static const struct fs_parameter_spec ceph_param_specs[] = {
+       fsparam_flag    ("abort_on_full",               Opt_abort_on_full),
+       fsparam_flag_no ("cephx_require_signatures",    Opt_cephx_require_signatures),
+       fsparam_flag_no ("cephx_sign_messages",         Opt_cephx_sign_messages),
+       fsparam_flag_no ("crc",                         Opt_crc),
+       fsparam_string  ("fsid",                        Opt_fsid),
+       fsparam_string  ("ip",                          Opt_ip),
+       fsparam_string  ("key",                         Opt_key),
+       fsparam_u32     ("mount_timeout",               Opt_mount_timeout),
+       fsparam_string  ("name",                        Opt_name),
+       fsparam_u32     ("osd_idle_ttl",                Opt_osd_idle_ttl),
+       fsparam_u32     ("osd_request_timeout",         Opt_osd_request_timeout),
+       fsparam_u32     ("osdkeepalive",                Opt_osdkeepalivetimeout),
+       __fsparam       (fs_param_is_s32, "osdtimeout", Opt_osdtimeout,
+                        fs_param_deprecated),
+       fsparam_string  ("secret",                      Opt_secret),
+       fsparam_flag_no ("share",                       Opt_share),
+       fsparam_flag_no ("tcp_nodelay",                 Opt_tcp_nodelay),
+       {}
+};
+
+static const struct fs_parameter_description ceph_parameters = {
+        .name           = "libceph",
+        .specs          = ceph_param_specs,
 };
 
+struct ceph_options *ceph_alloc_options(void)
+{
+       struct ceph_options *opt;
+
+       opt = kzalloc(sizeof(*opt), GFP_KERNEL);
+       if (!opt)
+               return NULL;
+
+       opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
+                               GFP_KERNEL);
+       if (!opt->mon_addr) {
+               kfree(opt);
+               return NULL;
+       }
+
+       opt->flags = CEPH_OPT_DEFAULT;
+       opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
+       opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
+       opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
+       opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT;
+       return opt;
+}
+EXPORT_SYMBOL(ceph_alloc_options);
+
 void ceph_destroy_options(struct ceph_options *opt)
 {
        dout("destroy_options %p\n", opt);
+       if (!opt)
+               return;
+
        kfree(opt->name);
        if (opt->key) {
                ceph_crypto_key_destroy(opt->key);
@@ -317,7 +336,9 @@ void ceph_destroy_options(struct ceph_options *opt)
 EXPORT_SYMBOL(ceph_destroy_options);
 
 /* get secret from key store */
-static int get_secret(struct ceph_crypto_key *dst, const char *name) {
+static int get_secret(struct ceph_crypto_key *dst, const char *name,
+                     struct fs_context *fc)
+{
        struct key *ukey;
        int key_err;
        int err = 0;
@@ -330,20 +351,20 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name) {
                key_err = PTR_ERR(ukey);
                switch (key_err) {
                case -ENOKEY:
-                       pr_warn("ceph: Mount failed due to key not found: %s\n",
-                               name);
+                       errorf(fc, "libceph: Failed due to key not found: %s",
+                              name);
                        break;
                case -EKEYEXPIRED:
-                       pr_warn("ceph: Mount failed due to expired key: %s\n",
-                               name);
+                       errorf(fc, "libceph: Failed due to expired key: %s",
+                              name);
                        break;
                case -EKEYREVOKED:
-                       pr_warn("ceph: Mount failed due to revoked key: %s\n",
-                               name);
+                       errorf(fc, "libceph: Failed due to revoked key: %s",
+                              name);
                        break;
                default:
-                       pr_warn("ceph: Mount failed due to unknown key error %d: %s\n",
-                               key_err, name);
+                       errorf(fc, "libceph: Failed due to key error %d: %s",
+                              key_err, name);
                }
                err = -EPERM;
                goto out;
@@ -361,217 +382,157 @@ out:
        return err;
 }
 
-struct ceph_options *
-ceph_parse_options(char *options, const char *dev_name,
-                       const char *dev_name_end,
-                       int (*parse_extra_token)(char *c, void *private),
-                       void *private)
+int ceph_parse_mon_ips(const char *buf, size_t len, struct ceph_options *opt,
+                      struct fs_context *fc)
 {
-       struct ceph_options *opt;
-       const char *c;
-       int err = -ENOMEM;
-       substring_t argstr[MAX_OPT_ARGS];
-
-       opt = kzalloc(sizeof(*opt), GFP_KERNEL);
-       if (!opt)
-               return ERR_PTR(-ENOMEM);
-       opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
-                               GFP_KERNEL);
-       if (!opt->mon_addr)
-               goto out;
-
-       dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
-            dev_name);
-
-       /* start with defaults */
-       opt->flags = CEPH_OPT_DEFAULT;
-       opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
-       opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
-       opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
-       opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT;
+       int ret;
 
-       /* get mon ip(s) */
        /* ip1[:port1][,ip2[:port2]...] */
-       err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
-                            CEPH_MAX_MON, &opt->num_mon);
-       if (err < 0)
-               goto out;
+       ret = ceph_parse_ips(buf, buf + len, opt->mon_addr, CEPH_MAX_MON,
+                            &opt->num_mon);
+       if (ret) {
+               errorf(fc, "libceph: Failed to parse monitor IPs: %d", ret);
+               return ret;
+       }
 
-       /* parse mount options */
-       while ((c = strsep(&options, ",")) != NULL) {
-               int token, intval;
-               if (!*c)
-                       continue;
-               err = -EINVAL;
-               token = match_token((char *)c, opt_tokens, argstr);
-               if (token < 0 && parse_extra_token) {
-                       /* extra? */
-                       err = parse_extra_token((char *)c, private);
-                       if (err < 0) {
-                               pr_err("bad option at '%s'\n", c);
-                               goto out;
-                       }
-                       continue;
-               }
-               if (token < Opt_last_int) {
-                       err = match_int(&argstr[0], &intval);
-                       if (err < 0) {
-                               pr_err("bad option arg (not int) at '%s'\n", c);
-                               goto out;
-                       }
-                       dout("got int token %d val %d\n", token, intval);
-               } else if (token > Opt_last_int && token < Opt_last_string) {
-                       dout("got string token %d val %s\n", token,
-                            argstr[0].from);
-               } else {
-                       dout("got token %d\n", token);
+       return 0;
+}
+EXPORT_SYMBOL(ceph_parse_mon_ips);
+
+int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt,
+                    struct fs_context *fc)
+{
+       struct fs_parse_result result;
+       int token, err;
+
+       token = fs_parse(fc, &ceph_parameters, param, &result);
+       dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
+       if (token < 0)
+               return token;
+
+       switch (token) {
+       case Opt_ip:
+               err = ceph_parse_ips(param->string,
+                                    param->string + param->size,
+                                    &opt->my_addr,
+                                    1, NULL);
+               if (err) {
+                       errorf(fc, "libceph: Failed to parse ip: %d", err);
+                       return err;
                }
-               switch (token) {
-               case Opt_ip:
-                       err = ceph_parse_ips(argstr[0].from,
-                                            argstr[0].to,
-                                            &opt->my_addr,
-                                            1, NULL);
-                       if (err < 0)
-                               goto out;
-                       opt->flags |= CEPH_OPT_MYIP;
-                       break;
+               opt->flags |= CEPH_OPT_MYIP;
+               break;
 
-               case Opt_fsid:
-                       err = parse_fsid(argstr[0].from, &opt->fsid);
-                       if (err == 0)
-                               opt->flags |= CEPH_OPT_FSID;
-                       break;
-               case Opt_name:
-                       kfree(opt->name);
-                       opt->name = kstrndup(argstr[0].from,
-                                             argstr[0].to-argstr[0].from,
-                                             GFP_KERNEL);
-                       if (!opt->name) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       break;
-               case Opt_secret:
-                       ceph_crypto_key_destroy(opt->key);
-                       kfree(opt->key);
-
-                       opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
-                       if (!opt->key) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       err = ceph_crypto_key_unarmor(opt->key, argstr[0].from);
-                       if (err < 0)
-                               goto out;
-                       break;
-               case Opt_key:
-                       ceph_crypto_key_destroy(opt->key);
-                       kfree(opt->key);
-
-                       opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
-                       if (!opt->key) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       err = get_secret(opt->key, argstr[0].from);
-                       if (err < 0)
-                               goto out;
-                       break;
+       case Opt_fsid:
+               err = parse_fsid(param->string, &opt->fsid);
+               if (err) {
+                       errorf(fc, "libceph: Failed to parse fsid: %d", err);
+                       return err;
+               }
+               opt->flags |= CEPH_OPT_FSID;
+               break;
+       case Opt_name:
+               kfree(opt->name);
+               opt->name = param->string;
+               param->string = NULL;
+               break;
+       case Opt_secret:
+               ceph_crypto_key_destroy(opt->key);
+               kfree(opt->key);
 
-                       /* misc */
-               case Opt_osdtimeout:
-                       pr_warn("ignoring deprecated osdtimeout option\n");
-                       break;
-               case Opt_osdkeepalivetimeout:
-                       /* 0 isn't well defined right now, reject it */
-                       if (intval < 1 || intval > INT_MAX / 1000) {
-                               pr_err("osdkeepalive out of range\n");
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       opt->osd_keepalive_timeout =
-                                       msecs_to_jiffies(intval * 1000);
-                       break;
-               case Opt_osd_idle_ttl:
-                       /* 0 isn't well defined right now, reject it */
-                       if (intval < 1 || intval > INT_MAX / 1000) {
-                               pr_err("osd_idle_ttl out of range\n");
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       opt->osd_idle_ttl = msecs_to_jiffies(intval * 1000);
-                       break;
-               case Opt_mount_timeout:
-                       /* 0 is "wait forever" (i.e. infinite timeout) */
-                       if (intval < 0 || intval > INT_MAX / 1000) {
-                               pr_err("mount_timeout out of range\n");
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       opt->mount_timeout = msecs_to_jiffies(intval * 1000);
-                       break;
-               case Opt_osd_request_timeout:
-                       /* 0 is "wait forever" (i.e. infinite timeout) */
-                       if (intval < 0 || intval > INT_MAX / 1000) {
-                               pr_err("osd_request_timeout out of range\n");
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       opt->osd_request_timeout = msecs_to_jiffies(intval * 1000);
-                       break;
+               opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+               if (!opt->key)
+                       return -ENOMEM;
+               err = ceph_crypto_key_unarmor(opt->key, param->string);
+               if (err) {
+                       errorf(fc, "libceph: Failed to parse secret: %d", err);
+                       return err;
+               }
+               break;
+       case Opt_key:
+               ceph_crypto_key_destroy(opt->key);
+               kfree(opt->key);
 
-               case Opt_share:
+               opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+               if (!opt->key)
+                       return -ENOMEM;
+               return get_secret(opt->key, param->string, fc);
+
+       case Opt_osdtimeout:
+               warnf(fc, "libceph: Ignoring osdtimeout");
+               break;
+       case Opt_osdkeepalivetimeout:
+               /* 0 isn't well defined right now, reject it */
+               if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000)
+                       goto out_of_range;
+               opt->osd_keepalive_timeout =
+                   msecs_to_jiffies(result.uint_32 * 1000);
+               break;
+       case Opt_osd_idle_ttl:
+               /* 0 isn't well defined right now, reject it */
+               if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000)
+                       goto out_of_range;
+               opt->osd_idle_ttl = msecs_to_jiffies(result.uint_32 * 1000);
+               break;
+       case Opt_mount_timeout:
+               /* 0 is "wait forever" (i.e. infinite timeout) */
+               if (result.uint_32 > INT_MAX / 1000)
+                       goto out_of_range;
+               opt->mount_timeout = msecs_to_jiffies(result.uint_32 * 1000);
+               break;
+       case Opt_osd_request_timeout:
+               /* 0 is "wait forever" (i.e. infinite timeout) */
+               if (result.uint_32 > INT_MAX / 1000)
+                       goto out_of_range;
+               opt->osd_request_timeout =
+                   msecs_to_jiffies(result.uint_32 * 1000);
+               break;
+
+       case Opt_share:
+               if (!result.negated)
                        opt->flags &= ~CEPH_OPT_NOSHARE;
-                       break;
-               case Opt_noshare:
+               else
                        opt->flags |= CEPH_OPT_NOSHARE;
-                       break;
-
-               case Opt_crc:
+               break;
+       case Opt_crc:
+               if (!result.negated)
                        opt->flags &= ~CEPH_OPT_NOCRC;
-                       break;
-               case Opt_nocrc:
+               else
                        opt->flags |= CEPH_OPT_NOCRC;
-                       break;
-
-               case Opt_cephx_require_signatures:
+               break;
+       case Opt_cephx_require_signatures:
+               if (!result.negated)
                        opt->flags &= ~CEPH_OPT_NOMSGAUTH;
-                       break;
-               case Opt_nocephx_require_signatures:
+               else
                        opt->flags |= CEPH_OPT_NOMSGAUTH;
-                       break;
-               case Opt_cephx_sign_messages:
+               break;
+       case Opt_cephx_sign_messages:
+               if (!result.negated)
                        opt->flags &= ~CEPH_OPT_NOMSGSIGN;
-                       break;
-               case Opt_nocephx_sign_messages:
+               else
                        opt->flags |= CEPH_OPT_NOMSGSIGN;
-                       break;
-
-               case Opt_tcp_nodelay:
+               break;
+       case Opt_tcp_nodelay:
+               if (!result.negated)
                        opt->flags |= CEPH_OPT_TCP_NODELAY;
-                       break;
-               case Opt_notcp_nodelay:
+               else
                        opt->flags &= ~CEPH_OPT_TCP_NODELAY;
-                       break;
+               break;
 
-               case Opt_abort_on_full:
-                       opt->flags |= CEPH_OPT_ABORT_ON_FULL;
-                       break;
+       case Opt_abort_on_full:
+               opt->flags |= CEPH_OPT_ABORT_ON_FULL;
+               break;
 
-               default:
-                       BUG_ON(token);
-               }
+       default:
+               BUG();
        }
 
-       /* success */
-       return opt;
+       return 0;
 
-out:
-       ceph_destroy_options(opt);
-       return ERR_PTR(err);
+out_of_range:
+       return invalf(fc, "libceph: %s out of range", param->key);
 }
-EXPORT_SYMBOL(ceph_parse_options);
+EXPORT_SYMBOL(ceph_parse_param);
 
 int ceph_print_client_options(struct seq_file *m, struct ceph_client *client,
                              bool show_all)
index e4cb3db..5b4bd82 100644 (file)
@@ -2004,10 +2004,8 @@ int ceph_parse_ips(const char *c, const char *end,
        return 0;
 
 bad:
-       pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c);
        return ret;
 }
-EXPORT_SYMBOL(ceph_parse_ips);
 
 static int process_banner(struct ceph_connection *con)
 {
index 7256c40..9d9e4e4 100644 (file)
@@ -1233,9 +1233,6 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
        struct ceph_mon_client *monc = con->private;
        int type = le16_to_cpu(msg->hdr.type);
 
-       if (!monc)
-               return;
-
        switch (type) {
        case CEPH_MSG_AUTH_REPLY:
                handle_auth_reply(monc, msg);
index b0ed048..f1e703e 100644 (file)
@@ -2299,7 +2299,7 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
        WARN_ON_ONCE(last_sge == first_sge);
        shift = last_sge > first_sge ?
                last_sge - first_sge - 1 :
-               MAX_SKB_FRAGS - first_sge + last_sge - 1;
+               NR_MSG_FRAG_IDS - first_sge + last_sge - 1;
        if (!shift)
                goto out;
 
@@ -2308,8 +2308,8 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
        do {
                u32 move_from;
 
-               if (i + shift >= MAX_MSG_FRAGS)
-                       move_from = i + shift - MAX_MSG_FRAGS;
+               if (i + shift >= NR_MSG_FRAG_IDS)
+                       move_from = i + shift - NR_MSG_FRAG_IDS;
                else
                        move_from = i + shift;
                if (move_from == msg->sg.end)
@@ -2323,7 +2323,7 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
        } while (1);
 
        msg->sg.end = msg->sg.end - shift > msg->sg.end ?
-                     msg->sg.end - shift + MAX_MSG_FRAGS :
+                     msg->sg.end - shift + NR_MSG_FRAG_IDS :
                      msg->sg.end - shift;
 out:
        msg->data = sg_virt(&msg->sg.data[first_sge]) + start - offset;
index a469d21..ded2d52 100644 (file)
@@ -421,7 +421,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
        copied = skb->len;
        msg->sg.start = 0;
        msg->sg.size = copied;
-       msg->sg.end = num_sge == MAX_MSG_FRAGS ? 0 : num_sge;
+       msg->sg.end = num_sge;
        msg->skb = skb;
 
        sk_psock_queue_msg(psock, msg);
index 8a56e09..e387051 100644 (file)
@@ -301,7 +301,7 @@ EXPORT_SYMBOL_GPL(tcp_bpf_sendmsg_redir);
 static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
                                struct sk_msg *msg, int *copied, int flags)
 {
-       bool cork = false, enospc = msg->sg.start == msg->sg.end;
+       bool cork = false, enospc = sk_msg_full(msg);
        struct sock *sk_redir;
        u32 tosend, delta = 0;
        int ret;
index 293d528..1047e80 100644 (file)
@@ -905,7 +905,10 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
        retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
                                        info->snd_portid, info->snd_seq, 0,
                                        cmd, ufid_flags);
-       BUG_ON(retval < 0);
+       if (WARN_ON_ONCE(retval < 0)) {
+               kfree_skb(skb);
+               skb = ERR_PTR(retval);
+       }
        return skb;
 }
 
@@ -1369,7 +1372,10 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
                                                     OVS_FLOW_CMD_DEL,
                                                     ufid_flags);
                        rcu_read_unlock();
-                       BUG_ON(err < 0);
+                       if (WARN_ON_ONCE(err < 0)) {
+                               kfree_skb(reply);
+                               goto out_free;
+                       }
 
                        ovs_notify(&dp_flow_genl_family, reply, info);
                } else {
@@ -1377,6 +1383,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+out_free:
        ovs_flow_free(flow, true);
        return 0;
 unlock:
index 0d57833..278c0b2 100644 (file)
@@ -245,7 +245,8 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
        struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
 
        sch = dev_queue->qdisc_sleeping;
-       if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 ||
+       if (gnet_stats_copy_basic(&sch->running, d, sch->cpu_bstats,
+                                 &sch->bstats) < 0 ||
            qdisc_qstats_copy(d, sch) < 0)
                return -1;
        return 0;
index 46980b8..0d0113a 100644 (file)
@@ -557,8 +557,8 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
                struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl);
 
                sch = dev_queue->qdisc_sleeping;
-               if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
-                                         d, NULL, &sch->bstats) < 0 ||
+               if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d,
+                                         sch->cpu_bstats, &sch->bstats) < 0 ||
                    qdisc_qstats_copy(d, sch) < 0)
                        return -1;
        }
index b2b7fdb..1330ad2 100644 (file)
@@ -339,7 +339,7 @@ static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
 
        cl_q = q->queues[cl - 1];
        if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
-                                 d, NULL, &cl_q->bstats) < 0 ||
+                                 d, cl_q->cpu_bstats, &cl_q->bstats) < 0 ||
            qdisc_qstats_copy(d, cl_q) < 0)
                return -1;
 
index 0f8fedb..18b884c 100644 (file)
@@ -356,7 +356,7 @@ static int prio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
 
        cl_q = q->queues[cl - 1];
        if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
-                                 d, NULL, &cl_q->bstats) < 0 ||
+                                 d, cl_q->cpu_bstats, &cl_q->bstats) < 0 ||
            qdisc_qstats_copy(d, cl_q) < 0)
                return -1;
 
index b71a39d..39e14d5 100644 (file)
@@ -51,7 +51,7 @@ static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list);
 
 int rpc_pipefs_notifier_register(struct notifier_block *nb)
 {
-       return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb);
+       return blocking_notifier_chain_register(&rpc_pipefs_notifier_list, nb);
 }
 EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register);
 
index a1c8d72..41688da 100644 (file)
@@ -532,7 +532,7 @@ static void __tipc_shutdown(struct socket *sock, int error)
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
        struct net *net = sock_net(sk);
-       long timeout = CONN_TIMEOUT_DEFAULT;
+       long timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
        u32 dnode = tsk_peer_node(tsk);
        struct sk_buff *skb;
 
@@ -540,12 +540,10 @@ static void __tipc_shutdown(struct socket *sock, int error)
        tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt &&
                                            !tsk_conn_cong(tsk)));
 
-       /* Push out unsent messages or remove if pending SYN */
-       skb = skb_peek(&sk->sk_write_queue);
-       if (skb && !msg_is_syn(buf_msg(skb)))
-               tipc_sk_push_backlog(tsk);
-       else
-               __skb_queue_purge(&sk->sk_write_queue);
+       /* Push out delayed messages if in Nagle mode */
+       tipc_sk_push_backlog(tsk);
+       /* Remove pending SYN */
+       __skb_queue_purge(&sk->sk_write_queue);
 
        /* Reject all unreceived messages, except on an active connection
         * (which disconnects locally & sends a 'FIN+' to peer).
@@ -1248,9 +1246,14 @@ static void tipc_sk_push_backlog(struct tipc_sock *tsk)
        struct sk_buff_head *txq = &tsk->sk.sk_write_queue;
        struct net *net = sock_net(&tsk->sk);
        u32 dnode = tsk_peer_node(tsk);
+       struct sk_buff *skb = skb_peek(txq);
        int rc;
 
-       if (skb_queue_empty(txq) || tsk->cong_link_cnt)
+       if (!skb || tsk->cong_link_cnt)
+               return;
+
+       /* Do not send SYN again after congestion */
+       if (msg_is_syn(buf_msg(skb)))
                return;
 
        tsk->snt_unacked += tsk->snd_backlog;
@@ -1447,8 +1450,10 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
        rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
        if (unlikely(rc != dlen))
                return rc;
-       if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue)))
+       if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue))) {
+               __skb_queue_purge(&pkts);
                return -ENOMEM;
+       }
 
        trace_tipc_sk_sendmsg(sk, skb_peek(&pkts), TIPC_DUMP_SK_SNDQ, " ");
        rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
@@ -2757,6 +2762,7 @@ static void tipc_sk_timeout(struct timer_list *t)
        if (sock_owned_by_user(sk)) {
                sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 20);
                bh_unlock_sock(sk);
+               sock_put(sk);
                return;
        }
 
index bdca31f..b3da6c5 100644 (file)
@@ -209,24 +209,15 @@ int tls_push_partial_record(struct sock *sk, struct tls_context *ctx,
        return tls_push_sg(sk, ctx, sg, offset, flags);
 }
 
-bool tls_free_partial_record(struct sock *sk, struct tls_context *ctx)
+void tls_free_partial_record(struct sock *sk, struct tls_context *ctx)
 {
        struct scatterlist *sg;
 
-       sg = ctx->partially_sent_record;
-       if (!sg)
-               return false;
-
-       while (1) {
+       for (sg = ctx->partially_sent_record; sg; sg = sg_next(sg)) {
                put_page(sg_page(sg));
                sk_mem_uncharge(sk, sg->length);
-
-               if (sg_is_last(sg))
-                       break;
-               sg++;
        }
        ctx->partially_sent_record = NULL;
-       return true;
 }
 
 static void tls_write_space(struct sock *sk)
index da9f9ce..2b2d0ba 100644 (file)
@@ -710,8 +710,7 @@ static int tls_push_record(struct sock *sk, int flags,
        }
 
        i = msg_pl->sg.start;
-       sg_chain(rec->sg_aead_in, 2, rec->inplace_crypto ?
-                &msg_en->sg.data[i] : &msg_pl->sg.data[i]);
+       sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]);
 
        i = msg_en->sg.end;
        sk_msg_iter_var_prev(i);
@@ -771,8 +770,14 @@ static int bpf_exec_tx_verdict(struct sk_msg *msg, struct sock *sk,
 
        policy = !(flags & MSG_SENDPAGE_NOPOLICY);
        psock = sk_psock_get(sk);
-       if (!psock || !policy)
-               return tls_push_record(sk, flags, record_type);
+       if (!psock || !policy) {
+               err = tls_push_record(sk, flags, record_type);
+               if (err) {
+                       *copied -= sk_msg_free(sk, msg);
+                       tls_free_open_rec(sk);
+               }
+               return err;
+       }
 more_data:
        enospc = sk_msg_full(msg);
        if (psock->eval == __SK_NONE) {
@@ -970,8 +975,6 @@ alloc_encrypted:
                        if (ret)
                                goto fallback_to_reg_send;
 
-                       rec->inplace_crypto = 0;
-
                        num_zc++;
                        copied += try_to_copy;
 
@@ -984,7 +987,7 @@ alloc_encrypted:
                                        num_async++;
                                else if (ret == -ENOMEM)
                                        goto wait_for_memory;
-                               else if (ret == -ENOSPC)
+                               else if (ctx->open_rec && ret == -ENOSPC)
                                        goto rollback_iter;
                                else if (ret != -EAGAIN)
                                        goto send_end;
@@ -1053,11 +1056,12 @@ wait_for_memory:
                ret = sk_stream_wait_memory(sk, &timeo);
                if (ret) {
 trim_sgl:
-                       tls_trim_both_msgs(sk, orig_size);
+                       if (ctx->open_rec)
+                               tls_trim_both_msgs(sk, orig_size);
                        goto send_end;
                }
 
-               if (msg_en->sg.size < required_size)
+               if (ctx->open_rec && msg_en->sg.size < required_size)
                        goto alloc_encrypted;
        }
 
@@ -1169,7 +1173,6 @@ alloc_payload:
 
                tls_ctx->pending_open_record_frags = true;
                if (full_record || eor || sk_msg_full(msg_pl)) {
-                       rec->inplace_crypto = 0;
                        ret = bpf_exec_tx_verdict(msg_pl, sk, full_record,
                                                  record_type, &copied, flags);
                        if (ret) {
@@ -1190,11 +1193,13 @@ wait_for_sndbuf:
 wait_for_memory:
                ret = sk_stream_wait_memory(sk, &timeo);
                if (ret) {
-                       tls_trim_both_msgs(sk, msg_pl->sg.size);
+                       if (ctx->open_rec)
+                               tls_trim_both_msgs(sk, msg_pl->sg.size);
                        goto sendpage_end;
                }
 
-               goto alloc_payload;
+               if (ctx->open_rec)
+                       goto alloc_payload;
        }
 
        if (num_async) {
@@ -2084,7 +2089,8 @@ void tls_sw_release_resources_tx(struct sock *sk)
        /* Free up un-sent records in tx_list. First, free
         * the partially sent record if any at head of tx_list.
         */
-       if (tls_free_partial_record(sk, tls_ctx)) {
+       if (tls_ctx->partially_sent_record) {
+               tls_free_partial_record(sk, tls_ctx);
                rec = list_first_entry(&ctx->tx_list,
                                       struct tls_rec, list);
                list_del(&rec->list);
index 17f8cef..4aa1806 100644 (file)
@@ -4,7 +4,6 @@
 bin2c
 conmakehash
 kallsyms
-pnmtologo
 unifdef
 recordmcount
 sortextable
index 10ba926..bc5f257 100644 (file)
@@ -210,17 +210,20 @@ endif
 # (needed for the shell)
 make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
 
-# Find any prerequisites that is newer than target or that does not exist.
+# Find any prerequisites that are newer than target or that do not exist.
+# (This is not true for now; $? should contain any non-existent prerequisites,
+# but it does not work as expected when .SECONDARY is present. This seems a bug
+# of GNU Make.)
 # PHONY targets skipped in both cases.
-any-prereq = $(filter-out $(PHONY),$?)$(filter-out $(PHONY) $(wildcard $^),$^)
+newer-prereqs = $(filter-out $(PHONY),$?)
 
 # Execute command if command has changed or prerequisite(s) are updated.
-if_changed = $(if $(any-prereq)$(cmd-check),                                 \
+if_changed = $(if $(newer-prereqs)$(cmd-check),                              \
        $(cmd);                                                              \
        printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
 
 # Execute the command and also postprocess generated .d dependencies file.
-if_changed_dep = $(if $(any-prereq)$(cmd-check),$(cmd_and_fixdep),@:)
+if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),@:)
 
 cmd_and_fixdep =                                                             \
        $(cmd);                                                              \
@@ -230,7 +233,7 @@ cmd_and_fixdep =                                                             \
 # Usage: $(call if_changed_rule,foo)
 # Will check if $(cmd_foo) or any of the prerequisites changed,
 # and if so will execute $(rule_foo).
-if_changed_rule = $(if $(any-prereq)$(cmd-check),$(rule_$(1)),@:)
+if_changed_rule = $(if $(newer-prereqs)$(cmd-check),$(rule_$(1)),@:)
 
 ###
 # why - tell why a target got built
@@ -255,7 +258,7 @@ ifeq ($(KBUILD_VERBOSE),2)
 why =                                                                        \
     $(if $(filter $@, $(PHONY)),- due to target is PHONY,                    \
         $(if $(wildcard $@),                                                 \
-            $(if $(any-prereq),- due to: $(any-prereq),                      \
+            $(if $(newer-prereqs),- due to: $(newer-prereqs),                \
                 $(if $(cmd-check),                                           \
                     $(if $(cmd_$@),- due to command line change,             \
                         $(if $(filter $@, $(targets)),                       \
index 3e86b30..00c4790 100644 (file)
@@ -4,7 +4,6 @@
 # the kernel for the build process.
 # ---------------------------------------------------------------------------
 # kallsyms:      Find all symbols in vmlinux
-# pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
 
@@ -12,7 +11,6 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
 hostprogs-$(CONFIG_BUILD_BIN2C)  += bin2c
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
-hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
 hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
index a9e4795..b734ac8 100644 (file)
@@ -283,15 +283,6 @@ quiet_cmd_cc_lst_c = MKLST   $@
 $(obj)/%.lst: $(src)/%.c FORCE
        $(call if_changed_dep,cc_lst_c)
 
-# header test (header-test-y, header-test-m target)
-# ---------------------------------------------------------------------------
-
-quiet_cmd_cc_s_h = CC      $@
-      cmd_cc_s_h = $(CC) $(c_flags) -S -o $@ -x c /dev/null -include $<
-
-$(obj)/%.h.s: $(src)/%.h FORCE
-       $(call if_changed_dep,cc_s_h)
-
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
 
@@ -469,17 +460,20 @@ targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \
 
 ifdef single-build
 
+KBUILD_SINGLE_TARGETS := $(filter $(obj)/%, $(KBUILD_SINGLE_TARGETS))
+
 curdir-single := $(sort $(foreach x, $(KBUILD_SINGLE_TARGETS), \
                        $(if $(filter $(x) $(basename $(x)).o, $(targets)), $(x))))
 
 # Handle single targets without any rule: show "Nothing to be done for ..." or
 # "No rule to make target ..." depending on whether the target exists.
 unknown-single := $(filter-out $(addsuffix /%, $(subdir-ym)), \
-                       $(filter $(obj)/%, \
-                               $(filter-out $(curdir-single), \
-                                       $(KBUILD_SINGLE_TARGETS))))
+                       $(filter-out $(curdir-single), $(KBUILD_SINGLE_TARGETS)))
+
+single-subdirs := $(foreach d, $(subdir-ym), \
+                       $(if $(filter $(d)/%, $(KBUILD_SINGLE_TARGETS)), $(d)))
 
-__build: $(curdir-single) $(subdir-ym)
+__build: $(curdir-single) $(single-subdirs)
 ifneq ($(unknown-single),)
        $(Q)$(MAKE) -f /dev/null $(unknown-single)
 endif
index 1b405a7..708fbd0 100644 (file)
@@ -56,9 +56,6 @@ new-dirs      := $(filter-out $(existing-dirs), $(wanted-dirs))
 $(if $(new-dirs), $(shell mkdir -p $(new-dirs)))
 
 # Rules
-
-ifndef HDRCHECK
-
 quiet_cmd_install = HDRINST $@
       cmd_install = $(CONFIG_SHELL) $(srctree)/scripts/headers_install.sh $< $@
 
@@ -81,21 +78,6 @@ existing-headers := $(filter $(old-headers), $(all-headers))
 
 -include $(foreach f,$(existing-headers),$(dir $(f)).$(notdir $(f)).cmd)
 
-else
-
-quiet_cmd_check = HDRCHK  $<
-      cmd_check = $(PERL) $(srctree)/scripts/headers_check.pl $(dst) $(SRCARCH) $<; touch $@
-
-check-files := $(addsuffix .chk, $(all-headers))
-
-$(check-files): $(dst)/%.chk : $(dst)/% $(srctree)/scripts/headers_check.pl
-       $(call cmd,check)
-
-__headers: $(check-files)
-       @:
-
-endif
-
 PHONY += FORCE
 FORCE:
 
index 179d55a..3fa32f8 100644 (file)
@@ -65,20 +65,6 @@ extra-y += $(patsubst %.dtb,%.dt.yaml, $(dtb-y))
 extra-$(CONFIG_OF_ALL_DTBS) += $(patsubst %.dtb,%.dt.yaml, $(dtb-))
 endif
 
-# Test self-contained headers
-
-# Wildcard searches in $(srctree)/$(src)/, but not in $(objtree)/$(obj)/.
-# Stale generated headers are often left over, so pattern matching should
-# be avoided. Please notice $(srctree)/$(src)/ and $(objtree)/$(obj) point
-# to the same location for in-tree building. So, header-test-pattern-y should
-# be used with care.
-header-test-y  += $(filter-out $(header-test-), \
-               $(patsubst $(srctree)/$(src)/%, %, \
-               $(wildcard $(addprefix $(srctree)/$(src)/, \
-               $(header-test-pattern-y)))))
-
-extra-$(CONFIG_HEADER_TEST) += $(addsuffix .s, $(header-test-y) $(header-test-m))
-
 # Add subdir path
 
 extra-y                := $(addprefix $(obj)/,$(extra-y))
index 952fff4..69897d5 100644 (file)
@@ -50,12 +50,10 @@ MODPOST = scripts/mod/modpost                                               \
        $(if $(CONFIG_MODVERSIONS),-m)                                  \
        $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a)                        \
        $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)                   \
-       $(if $(KBUILD_EXTMOD),-I $(modulesymfile))                      \
        $(if $(KBUILD_EXTMOD),$(addprefix -e ,$(KBUILD_EXTRA_SYMBOLS))) \
        $(if $(KBUILD_EXTMOD),-o $(modulesymfile))                      \
        $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E)                  \
-       $(if $(KBUILD_MODPOST_WARN),-w)                                 \
-       $(if $(filter nsdeps,$(MAKECMDGOALS)),-d)
+       $(if $(KBUILD_MODPOST_WARN),-w)
 
 ifdef MODPOST_VMLINUX
 
@@ -67,10 +65,14 @@ __modpost:
 
 else
 
-# When building external modules load the Kbuild file to retrieve EXTRA_SYMBOLS info
-ifneq ($(KBUILD_EXTMOD),)
+MODPOST += $(subst -i,-n,$(filter -i,$(MAKEFLAGS))) -s -T - \
+       $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS))
 
-# set src + obj - they may be used when building the .mod.c file
+ifeq ($(KBUILD_EXTMOD),)
+MODPOST += $(wildcard vmlinux)
+else
+
+# set src + obj - they may be used in the modules's Makefile
 obj := $(KBUILD_EXTMOD)
 src := $(obj)
 
@@ -79,8 +81,6 @@ include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \
              $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile)
 endif
 
-MODPOST += $(subst -i,-n,$(filter -i,$(MAKEFLAGS))) -s -T - $(wildcard vmlinux)
-
 # find all modules listed in modules.order
 modules := $(sort $(shell cat $(MODORDER)))
 
@@ -96,8 +96,6 @@ ifneq ($(KBUILD_MODPOST_NOFINAL),1)
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
 endif
 
-nsdeps: __modpost
-
 endif
 
 .PHONY: $(PHONY)
index 56eadcc..02135d2 100644 (file)
@@ -103,7 +103,7 @@ snap-pkg:
 
 # tarball targets
 # ---------------------------------------------------------------------------
-tar-pkgs := tar-pkg targz-pkg tarbz2-pkg tarxz-pkg
+tar-pkgs := dir-pkg tar-pkg targz-pkg tarbz2-pkg tarxz-pkg
 PHONY += $(tar-pkgs)
 $(tar-pkgs):
        $(MAKE) -f $(srctree)/Makefile
@@ -146,7 +146,9 @@ help:
        @echo '  binrpm-pkg          - Build only the binary kernel RPM package'
        @echo '  deb-pkg             - Build both source and binary deb kernel packages'
        @echo '  bindeb-pkg          - Build only the binary kernel deb package'
-       @echo '  snap-pkg            - Build only the binary kernel snap package (will connect to external hosts)'
+       @echo '  snap-pkg            - Build only the binary kernel snap package'
+       @echo '                        (will connect to external hosts)'
+       @echo '  dir-pkg             - Build the kernel as a plain directory structure'
        @echo '  tar-pkg             - Build the kernel as an uncompressed tarball'
        @echo '  targz-pkg           - Build the kernel as a gzip compressed tarball'
        @echo '  tarbz2-pkg          - Build the kernel as a bzip2 compressed tarball'
index 64890be..7cbe6e7 100755 (executable)
@@ -874,14 +874,18 @@ sub seed_camelcase_file {
        }
 }
 
+our %maintained_status = ();
+
 sub is_maintained_obsolete {
        my ($filename) = @_;
 
        return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl"));
 
-       my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`;
+       if (!exists($maintained_status{$filename})) {
+               $maintained_status{$filename} = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`;
+       }
 
-       return $status =~ /obsolete/i;
+       return $maintained_status{$filename} =~ /obsolete/i;
 }
 
 sub is_SPDX_License_valid {
@@ -2826,6 +2830,14 @@ sub process {
                             "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
                }
 
+# Check for adding new DT bindings not in schema format
+               if (!$in_commit_log &&
+                   ($line =~ /^new file mode\s*\d+\s*$/) &&
+                   ($realfile =~ m@^Documentation/devicetree/bindings/.*\.txt$@)) {
+                       WARN("DT_SCHEMA_BINDING_PATCH",
+                            "DT bindings should be in DT schema format. See: Documentation/devicetree/writing-schema.rst\n");
+               }
+
 # Check for wrappage within a valid hunk of the file
                if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
                        ERROR("CORRUPTED_PATCH",
@@ -5030,8 +5042,9 @@ sub process {
                            $var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
 #Ignore Page<foo> variants
                            $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
-#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show)
-                           $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/ &&
+#Ignore SI style variants like nS, mV and dB
+#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE)
+                           $var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ &&
 #Ignore some three character SI units explicitly, like MiB and KHz
                            $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) {
                                while ($var =~ m{($Ident)}g) {
index 8216080..b5a5b1c 100644 (file)
@@ -11,7 +11,7 @@ dtc-objs      += dtc-lexer.lex.o dtc-parser.tab.o
 # Source files need to get at the userspace version of libfdt_env.h to compile
 HOST_EXTRACFLAGS := -I $(srctree)/$(src)/libfdt
 
-ifeq ($(wildcard /usr/include/yaml.h),)
+ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),)
 ifneq ($(CHECK_DTBS),)
 $(error dtc needs libyaml for DT schema validation support. \
        Install the necessary libyaml development package.)
@@ -19,7 +19,7 @@ endif
 HOST_EXTRACFLAGS += -DNO_YAML
 else
 dtc-objs       += yamltree.o
-HOSTLDLIBS_dtc := -lyaml
+HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs)
 endif
 
 # Generated files need one more search path to include headers in source tree
index 00fd473..541c432 100755 (executable)
@@ -20,6 +20,8 @@ Usage:
 
 
       --annotate    synonym for -T
+      --color       synonym for -c (requires diff with --color support)
+       -c           enable colored output
        -f           print full dts in diff (--unified=99999)
        -h           synonym for --help
        -help        synonym for --help
@@ -177,6 +179,7 @@ compile_to_dts() {
 annotate=""
 cmd_diff=0
 diff_flags="-u"
+diff_color=""
 dtx_file_1=""
 dtx_file_2=""
 dtc_sort="-s"
@@ -188,6 +191,13 @@ while [ $# -gt 0 ] ; do
 
        case $1 in
 
+       -c | --color )
+               if diff --color /dev/null /dev/null 2>/dev/null ; then
+                       diff_color="--color=always"
+               fi
+               shift
+               ;;
+
        -f )
                diff_flags="--unified=999999"
                shift
@@ -343,7 +353,7 @@ DTC="\
 
 if (( ${cmd_diff} )) ; then
 
-       diff ${diff_flags} --label "${dtx_file_1}" --label "${dtx_file_2}" \
+       diff ${diff_flags} ${diff_color} --label "${dtx_file_1}" --label "${dtx_file_2}" \
                <(compile_to_dts "${dtx_file_1}" "${dtx_path_1_dtc_include}") \
                <(compile_to_dts "${dtx_file_2}" "${dtx_path_2_dtc_include}")
 
index 5ef5921..34085d1 100755 (executable)
@@ -26,6 +26,7 @@ my $email = 1;
 my $email_usename = 1;
 my $email_maintainer = 1;
 my $email_reviewer = 1;
+my $email_fixes = 1;
 my $email_list = 1;
 my $email_moderated_list = 1;
 my $email_subscriber_list = 0;
@@ -249,6 +250,7 @@ if (!GetOptions(
                'r!' => \$email_reviewer,
                'n!' => \$email_usename,
                'l!' => \$email_list,
+               'fixes!' => \$email_fixes,
                'moderated!' => \$email_moderated_list,
                's!' => \$email_subscriber_list,
                'multiline!' => \$output_multiline,
@@ -503,6 +505,7 @@ sub read_mailmap {
 ## use the filenames on the command line or find the filenames in the patchfiles
 
 my @files = ();
+my @fixes = ();                        # If a patch description includes Fixes: lines
 my @range = ();
 my @keyword_tvi = ();
 my @file_emails = ();
@@ -568,6 +571,8 @@ foreach my $file (@ARGV) {
                my $filename2 = $2;
                push(@files, $filename1);
                push(@files, $filename2);
+           } elsif (m/^Fixes:\s+([0-9a-fA-F]{6,40})/) {
+               push(@fixes, $1) if ($email_fixes);
            } elsif (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
                my $filename = $1;
                $filename =~ s@^[^/]*/@@;
@@ -598,6 +603,7 @@ foreach my $file (@ARGV) {
 }
 
 @file_emails = uniq(@file_emails);
+@fixes = uniq(@fixes);
 
 my %email_hash_name;
 my %email_hash_address;
@@ -612,7 +618,6 @@ my %deduplicate_name_hash = ();
 my %deduplicate_address_hash = ();
 
 my @maintainers = get_maintainers();
-
 if (@maintainers) {
     @maintainers = merge_email(@maintainers);
     output(@maintainers);
@@ -927,6 +932,10 @@ sub get_maintainers {
        }
     }
 
+    foreach my $fix (@fixes) {
+       vcs_add_commit_signers($fix, "blamed_fixes");
+    }
+
     foreach my $email (@email_to, @list_to) {
        $email->[0] = deduplicate_email($email->[0]);
     }
@@ -1031,6 +1040,7 @@ MAINTAINER field selection options:
     --roles => show roles (status:subsystem, git-signer, list, etc...)
     --rolestats => show roles and statistics (commits/total_commits, %)
     --file-emails => add email addresses found in -f file (default: 0 (off))
+    --fixes => for patches, add signatures of commits with 'Fixes: <commit>' (default: 1 (on))
   --scm => print SCM tree(s) if any
   --status => print status if any
   --subsystem => print subsystem name if any
@@ -1730,6 +1740,32 @@ sub vcs_is_hg {
     return $vcs_used == 2;
 }
 
+sub vcs_add_commit_signers {
+    return if (!vcs_exists());
+
+    my ($commit, $desc) = @_;
+    my $commit_count = 0;
+    my $commit_authors_ref;
+    my $commit_signers_ref;
+    my $stats_ref;
+    my @commit_authors = ();
+    my @commit_signers = ();
+    my $cmd;
+
+    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+    $cmd =~ s/(\$\w+)/$1/eeg;  #substitute variables in $cmd
+
+    ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, "");
+    @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
+    @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
+
+    foreach my $signer (@commit_signers) {
+       $signer = deduplicate_email($signer);
+    }
+
+    vcs_assign($desc, 1, @commit_signers);
+}
+
 sub interactive_get_maintainers {
     my ($list_ref) = @_;
     my @list = @$list_ref;
diff --git a/scripts/jobserver-exec b/scripts/jobserver-exec
new file mode 100755 (executable)
index 0000000..0fdb31a
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# This determines how many parallel tasks "make" is expecting, as it is
+# not exposed via an special variables, reserves them all, runs a subprocess
+# with PARALLELISM environment variable set, and releases the jobs back again.
+#
+# https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver
+from __future__ import print_function
+import os, sys, errno
+import subprocess
+
+# Extract and prepare jobserver file descriptors from envirnoment.
+claim = 0
+jobs = b""
+try:
+       # Fetch the make environment options.
+       flags = os.environ['MAKEFLAGS']
+
+       # Look for "--jobserver=R,W"
+       # Note that GNU Make has used --jobserver-fds and --jobserver-auth
+       # so this handles all of them.
+       opts = [x for x in flags.split(" ") if x.startswith("--jobserver")]
+
+       # Parse out R,W file descriptor numbers and set them nonblocking.
+       fds = opts[0].split("=", 1)[1]
+       reader, writer = [int(x) for x in fds.split(",", 1)]
+       # Open a private copy of reader to avoid setting nonblocking
+       # on an unexpecting process with the same reader fd.
+       reader = os.open("/proc/self/fd/%d" % (reader),
+                        os.O_RDONLY | os.O_NONBLOCK)
+
+       # Read out as many jobserver slots as possible.
+       while True:
+               try:
+                       slot = os.read(reader, 8)
+                       jobs += slot
+               except (OSError, IOError) as e:
+                       if e.errno == errno.EWOULDBLOCK:
+                               # Stop at the end of the jobserver queue.
+                               break
+                       # If something went wrong, give back the jobs.
+                       if len(jobs):
+                               os.write(writer, jobs)
+                       raise e
+       # Add a bump for our caller's reserveration, since we're just going
+       # to sit here blocked on our child.
+       claim = len(jobs) + 1
+except (KeyError, IndexError, ValueError, OSError, IOError) as e:
+       # Any missing environment strings or bad fds should result in just
+       # not being parallel.
+       pass
+
+# We can only claim parallelism if there was a jobserver (i.e. a top-level
+# "-jN" argument) and there were no other failures. Otherwise leave out the
+# environment variable and let the child figure out what is best.
+if claim > 0:
+       os.environ['PARALLELISM'] = '%d' % (claim)
+
+rc = subprocess.call(sys.argv[1:])
+
+# Return all the reserved slots.
+if len(jobs):
+       os.write(writer, jobs)
+
+sys.exit(rc)
index ae6504d..fb55f26 100644 (file)
  *
  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include <limits.h>
 
-#ifndef ARRAY_SIZE
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
-#endif
 
 #define KSYM_NAME_LEN          128
 
@@ -58,9 +57,9 @@ static struct addr_range percpu_range = {
 
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
-static int all_symbols = 0;
-static int absolute_percpu = 0;
-static int base_relative = 0;
+static int all_symbols;
+static int absolute_percpu;
+static int base_relative;
 
 static int token_profit[0x10000];
 
@@ -76,18 +75,88 @@ static void usage(void)
        exit(1);
 }
 
-/*
- * This ignores the intensely annoying "mapping symbols" found
- * in ARM ELF files: $a, $t and $d.
- */
-static int is_arm_mapping_symbol(const char *str)
+static char *sym_name(const struct sym_entry *s)
+{
+       return (char *)s->sym + 1;
+}
+
+static bool is_ignored_symbol(const char *name, char type)
 {
-       return str[0] == '$' && strchr("axtd", str[1])
-              && (str[2] == '\0' || str[2] == '.');
+       static const char * const ignored_symbols[] = {
+               /*
+                * Symbols which vary between passes. Passes 1 and 2 must have
+                * identical symbol lists. The kallsyms_* symbols below are
+                * only added after pass 1, they would be included in pass 2
+                * when --all-symbols is specified so exclude them to get a
+                * stable symbol list.
+                */
+               "kallsyms_addresses",
+               "kallsyms_offsets",
+               "kallsyms_relative_base",
+               "kallsyms_num_syms",
+               "kallsyms_names",
+               "kallsyms_markers",
+               "kallsyms_token_table",
+               "kallsyms_token_index",
+               /* Exclude linker generated symbols which vary between passes */
+               "_SDA_BASE_",           /* ppc */
+               "_SDA2_BASE_",          /* ppc */
+               NULL
+       };
+
+       static const char * const ignored_prefixes[] = {
+               "$",                    /* local symbols for ARM, MIPS, etc. */
+               ".LASANPC",             /* s390 kasan local symbols */
+               "__crc_",               /* modversions */
+               "__efistub_",           /* arm64 EFI stub namespace */
+               NULL
+       };
+
+       static const char * const ignored_suffixes[] = {
+               "_from_arm",            /* arm */
+               "_from_thumb",          /* arm */
+               "_veneer",              /* arm */
+               NULL
+       };
+
+       const char * const *p;
+
+       /* Exclude symbols which vary between passes. */
+       for (p = ignored_symbols; *p; p++)
+               if (!strcmp(name, *p))
+                       return true;
+
+       for (p = ignored_prefixes; *p; p++)
+               if (!strncmp(name, *p, strlen(*p)))
+                       return true;
+
+       for (p = ignored_suffixes; *p; p++) {
+               int l = strlen(name) - strlen(*p);
+
+               if (l >= 0 && !strcmp(name + l, *p))
+                       return true;
+       }
+
+       if (type == 'U' || type == 'u')
+               return true;
+       /* exclude debugging symbols */
+       if (type == 'N' || type == 'n')
+               return true;
+
+       if (toupper(type) == 'A') {
+               /* Keep these useful absolute symbols */
+               if (strcmp(name, "__kernel_syscall_via_break") &&
+                   strcmp(name, "__kernel_syscall_via_epc") &&
+                   strcmp(name, "__kernel_sigtramp") &&
+                   strcmp(name, "__gp"))
+                       return true;
+       }
+
+       return false;
 }
 
-static int check_symbol_range(const char *sym, unsigned long long addr,
-                             struct addr_range *ranges, int entries)
+static void check_symbol_range(const char *sym, unsigned long long addr,
+                              struct addr_range *ranges, int entries)
 {
        size_t i;
        struct addr_range *ar;
@@ -97,14 +166,12 @@ static int check_symbol_range(const char *sym, unsigned long long addr,
 
                if (strcmp(sym, ar->start_sym) == 0) {
                        ar->start = addr;
-                       return 0;
+                       return;
                } else if (strcmp(sym, ar->end_sym) == 0) {
                        ar->end = addr;
-                       return 0;
+                       return;
                }
        }
-
-       return 1;
 }
 
 static int read_symbol(FILE *in, struct sym_entry *s)
@@ -125,34 +192,15 @@ static int read_symbol(FILE *in, struct sym_entry *s)
                return -1;
        }
 
+       if (is_ignored_symbol(sym, stype))
+               return -1;
+
        /* Ignore most absolute/undefined (?) symbols. */
        if (strcmp(sym, "_text") == 0)
                _text = s->addr;
-       else if (check_symbol_range(sym, s->addr, text_ranges,
-                                   ARRAY_SIZE(text_ranges)) == 0)
-               /* nothing to do */;
-       else if (toupper(stype) == 'A')
-       {
-               /* Keep these useful absolute symbols */
-               if (strcmp(sym, "__kernel_syscall_via_break") &&
-                   strcmp(sym, "__kernel_syscall_via_epc") &&
-                   strcmp(sym, "__kernel_sigtramp") &&
-                   strcmp(sym, "__gp"))
-                       return -1;
 
-       }
-       else if (toupper(stype) == 'U' ||
-                is_arm_mapping_symbol(sym))
-               return -1;
-       /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
-       else if (sym[0] == '$')
-               return -1;
-       /* exclude debugging symbols */
-       else if (stype == 'N' || stype == 'n')
-               return -1;
-       /* exclude s390 kasan local symbols */
-       else if (!strncmp(sym, ".LASANPC", 8))
-               return -1;
+       check_symbol_range(sym, s->addr, text_ranges, ARRAY_SIZE(text_ranges));
+       check_symbol_range(sym, s->addr, &percpu_range, 1);
 
        /* include the type field in the symbol name, so that it gets
         * compressed together */
@@ -163,22 +211,19 @@ static int read_symbol(FILE *in, struct sym_entry *s)
                        "unable to allocate required amount of memory\n");
                exit(EXIT_FAILURE);
        }
-       strcpy((char *)s->sym + 1, sym);
+       strcpy(sym_name(s), sym);
        s->sym[0] = stype;
 
        s->percpu_absolute = 0;
 
-       /* Record if we've found __per_cpu_start/end. */
-       check_symbol_range(sym, s->addr, &percpu_range, 1);
-
        return 0;
 }
 
-static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges,
-                          int entries)
+static int symbol_in_range(const struct sym_entry *s,
+                          const struct addr_range *ranges, int entries)
 {
        size_t i;
-       struct addr_range *ar;
+       const struct addr_range *ar;
 
        for (i = 0; i < entries; ++i) {
                ar = &ranges[i];
@@ -190,41 +235,9 @@ static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges,
        return 0;
 }
 
-static int symbol_valid(struct sym_entry *s)
+static int symbol_valid(const struct sym_entry *s)
 {
-       /* Symbols which vary between passes.  Passes 1 and 2 must have
-        * identical symbol lists.  The kallsyms_* symbols below are only added
-        * after pass 1, they would be included in pass 2 when --all-symbols is
-        * specified so exclude them to get a stable symbol list.
-        */
-       static char *special_symbols[] = {
-               "kallsyms_addresses",
-               "kallsyms_offsets",
-               "kallsyms_relative_base",
-               "kallsyms_num_syms",
-               "kallsyms_names",
-               "kallsyms_markers",
-               "kallsyms_token_table",
-               "kallsyms_token_index",
-
-       /* Exclude linker generated symbols which vary between passes */
-               "_SDA_BASE_",           /* ppc */
-               "_SDA2_BASE_",          /* ppc */
-               NULL };
-
-       static char *special_prefixes[] = {
-               "__crc_",               /* modversions */
-               "__efistub_",           /* arm64 EFI stub namespace */
-               NULL };
-
-       static char *special_suffixes[] = {
-               "_veneer",              /* arm */
-               "_from_arm",            /* arm */
-               "_from_thumb",          /* arm */
-               NULL };
-
-       int i;
-       char *sym_name = (char *)s->sym + 1;
+       const char *name = sym_name(s);
 
        /* if --all-symbols is not specified, then symbols outside the text
         * and inittext sections are discarded */
@@ -239,35 +252,37 @@ static int symbol_valid(struct sym_entry *s)
                 * rules.
                 */
                if ((s->addr == text_range_text->end &&
-                               strcmp(sym_name,
-                                      text_range_text->end_sym)) ||
+                    strcmp(name, text_range_text->end_sym)) ||
                    (s->addr == text_range_inittext->end &&
-                               strcmp(sym_name,
-                                      text_range_inittext->end_sym)))
+                    strcmp(name, text_range_inittext->end_sym)))
                        return 0;
        }
 
-       /* Exclude symbols which vary between passes. */
-       for (i = 0; special_symbols[i]; i++)
-               if (strcmp(sym_name, special_symbols[i]) == 0)
-                       return 0;
+       return 1;
+}
 
-       for (i = 0; special_prefixes[i]; i++) {
-               int l = strlen(special_prefixes[i]);
+/* remove all the invalid symbols from the table */
+static void shrink_table(void)
+{
+       unsigned int i, pos;
 
-               if (l <= strlen(sym_name) &&
-                   strncmp(sym_name, special_prefixes[i], l) == 0)
-                       return 0;
+       pos = 0;
+       for (i = 0; i < table_cnt; i++) {
+               if (symbol_valid(&table[i])) {
+                       if (pos != i)
+                               table[pos] = table[i];
+                       pos++;
+               } else {
+                       free(table[i].sym);
+               }
        }
+       table_cnt = pos;
 
-       for (i = 0; special_suffixes[i]; i++) {
-               int l = strlen(sym_name) - strlen(special_suffixes[i]);
-
-               if (l >= 0 && strcmp(sym_name + l, special_suffixes[i]) == 0)
-                       return 0;
+       /* When valid symbol is not registered, exit to error */
+       if (!table_cnt) {
+               fprintf(stderr, "No valid symbol.\n");
+               exit(1);
        }
-
-       return 1;
 }
 
 static void read_map(FILE *in)
@@ -288,7 +303,7 @@ static void read_map(FILE *in)
        }
 }
 
-static void output_label(char *label)
+static void output_label(const char *label)
 {
        printf(".globl %s\n", label);
        printf("\tALGN\n");
@@ -297,7 +312,7 @@ static void output_label(char *label)
 
 /* uncompress a compressed symbol. When this function is called, the best table
  * might still be compressed itself, so the function needs to be recursive */
-static int expand_symbol(unsigned char *data, int len, char *result)
+static int expand_symbol(const unsigned char *data, int len, char *result)
 {
        int c, rlen, total=0;
 
@@ -322,7 +337,7 @@ static int expand_symbol(unsigned char *data, int len, char *result)
        return total;
 }
 
-static int symbol_absolute(struct sym_entry *s)
+static int symbol_absolute(const struct sym_entry *s)
 {
        return s->percpu_absolute;
 }
@@ -460,7 +475,7 @@ static void write_src(void)
 /* table lookup compression functions */
 
 /* count all the possible tokens in a symbol */
-static void learn_symbol(unsigned char *symbol, int len)
+static void learn_symbol(const unsigned char *symbol, int len)
 {
        int i;
 
@@ -469,7 +484,7 @@ static void learn_symbol(unsigned char *symbol, int len)
 }
 
 /* decrease the count for all the possible tokens in a symbol */
-static void forget_symbol(unsigned char *symbol, int len)
+static void forget_symbol(const unsigned char *symbol, int len)
 {
        int i;
 
@@ -477,24 +492,17 @@ static void forget_symbol(unsigned char *symbol, int len)
                token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
 }
 
-/* remove all the invalid symbols from the table and do the initial token count */
+/* do the initial token count */
 static void build_initial_tok_table(void)
 {
-       unsigned int i, pos;
+       unsigned int i;
 
-       pos = 0;
-       for (i = 0; i < table_cnt; i++) {
-               if ( symbol_valid(&table[i]) ) {
-                       if (pos != i)
-                               table[pos] = table[i];
-                       learn_symbol(table[pos].sym, table[pos].len);
-                       pos++;
-               }
-       }
-       table_cnt = pos;
+       for (i = 0; i < table_cnt; i++)
+               learn_symbol(table[i].sym, table[i].len);
 }
 
-static void *find_token(unsigned char *str, int len, unsigned char *token)
+static unsigned char *find_token(unsigned char *str, int len,
+                                const unsigned char *token)
 {
        int i;
 
@@ -507,7 +515,7 @@ static void *find_token(unsigned char *str, int len, unsigned char *token)
 
 /* replace a given token in all the valid symbols. Use the sampled symbols
  * to update the counts */
-static void compress_symbols(unsigned char *str, int idx)
+static void compress_symbols(const unsigned char *str, int idx)
 {
        unsigned int i, len, size;
        unsigned char *p1, *p2;
@@ -614,19 +622,13 @@ static void optimize_token_table(void)
 
        insert_real_symbols_in_table();
 
-       /* When valid symbol is not registered, exit to error */
-       if (!table_cnt) {
-               fprintf(stderr, "No valid symbol.\n");
-               exit(1);
-       }
-
        optimize_result();
 }
 
 /* guess for "linker script provide" symbol */
 static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
 {
-       const char *symbol = (char *)se->sym + 1;
+       const char *symbol = sym_name(se);
        int len = se->len - 1;
 
        if (len < 8)
@@ -658,16 +660,6 @@ static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
        return 0;
 }
 
-static int prefix_underscores_count(const char *str)
-{
-       const char *tail = str;
-
-       while (*tail == '_')
-               tail++;
-
-       return tail - str;
-}
-
 static int compare_symbols(const void *a, const void *b)
 {
        const struct sym_entry *sa;
@@ -696,8 +688,8 @@ static int compare_symbols(const void *a, const void *b)
                return wa - wb;
 
        /* sort by the number of prefix underscores */
-       wa = prefix_underscores_count((const char *)sa->sym + 1);
-       wb = prefix_underscores_count((const char *)sb->sym + 1);
+       wa = strspn(sym_name(sa), "_");
+       wb = strspn(sym_name(sb), "_");
        if (wa != wb)
                return wa - wb;
 
@@ -731,11 +723,15 @@ static void record_relative_base(void)
 {
        unsigned int i;
 
-       relative_base = -1ULL;
        for (i = 0; i < table_cnt; i++)
-               if (!symbol_absolute(&table[i]) &&
-                   table[i].addr < relative_base)
+               if (!symbol_absolute(&table[i])) {
+                       /*
+                        * The table is sorted by address.
+                        * Take the first non-absolute symbol value.
+                        */
                        relative_base = table[i].addr;
+                       return;
+               }
 }
 
 int main(int argc, char **argv)
@@ -756,11 +752,12 @@ int main(int argc, char **argv)
                usage();
 
        read_map(stdin);
+       shrink_table();
        if (absolute_percpu)
                make_percpus_absolute();
+       sort_symbols();
        if (base_relative)
                record_relative_base();
-       sort_symbols();
        optimize_token_table();
        write_src();
 
index ef2f233..2f1a59f 100644 (file)
@@ -66,7 +66,9 @@ localyesconfig localmodconfig: $(obj)/conf
 #  syncconfig has become an internal implementation detail and is now
 #  deprecated for external use
 simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
-       alldefconfig randconfig listnewconfig olddefconfig syncconfig
+       alldefconfig randconfig listnewconfig olddefconfig syncconfig \
+       helpnewconfig
+
 PHONY += $(simple-targets)
 
 $(simple-targets): $(obj)/conf
@@ -134,17 +136,19 @@ help:
        @echo  '  alldefconfig    - New config with all symbols set to default'
        @echo  '  randconfig      - New config with random answer to all options'
        @echo  '  listnewconfig   - List new options'
+       @echo  '  helpnewconfig   - List new options and help text'
        @echo  '  olddefconfig    - Same as oldconfig but sets new symbols to their'
        @echo  '                    default value without prompting'
        @echo  '  kvmconfig       - Enable additional options for kvm guest kernel support'
-       @echo  '  xenconfig       - Enable additional options for xen dom0 and guest kernel support'
+       @echo  '  xenconfig       - Enable additional options for xen dom0 and guest kernel'
+       @echo  '                    support'
        @echo  '  tinyconfig      - Configure the tiniest possible kernel'
        @echo  '  testconfig      - Run Kconfig unit tests (requires python3 and pytest)'
 
 # ===========================================================================
 # object files used by all kconfig flavours
 common-objs    := confdata.o expr.o lexer.lex.o parser.tab.o preprocess.o \
-                  symbol.o
+                  symbol.o util.o
 
 $(obj)/lexer.lex.o: $(obj)/parser.tab.h
 HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src)
index 40e16e8..1f89bf1 100644 (file)
@@ -32,6 +32,7 @@ enum input_mode {
        defconfig,
        savedefconfig,
        listnewconfig,
+       helpnewconfig,
        olddefconfig,
 };
 static enum input_mode input_mode = oldaskconfig;
@@ -434,6 +435,11 @@ static void check_conf(struct menu *menu)
                                                printf("%s%s=%s\n", CONFIG_, sym->name, str);
                                        }
                                }
+                       } else if (input_mode == helpnewconfig) {
+                               printf("-----\n");
+                               print_help(menu);
+                               printf("-----\n");
+
                        } else {
                                if (!conf_cnt++)
                                        printf("*\n* Restart config...\n*\n");
@@ -459,6 +465,7 @@ static struct option long_opts[] = {
        {"alldefconfig",    no_argument,       NULL, alldefconfig},
        {"randconfig",      no_argument,       NULL, randconfig},
        {"listnewconfig",   no_argument,       NULL, listnewconfig},
+       {"helpnewconfig",   no_argument,       NULL, helpnewconfig},
        {"olddefconfig",    no_argument,       NULL, olddefconfig},
        {NULL, 0, NULL, 0}
 };
@@ -469,6 +476,7 @@ static void conf_usage(const char *progname)
        printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
        printf("[option] is _one_ of the following:\n");
        printf("  --listnewconfig         List new options\n");
+       printf("  --helpnewconfig         List new options and help text\n");
        printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
        printf("  --oldconfig             Update a configuration using a provided .config as base\n");
        printf("  --syncconfig            Similar to oldconfig but generates configuration in\n"
@@ -543,6 +551,7 @@ int main(int ac, char **av)
                case allmodconfig:
                case alldefconfig:
                case listnewconfig:
+               case helpnewconfig:
                case olddefconfig:
                        break;
                case '?':
@@ -576,6 +585,7 @@ int main(int ac, char **av)
        case oldaskconfig:
        case oldconfig:
        case listnewconfig:
+       case helpnewconfig:
        case olddefconfig:
                conf_read(NULL);
                break;
@@ -657,6 +667,7 @@ int main(int ac, char **av)
                /* fall through */
        case oldconfig:
        case listnewconfig:
+       case helpnewconfig:
        case syncconfig:
                /* Update until a loop caused no more changes */
                do {
@@ -675,7 +686,7 @@ int main(int ac, char **av)
                                defconfig_file);
                        return 1;
                }
-       } else if (input_mode != listnewconfig) {
+       } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
                if (!no_conf_write && conf_write(NULL)) {
                        fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
                        exit(1);
index c812872..aa68ec9 100755 (executable)
@@ -44,4 +44,7 @@ echo >&2 "* Unable to find the ncurses package."
 echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
 echo >&2 "* depending on your distribution)."
 echo >&2 "*"
+echo >&2 "* You may also need to install pkg-config to find the"
+echo >&2 "* ncurses installed in a non-default location."
+echo >&2 "*"
 exit 1
index 001559e..c212255 100755 (executable)
@@ -44,4 +44,7 @@ echo >&2 "* Unable to find the ncurses package."
 echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
 echo >&2 "* depending on your distribution)."
 echo >&2 "*"
+echo >&2 "* You may also need to install pkg-config to find the"
+echo >&2 "* ncurses installed in a non-default location."
+echo >&2 "*"
 exit 1
index 60936c7..b3eff96 100644 (file)
@@ -727,5 +727,4 @@ void zconfdump(FILE *out)
        }
 }
 
-#include "util.c"
 #include "menu.c"
index 81dc917..f2d73f0 100755 (executable)
@@ -1062,7 +1062,7 @@ sub dump_struct($$) {
     my $x = shift;
     my $file = shift;
 
-    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
+    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
        my $decl_type = $1;
        $declaration_name = $2;
        my $members = $3;
@@ -1073,10 +1073,11 @@ sub dump_struct($$) {
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
        # strip attributes
-       $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)//gi;
-       $members =~ s/\s*__aligned\s*\([^;]*\)//gos;
-       $members =~ s/\s*__packed\s*//gos;
-       $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
+       $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi;
+       $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos;
+       $members =~ s/\s*__packed\s*/ /gos;
+       $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
+       $members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
        # replace DECLARE_BITMAP
        $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
        # replace DECLARE_HASHTABLE
@@ -1449,6 +1450,10 @@ sub push_parameter($$$$) {
              # handles unnamed variable parameters
              $param = "...";
            }
+           elsif ($param =~ /\w\.\.\.$/) {
+             # for named variable parameters of the form `x...`, remove the dots
+             $param =~ s/\.\.\.$//;
+           }
            if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") {
                $parameterdescs{$param} = "variable arguments";
            }
@@ -1936,6 +1941,18 @@ sub process_name($$) {
 sub process_body($$) {
     my $file = shift;
 
+    # Until all named variable macro parameters are
+    # documented using the bare name (`x`) rather than with
+    # dots (`x...`), strip the dots:
+    if ($section =~ /\w\.\.\.$/) {
+       $section =~ s/\.\.\.$//;
+
+       if ($verbose) {
+           print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n";
+           ++$warnings;
+       }
+    }
+
     if (/$doc_sect/i) { # case insensitive for supported section names
        $newsection = $1;
        $newcontents = $2;
index d2a30a7..6e892c9 100644 (file)
@@ -38,8 +38,6 @@ static int sec_mismatch_count = 0;
 static int sec_mismatch_fatal = 0;
 /* ignore missing files */
 static int ignore_missing_files;
-/* write namespace dependencies */
-static int write_namespace_deps;
 
 enum export {
        export_plain,      export_unused,     export_gpl,
@@ -171,7 +169,6 @@ struct symbol {
        unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
        unsigned int kernel:1;     /* 1 if symbol is from kernel
                                    *  (only for external modules) **/
-       unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
        unsigned int is_static:1;  /* 1 if symbol is not global */
        enum export  export;       /* Type of export */
        char name[0];
@@ -214,13 +211,11 @@ static struct symbol *new_symbol(const char *name, struct module *module,
                                 enum export export)
 {
        unsigned int hash;
-       struct symbol *new;
 
        hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
-       new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
-       new->module = module;
-       new->export = export;
-       return new;
+       symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
+
+       return symbolhash[hash];
 }
 
 static struct symbol *find_symbol(const char *name)
@@ -241,10 +236,8 @@ static struct symbol *find_symbol(const char *name)
 static bool contains_namespace(struct namespace_list *list,
                               const char *namespace)
 {
-       struct namespace_list *ns_entry;
-
-       for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
-               if (strcmp(ns_entry->namespace, namespace) == 0)
+       for (; list; list = list->next)
+               if (!strcmp(list->namespace, namespace))
                        return true;
 
        return false;
@@ -312,6 +305,18 @@ static const char *sec_name(struct elf_info *elf, int secindex)
        return sech_name(elf, &elf->sechdrs[secindex]);
 }
 
+static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+{
+       Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
+       unsigned long offset;
+
+       offset = sym->st_value;
+       if (info->hdr->e_type != ET_REL)
+               offset -= sechdr->sh_addr;
+
+       return (void *)info->hdr + sechdr->sh_offset + offset;
+}
+
 #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
 
 static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
@@ -348,10 +353,10 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
                return export_unknown;
 }
 
-static const char *namespace_from_kstrtabns(struct elf_info *info,
-                                           Elf_Sym *kstrtabns)
+static const char *namespace_from_kstrtabns(const struct elf_info *info,
+                                           const Elf_Sym *sym)
 {
-       char *value = info->ksymtab_strings + kstrtabns->st_value;
+       const char *value = sym_get_data(info, sym);
        return value[0] ? value : NULL;
 }
 
@@ -385,33 +390,32 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
 
        if (!s) {
                s = new_symbol(name, mod, export);
-       } else {
-               if (!s->preloaded) {
-                       warn("%s: '%s' exported twice. Previous export was in %s%s\n",
-                            mod->name, name, s->module->name,
-                            is_vmlinux(s->module->name) ? "" : ".ko");
-               } else {
-                       /* In case Module.symvers was out of date */
-                       s->module = mod;
-               }
+       } else if (!external_module || is_vmlinux(s->module->name) ||
+                  s->module == mod) {
+               warn("%s: '%s' exported twice. Previous export was in %s%s\n",
+                    mod->name, name, s->module->name,
+                    is_vmlinux(s->module->name) ? "" : ".ko");
+               return s;
        }
-       s->preloaded = 0;
+
+       s->module = mod;
        s->vmlinux   = is_vmlinux(mod->name);
        s->kernel    = 0;
        s->export    = export;
        return s;
 }
 
-static void sym_update_crc(const char *name, struct module *mod,
-                          unsigned int crc, enum export export)
+static void sym_set_crc(const char *name, unsigned int crc)
 {
        struct symbol *s = find_symbol(name);
 
-       if (!s) {
-               s = new_symbol(name, mod, export);
-               /* Don't complain when we find it later. */
-               s->preloaded = 1;
-       }
+       /*
+        * Ignore stand-alone __crc_*, which might be auto-generated symbols
+        * such as __*_veneer in ARM ELF.
+        */
+       if (!s)
+               return;
+
        s->crc = crc;
        s->crc_valid = 1;
 }
@@ -593,10 +597,6 @@ static int parse_elf(struct elf_info *info, const char *filename)
                        info->export_unused_gpl_sec = i;
                else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
                        info->export_gpl_future_sec = i;
-               else if (strcmp(secname, "__ksymtab_strings") == 0)
-                       info->ksymtab_strings = (void *)hdr +
-                                               sechdrs[i].sh_offset -
-                                               sechdrs[i].sh_addr;
 
                if (sechdrs[i].sh_type == SHT_SYMTAB) {
                        unsigned int sh_link_idx;
@@ -679,12 +679,34 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
        return 0;
 }
 
-static void handle_modversions(struct module *mod, struct elf_info *info,
-                              Elf_Sym *sym, const char *symname)
+static void handle_modversion(const struct module *mod,
+                             const struct elf_info *info,
+                             const Elf_Sym *sym, const char *symname)
 {
        unsigned int crc;
+
+       if (sym->st_shndx == SHN_UNDEF) {
+               warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
+                    symname, mod->name, is_vmlinux(mod->name) ? "":".ko");
+               return;
+       }
+
+       if (sym->st_shndx == SHN_ABS) {
+               crc = sym->st_value;
+       } else {
+               unsigned int *crcp;
+
+               /* symbol points to the CRC in the ELF object */
+               crcp = sym_get_data(info, sym);
+               crc = TO_NATIVE(*crcp);
+       }
+       sym_set_crc(symname, crc);
+}
+
+static void handle_symbol(struct module *mod, struct elf_info *info,
+                         const Elf_Sym *sym, const char *symname)
+{
        enum export export;
-       bool is_crc = false;
        const char *name;
 
        if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
@@ -693,24 +715,6 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
        else
                export = export_from_sec(info, get_secindex(info, sym));
 
-       /* CRC'd symbol */
-       if (strstarts(symname, "__crc_")) {
-               is_crc = true;
-               crc = (unsigned int) sym->st_value;
-               if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
-                       unsigned int *crcp;
-
-                       /* symbol points to the CRC in the ELF object */
-                       crcp = (void *)info->hdr + sym->st_value +
-                              info->sechdrs[sym->st_shndx].sh_offset -
-                              (info->hdr->e_type != ET_REL ?
-                               info->sechdrs[sym->st_shndx].sh_addr : 0);
-                       crc = TO_NATIVE(*crcp);
-               }
-               sym_update_crc(symname + strlen("__crc_"), mod, crc,
-                               export);
-       }
-
        switch (sym->st_shndx) {
        case SHN_COMMON:
                if (strstarts(symname, "__gnu_lto_")) {
@@ -745,11 +749,6 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
                }
 #endif
 
-               if (is_crc) {
-                       const char *e = is_vmlinux(mod->name) ?"":".ko";
-                       warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
-                            symname + strlen("__crc_"), mod->name, e);
-               }
                mod->unres = alloc_symbol(symname,
                                          ELF_ST_BIND(sym->st_info) == STB_WEAK,
                                          mod->unres);
@@ -2050,18 +2049,22 @@ static void read_symbols(const char *modname)
        for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
                symname = remove_dot(info.strtab + sym->st_name);
 
-               handle_modversions(mod, &info, sym, symname);
+               handle_symbol(mod, &info, sym, symname);
                handle_moddevtable(mod, &info, sym, symname);
        }
 
-       /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
        for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
                symname = remove_dot(info.strtab + sym->st_name);
 
+               /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
                if (strstarts(symname, "__kstrtabns_"))
                        sym_update_namespace(symname + strlen("__kstrtabns_"),
                                             namespace_from_kstrtabns(&info,
                                                                      sym));
+
+               if (strstarts(symname, "__crc_"))
+                       handle_modversion(mod, &info, sym,
+                                         symname + strlen("__crc_"));
        }
 
        // check for static EXPORT_SYMBOL_* functions && global vars
@@ -2217,15 +2220,11 @@ static int check_exports(struct module *mod)
                else
                        basename = mod->name;
 
-               if (exp->namespace) {
-                       add_namespace(&mod->required_namespaces,
-                                     exp->namespace);
-
-                       if (!write_namespace_deps &&
-                           !module_imports_namespace(mod, exp->namespace)) {
-                               warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
-                                    basename, exp->name, exp->namespace);
-                       }
+               if (exp->namespace &&
+                   !module_imports_namespace(mod, exp->namespace)) {
+                       warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
+                            basename, exp->name, exp->namespace);
+                       add_namespace(&mod->missing_namespaces, exp->namespace);
                }
 
                if (!mod->gpl_compatible)
@@ -2477,9 +2476,8 @@ static void read_dump(const char *fname, unsigned int kernel)
                }
                s = sym_add_exported(symname, mod, export_no(export));
                s->kernel    = kernel;
-               s->preloaded = 1;
                s->is_static = 0;
-               sym_update_crc(symname, mod, crc, export_no(export));
+               sym_set_crc(symname, crc);
                sym_update_namespace(symname, namespace);
        }
        release_file(file, size);
@@ -2527,29 +2525,27 @@ static void write_dump(const char *fname)
        free(buf.p);
 }
 
-static void write_namespace_deps_files(void)
+static void write_namespace_deps_files(const char *fname)
 {
        struct module *mod;
        struct namespace_list *ns;
        struct buffer ns_deps_buf = {};
 
        for (mod = modules; mod; mod = mod->next) {
-               char fname[PATH_MAX];
 
-               if (mod->skip)
+               if (mod->skip || !mod->missing_namespaces)
                        continue;
 
-               ns_deps_buf.pos = 0;
-
-               for (ns = mod->required_namespaces; ns; ns = ns->next)
-                       buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
+               buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
 
-               if (ns_deps_buf.pos == 0)
-                       continue;
+               for (ns = mod->missing_namespaces; ns; ns = ns->next)
+                       buf_printf(&ns_deps_buf, " %s", ns->namespace);
 
-               sprintf(fname, "%s.ns_deps", mod->name);
-               write_if_changed(&ns_deps_buf, fname);
+               buf_printf(&ns_deps_buf, "\n");
        }
+
+       write_if_changed(&ns_deps_buf, fname);
+       free(ns_deps_buf.p);
 }
 
 struct ext_sym_list {
@@ -2561,7 +2557,8 @@ int main(int argc, char **argv)
 {
        struct module *mod;
        struct buffer buf = { };
-       char *kernel_read = NULL, *module_read = NULL;
+       char *kernel_read = NULL;
+       char *missing_namespace_deps = NULL;
        char *dump_write = NULL, *files_source = NULL;
        int opt;
        int err;
@@ -2569,13 +2566,10 @@ int main(int argc, char **argv)
        struct ext_sym_list *extsym_iter;
        struct ext_sym_list *extsym_start = NULL;
 
-       while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
+       while ((opt = getopt(argc, argv, "i:e:mnsT:o:awEd:")) != -1) {
                switch (opt) {
                case 'i':
                        kernel_read = optarg;
-                       break;
-               case 'I':
-                       module_read = optarg;
                        external_module = 1;
                        break;
                case 'e':
@@ -2611,7 +2605,7 @@ int main(int argc, char **argv)
                        sec_mismatch_fatal = 1;
                        break;
                case 'd':
-                       write_namespace_deps = 1;
+                       missing_namespace_deps = optarg;
                        break;
                default:
                        exit(1);
@@ -2620,8 +2614,6 @@ int main(int argc, char **argv)
 
        if (kernel_read)
                read_dump(kernel_read, 1);
-       if (module_read)
-               read_dump(module_read, 0);
        while (extsym_start) {
                read_dump(extsym_start->file, 0);
                extsym_iter = extsym_start->next;
@@ -2647,8 +2639,6 @@ int main(int argc, char **argv)
 
                err |= check_modname_len(mod);
                err |= check_exports(mod);
-               if (write_namespace_deps)
-                       continue;
 
                add_header(&buf, mod);
                add_intree_flag(&buf, !external_module);
@@ -2663,10 +2653,8 @@ int main(int argc, char **argv)
                write_if_changed(&buf, fname);
        }
 
-       if (write_namespace_deps) {
-               write_namespace_deps_files();
-               return 0;
-       }
+       if (missing_namespace_deps)
+               write_namespace_deps_files(missing_namespace_deps);
 
        if (dump_write)
                write_dump(dump_write);
index ad271bc..64a82d2 100644 (file)
@@ -126,8 +126,8 @@ struct module {
        struct buffer dev_table_buf;
        char         srcversion[25];
        int is_dot_o;
-       // Required namespace dependencies
-       struct namespace_list *required_namespaces;
+       // Missing namespace dependencies
+       struct namespace_list *missing_namespaces;
        // Actual imported namespaces
        struct namespace_list *imported_namespaces;
 };
@@ -143,7 +143,6 @@ struct elf_info {
        Elf_Section  export_gpl_sec;
        Elf_Section  export_unused_gpl_sec;
        Elf_Section  export_gpl_future_sec;
-       char         *ksymtab_strings;
        char         *strtab;
        char         *modinfo;
        unsigned int modinfo_len;
index 04cea09..03a8e7c 100644 (file)
@@ -21,21 +21,26 @@ if [ "$SPATCH_VERSION_NUM" -lt "$SPATCH_REQ_VERSION_NUM" ] ; then
        exit 1
 fi
 
+if [ "$KBUILD_EXTMOD" ]; then
+       src_prefix=
+else
+       src_prefix=$srctree/
+fi
+
 generate_deps_for_ns() {
        $SPATCH --very-quiet --in-place --sp-file \
                $srctree/scripts/coccinelle/misc/add_namespace.cocci -D ns=$1 $2
 }
 
 generate_deps() {
-       local mod_name=`basename $@ .ko`
-       local mod_file=`echo $@ | sed -e 's/\.ko/\.mod/'`
-       local ns_deps_file=`echo $@ | sed -e 's/\.ko/\.ns_deps/'`
-       if [ ! -f "$ns_deps_file" ]; then return; fi
-       local mod_source_files="`cat $mod_file | sed -n 1p                      \
+       local mod=${1%.ko:}
+       shift
+       local namespaces="$*"
+       local mod_source_files="`cat $mod.mod | sed -n 1p                      \
                                              | sed -e 's/\.o/\.c/g'           \
-                                             | sed "s|[^ ]* *|${srctree}/&|g"`"
-       for ns in `cat $ns_deps_file`; do
-               echo "Adding namespace $ns to module $mod_name (if needed)."
+                                             | sed "s|[^ ]* *|${src_prefix}&|g"`"
+       for ns in $namespaces; do
+               echo "Adding namespace $ns to module $mod.ko."
                generate_deps_for_ns $ns "$mod_source_files"
                # sort the imports
                for source_file in $mod_source_files; do
@@ -52,7 +57,7 @@ generate_deps() {
        done
 }
 
-for f in `cat $objtree/modules.order`; do
-       generate_deps $f
-done
-
+while read line
+do
+       generate_deps $line
+done < $MODULES_NSDEPS
index 2f66c81..77c7cae 100755 (executable)
@@ -2,7 +2,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 #
-# buildtar 0.0.4
+# buildtar 0.0.5
 #
 # (C) 2004-2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
 #
@@ -24,7 +24,7 @@ tarball="${objtree}/linux-${KERNELRELEASE}-${ARCH}.tar"
 # Figure out how to compress, if requested at all
 #
 case "${1}" in
-       tar-pkg)
+       dir-pkg|tar-pkg)
                opts=
                ;;
        targz-pkg)
@@ -125,6 +125,10 @@ case "${ARCH}" in
                ;;
 esac
 
+if [ "${1}" = dir-pkg ]; then
+       echo "Kernel tree successfully created in $tmpdir"
+       exit 0
+fi
 
 #
 # Create the tarball
diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c
deleted file mode 100644 (file)
index 4718d78..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-
-/*
- *  Convert a logo in ASCII PNM format to C source suitable for inclusion in
- *  the Linux kernel
- *
- *  (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
- *
- *  --------------------------------------------------------------------------
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License. See the file COPYING in the main directory of the Linux
- *  distribution for more details.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-
-static const char *programname;
-static const char *filename;
-static const char *logoname = "linux_logo";
-static const char *outputname;
-static FILE *out;
-
-
-#define LINUX_LOGO_MONO                1       /* monochrome black/white */
-#define LINUX_LOGO_VGA16       2       /* 16 colors VGA text palette */
-#define LINUX_LOGO_CLUT224     3       /* 224 colors */
-#define LINUX_LOGO_GRAY256     4       /* 256 levels grayscale */
-
-static const char *logo_types[LINUX_LOGO_GRAY256+1] = {
-    [LINUX_LOGO_MONO] = "LINUX_LOGO_MONO",
-    [LINUX_LOGO_VGA16] = "LINUX_LOGO_VGA16",
-    [LINUX_LOGO_CLUT224] = "LINUX_LOGO_CLUT224",
-    [LINUX_LOGO_GRAY256] = "LINUX_LOGO_GRAY256"
-};
-
-#define MAX_LINUX_LOGO_COLORS  224
-
-struct color {
-    unsigned char red;
-    unsigned char green;
-    unsigned char blue;
-};
-
-static const struct color clut_vga16[16] = {
-    { 0x00, 0x00, 0x00 },
-    { 0x00, 0x00, 0xaa },
-    { 0x00, 0xaa, 0x00 },
-    { 0x00, 0xaa, 0xaa },
-    { 0xaa, 0x00, 0x00 },
-    { 0xaa, 0x00, 0xaa },
-    { 0xaa, 0x55, 0x00 },
-    { 0xaa, 0xaa, 0xaa },
-    { 0x55, 0x55, 0x55 },
-    { 0x55, 0x55, 0xff },
-    { 0x55, 0xff, 0x55 },
-    { 0x55, 0xff, 0xff },
-    { 0xff, 0x55, 0x55 },
-    { 0xff, 0x55, 0xff },
-    { 0xff, 0xff, 0x55 },
-    { 0xff, 0xff, 0xff },
-};
-
-
-static int logo_type = LINUX_LOGO_CLUT224;
-static unsigned int logo_width;
-static unsigned int logo_height;
-static struct color **logo_data;
-static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
-static unsigned int logo_clutsize;
-static int is_plain_pbm = 0;
-
-static void die(const char *fmt, ...)
-    __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
-static void usage(void) __attribute ((noreturn));
-
-
-static unsigned int get_number(FILE *fp)
-{
-    int c, val;
-
-    /* Skip leading whitespace */
-    do {
-       c = fgetc(fp);
-       if (c == EOF)
-           die("%s: end of file\n", filename);
-       if (c == '#') {
-           /* Ignore comments 'till end of line */
-           do {
-               c = fgetc(fp);
-               if (c == EOF)
-                   die("%s: end of file\n", filename);
-           } while (c != '\n');
-       }
-    } while (isspace(c));
-
-    /* Parse decimal number */
-    val = 0;
-    while (isdigit(c)) {
-       val = 10*val+c-'0';
-       /* some PBM are 'broken'; GiMP for example exports a PBM without space
-        * between the digits. This is Ok cause we know a PBM can only have a '1'
-        * or a '0' for the digit. */
-       if (is_plain_pbm)
-               break;
-       c = fgetc(fp);
-       if (c == EOF)
-           die("%s: end of file\n", filename);
-    }
-    return val;
-}
-
-static unsigned int get_number255(FILE *fp, unsigned int maxval)
-{
-    unsigned int val = get_number(fp);
-    return (255*val+maxval/2)/maxval;
-}
-
-static void read_image(void)
-{
-    FILE *fp;
-    unsigned int i, j;
-    int magic;
-    unsigned int maxval;
-
-    /* open image file */
-    fp = fopen(filename, "r");
-    if (!fp)
-       die("Cannot open file %s: %s\n", filename, strerror(errno));
-
-    /* check file type and read file header */
-    magic = fgetc(fp);
-    if (magic != 'P')
-       die("%s is not a PNM file\n", filename);
-    magic = fgetc(fp);
-    switch (magic) {
-       case '1':
-       case '2':
-       case '3':
-           /* Plain PBM/PGM/PPM */
-           break;
-
-       case '4':
-       case '5':
-       case '6':
-           /* Binary PBM/PGM/PPM */
-           die("%s: Binary PNM is not supported\n"
-               "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename);
-
-       default:
-           die("%s is not a PNM file\n", filename);
-    }
-    logo_width = get_number(fp);
-    logo_height = get_number(fp);
-
-    /* allocate image data */
-    logo_data = (struct color **)malloc(logo_height*sizeof(struct color *));
-    if (!logo_data)
-       die("%s\n", strerror(errno));
-    for (i = 0; i < logo_height; i++) {
-       logo_data[i] = malloc(logo_width*sizeof(struct color));
-       if (!logo_data[i])
-           die("%s\n", strerror(errno));
-    }
-
-    /* read image data */
-    switch (magic) {
-       case '1':
-           /* Plain PBM */
-           is_plain_pbm = 1;
-           for (i = 0; i < logo_height; i++)
-               for (j = 0; j < logo_width; j++)
-                   logo_data[i][j].red = logo_data[i][j].green =
-                       logo_data[i][j].blue = 255*(1-get_number(fp));
-           break;
-
-       case '2':
-           /* Plain PGM */
-           maxval = get_number(fp);
-           for (i = 0; i < logo_height; i++)
-               for (j = 0; j < logo_width; j++)
-                   logo_data[i][j].red = logo_data[i][j].green =
-                       logo_data[i][j].blue = get_number255(fp, maxval);
-           break;
-
-       case '3':
-           /* Plain PPM */
-           maxval = get_number(fp);
-           for (i = 0; i < logo_height; i++)
-               for (j = 0; j < logo_width; j++) {
-                   logo_data[i][j].red = get_number255(fp, maxval);
-                   logo_data[i][j].green = get_number255(fp, maxval);
-                   logo_data[i][j].blue = get_number255(fp, maxval);
-               }
-           break;
-    }
-
-    /* close file */
-    fclose(fp);
-}
-
-static inline int is_black(struct color c)
-{
-    return c.red == 0 && c.green == 0 && c.blue == 0;
-}
-
-static inline int is_white(struct color c)
-{
-    return c.red == 255 && c.green == 255 && c.blue == 255;
-}
-
-static inline int is_gray(struct color c)
-{
-    return c.red == c.green && c.red == c.blue;
-}
-
-static inline int is_equal(struct color c1, struct color c2)
-{
-    return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;
-}
-
-static void write_header(void)
-{
-    /* open logo file */
-    if (outputname) {
-       out = fopen(outputname, "w");
-       if (!out)
-           die("Cannot create file %s: %s\n", outputname, strerror(errno));
-    } else {
-       out = stdout;
-    }
-
-    fputs("/*\n", out);
-    fputs(" *  DO NOT EDIT THIS FILE!\n", out);
-    fputs(" *\n", out);
-    fprintf(out, " *  It was automatically generated from %s\n", filename);
-    fputs(" *\n", out);
-    fprintf(out, " *  Linux logo %s\n", logoname);
-    fputs(" */\n\n", out);
-    fputs("#include <linux/linux_logo.h>\n\n", out);
-    fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
-           logoname);
-}
-
-static void write_footer(void)
-{
-    fputs("\n};\n\n", out);
-    fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname);
-    fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
-    fprintf(out, "\t.width\t\t= %d,\n", logo_width);
-    fprintf(out, "\t.height\t\t= %d,\n", logo_height);
-    if (logo_type == LINUX_LOGO_CLUT224) {
-       fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
-       fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
-    }
-    fprintf(out, "\t.data\t\t= %s_data\n", logoname);
-    fputs("};\n\n", out);
-
-    /* close logo file */
-    if (outputname)
-       fclose(out);
-}
-
-static int write_hex_cnt;
-
-static void write_hex(unsigned char byte)
-{
-    if (write_hex_cnt % 12)
-       fprintf(out, ", 0x%02x", byte);
-    else if (write_hex_cnt)
-       fprintf(out, ",\n\t0x%02x", byte);
-    else
-       fprintf(out, "\t0x%02x", byte);
-    write_hex_cnt++;
-}
-
-static void write_logo_mono(void)
-{
-    unsigned int i, j;
-    unsigned char val, bit;
-
-    /* validate image */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++)
-           if (!is_black(logo_data[i][j]) && !is_white(logo_data[i][j]))
-               die("Image must be monochrome\n");
-
-    /* write file header */
-    write_header();
-
-    /* write logo data */
-    for (i = 0; i < logo_height; i++) {
-       for (j = 0; j < logo_width;) {
-           for (val = 0, bit = 0x80; bit && j < logo_width; j++, bit >>= 1)
-               if (logo_data[i][j].red)
-                   val |= bit;
-           write_hex(val);
-       }
-    }
-
-    /* write logo structure and file footer */
-    write_footer();
-}
-
-static void write_logo_vga16(void)
-{
-    unsigned int i, j, k;
-    unsigned char val;
-
-    /* validate image */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++) {
-           for (k = 0; k < 16; k++)
-               if (is_equal(logo_data[i][j], clut_vga16[k]))
-                   break;
-           if (k == 16)
-               die("Image must use the 16 console colors only\n"
-                   "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "
-                   "of colors\n");
-       }
-
-    /* write file header */
-    write_header();
-
-    /* write logo data */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++) {
-           for (k = 0; k < 16; k++)
-               if (is_equal(logo_data[i][j], clut_vga16[k]))
-                   break;
-           val = k<<4;
-           if (++j < logo_width) {
-               for (k = 0; k < 16; k++)
-                   if (is_equal(logo_data[i][j], clut_vga16[k]))
-                       break;
-               val |= k;
-           }
-           write_hex(val);
-       }
-
-    /* write logo structure and file footer */
-    write_footer();
-}
-
-static void write_logo_clut224(void)
-{
-    unsigned int i, j, k;
-
-    /* validate image */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++) {
-           for (k = 0; k < logo_clutsize; k++)
-               if (is_equal(logo_data[i][j], logo_clut[k]))
-                   break;
-           if (k == logo_clutsize) {
-               if (logo_clutsize == MAX_LINUX_LOGO_COLORS)
-                   die("Image has more than %d colors\n"
-                       "Use ppmquant(1) to reduce the number of colors\n",
-                       MAX_LINUX_LOGO_COLORS);
-               logo_clut[logo_clutsize++] = logo_data[i][j];
-           }
-       }
-
-    /* write file header */
-    write_header();
-
-    /* write logo data */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++) {
-           for (k = 0; k < logo_clutsize; k++)
-               if (is_equal(logo_data[i][j], logo_clut[k]))
-                   break;
-           write_hex(k+32);
-       }
-    fputs("\n};\n\n", out);
-
-    /* write logo clut */
-    fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
-           logoname);
-    write_hex_cnt = 0;
-    for (i = 0; i < logo_clutsize; i++) {
-       write_hex(logo_clut[i].red);
-       write_hex(logo_clut[i].green);
-       write_hex(logo_clut[i].blue);
-    }
-
-    /* write logo structure and file footer */
-    write_footer();
-}
-
-static void write_logo_gray256(void)
-{
-    unsigned int i, j;
-
-    /* validate image */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++)
-           if (!is_gray(logo_data[i][j]))
-               die("Image must be grayscale\n");
-
-    /* write file header */
-    write_header();
-
-    /* write logo data */
-    for (i = 0; i < logo_height; i++)
-       for (j = 0; j < logo_width; j++)
-           write_hex(logo_data[i][j].red);
-
-    /* write logo structure and file footer */
-    write_footer();
-}
-
-static void die(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-
-    exit(1);
-}
-
-static void usage(void)
-{
-    die("\n"
-       "Usage: %s [options] <filename>\n"
-       "\n"
-       "Valid options:\n"
-       "    -h          : display this usage information\n"
-       "    -n <name>   : specify logo name (default: linux_logo)\n"
-       "    -o <output> : output to file <output> instead of stdout\n"
-       "    -t <type>   : specify logo type, one of\n"
-       "                      mono    : monochrome black/white\n"
-       "                      vga16   : 16 colors VGA text palette\n"
-       "                      clut224 : 224 colors (default)\n"
-       "                      gray256 : 256 levels grayscale\n"
-       "\n", programname);
-}
-
-int main(int argc, char *argv[])
-{
-    int opt;
-
-    programname = argv[0];
-
-    opterr = 0;
-    while (1) {
-       opt = getopt(argc, argv, "hn:o:t:");
-       if (opt == -1)
-           break;
-
-       switch (opt) {
-           case 'h':
-               usage();
-               break;
-
-           case 'n':
-               logoname = optarg;
-               break;
-
-           case 'o':
-               outputname = optarg;
-               break;
-
-           case 't':
-               if (!strcmp(optarg, "mono"))
-                   logo_type = LINUX_LOGO_MONO;
-               else if (!strcmp(optarg, "vga16"))
-                   logo_type = LINUX_LOGO_VGA16;
-               else if (!strcmp(optarg, "clut224"))
-                   logo_type = LINUX_LOGO_CLUT224;
-               else if (!strcmp(optarg, "gray256"))
-                   logo_type = LINUX_LOGO_GRAY256;
-               else
-                   usage();
-               break;
-
-           default:
-               usage();
-               break;
-       }
-    }
-    if (optind != argc-1)
-       usage();
-
-    filename = argv[optind];
-
-    read_image();
-    switch (logo_type) {
-       case LINUX_LOGO_MONO:
-           write_logo_mono();
-           break;
-
-       case LINUX_LOGO_VGA16:
-           write_logo_vga16();
-           break;
-
-       case LINUX_LOGO_CLUT224:
-           write_logo_clut224();
-           break;
-
-       case LINUX_LOGO_GRAY256:
-           write_logo_gray256();
-           break;
-    }
-    exit(0);
-}
index a2998b1..20f2efd 100755 (executable)
@@ -45,11 +45,11 @@ scm_version()
 
        # Check for git and a git repo.
        if test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
-          head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
+          head=$(git rev-parse --verify --short HEAD 2>/dev/null); then
 
                # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
                # it, because this version is defined in the top level Makefile.
-               if [ -z "`git describe --exact-match 2>/dev/null`" ]; then
+               if [ -z "$(git describe --exact-match 2>/dev/null)" ]; then
 
                        # If only the short version is requested, don't bother
                        # running further git commands
@@ -59,7 +59,7 @@ scm_version()
                        fi
                        # If we are past a tagged commit (like
                        # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
-                       if atag="`git describe 2>/dev/null`"; then
+                       if atag="$(git describe 2>/dev/null)"; then
                                echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
 
                        # If we don't have a tag at all we print -g{commitish}.
@@ -70,7 +70,7 @@ scm_version()
 
                # Is this git on svn?
                if git config --get svn-remote.svn.url >/dev/null; then
-                       printf -- '-svn%s' "`git svn find-rev $head`"
+                       printf -- '-svn%s' "$(git svn find-rev $head)"
                fi
 
                # Check for uncommitted changes.
@@ -91,15 +91,15 @@ scm_version()
        fi
 
        # Check for mercurial and a mercurial repo.
-       if test -d .hg && hgid=`hg id 2>/dev/null`; then
+       if test -d .hg && hgid=$(hg id 2>/dev/null); then
                # Do we have an tagged version?  If so, latesttagdistance == 1
-               if [ "`hg log -r . --template '{latesttagdistance}'`" = "1" ]; then
-                       id=`hg log -r . --template '{latesttag}'`
+               if [ "$(hg log -r . --template '{latesttagdistance}')" = "1" ]; then
+                       id=$(hg log -r . --template '{latesttag}')
                        printf '%s%s' -hg "$id"
                else
-                       tag=`printf '%s' "$hgid" | cut -d' ' -f2`
+                       tag=$(printf '%s' "$hgid" | cut -d' ' -f2)
                        if [ -z "$tag" -o "$tag" = tip ]; then
-                               id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
+                               id=$(printf '%s' "$hgid" | sed 's/[+ ].*//')
                                printf '%s%s' -hg "$id"
                        fi
                fi
@@ -115,8 +115,8 @@ scm_version()
        fi
 
        # Check for svn and a svn repo.
-       if rev=`LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'`; then
-               rev=`echo $rev | awk '{print $NF}'`
+       if rev=$(LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'); then
+               rev=$(echo $rev | awk '{print $NF}')
                printf -- '-svn%s' "$rev"
 
                # All done with svn
index de75b9f..672b593 100644 (file)
@@ -87,6 +87,7 @@ algorith||algorithm
 algorithmical||algorithmically
 algoritm||algorithm
 algoritms||algorithms
+algorithmn||algorithm
 algorrithm||algorithm
 algorritm||algorithm
 aligment||alignment
@@ -109,6 +110,7 @@ alredy||already
 altough||although
 alue||value
 ambigious||ambiguous
+ambigous||ambiguous
 amoung||among
 amout||amount
 amplifer||amplifier
@@ -179,6 +181,7 @@ attepmpt||attempt
 attnetion||attention
 attruibutes||attributes
 authentification||authentication
+authenicated||authenticated
 automaticaly||automatically
 automaticly||automatically
 automatize||automate
@@ -286,6 +289,7 @@ claread||cleared
 clared||cleared
 closeing||closing
 clustred||clustered
+cnfiguration||configuration
 coexistance||coexistence
 colescing||coalescing
 collapsable||collapsible
@@ -325,9 +329,11 @@ comression||compression
 comunication||communication
 conbination||combination
 conditionaly||conditionally
+conditon||condition
 conected||connected
 conector||connector
 connecetd||connected
+configration||configuration
 configuartion||configuration
 configuation||configuration
 configued||configured
@@ -347,6 +353,7 @@ containts||contains
 contaisn||contains
 contant||contact
 contence||contents
+contiguos||contiguous
 continious||continuous
 continous||continuous
 continously||continuously
@@ -380,6 +387,7 @@ cylic||cyclic
 dafault||default
 deafult||default
 deamon||daemon
+debouce||debounce
 decompres||decompress
 decsribed||described
 decription||description
@@ -448,6 +456,7 @@ diffrent||different
 differenciate||differentiate
 diffrentiate||differentiate
 difinition||definition
+digial||digital
 dimention||dimension
 dimesions||dimensions
 dispalying||displaying
@@ -489,6 +498,7 @@ droput||dropout
 druing||during
 dynmaic||dynamic
 eanable||enable
+eanble||enable
 easilly||easily
 ecspecially||especially
 edditable||editable
@@ -502,6 +512,7 @@ elementry||elementary
 eletronic||electronic
 embeded||embedded
 enabledi||enabled
+enbale||enable
 enble||enable
 enchanced||enhanced
 encorporating||incorporating
@@ -536,6 +547,7 @@ excellant||excellent
 execeeded||exceeded
 execeeds||exceeds
 exeed||exceed
+exeuction||execution
 existance||existence
 existant||existent
 exixt||exist
@@ -601,10 +613,12 @@ frambuffer||framebuffer
 framming||framing
 framwork||framework
 frequncy||frequency
+frequancy||frequency
 frome||from
 fucntion||function
 fuction||function
 fuctions||functions
+fullill||fulfill
 funcation||function
 funcion||function
 functionallity||functionality
@@ -642,6 +656,7 @@ happend||happened
 harware||hardware
 heirarchically||hierarchically
 helpfull||helpful
+hexdecimal||hexadecimal
 hybernate||hibernate
 hierachy||hierarchy
 hierarchie||hierarchy
@@ -709,12 +724,14 @@ initalize||initialize
 initation||initiation
 initators||initiators
 initialiazation||initialization
+initializationg||initialization
 initializiation||initialization
 initialze||initialize
 initialzed||initialized
 initialzing||initializing
 initilization||initialization
 initilize||initialize
+initliaze||initialize
 inofficial||unofficial
 inrerface||interface
 insititute||institute
@@ -779,6 +796,7 @@ itertation||iteration
 itslef||itself
 jave||java
 jeffies||jiffies
+jumpimng||jumping
 juse||just
 jus||just
 kown||known
@@ -839,6 +857,7 @@ messags||messages
 messgaes||messages
 messsage||message
 messsages||messages
+metdata||metadata
 micropone||microphone
 microprocesspr||microprocessor
 migrateable||migratable
@@ -857,6 +876,7 @@ mismactch||mismatch
 missign||missing
 missmanaged||mismanaged
 missmatch||mismatch
+misssing||missing
 miximum||maximum
 mmnemonic||mnemonic
 mnay||many
@@ -912,6 +932,7 @@ occured||occurred
 occuring||occurring
 offser||offset
 offet||offset
+offlaod||offload
 offloded||offloaded
 offseting||offsetting
 omited||omitted
@@ -993,6 +1014,7 @@ poiter||pointer
 posible||possible
 positon||position
 possibilites||possibilities
+potocol||protocol
 powerfull||powerful
 pramater||parameter
 preamle||preamble
@@ -1061,11 +1083,13 @@ psychadelic||psychedelic
 pwoer||power
 queing||queuing
 quering||querying
+queus||queues
 randomally||randomly
 raoming||roaming
 reasearcher||researcher
 reasearchers||researchers
 reasearch||research
+receieve||receive
 recepient||recipient
 recevied||received
 receving||receiving
@@ -1166,6 +1190,7 @@ scaleing||scaling
 scaned||scanned
 scaning||scanning
 scarch||search
+schdule||schedule
 seach||search
 searchs||searches
 secquence||sequence
@@ -1308,6 +1333,7 @@ taskelt||tasklet
 teh||the
 temorary||temporary
 temproarily||temporarily
+temperture||temperature
 thead||thread
 therfore||therefore
 thier||their
@@ -1354,6 +1380,7 @@ uknown||unknown
 usupported||unsupported
 uncommited||uncommitted
 unconditionaly||unconditionally
+undeflow||underflow
 underun||underrun
 unecessary||unnecessary
 unexecpted||unexpected
@@ -1414,6 +1441,7 @@ varible||variable
 varient||variant
 vaule||value
 verbse||verbose
+veify||verify
 verisons||versions
 verison||version
 verson||version
index 3b638c0..470ccfe 100755 (executable)
@@ -124,11 +124,13 @@ sub add_package($$)
 
 sub check_missing_file($$$)
 {
-       my $file = shift;
+       my $files = shift;
        my $package = shift;
        my $is_optional = shift;
 
-       return if(-e $file);
+       for (@$files) {
+               return if(-e $_);
+       }
 
        add_package($package, $is_optional);
 }
@@ -343,10 +345,11 @@ sub give_debian_hints()
        );
 
        if ($pdf) {
-               check_missing_file("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
+               check_missing_file(["/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"],
                                   "fonts-dejavu", 2);
 
-               check_missing_file("/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
+               check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
+                                  "/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc"],
                                   "fonts-noto-cjk", 2);
        }
 
@@ -413,7 +416,7 @@ sub give_redhat_hints()
        }
 
        if ($pdf) {
-               check_missing_file("/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc",
+               check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc"],
                                   "google-noto-sans-cjk-ttc-fonts", 2);
        }
 
@@ -498,7 +501,7 @@ sub give_mageia_hints()
        $map{"latexmk"} = "texlive-collection-basic";
 
        if ($pdf) {
-               check_missing_file("/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc",
+               check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc"],
                                   "google-noto-sans-cjk-ttc-fonts", 2);
        }
 
@@ -517,6 +520,7 @@ sub give_arch_linux_hints()
                "dot"                   => "graphviz",
                "convert"               => "imagemagick",
                "xelatex"               => "texlive-bin",
+               "latexmk"               => "texlive-core",
                "rsvg-convert"          => "extra/librsvg",
        );
 
@@ -528,7 +532,7 @@ sub give_arch_linux_hints()
        check_pacman_missing(\@archlinux_tex_pkgs, 2) if ($pdf);
 
        if ($pdf) {
-               check_missing_file("/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
+               check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"],
                                   "noto-fonts-cjk", 2);
        }
 
@@ -549,11 +553,11 @@ sub give_gentoo_hints()
                "rsvg-convert"          => "gnome-base/librsvg",
        );
 
-       check_missing_file("/usr/share/fonts/dejavu/DejaVuSans.ttf",
+       check_missing_file(["/usr/share/fonts/dejavu/DejaVuSans.ttf"],
                           "media-fonts/dejavu", 2) if ($pdf);
 
        if ($pdf) {
-               check_missing_file("/usr/share/fonts/noto-cjk/NotoSansCJKsc-Regular.otf",
+               check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJKsc-Regular.otf"],
                                   "media-fonts/noto-cjk", 2);
        }
 
@@ -645,6 +649,12 @@ sub check_distros()
 # Common dependencies
 #
 
+sub deactivate_help()
+{
+       printf "\tIf you want to exit the virtualenv, you can use:\n";
+       printf "\tdeactivate\n";
+}
+
 sub check_needs()
 {
        # Check for needed programs/tools
@@ -686,6 +696,7 @@ sub check_needs()
                if ($need_sphinx && scalar @activates > 0 && $activates[0] ge $min_activate) {
                        printf "\nNeed to activate a compatible Sphinx version on virtualenv with:\n";
                        printf "\t. $activates[0]\n";
+                       deactivate_help();
                        exit (1);
                } else {
                        my $rec_activate = "$virtenv_dir/bin/activate";
@@ -697,6 +708,7 @@ sub check_needs()
                        printf "\t$virtualenv $virtenv_dir\n";
                        printf "\t. $rec_activate\n";
                        printf "\tpip install -r $requirement_file\n";
+                       deactivate_help();
 
                        $need++ if (!$rec_sphinx_upgrade);
                }
index 810e608..85005d6 100755 (executable)
@@ -32,6 +32,8 @@ BEGIN {
        printversion("PPP", version("pppd --version"))
        printversion("Isdn4k-utils", version("isdnctrl"))
        printversion("Nfs-utils", version("showmount --version"))
+       printversion("Bison", version("bison --version"))
+       printversion("Flex", version("flex --version"))
 
        while (getline <"/proc/self/maps" > 0) {
                if (/libc.*\.so$/) {
index d8b1a36..a422a34 100644 (file)
@@ -6,6 +6,8 @@ config SECURITY_APPARMOR
        select SECURITY_PATH
        select SECURITYFS
        select SECURITY_NETWORK
+       select ZLIB_INFLATE
+       select ZLIB_DEFLATE
        default n
        help
          This enables the AppArmor security module.
index 45d13b6..09996f2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/fs_context.h>
 #include <linux/poll.h>
+#include <linux/zlib.h>
 #include <uapi/linux/major.h>
 #include <uapi/linux/magic.h>
 
  * support fns
  */
 
+struct rawdata_f_data {
+       struct aa_loaddata *loaddata;
+};
+
+#define RAWDATA_F_DATA_BUF(p) (char *)(p + 1)
+
+static void rawdata_f_data_free(struct rawdata_f_data *private)
+{
+       if (!private)
+               return;
+
+       aa_put_loaddata(private->loaddata);
+       kvfree(private);
+}
+
+static struct rawdata_f_data *rawdata_f_data_alloc(size_t size)
+{
+       struct rawdata_f_data *ret;
+
+       if (size > SIZE_MAX - sizeof(*ret))
+               return ERR_PTR(-EINVAL);
+
+       ret = kvzalloc(sizeof(*ret) + size, GFP_KERNEL);
+       if (!ret)
+               return ERR_PTR(-ENOMEM);
+
+       return ret;
+}
+
 /**
  * aa_mangle_name - mangle a profile name to std profile layout form
  * @name: profile name to mangle  (NOT NULL)
@@ -1280,36 +1310,117 @@ static int seq_rawdata_hash_show(struct seq_file *seq, void *v)
        return 0;
 }
 
+static int seq_rawdata_compressed_size_show(struct seq_file *seq, void *v)
+{
+       struct aa_loaddata *data = seq->private;
+
+       seq_printf(seq, "%zu\n", data->compressed_size);
+
+       return 0;
+}
+
 SEQ_RAWDATA_FOPS(abi);
 SEQ_RAWDATA_FOPS(revision);
 SEQ_RAWDATA_FOPS(hash);
+SEQ_RAWDATA_FOPS(compressed_size);
+
+static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
+{
+       int error;
+       struct z_stream_s strm;
+
+       if (aa_g_rawdata_compression_level == 0) {
+               if (dlen < slen)
+                       return -EINVAL;
+               memcpy(dst, src, slen);
+               return 0;
+       }
+
+       memset(&strm, 0, sizeof(strm));
+
+       strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+       if (!strm.workspace)
+               return -ENOMEM;
+
+       strm.next_in = src;
+       strm.avail_in = slen;
+
+       error = zlib_inflateInit(&strm);
+       if (error != Z_OK) {
+               error = -ENOMEM;
+               goto fail_inflate_init;
+       }
+
+       strm.next_out = dst;
+       strm.avail_out = dlen;
+
+       error = zlib_inflate(&strm, Z_FINISH);
+       if (error != Z_STREAM_END)
+               error = -EINVAL;
+       else
+               error = 0;
+
+       zlib_inflateEnd(&strm);
+fail_inflate_init:
+       kvfree(strm.workspace);
+       return error;
+}
 
 static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
                            loff_t *ppos)
 {
-       struct aa_loaddata *rawdata = file->private_data;
+       struct rawdata_f_data *private = file->private_data;
 
-       return simple_read_from_buffer(buf, size, ppos, rawdata->data,
-                                      rawdata->size);
+       return simple_read_from_buffer(buf, size, ppos,
+                                      RAWDATA_F_DATA_BUF(private),
+                                      private->loaddata->size);
 }
 
 static int rawdata_release(struct inode *inode, struct file *file)
 {
-       aa_put_loaddata(file->private_data);
+       rawdata_f_data_free(file->private_data);
 
        return 0;
 }
 
 static int rawdata_open(struct inode *inode, struct file *file)
 {
+       int error;
+       struct aa_loaddata *loaddata;
+       struct rawdata_f_data *private;
+
        if (!policy_view_capable(NULL))
                return -EACCES;
-       file->private_data = __aa_get_loaddata(inode->i_private);
-       if (!file->private_data)
+
+       loaddata = __aa_get_loaddata(inode->i_private);
+       if (!loaddata)
                /* lost race: this entry is being reaped */
                return -ENOENT;
 
+       private = rawdata_f_data_alloc(loaddata->size);
+       if (IS_ERR(private)) {
+               error = PTR_ERR(private);
+               goto fail_private_alloc;
+       }
+
+       private->loaddata = loaddata;
+
+       error = deflate_decompress(loaddata->data, loaddata->compressed_size,
+                                  RAWDATA_F_DATA_BUF(private),
+                                  loaddata->size);
+       if (error)
+               goto fail_decompress;
+
+       file->private_data = private;
        return 0;
+
+fail_decompress:
+       rawdata_f_data_free(private);
+       return error;
+
+fail_private_alloc:
+       aa_put_loaddata(loaddata);
+       return error;
 }
 
 static const struct file_operations rawdata_fops = {
@@ -1388,6 +1499,13 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata)
                rawdata->dents[AAFS_LOADDATA_HASH] = dent;
        }
 
+       dent = aafs_create_file("compressed_size", S_IFREG | 0444, dir,
+                               rawdata,
+                               &seq_rawdata_compressed_size_fops);
+       if (IS_ERR(dent))
+               goto fail;
+       rawdata->dents[AAFS_LOADDATA_COMPRESSED_SIZE] = dent;
+
        dent = aafs_create_file("raw_data", S_IFREG | 0444,
                                      dir, rawdata, &rawdata_fops);
        if (IS_ERR(dent))
index 9e04927..9be7ccb 100644 (file)
@@ -520,7 +520,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
                                label = &new_profile->label;
                        continue;
                }
-               label = aa_label_parse(&profile->label, *name, GFP_ATOMIC,
+               label = aa_label_parse(&profile->label, *name, GFP_KERNEL,
                                       true, false);
                if (IS_ERR(label))
                        label = NULL;
@@ -600,7 +600,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
                /* base the stack on post domain transition */
                struct aa_label *base = new;
 
-               new = aa_label_parse(base, stack, GFP_ATOMIC, true, false);
+               new = aa_label_parse(base, stack, GFP_KERNEL, true, false);
                if (IS_ERR(new))
                        new = NULL;
                aa_put_label(base);
@@ -685,20 +685,9 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
        } else if (COMPLAIN_MODE(profile)) {
                /* no exec permission - learning mode */
                struct aa_profile *new_profile = NULL;
-               char *n = kstrdup(name, GFP_ATOMIC);
-
-               if (n) {
-                       /* name is ptr into buffer */
-                       long pos = name - buffer;
-                       /* break per cpu buffer hold */
-                       put_buffers(buffer);
-                       new_profile = aa_new_null_profile(profile, false, n,
-                                                         GFP_KERNEL);
-                       get_buffers(buffer);
-                       name = buffer + pos;
-                       strcpy((char *)name, n);
-                       kfree(n);
-               }
+
+               new_profile = aa_new_null_profile(profile, false, name,
+                                                 GFP_KERNEL);
                if (!new_profile) {
                        error = -ENOMEM;
                        info = "could not create null profile";
@@ -719,7 +708,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
                if (DEBUG_ON) {
                        dbg_printk("apparmor: scrubbing environment variables"
                                   " for %s profile=", name);
-                       aa_label_printk(new, GFP_ATOMIC);
+                       aa_label_printk(new, GFP_KERNEL);
                        dbg_printk("\n");
                }
                *secure_exec = true;
@@ -795,7 +784,7 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
                if (DEBUG_ON) {
                        dbg_printk("apparmor: scrubbing environment "
                                   "variables for %s label=", xname);
-                       aa_label_printk(onexec, GFP_ATOMIC);
+                       aa_label_printk(onexec, GFP_KERNEL);
                        dbg_printk("\n");
                }
                *secure_exec = true;
@@ -829,7 +818,7 @@ static struct aa_label *handle_onexec(struct aa_label *label,
                                               bprm, buffer, cond, unsafe));
                if (error)
                        return ERR_PTR(error);
-               new = fn_label_build_in_ns(label, profile, GFP_ATOMIC,
+               new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
                                aa_get_newest_label(onexec),
                                profile_transition(profile, bprm, buffer,
                                                   cond, unsafe));
@@ -841,9 +830,9 @@ static struct aa_label *handle_onexec(struct aa_label *label,
                                               buffer, cond, unsafe));
                if (error)
                        return ERR_PTR(error);
-               new = fn_label_build_in_ns(label, profile, GFP_ATOMIC,
+               new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
                                aa_label_merge(&profile->label, onexec,
-                                              GFP_ATOMIC),
+                                              GFP_KERNEL),
                                profile_transition(profile, bprm, buffer,
                                                   cond, unsafe));
        }
@@ -903,13 +892,18 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                ctx->nnp = aa_get_label(label);
 
        /* buffer freed below, name is pointer into buffer */
-       get_buffers(buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer) {
+               error = -ENOMEM;
+               goto done;
+       }
+
        /* Test for onexec first as onexec override other x transitions. */
        if (ctx->onexec)
                new = handle_onexec(label, ctx->onexec, ctx->token,
                                    bprm, buffer, &cond, &unsafe);
        else
-               new = fn_label_build(label, profile, GFP_ATOMIC,
+               new = fn_label_build(label, profile, GFP_KERNEL,
                                profile_transition(profile, bprm, buffer,
                                                   &cond, &unsafe));
 
@@ -953,7 +947,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                if (DEBUG_ON) {
                        dbg_printk("scrubbing environment variables for %s "
                                   "label=", bprm->filename);
-                       aa_label_printk(new, GFP_ATOMIC);
+                       aa_label_printk(new, GFP_KERNEL);
                        dbg_printk("\n");
                }
                bprm->secureexec = 1;
@@ -964,7 +958,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                if (DEBUG_ON) {
                        dbg_printk("apparmor: clearing unsafe personality "
                                   "bits. %s label=", bprm->filename);
-                       aa_label_printk(new, GFP_ATOMIC);
+                       aa_label_printk(new, GFP_KERNEL);
                        dbg_printk("\n");
                }
                bprm->per_clear |= PER_CLEAR_ON_SETID;
@@ -975,7 +969,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
 
 done:
        aa_put_label(label);
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 
index 4c1b05e..fe2ebe5 100644 (file)
@@ -76,7 +76,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
        if (aad(sa)->peer) {
                audit_log_format(ab, " target=");
                aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
-                               FLAG_VIEW_SUBNS, GFP_ATOMIC);
+                               FLAG_VIEW_SUBNS, GFP_KERNEL);
        } else if (aad(sa)->fs.target) {
                audit_log_format(ab, " target=");
                audit_log_untrustedstring(ab, aad(sa)->fs.target);
@@ -332,12 +332,14 @@ int aa_path_perm(const char *op, struct aa_label *label,
 
        flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR :
                                                                0);
-       get_buffers(buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer)
+               return -ENOMEM;
        error = fn_for_each_confined(label, profile,
                        profile_path_perm(op, profile, path, buffer, request,
                                          cond, flags, &perms));
 
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -475,12 +477,18 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
        int error;
 
        /* buffer freed below, lname is pointer in buffer */
-       get_buffers(buffer, buffer2);
+       buffer = aa_get_buffer(false);
+       buffer2 = aa_get_buffer(false);
+       error = -ENOMEM;
+       if (!buffer || !buffer2)
+               goto out;
+
        error = fn_for_each_confined(label, profile,
                        profile_path_link(profile, &link, buffer, &target,
                                          buffer2, &cond));
-       put_buffers(buffer, buffer2);
-
+out:
+       aa_put_buffer(buffer);
+       aa_put_buffer(buffer2);
        return error;
 }
 
@@ -507,7 +515,7 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label,
 
 static int __file_path_perm(const char *op, struct aa_label *label,
                            struct aa_label *flabel, struct file *file,
-                           u32 request, u32 denied)
+                           u32 request, u32 denied, bool in_atomic)
 {
        struct aa_profile *profile;
        struct aa_perms perms = {};
@@ -524,7 +532,9 @@ static int __file_path_perm(const char *op, struct aa_label *label,
                return 0;
 
        flags = PATH_DELEGATE_DELETED | (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0);
-       get_buffers(buffer);
+       buffer = aa_get_buffer(in_atomic);
+       if (!buffer)
+               return -ENOMEM;
 
        /* check every profile in task label not in current cache */
        error = fn_for_each_not_in_set(flabel, label, profile,
@@ -553,7 +563,7 @@ static int __file_path_perm(const char *op, struct aa_label *label,
        if (!error)
                update_file_ctx(file_ctx(file), label, request);
 
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -590,11 +600,12 @@ static int __file_sock_perm(const char *op, struct aa_label *label,
  * @label: label being enforced   (NOT NULL)
  * @file: file to revalidate access permissions on  (NOT NULL)
  * @request: requested permissions
+ * @in_atomic: whether allocations need to be done in atomic context
  *
  * Returns: %0 if access allowed else error
  */
 int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
-                u32 request)
+                u32 request, bool in_atomic)
 {
        struct aa_file_ctx *fctx;
        struct aa_label *flabel;
@@ -607,7 +618,8 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
        fctx = file_ctx(file);
 
        rcu_read_lock();
-       flabel  = rcu_dereference(fctx->label);
+       flabel  = aa_get_newest_label(rcu_dereference(fctx->label));
+       rcu_read_unlock();
        AA_BUG(!flabel);
 
        /* revalidate access, if task is unconfined, or the cached cred
@@ -626,14 +638,13 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
 
        if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
                error = __file_path_perm(op, label, flabel, file, request,
-                                        denied);
+                                        denied, in_atomic);
 
        else if (S_ISSOCK(file_inode(file)->i_mode))
                error = __file_sock_perm(op, label, flabel, file, request,
                                         denied);
 done:
-       rcu_read_unlock();
-
+       aa_put_label(flabel);
        return error;
 }
 
@@ -655,7 +666,8 @@ static void revalidate_tty(struct aa_label *label)
                                             struct tty_file_private, list);
                file = file_priv->file;
 
-               if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE))
+               if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE,
+                                IN_ATOMIC))
                        drop_tty = 1;
        }
        spin_unlock(&tty->files_lock);
@@ -669,7 +681,8 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
 {
        struct aa_label *label = (struct aa_label *)p;
 
-       if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file)))
+       if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file),
+                        IN_ATOMIC))
                return fd + 1;
        return 0;
 }
index 6b7e6e1..1fbabdb 100644 (file)
@@ -36,6 +36,7 @@ extern enum audit_mode aa_g_audit;
 extern bool aa_g_audit_header;
 extern bool aa_g_debug;
 extern bool aa_g_hash_policy;
+extern int aa_g_rawdata_compression_level;
 extern bool aa_g_lock_policy;
 extern bool aa_g_logsyscall;
 extern bool aa_g_paranoid_load;
index a852be8..aff26fc 100644 (file)
@@ -197,7 +197,7 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
                 const struct path *new_dir, struct dentry *new_dentry);
 
 int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
-                u32 request);
+                u32 request, bool in_atomic);
 
 void aa_inherit_files(const struct cred *cred, struct files_struct *files);
 
index 6b0af63..e23f4aa 100644 (file)
@@ -134,7 +134,7 @@ unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
 
 void aa_dfa_free_kref(struct kref *kref);
 
-#define WB_HISTORY_SIZE 8
+#define WB_HISTORY_SIZE 24
 struct match_workbuf {
        unsigned int count;
        unsigned int pos;
@@ -147,7 +147,6 @@ struct match_workbuf N = {          \
        .count = 0,                     \
        .pos = 0,                       \
        .len = 0,                       \
-       .size = WB_HISTORY_SIZE,                        \
 }
 
 unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start,
index 35a8295..44a7945 100644 (file)
@@ -11,7 +11,6 @@
 #ifndef __AA_PATH_H
 #define __AA_PATH_H
 
-
 enum path_flags {
        PATH_IS_DIR = 0x1,              /* path is a directory */
        PATH_CONNECT_PATH = 0x4,        /* connect disconnected paths to / */
@@ -26,51 +25,8 @@ int aa_path_name(const struct path *path, int flags, char *buffer,
                 const char **name, const char **info,
                 const char *disconnected);
 
-#define MAX_PATH_BUFFERS 2
-
-/* Per cpu buffers used during mediation */
-/* preallocated buffers to use during path lookups */
-struct aa_buffers {
-       char *buf[MAX_PATH_BUFFERS];
-};
-
-#include <linux/percpu.h>
-#include <linux/preempt.h>
-
-DECLARE_PER_CPU(struct aa_buffers, aa_buffers);
-
-#define ASSIGN(FN, A, X, N) ((X) = FN(A, N))
-#define EVAL1(FN, A, X) ASSIGN(FN, A, X, 0) /*X = FN(0)*/
-#define EVAL2(FN, A, X, Y...)  \
-       do { ASSIGN(FN, A, X, 1);  EVAL1(FN, A, Y); } while (0)
-#define EVAL(FN, A, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, A, X)
-
-#define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++)
-
-#ifdef CONFIG_DEBUG_PREEMPT
-#define AA_BUG_PREEMPT_ENABLED(X) AA_BUG(preempt_count() <= 0, X)
-#else
-#define AA_BUG_PREEMPT_ENABLED(X) /* nop */
-#endif
-
-#define __get_buffer(C, N) ({                                          \
-       AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled");  \
-       (C)->buf[(N)]; })
-
-#define __get_buffers(C, X...)    EVAL(__get_buffer, C, X)
-
-#define __put_buffers(X, Y...) ((void)&(X))
-
-#define get_buffers(X...)                                              \
-do {                                                                   \
-       struct aa_buffers *__cpu_var = get_cpu_ptr(&aa_buffers);        \
-       __get_buffers(__cpu_var, X);                                    \
-} while (0)
-
-#define put_buffers(X, Y...)           \
-do {                                   \
-       __put_buffers(X, Y);            \
-       put_cpu_ptr(&aa_buffers);       \
-} while (0)
+#define IN_ATOMIC true
+char *aa_get_buffer(bool in_atomic);
+void aa_put_buffer(char *buf);
 
 #endif /* __AA_PATH_H */
index 46aefae..e0e1ca7 100644 (file)
@@ -41,6 +41,7 @@ enum {
        AAFS_LOADDATA_REVISION,
        AAFS_LOADDATA_HASH,
        AAFS_LOADDATA_DATA,
+       AAFS_LOADDATA_COMPRESSED_SIZE,
        AAFS_LOADDATA_DIR,              /* must be last actual entry */
        AAFS_LOADDATA_NDENTS            /* count of entries */
 };
@@ -61,11 +62,16 @@ struct aa_loaddata {
        struct dentry *dents[AAFS_LOADDATA_NDENTS];
        struct aa_ns *ns;
        char *name;
-       size_t size;
+       size_t size;                    /* the original size of the payload */
+       size_t compressed_size;         /* the compressed size of the payload */
        long revision;                  /* the ns policy revision this caused */
        int abi;
        unsigned char *hash;
 
+       /* Pointer to payload. If @compressed_size > 0, then this is the
+        * compressed version of the payload, else it is the uncompressed
+        * version (with the size indicated by @size).
+        */
        char *data;
 };
 
index 59f1cc2..4706932 100644 (file)
@@ -1458,11 +1458,13 @@ static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
 /* helper macro for snprint routines */
 #define update_for_len(total, len, size, str)  \
 do {                                   \
+       size_t ulen = len;              \
+                                       \
        AA_BUG(len < 0);                \
-       total += len;                   \
-       len = min(len, size);           \
-       size -= len;                    \
-       str += len;                     \
+       total += ulen;                  \
+       ulen = min(ulen, size);         \
+       size -= ulen;                   \
+       str += ulen;                    \
 } while (0)
 
 /**
@@ -1597,7 +1599,7 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
        struct aa_ns *prev_ns = NULL;
        struct label_it i;
        int count = 0, total = 0;
-       size_t len;
+       ssize_t len;
 
        AA_BUG(!str && size != 0);
        AA_BUG(!label);
index ec3a928..b621ad7 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/user_namespace.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
+#include <linux/zlib.h>
 #include <net/sock.h>
 #include <uapi/linux/mount.h>
 
 /* Flag indicating whether initialization completed */
 int apparmor_initialized;
 
-DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
+union aa_buffer {
+       struct list_head list;
+       char buffer[1];
+};
+
+#define RESERVE_COUNT 2
+static int reserve_count = RESERVE_COUNT;
+static int buffer_count;
 
+static LIST_HEAD(aa_global_buffers);
+static DEFINE_SPINLOCK(aa_buffers_lock);
 
 /*
  * LSM hook functions
@@ -442,7 +452,8 @@ static void apparmor_file_free_security(struct file *file)
                aa_put_label(rcu_access_pointer(ctx->label));
 }
 
-static int common_file_perm(const char *op, struct file *file, u32 mask)
+static int common_file_perm(const char *op, struct file *file, u32 mask,
+                           bool in_atomic)
 {
        struct aa_label *label;
        int error = 0;
@@ -452,7 +463,7 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
                return -EACCES;
 
        label = __begin_current_label_crit_section();
-       error = aa_file_perm(op, label, file, mask);
+       error = aa_file_perm(op, label, file, mask, in_atomic);
        __end_current_label_crit_section(label);
 
        return error;
@@ -460,12 +471,13 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
 
 static int apparmor_file_receive(struct file *file)
 {
-       return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file));
+       return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file),
+                               false);
 }
 
 static int apparmor_file_permission(struct file *file, int mask)
 {
-       return common_file_perm(OP_FPERM, file, mask);
+       return common_file_perm(OP_FPERM, file, mask, false);
 }
 
 static int apparmor_file_lock(struct file *file, unsigned int cmd)
@@ -475,11 +487,11 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
        if (cmd == F_WRLCK)
                mask |= MAY_WRITE;
 
-       return common_file_perm(OP_FLOCK, file, mask);
+       return common_file_perm(OP_FLOCK, file, mask, false);
 }
 
 static int common_mmap(const char *op, struct file *file, unsigned long prot,
-                      unsigned long flags)
+                      unsigned long flags, bool in_atomic)
 {
        int mask = 0;
 
@@ -497,20 +509,21 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot,
        if (prot & PROT_EXEC)
                mask |= AA_EXEC_MMAP;
 
-       return common_file_perm(op, file, mask);
+       return common_file_perm(op, file, mask, in_atomic);
 }
 
 static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
                              unsigned long prot, unsigned long flags)
 {
-       return common_mmap(OP_FMMAP, file, prot, flags);
+       return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC);
 }
 
 static int apparmor_file_mprotect(struct vm_area_struct *vma,
                                  unsigned long reqprot, unsigned long prot)
 {
        return common_mmap(OP_FMPROT, vma->vm_file, prot,
-                          !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+                          !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0,
+                          false);
 }
 
 static int apparmor_sb_mount(const char *dev_name, const struct path *path,
@@ -1262,6 +1275,16 @@ static const struct kernel_param_ops param_ops_aauint = {
        .get = param_get_aauint
 };
 
+static int param_set_aacompressionlevel(const char *val,
+                                       const struct kernel_param *kp);
+static int param_get_aacompressionlevel(char *buffer,
+                                       const struct kernel_param *kp);
+#define param_check_aacompressionlevel param_check_int
+static const struct kernel_param_ops param_ops_aacompressionlevel = {
+       .set = param_set_aacompressionlevel,
+       .get = param_get_aacompressionlevel
+};
+
 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
 #define param_check_aalockpolicy param_check_bool
@@ -1292,6 +1315,11 @@ bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT);
 module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
 #endif
 
+/* policy loaddata compression level */
+int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION;
+module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
+                  aacompressionlevel, 0400);
+
 /* Debug mode */
 bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES);
 module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
@@ -1402,6 +1430,7 @@ static int param_set_aauint(const char *val, const struct kernel_param *kp)
                return -EPERM;
 
        error = param_set_uint(val, kp);
+       aa_g_path_max = max_t(uint32_t, aa_g_path_max, sizeof(union aa_buffer));
        pr_info("AppArmor: buffer size set to %d bytes\n", aa_g_path_max);
 
        return error;
@@ -1456,6 +1485,37 @@ static int param_get_aaintbool(char *buffer, const struct kernel_param *kp)
        return param_get_bool(buffer, &kp_local);
 }
 
+static int param_set_aacompressionlevel(const char *val,
+                                       const struct kernel_param *kp)
+{
+       int error;
+
+       if (!apparmor_enabled)
+               return -EINVAL;
+       if (apparmor_initialized)
+               return -EPERM;
+
+       error = param_set_int(val, kp);
+
+       aa_g_rawdata_compression_level = clamp(aa_g_rawdata_compression_level,
+                                              Z_NO_COMPRESSION,
+                                              Z_BEST_COMPRESSION);
+       pr_info("AppArmor: policy rawdata compression level set to %u\n",
+               aa_g_rawdata_compression_level);
+
+       return error;
+}
+
+static int param_get_aacompressionlevel(char *buffer,
+                                       const struct kernel_param *kp)
+{
+       if (!apparmor_enabled)
+               return -EINVAL;
+       if (apparmor_initialized && !policy_view_capable(NULL))
+               return -EPERM;
+       return param_get_int(buffer, kp);
+}
+
 static int param_get_audit(char *buffer, const struct kernel_param *kp)
 {
        if (!apparmor_enabled)
@@ -1514,6 +1574,61 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
        return 0;
 }
 
+char *aa_get_buffer(bool in_atomic)
+{
+       union aa_buffer *aa_buf;
+       bool try_again = true;
+       gfp_t flags = (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
+
+retry:
+       spin_lock(&aa_buffers_lock);
+       if (buffer_count > reserve_count ||
+           (in_atomic && !list_empty(&aa_global_buffers))) {
+               aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer,
+                                         list);
+               list_del(&aa_buf->list);
+               buffer_count--;
+               spin_unlock(&aa_buffers_lock);
+               return &aa_buf->buffer[0];
+       }
+       if (in_atomic) {
+               /*
+                * out of reserve buffers and in atomic context so increase
+                * how many buffers to keep in reserve
+                */
+               reserve_count++;
+               flags = GFP_ATOMIC;
+       }
+       spin_unlock(&aa_buffers_lock);
+
+       if (!in_atomic)
+               might_sleep();
+       aa_buf = kmalloc(aa_g_path_max, flags);
+       if (!aa_buf) {
+               if (try_again) {
+                       try_again = false;
+                       goto retry;
+               }
+               pr_warn_once("AppArmor: Failed to allocate a memory buffer.\n");
+               return NULL;
+       }
+       return &aa_buf->buffer[0];
+}
+
+void aa_put_buffer(char *buf)
+{
+       union aa_buffer *aa_buf;
+
+       if (!buf)
+               return;
+       aa_buf = container_of(buf, union aa_buffer, buffer[0]);
+
+       spin_lock(&aa_buffers_lock);
+       list_add(&aa_buf->list, &aa_global_buffers);
+       buffer_count++;
+       spin_unlock(&aa_buffers_lock);
+}
+
 /*
  * AppArmor init functions
  */
@@ -1525,7 +1640,7 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
  */
 static int __init set_init_ctx(void)
 {
-       struct cred *cred = (struct cred *)current->real_cred;
+       struct cred *cred = (__force struct cred *)current->real_cred;
 
        set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
 
@@ -1534,38 +1649,48 @@ static int __init set_init_ctx(void)
 
 static void destroy_buffers(void)
 {
-       u32 i, j;
+       union aa_buffer *aa_buf;
 
-       for_each_possible_cpu(i) {
-               for_each_cpu_buffer(j) {
-                       kfree(per_cpu(aa_buffers, i).buf[j]);
-                       per_cpu(aa_buffers, i).buf[j] = NULL;
-               }
+       spin_lock(&aa_buffers_lock);
+       while (!list_empty(&aa_global_buffers)) {
+               aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer,
+                                        list);
+               list_del(&aa_buf->list);
+               spin_unlock(&aa_buffers_lock);
+               kfree(aa_buf);
+               spin_lock(&aa_buffers_lock);
        }
+       spin_unlock(&aa_buffers_lock);
 }
 
 static int __init alloc_buffers(void)
 {
-       u32 i, j;
-
-       for_each_possible_cpu(i) {
-               for_each_cpu_buffer(j) {
-                       char *buffer;
-
-                       if (cpu_to_node(i) > num_online_nodes())
-                               /* fallback to kmalloc for offline nodes */
-                               buffer = kmalloc(aa_g_path_max, GFP_KERNEL);
-                       else
-                               buffer = kmalloc_node(aa_g_path_max, GFP_KERNEL,
-                                                     cpu_to_node(i));
-                       if (!buffer) {
-                               destroy_buffers();
-                               return -ENOMEM;
-                       }
-                       per_cpu(aa_buffers, i).buf[j] = buffer;
+       union aa_buffer *aa_buf;
+       int i, num;
+
+       /*
+        * A function may require two buffers at once. Usually the buffers are
+        * used for a short period of time and are shared. On UP kernel buffers
+        * two should be enough, with more CPUs it is possible that more
+        * buffers will be used simultaneously. The preallocated pool may grow.
+        * This preallocation has also the side-effect that AppArmor will be
+        * disabled early at boot if aa_g_path_max is extremly high.
+        */
+       if (num_online_cpus() > 1)
+               num = 4 + RESERVE_COUNT;
+       else
+               num = 2 + RESERVE_COUNT;
+
+       for (i = 0; i < num; i++) {
+
+               aa_buf = kmalloc(aa_g_path_max, GFP_KERNEL |
+                                __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
+               if (!aa_buf) {
+                       destroy_buffers();
+                       return -ENOMEM;
                }
+               aa_put_buffer(&aa_buf->buffer[0]);
        }
-
        return 0;
 }
 
@@ -1730,7 +1855,7 @@ static int __init apparmor_init(void)
        error = alloc_buffers();
        if (error) {
                AA_ERROR("Unable to allocate work buffers\n");
-               goto buffers_out;
+               goto alloc_out;
        }
 
        error = set_init_ctx();
@@ -1755,7 +1880,6 @@ static int __init apparmor_init(void)
 
 buffers_out:
        destroy_buffers();
-
 alloc_out:
        aa_destroy_aafs();
        aa_teardown_dfa_engine();
index 6ccd373..525ce22 100644 (file)
@@ -616,8 +616,8 @@ unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
 
 #define inc_wb_pos(wb)                                         \
 do {                                                           \
-       wb->pos = (wb->pos + 1) & (wb->size - 1);               \
-       wb->len = (wb->len + 1) & (wb->size - 1);               \
+       wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1);                \
+       wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1);                \
 } while (0)
 
 /* For DFAs that don't support extended tagging of states */
@@ -636,7 +636,7 @@ static bool is_loop(struct match_workbuf *wb, unsigned int state,
                        return true;
                }
                if (pos == 0)
-                       pos = wb->size;
+                       pos = WB_HISTORY_SIZE;
                pos--;
        }
 
index 17081c8..4ed6688 100644 (file)
@@ -408,11 +408,13 @@ int aa_remount(struct aa_label *label, const struct path *path,
 
        binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
 
-       get_buffers(buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer)
+               return -ENOMEM;
        error = fn_for_each_confined(label, profile,
                        match_mnt(profile, path, buffer, NULL, NULL, NULL,
                                  flags, data, binary));
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -437,11 +439,18 @@ int aa_bind_mount(struct aa_label *label, const struct path *path,
        if (error)
                return error;
 
-       get_buffers(buffer, old_buffer);
+       buffer = aa_get_buffer(false);
+       old_buffer = aa_get_buffer(false);
+       error = -ENOMEM;
+       if (!buffer || old_buffer)
+               goto out;
+
        error = fn_for_each_confined(label, profile,
                        match_mnt(profile, path, buffer, &old_path, old_buffer,
                                  NULL, flags, NULL, false));
-       put_buffers(buffer, old_buffer);
+out:
+       aa_put_buffer(buffer);
+       aa_put_buffer(old_buffer);
        path_put(&old_path);
 
        return error;
@@ -461,11 +470,13 @@ int aa_mount_change_type(struct aa_label *label, const struct path *path,
        flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
                  MS_UNBINDABLE);
 
-       get_buffers(buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer)
+               return -ENOMEM;
        error = fn_for_each_confined(label, profile,
                        match_mnt(profile, path, buffer, NULL, NULL, NULL,
                                  flags, NULL, false));
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -488,11 +499,17 @@ int aa_move_mount(struct aa_label *label, const struct path *path,
        if (error)
                return error;
 
-       get_buffers(buffer, old_buffer);
+       buffer = aa_get_buffer(false);
+       old_buffer = aa_get_buffer(false);
+       error = -ENOMEM;
+       if (!buffer || !old_buffer)
+               goto out;
        error = fn_for_each_confined(label, profile,
                        match_mnt(profile, path, buffer, &old_path, old_buffer,
                                  NULL, MS_MOVE, NULL, false));
-       put_buffers(buffer, old_buffer);
+out:
+       aa_put_buffer(buffer);
+       aa_put_buffer(old_buffer);
        path_put(&old_path);
 
        return error;
@@ -533,8 +550,17 @@ int aa_new_mount(struct aa_label *label, const char *dev_name,
                }
        }
 
-       get_buffers(buffer, dev_buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer) {
+               error = -ENOMEM;
+               goto out;
+       }
        if (dev_path) {
+               dev_buffer = aa_get_buffer(false);
+               if (!dev_buffer) {
+                       error = -ENOMEM;
+                       goto out;
+               }
                error = fn_for_each_confined(label, profile,
                        match_mnt(profile, path, buffer, dev_path, dev_buffer,
                                  type, flags, data, binary));
@@ -543,7 +569,10 @@ int aa_new_mount(struct aa_label *label, const char *dev_name,
                        match_mnt_path_str(profile, path, buffer, dev_name,
                                           type, flags, data, binary, NULL));
        }
-       put_buffers(buffer, dev_buffer);
+
+out:
+       aa_put_buffer(buffer);
+       aa_put_buffer(dev_buffer);
        if (dev_path)
                path_put(dev_path);
 
@@ -591,10 +620,13 @@ int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
        AA_BUG(!label);
        AA_BUG(!mnt);
 
-       get_buffers(buffer);
+       buffer = aa_get_buffer(false);
+       if (!buffer)
+               return -ENOMEM;
+
        error = fn_for_each_confined(label, profile,
                        profile_umount(profile, &path, buffer));
-       put_buffers(buffer);
+       aa_put_buffer(buffer);
 
        return error;
 }
@@ -667,8 +699,12 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path,
        AA_BUG(!old_path);
        AA_BUG(!new_path);
 
-       get_buffers(old_buffer, new_buffer);
-       target = fn_label_build(label, profile, GFP_ATOMIC,
+       old_buffer = aa_get_buffer(false);
+       new_buffer = aa_get_buffer(false);
+       error = -ENOMEM;
+       if (!old_buffer || !new_buffer)
+               goto out;
+       target = fn_label_build(label, profile, GFP_KERNEL,
                        build_pivotroot(profile, new_path, new_buffer,
                                        old_path, old_buffer));
        if (!target) {
@@ -686,7 +722,8 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path,
                /* already audited error */
                error = PTR_ERR(target);
 out:
-       put_buffers(old_buffer, new_buffer);
+       aa_put_buffer(old_buffer);
+       aa_put_buffer(new_buffer);
 
        return error;
 
index ade3330..0310483 100644 (file)
@@ -582,7 +582,7 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
 {
        if (profile) {
                if (profile->label.flags & FLAG_IMMUTIBLE) {
-                       *info = "cannot replace immutible profile";
+                       *info = "cannot replace immutable profile";
                        return -EPERM;
                } else if (noreplace) {
                        *info = "profile already exists";
@@ -856,7 +856,7 @@ static struct aa_profile *update_to_newest_parent(struct aa_profile *new)
 ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
                            u32 mask, struct aa_loaddata *udata)
 {
-       const char *ns_name, *info = NULL;
+       const char *ns_name = NULL, *info = NULL;
        struct aa_ns *ns = NULL;
        struct aa_load_ent *ent, *tmp;
        struct aa_loaddata *rawdata_ent;
@@ -1043,6 +1043,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
 out:
        aa_put_ns(ns);
        aa_put_loaddata(udata);
+       kfree(ns_name);
 
        if (error)
                return error;
index 8cfc949..8036431 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/unaligned.h>
 #include <linux/ctype.h>
 #include <linux/errno.h>
+#include <linux/zlib.h>
 
 #include "include/apparmor.h"
 #include "include/audit.h"
@@ -139,9 +140,11 @@ bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
 {
        if (l->size != r->size)
                return false;
+       if (l->compressed_size != r->compressed_size)
+               return false;
        if (aa_g_hash_policy && memcmp(l->hash, r->hash, aa_hash_size()) != 0)
                return false;
-       return memcmp(l->data, r->data, r->size) == 0;
+       return memcmp(l->data, r->data, r->compressed_size ?: r->size) == 0;
 }
 
 /*
@@ -968,11 +971,14 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
                                    e, error);
                        return error;
                }
-               if (*ns && strcmp(*ns, name))
+               if (*ns && strcmp(*ns, name)) {
                        audit_iface(NULL, NULL, NULL, "invalid ns change", e,
                                    error);
-               else if (!*ns)
-                       *ns = name;
+               } else if (!*ns) {
+                       *ns = kstrdup(name, GFP_KERNEL);
+                       if (!*ns)
+                               return -ENOMEM;
+               }
        }
 
        return 0;
@@ -1039,6 +1045,105 @@ struct aa_load_ent *aa_load_ent_alloc(void)
        return ent;
 }
 
+static int deflate_compress(const char *src, size_t slen, char **dst,
+                           size_t *dlen)
+{
+       int error;
+       struct z_stream_s strm;
+       void *stgbuf, *dstbuf;
+       size_t stglen = deflateBound(slen);
+
+       memset(&strm, 0, sizeof(strm));
+
+       if (stglen < slen)
+               return -EFBIG;
+
+       strm.workspace = kvzalloc(zlib_deflate_workspacesize(MAX_WBITS,
+                                                            MAX_MEM_LEVEL),
+                                 GFP_KERNEL);
+       if (!strm.workspace)
+               return -ENOMEM;
+
+       error = zlib_deflateInit(&strm, aa_g_rawdata_compression_level);
+       if (error != Z_OK) {
+               error = -ENOMEM;
+               goto fail_deflate_init;
+       }
+
+       stgbuf = kvzalloc(stglen, GFP_KERNEL);
+       if (!stgbuf) {
+               error = -ENOMEM;
+               goto fail_stg_alloc;
+       }
+
+       strm.next_in = src;
+       strm.avail_in = slen;
+       strm.next_out = stgbuf;
+       strm.avail_out = stglen;
+
+       error = zlib_deflate(&strm, Z_FINISH);
+       if (error != Z_STREAM_END) {
+               error = -EINVAL;
+               goto fail_deflate;
+       }
+       error = 0;
+
+       if (is_vmalloc_addr(stgbuf)) {
+               dstbuf = kvzalloc(strm.total_out, GFP_KERNEL);
+               if (dstbuf) {
+                       memcpy(dstbuf, stgbuf, strm.total_out);
+                       kvfree(stgbuf);
+               }
+       } else
+               /*
+                * If the staging buffer was kmalloc'd, then using krealloc is
+                * probably going to be faster. The destination buffer will
+                * always be smaller, so it's just shrunk, avoiding a memcpy
+                */
+               dstbuf = krealloc(stgbuf, strm.total_out, GFP_KERNEL);
+
+       if (!dstbuf) {
+               error = -ENOMEM;
+               goto fail_deflate;
+       }
+
+       *dst = dstbuf;
+       *dlen = strm.total_out;
+
+fail_stg_alloc:
+       zlib_deflateEnd(&strm);
+fail_deflate_init:
+       kvfree(strm.workspace);
+       return error;
+
+fail_deflate:
+       kvfree(stgbuf);
+       goto fail_stg_alloc;
+}
+
+static int compress_loaddata(struct aa_loaddata *data)
+{
+
+       AA_BUG(data->compressed_size > 0);
+
+       /*
+        * Shortcut the no compression case, else we increase the amount of
+        * storage required by a small amount
+        */
+       if (aa_g_rawdata_compression_level != 0) {
+               void *udata = data->data;
+               int error = deflate_compress(udata, data->size, &data->data,
+                                            &data->compressed_size);
+               if (error)
+                       return error;
+
+               kvfree(udata);
+       } else
+               data->compressed_size = data->size;
+
+       return 0;
+}
+
 /**
  * aa_unpack - unpack packed binary profile(s) data loaded from user space
  * @udata: user data copied to kmem  (NOT NULL)
@@ -1107,6 +1212,9 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh,
                        goto fail;
                }
        }
+       error = compress_loaddata(udata);
+       if (error)
+               goto fail;
        return 0;
 
 fail_profile:
index 0a0e911..8908c58 100644 (file)
@@ -695,16 +695,28 @@ AVXcode: 2
 4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev)
 4e: vrsqrt14ps/d Vpd,Wpd (66),(ev)
 4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev)
-# Skip 0x50-0x57
+50: vpdpbusd Vx,Hx,Wx (66),(ev)
+51: vpdpbusds Vx,Hx,Wx (66),(ev)
+52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66),(ev) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev)
+53: vpdpwssds Vx,Hx,Wx (66),(ev) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev)
+54: vpopcntb/w Vx,Wx (66),(ev)
+55: vpopcntd/q Vx,Wx (66),(ev)
 58: vpbroadcastd Vx,Wx (66),(v)
 59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo)
 5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo)
 5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev)
-# Skip 0x5c-0x63
+# Skip 0x5c-0x61
+62: vpexpandb/w Vx,Wx (66),(ev)
+63: vpcompressb/w Wx,Vx (66),(ev)
 64: vpblendmd/q Vx,Hx,Wx (66),(ev)
 65: vblendmps/d Vx,Hx,Wx (66),(ev)
 66: vpblendmb/w Vx,Hx,Wx (66),(ev)
-# Skip 0x67-0x74
+68: vp2intersectd/q Kx,Hx,Wx (F2),(ev)
+# Skip 0x69-0x6f
+70: vpshldvw Vx,Hx,Wx (66),(ev)
+71: vpshldvd/q Vx,Hx,Wx (66),(ev)
+72: vcvtne2ps2bf16 Vx,Hx,Wx (F2),(ev) | vcvtneps2bf16 Vx,Wx (F3),(ev) | vpshrdvw Vx,Hx,Wx (66),(ev)
+73: vpshrdvd/q Vx,Hx,Wx (66),(ev)
 75: vpermi2b/w Vx,Hx,Wx (66),(ev)
 76: vpermi2d/q Vx,Hx,Wx (66),(ev)
 77: vpermi2ps/d Vx,Hx,Wx (66),(ev)
@@ -727,6 +739,7 @@ AVXcode: 2
 8c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
 8d: vpermb/w Vx,Hx,Wx (66),(ev)
 8e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
+8f: vpshufbitqmb Kx,Hx,Wx (66),(ev)
 # 0x0f 0x38 0x90-0xbf (FMA)
 90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo)
 91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo)
@@ -738,8 +751,8 @@ AVXcode: 2
 97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v)
 98: vfmadd132ps/d Vx,Hx,Wx (66),(v)
 99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
-9a: vfmsub132ps/d Vx,Hx,Wx (66),(v)
-9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
+9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) | v4fmaddps Vdqq,Hdqq,Wdq (F2),(ev)
+9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) | v4fmaddss Vdq,Hdq,Wdq (F2),(ev)
 9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v)
 9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
 9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
@@ -752,8 +765,8 @@ a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
 a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
 a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
 a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
-aa: vfmsub213ps/d Vx,Hx,Wx (66),(v)
-ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
+aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) | v4fnmaddps Vdqq,Hdqq,Wdq (F2),(ev)
+ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) | v4fnmaddss Vdq,Hdq,Wdq (F2),(ev)
 ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v)
 ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
 ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
@@ -780,11 +793,12 @@ ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev)
 cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev)
 cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev)
 cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev)
+cf: vgf2p8mulb Vx,Wx (66)
 db: VAESIMC Vdq,Wdq (66),(v1)
-dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
-dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
-de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
-df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
+dc: vaesenc Vx,Hx,Wx (66)
+dd: vaesenclast Vx,Hx,Wx (66)
+de: vaesdec Vx,Hx,Wx (66)
+df: vaesdeclast Vx,Hx,Wx (66)
 f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2)
 f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2)
 f2: ANDN Gy,By,Ey (v)
@@ -848,7 +862,7 @@ AVXcode: 3
 41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
 42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo)
 43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev)
-44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
+44: vpclmulqdq Vx,Hx,Wx,Ib (66)
 46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
 4a: vblendvps Vx,Hx,Wx,Lx (66),(v)
 4b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
@@ -865,7 +879,13 @@ AVXcode: 3
 63: vpcmpistri Vdq,Wdq,Ib (66),(v1)
 66: vfpclassps/d Vk,Wx,Ib (66),(ev)
 67: vfpclassss/d Vk,Wx,Ib (66),(ev)
+70: vpshldw Vx,Hx,Wx,Ib (66),(ev)
+71: vpshldd/q Vx,Hx,Wx,Ib (66),(ev)
+72: vpshrdw Vx,Hx,Wx,Ib (66),(ev)
+73: vpshrdd/q Vx,Hx,Wx,Ib (66),(ev)
 cc: sha1rnds4 Vdq,Wdq,Ib
+ce: vgf2p8affineqb Vx,Wx,Ib (66)
+cf: vgf2p8affineinvqb Vx,Wx,Ib (66)
 df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
 f0: RORX Gy,Ey,Ib (F2),(v)
 EndTable
index 8a19753..574c2e0 100644 (file)
@@ -96,7 +96,8 @@ FEATURE_TESTS_EXTRA :=                  \
          cxx                            \
          llvm                           \
          llvm-version                   \
-         clang
+         clang                          \
+         libbpf
 
 FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC)
 
index 8499385..f30a890 100644 (file)
@@ -53,6 +53,7 @@ FILES=                                          \
          test-zlib.bin                          \
          test-lzma.bin                          \
          test-bpf.bin                           \
+         test-libbpf.bin                        \
          test-get_cpuid.bin                     \
          test-sdt.bin                           \
          test-cxx.bin                           \
@@ -270,6 +271,9 @@ $(OUTPUT)test-get_cpuid.bin:
 $(OUTPUT)test-bpf.bin:
        $(BUILD)
 
+$(OUTPUT)test-libbpf.bin:
+       $(BUILD) -lbpf
+
 $(OUTPUT)test-sdt.bin:
        $(BUILD)
 
diff --git a/tools/build/feature/test-libbpf.c b/tools/build/feature/test-libbpf.c
new file mode 100644 (file)
index 0000000..a508756
--- /dev/null
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <bpf/libbpf.h>
+
+int main(void)
+{
+       return bpf_object__open("test") ? 0 : -1;
+}
index cb1e51f..32b7c6f 100644 (file)
@@ -129,6 +129,7 @@ static int run_test(struct pci_test *test)
        }
 
        fflush(stdout);
+       close(fd);
        return (ret < 0) ? ret : 1 - ret; /* return 0 if test succeeded */
 }
 
index 1783427..c90f414 100644 (file)
@@ -483,6 +483,16 @@ ifndef NO_LIBELF
     ifeq ($(feature-bpf), 1)
       CFLAGS += -DHAVE_LIBBPF_SUPPORT
       $(call detected,CONFIG_LIBBPF)
+
+      # detecting libbpf without LIBBPF_DYNAMIC, so make VF=1 shows libbpf detection status
+      $(call feature_check,libbpf)
+      ifdef LIBBPF_DYNAMIC
+        ifeq ($(feature-libbpf), 1)
+          EXTLIBS += -lbpf
+        else
+          dummy := $(error Error: No libbpf devel library found, please install libbpf-devel);
+        endif
+      endif
     endif
 
     ifndef NO_DWARF
index 1cd2944..eae5d5e 100644 (file)
@@ -116,6 +116,8 @@ include ../scripts/utilities.mak
 #
 # Define TCMALLOC to enable tcmalloc heap profiling.
 #
+# Define LIBBPF_DYNAMIC to enable libbpf dynamic linking.
+#
 
 # As per kernel Makefile, avoid funny character set dependencies
 unexport LC_ALL
@@ -360,7 +362,9 @@ export PERL_PATH
 
 PERFLIBS = $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD) $(LIBPERF)
 ifndef NO_LIBBPF
-  PERFLIBS += $(LIBBPF)
+  ifndef LIBBPF_DYNAMIC
+    PERFLIBS += $(LIBBPF)
+  endif
 endif
 
 # We choose to avoid "if .. else if .. else .. endif endif"
index 2c35e53..ccfa870 100644 (file)
@@ -3,7 +3,7 @@
 #include "perf_regs.h"
 #include "thread.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "event.h"
 #include "debug.h"
 #include "tests/tests.h"
@@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
 
        sp = (unsigned long) regs[PERF_REG_ARM_SP];
 
-       map = map_groups__find(thread->mg, (u64)sp);
+       map = maps__find(thread->maps, (u64)sp);
        if (!map) {
                pr_debug("failed to get stack map\n");
                free(buf);
index a6a407f..46147a4 100644 (file)
@@ -3,7 +3,7 @@
 #include "perf_regs.h"
 #include "thread.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "event.h"
 #include "debug.h"
 #include "tests/tests.h"
@@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
 
        sp = (unsigned long) regs[PERF_REG_ARM64_SP];
 
-       map = map_groups__find(thread->mg, (u64)sp);
+       map = maps__find(thread->maps, (u64)sp);
        if (!map) {
                pr_debug("failed to get stack map\n");
                free(buf);
index 5c178e4..8efd9ed 100644 (file)
@@ -3,7 +3,7 @@
 #include "perf_regs.h"
 #include "thread.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "event.h"
 #include "debug.h"
 #include "tests/tests.h"
@@ -27,7 +27,7 @@ static int sample_ustack(struct perf_sample *sample,
 
        sp = (unsigned long) regs[PERF_REG_POWERPC_R1];
 
-       map = map_groups__find(thread->mg, (u64)sp);
+       map = maps__find(thread->maps, (u64)sp);
        if (!map) {
                pr_debug("failed to get stack map\n");
                free(buf);
index 2a6662e..0e13663 100644 (file)
@@ -38,7 +38,7 @@ static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
                return -1;
        target.addr = map__objdump_2mem(map, ops->target.addr);
 
-       if (map_groups__find_ams(ms->mg, &target) == 0 &&
+       if (maps__find_ams(ms->maps, &target) == 0 &&
            map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr)
                ops->target.sym = target.ms.sym;
 
index 6ad0a1c..ef43be9 100644 (file)
@@ -3,7 +3,7 @@
 #include "perf_regs.h"
 #include "thread.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "event.h"
 #include "debug.h"
 #include "tests/tests.h"
@@ -27,7 +27,7 @@ static int sample_ustack(struct perf_sample *sample,
 
        sp = (unsigned long) regs[PERF_REG_X86_SP];
 
-       map = map_groups__find(thread->mg, (u64)sp);
+       map = maps__find(thread->maps, (u64)sp);
        if (!map) {
                pr_debug("failed to get stack map\n");
                free(buf);
index 58f8f2a..e6461ab 100644 (file)
 "62 f2 55 0f 4f f4    \tvrsqrt14ss %xmm4,%xmm5,%xmm6{%k7}",},
 {{0x62, 0xf2, 0xd5, 0x0f, 0x4f, 0xf4, }, 6, 0, "", "",
 "62 f2 d5 0f 4f f4    \tvrsqrt14sd %xmm4,%xmm5,%xmm6{%k7}",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x50, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 50 d9    \tvpdpbusd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x50, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 50 d9    \tvpdpbusd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x50, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 50 d9    \tvpdpbusd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x50, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 50 9c c8 78 56 34 12 \tvpdpbusd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x51, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 51 d9    \tvpdpbusds %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x51, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 51 d9    \tvpdpbusds %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x51, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 51 d9    \tvpdpbusds %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x51, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 51 9c c8 78 56 34 12 \tvpdpbusds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6e, 0x08, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6e 08 52 d9    \tvdpbf16ps %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6e, 0x28, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6e 28 52 d9    \tvdpbf16ps %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6e, 0x48, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6e 48 52 d9    \tvdpbf16ps %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6e, 0x48, 0x52, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6e 48 52 9c c8 78 56 34 12 \tvdpbf16ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 52 d9    \tvpdpwssd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 52 d9    \tvpdpwssd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 52 d9    \tvpdpwssd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x52, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 52 9c c8 78 56 34 12 \tvpdpwssd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x52, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 52 20    \tvp4dpwssd (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x52, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 52 a4 c8 78 56 34 12 \tvp4dpwssd 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x53, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 53 d9    \tvpdpwssds %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x53, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 53 d9    \tvpdpwssds %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x53, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 53 d9    \tvpdpwssds %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x53, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 53 9c c8 78 56 34 12 \tvpdpwssds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x53, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 53 20    \tvp4dpwssds (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x53, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 53 a4 c8 78 56 34 12 \tvp4dpwssds 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 08 54 d1    \tvpopcntb %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 28 54 d1    \tvpopcntb %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 48 54 d1    \tvpopcntb %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x54, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 54 94 c8 78 56 34 12 \tvpopcntb 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 08 54 d1    \tvpopcntw %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 28 54 d1    \tvpopcntw %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 48 54 d1    \tvpopcntw %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x54, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 54 94 c8 78 56 34 12 \tvpopcntw 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 08 55 d1    \tvpopcntd %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 28 55 d1    \tvpopcntd %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 48 55 d1    \tvpopcntd %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x55, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 55 94 c8 78 56 34 12 \tvpopcntd 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 08 55 d1    \tvpopcntq %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 28 55 d1    \tvpopcntq %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 48 55 d1    \tvpopcntq %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x55, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 55 94 c8 78 56 34 12 \tvpopcntq 0x12345678(%eax,%ecx,8),%zmm2",},
 {{0xc4, 0xe2, 0x79, 0x59, 0xf4, }, 5, 0, "", "",
 "c4 e2 79 59 f4       \tvpbroadcastq %xmm4,%xmm6",},
 {{0x62, 0xf2, 0x7d, 0x48, 0x59, 0xf7, }, 6, 0, "", "",
 "62 f2 7d 48 5b 31    \tvbroadcasti32x8 (%ecx),%zmm6",},
 {{0x62, 0xf2, 0xfd, 0x48, 0x5b, 0x31, }, 6, 0, "", "",
 "62 f2 fd 48 5b 31    \tvbroadcasti64x4 (%ecx),%zmm6",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 08 62 d1    \tvpexpandb %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 28 62 d1    \tvpexpandb %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 48 62 d1    \tvpexpandb %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 62 94 c8 78 56 34 12 \tvpexpandb 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 08 62 d1    \tvpexpandw %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 28 62 d1    \tvpexpandw %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 48 62 d1    \tvpexpandw %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 62 94 c8 78 56 34 12 \tvpexpandw 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 7d 08 63 ca    \tvpcompressb %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 7d 28 63 ca    \tvpcompressb %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 7d 48 63 ca    \tvpcompressb %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x63, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 63 94 c8 78 56 34 12 \tvpcompressb %zmm2,0x12345678(%eax,%ecx,8)",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 fd 08 63 ca    \tvpcompressw %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 fd 28 63 ca    \tvpcompressw %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 fd 48 63 ca    \tvpcompressw %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x63, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 63 94 c8 78 56 34 12 \tvpcompressw %zmm2,0x12345678(%eax,%ecx,8)",},
 {{0x62, 0xf2, 0x55, 0x48, 0x64, 0xf4, }, 6, 0, "", "",
 "62 f2 55 48 64 f4    \tvpblendmd %zmm4,%zmm5,%zmm6",},
 {{0x62, 0xf2, 0xd5, 0x48, 0x64, 0xf4, }, 6, 0, "", "",
 "62 f2 55 48 66 f4    \tvpblendmb %zmm4,%zmm5,%zmm6",},
 {{0x62, 0xf2, 0xd5, 0x48, 0x66, 0xf4, }, 6, 0, "", "",
 "62 f2 d5 48 66 f4    \tvpblendmw %zmm4,%zmm5,%zmm6",},
+{{0x62, 0xf2, 0x6f, 0x08, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 08 68 d9    \tvp2intersectd %xmm1,%xmm2,%k3",},
+{{0x62, 0xf2, 0x6f, 0x28, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 28 68 d9    \tvp2intersectd %ymm1,%ymm2,%k3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 48 68 d9    \tvp2intersectd %zmm1,%zmm2,%k3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x68, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6f 48 68 9c c8 78 56 34 12 \tvp2intersectd 0x12345678(%eax,%ecx,8),%zmm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x08, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 ef 08 68 d9    \tvp2intersectq %xmm1,%xmm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x28, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 ef 28 68 d9    \tvp2intersectq %ymm1,%ymm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x48, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 ef 48 68 d9    \tvp2intersectq %zmm1,%zmm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x48, 0x68, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ef 48 68 9c c8 78 56 34 12 \tvp2intersectq 0x12345678(%eax,%ecx,8),%zmm2,%k3",},
+{{0x62, 0xf2, 0xed, 0x08, 0x70, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 70 d9    \tvpshldvw %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x70, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 70 d9    \tvpshldvw %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x70, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 70 d9    \tvpshldvw %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x70, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 70 9c c8 78 56 34 12 \tvpshldvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 71 d9    \tvpshldvd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 71 d9    \tvpshldvd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 71 d9    \tvpshldvd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x71, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 71 9c c8 78 56 34 12 \tvpshldvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x08, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 71 d9    \tvpshldvq %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 71 d9    \tvpshldvq %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 71 d9    \tvpshldvq %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x71, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 71 9c c8 78 56 34 12 \tvpshldvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6f, 0x08, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 08 72 d9    \tvcvtne2ps2bf16 %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6f, 0x28, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 28 72 d9    \tvcvtne2ps2bf16 %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 48 72 d9    \tvcvtne2ps2bf16 %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x72, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6f 48 72 9c c8 78 56 34 12 \tvcvtne2ps2bf16 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7e, 0x08, 0x72, 0xd1, }, 6, 0, "", "",
+"62 f2 7e 08 72 d1    \tvcvtneps2bf16 %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7e, 0x28, 0x72, 0xd1, }, 6, 0, "", "",
+"62 f2 7e 28 72 d1    \tvcvtneps2bf16 %ymm1,%xmm2",},
+{{0x62, 0xf2, 0x7e, 0x48, 0x72, 0xd1, }, 6, 0, "", "",
+"62 f2 7e 48 72 d1    \tvcvtneps2bf16 %zmm1,%ymm2",},
+{{0x62, 0xf2, 0x7e, 0x48, 0x72, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7e 48 72 94 c8 78 56 34 12 \tvcvtneps2bf16 0x12345678(%eax,%ecx,8),%ymm2",},
+{{0x62, 0xf2, 0xed, 0x08, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 72 d9    \tvpshrdvw %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 72 d9    \tvpshrdvw %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 72 d9    \tvpshrdvw %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x72, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 72 9c c8 78 56 34 12 \tvpshrdvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 73 d9    \tvpshrdvd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 73 d9    \tvpshrdvd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 73 d9    \tvpshrdvd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x73, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 73 9c c8 78 56 34 12 \tvpshrdvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x08, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 73 d9    \tvpshrdvq %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 73 d9    \tvpshrdvq %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 73 d9    \tvpshrdvq %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x73, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 73 9c c8 78 56 34 12 \tvpshrdvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
 {{0x62, 0xf2, 0x55, 0x48, 0x75, 0xf4, }, 6, 0, "", "",
 "62 f2 55 48 75 f4    \tvpermi2b %zmm4,%zmm5,%zmm6",},
 {{0x62, 0xf2, 0xd5, 0x48, 0x75, 0xf4, }, 6, 0, "", "",
 "62 f2 55 48 8d f4    \tvpermb %zmm4,%zmm5,%zmm6",},
 {{0x62, 0xf2, 0xd5, 0x48, 0x8d, 0xf4, }, 6, 0, "", "",
 "62 f2 d5 48 8d f4    \tvpermw %zmm4,%zmm5,%zmm6",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x8f, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 8f d9    \tvpshufbitqmb %xmm1,%xmm2,%k3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x8f, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 8f d9    \tvpshufbitqmb %ymm1,%ymm2,%k3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x8f, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 8f d9    \tvpshufbitqmb %zmm1,%zmm2,%k3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x8f, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 8f 9c c8 78 56 34 12 \tvpshufbitqmb 0x12345678(%eax,%ecx,8),%zmm2,%k3",},
 {{0xc4, 0xe2, 0x69, 0x90, 0x4c, 0x7d, 0x02, }, 7, 0, "", "",
 "c4 e2 69 90 4c 7d 02 \tvpgatherdd %xmm2,0x2(%ebp,%xmm7,2),%xmm1",},
 {{0xc4, 0xe2, 0xe9, 0x90, 0x4c, 0x7d, 0x04, }, 7, 0, "", "",
 "62 f2 7d 49 91 b4 fd 7b 00 00 00 \tvpgatherqd 0x7b(%ebp,%zmm7,8),%ymm6{%k1}",},
 {{0x62, 0xf2, 0xfd, 0x49, 0x91, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 f2 fd 49 91 b4 fd 7b 00 00 00 \tvpgatherqq 0x7b(%ebp,%zmm7,8),%zmm6{%k1}",},
+{{0xc4, 0xe2, 0x69, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 9a d9       \tvfmsub132ps %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d 9a d9       \tvfmsub132ps %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x9a, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 9a d9    \tvfmsub132ps %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x9a, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 9a 9c c8 78 56 34 12 \tvfmsub132ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0xe9, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 9a d9       \tvfmsub132pd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xed, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 ed 9a d9       \tvfmsub132pd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x9a, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 9a d9    \tvfmsub132pd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x9a, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 9a 9c c8 78 56 34 12 \tvfmsub132pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x9a, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 9a 20    \tv4fmaddps (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x9a, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 9a a4 c8 78 56 34 12 \tv4fmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0xc4, 0xe2, 0x69, 0x9b, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 9b d9       \tvfmsub132ss %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x69, 0x9b, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 69 9b 9c c8 78 56 34 12 \tvfmsub132ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0x9b, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 9b d9       \tvfmsub132sd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0x9b, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 e9 9b 9c c8 78 56 34 12 \tvfmsub132sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x7f, 0x08, 0x9b, 0x20, }, 6, 0, "", "",
+"62 f2 7f 08 9b 20    \tv4fmaddss (%eax),%xmm0,%xmm4",},
+{{0x62, 0xf2, 0x7f, 0x08, 0x9b, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 08 9b a4 c8 78 56 34 12 \tv4fmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4",},
 {{0x62, 0xf2, 0x7d, 0x49, 0xa0, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 f2 7d 49 a0 b4 fd 7b 00 00 00 \tvpscatterdd %zmm6,0x7b(%ebp,%zmm7,8){%k1}",},
 {{0x62, 0xf2, 0xfd, 0x49, 0xa0, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 f2 7d 49 a3 b4 fd 7b 00 00 00 \tvscatterqps %ymm6,0x7b(%ebp,%zmm7,8){%k1}",},
 {{0x62, 0xf2, 0xfd, 0x49, 0xa3, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 f2 fd 49 a3 b4 fd 7b 00 00 00 \tvscatterqpd %zmm6,0x7b(%ebp,%zmm7,8){%k1}",},
+{{0xc4, 0xe2, 0x69, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 aa d9       \tvfmsub213ps %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d aa d9       \tvfmsub213ps %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xaa, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 aa d9    \tvfmsub213ps %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xaa, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 aa 9c c8 78 56 34 12 \tvfmsub213ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0xe9, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 aa d9       \tvfmsub213pd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xed, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 ed aa d9       \tvfmsub213pd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0xaa, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 aa d9    \tvfmsub213pd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0xaa, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 aa 9c c8 78 56 34 12 \tvfmsub213pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0xaa, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 aa 20    \tv4fnmaddps (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0xaa, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 aa a4 c8 78 56 34 12 \tv4fnmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0xc4, 0xe2, 0x69, 0xab, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 ab d9       \tvfmsub213ss %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x69, 0xab, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 69 ab 9c c8 78 56 34 12 \tvfmsub213ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0xab, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 ab d9       \tvfmsub213sd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0xab, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 e9 ab 9c c8 78 56 34 12 \tvfmsub213sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x7f, 0x08, 0xab, 0x20, }, 6, 0, "", "",
+"62 f2 7f 08 ab 20    \tv4fnmaddss (%eax),%xmm0,%xmm4",},
+{{0x62, 0xf2, 0x7f, 0x08, 0xab, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 08 ab a4 c8 78 56 34 12 \tv4fnmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4",},
 {{0x62, 0xf2, 0xd5, 0x48, 0xb4, 0xf4, }, 6, 0, "", "",
 "62 f2 d5 48 b4 f4    \tvpmadd52luq %zmm4,%zmm5,%zmm6",},
 {{0x62, 0xf2, 0xd5, 0x48, 0xb5, 0xf4, }, 6, 0, "", "",
 "62 f2 4d 0f cd fd    \tvrsqrt28ss %xmm5,%xmm6,%xmm7{%k7}",},
 {{0x62, 0xf2, 0xcd, 0x0f, 0xcd, 0xfd, }, 6, 0, "", "",
 "62 f2 cd 0f cd fd    \tvrsqrt28sd %xmm5,%xmm6,%xmm7{%k7}",},
+{{0x66, 0x0f, 0x38, 0xcf, 0xd9, }, 5, 0, "", "",
+"66 0f 38 cf d9       \tgf2p8mulb %xmm1,%xmm3",},
+{{0x66, 0x0f, 0x38, 0xcf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"66 0f 38 cf 9c c8 78 56 34 12 \tgf2p8mulb 0x12345678(%eax,%ecx,8),%xmm3",},
+{{0xc4, 0xe2, 0x69, 0xcf, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 cf d9       \tvgf2p8mulb %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xcf, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d cf d9       \tvgf2p8mulb %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xcf, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 cf d9    \tvgf2p8mulb %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xcf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 cf 9c c8 78 56 34 12 \tvgf2p8mulb 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xdc, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 dc d9       \tvaesenc %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xdc, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d dc d9       \tvaesenc %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdc, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 dc d9    \tvaesenc %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdc, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 dc 9c c8 78 56 34 12 \tvaesenc 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xdd, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 dd d9       \tvaesenclast %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xdd, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d dd d9       \tvaesenclast %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdd, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 dd d9    \tvaesenclast %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdd, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 dd 9c c8 78 56 34 12 \tvaesenclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xde, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 de d9       \tvaesdec %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xde, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d de d9       \tvaesdec %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xde, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 de d9    \tvaesdec %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xde, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 de 9c c8 78 56 34 12 \tvaesdec 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xdf, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 df d9       \tvaesdeclast %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xdf, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d df d9       \tvaesdeclast %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdf, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 df d9    \tvaesdeclast %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 df 9c c8 78 56 34 12 \tvaesdeclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
 {{0x62, 0xf3, 0x4d, 0x48, 0x03, 0xfd, 0x12, }, 7, 0, "", "",
 "62 f3 4d 48 03 fd 12 \tvalignd $0x12,%zmm5,%zmm6,%zmm7",},
 {{0x62, 0xf3, 0xcd, 0x48, 0x03, 0xfd, 0x12, }, 7, 0, "", "",
 "62 f3 4d 48 43 fd 12 \tvshufi32x4 $0x12,%zmm5,%zmm6,%zmm7",},
 {{0x62, 0xf3, 0xcd, 0x48, 0x43, 0xfd, 0x12, }, 7, 0, "", "",
 "62 f3 cd 48 43 fd 12 \tvshufi64x2 $0x12,%zmm5,%zmm6,%zmm7",},
+{{0xc4, 0xe3, 0x69, 0x44, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 69 44 d9 12    \tvpclmulqdq $0x12,%xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe3, 0x6d, 0x44, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 6d 44 d9 12    \tvpclmulqdq $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0x6d, 0x48, 0x44, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 48 44 d9 12 \tvpclmulqdq $0x12,%zmm1,%zmm2,%zmm3",},
 {{0x62, 0xf3, 0x4d, 0x48, 0x50, 0xfd, 0x12, }, 7, 0, "", "",
 "62 f3 4d 48 50 fd 12 \tvrangeps $0x12,%zmm5,%zmm6,%zmm7",},
 {{0x62, 0xf3, 0xcd, 0x48, 0x50, 0xfd, 0x12, }, 7, 0, "", "",
 "62 f3 7d 08 67 ef 12 \tvfpclassss $0x12,%xmm7,%k5",},
 {{0x62, 0xf3, 0xfd, 0x08, 0x67, 0xef, 0x12, }, 7, 0, "", "",
 "62 f3 fd 08 67 ef 12 \tvfpclasssd $0x12,%xmm7,%k5",},
+{{0x62, 0xf3, 0xed, 0x08, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 70 d9 12 \tvpshldw $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 70 d9 12 \tvpshldw $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 70 d9 12 \tvpshldw $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf3, 0x6d, 0x08, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 08 71 d9 12 \tvpshldd $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0x6d, 0x28, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 28 71 d9 12 \tvpshldd $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0x6d, 0x48, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 48 71 d9 12 \tvpshldd $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf3, 0xed, 0x08, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 71 d9 12 \tvpshldq $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 71 d9 12 \tvpshldq $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 71 d9 12 \tvpshldq $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf3, 0xed, 0x08, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 72 d9 12 \tvpshrdw $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 72 d9 12 \tvpshrdw $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 72 d9 12 \tvpshrdw $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf3, 0x6d, 0x08, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 08 73 d9 12 \tvpshrdd $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0x6d, 0x28, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 28 73 d9 12 \tvpshrdd $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0x6d, 0x48, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 48 73 d9 12 \tvpshrdd $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf3, 0xed, 0x08, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 73 d9 12 \tvpshrdq $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 73 d9 12 \tvpshrdq $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 73 d9 12 \tvpshrdq $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x66, 0x0f, 0x3a, 0xce, 0xd9, 0x12, }, 6, 0, "", "",
+"66 0f 3a ce d9 12    \tgf2p8affineqb $0x12,%xmm1,%xmm3",},
+{{0xc4, 0xe3, 0xe9, 0xce, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 e9 ce d9 12    \tvgf2p8affineqb $0x12,%xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe3, 0xed, 0xce, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 ed ce d9 12    \tvgf2p8affineqb $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0xce, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 ce d9 12 \tvgf2p8affineqb $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x66, 0x0f, 0x3a, 0xcf, 0xd9, 0x12, }, 6, 0, "", "",
+"66 0f 3a cf d9 12    \tgf2p8affineinvqb $0x12,%xmm1,%xmm3",},
+{{0xc4, 0xe3, 0xe9, 0xcf, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 e9 cf d9 12    \tvgf2p8affineinvqb $0x12,%xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe3, 0xed, 0xcf, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 ed cf d9 12    \tvgf2p8affineinvqb $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0xcf, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 cf d9 12 \tvgf2p8affineinvqb $0x12,%zmm1,%zmm2,%zmm3",},
 {{0x62, 0xf1, 0x4d, 0x48, 0x72, 0xc5, 0x12, }, 7, 0, "", "",
 "62 f1 4d 48 72 c5 12 \tvprord $0x12,%zmm5,%zmm6",},
 {{0x62, 0xf1, 0xcd, 0x48, 0x72, 0xc5, 0x12, }, 7, 0, "", "",
index 656f8ae..567eccc 100644 (file)
 "62 02 35 07 4f d0    \tvrsqrt14ss %xmm24,%xmm25,%xmm26{%k7}",},
 {{0x62, 0x02, 0xb5, 0x07, 0x4f, 0xd0, }, 6, 0, "", "",
 "62 02 b5 07 4f d0    \tvrsqrt14sd %xmm24,%xmm25,%xmm26{%k7}",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x50, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 50 d9    \tvpdpbusd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x50, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 50 d9    \tvpdpbusd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x50, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 50 d9    \tvpdpbusd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x50, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 50 9c c8 78 56 34 12 \tvpdpbusd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x50, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 50 9c c8 78 56 34 12 \tvpdpbusd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x51, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 51 d9    \tvpdpbusds %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x51, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 51 d9    \tvpdpbusds %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x51, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 51 d9    \tvpdpbusds %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x51, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 51 9c c8 78 56 34 12 \tvpdpbusds 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x51, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 51 9c c8 78 56 34 12 \tvpdpbusds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6e, 0x08, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6e 08 52 d9    \tvdpbf16ps %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6e, 0x28, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6e 28 52 d9    \tvdpbf16ps %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6e, 0x48, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6e 48 52 d9    \tvdpbf16ps %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6e, 0x48, 0x52, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6e 48 52 9c c8 78 56 34 12 \tvdpbf16ps 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6e, 0x48, 0x52, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6e 48 52 9c c8 78 56 34 12 \tvdpbf16ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 52 d9    \tvpdpwssd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 52 d9    \tvpdpwssd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x52, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 52 d9    \tvpdpwssd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x52, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 52 9c c8 78 56 34 12 \tvpdpwssd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x52, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 52 9c c8 78 56 34 12 \tvpdpwssd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x52, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 52 20    \tvp4dpwssd (%rax),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0x52, 0x20, }, 7, 0, "", "",
+"67 62 f2 7f 48 52 20 \tvp4dpwssd (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x52, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 52 a4 c8 78 56 34 12 \tvp4dpwssd 0x12345678(%rax,%rcx,8),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0x52, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7f 48 52 a4 c8 78 56 34 12 \tvp4dpwssd 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x53, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 53 d9    \tvpdpwssds %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x53, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 53 d9    \tvpdpwssds %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x53, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 53 d9    \tvpdpwssds %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x53, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 53 9c c8 78 56 34 12 \tvpdpwssds 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x53, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 53 9c c8 78 56 34 12 \tvpdpwssds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x53, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 53 20    \tvp4dpwssds (%rax),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0x53, 0x20, }, 7, 0, "", "",
+"67 62 f2 7f 48 53 20 \tvp4dpwssds (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x53, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 53 a4 c8 78 56 34 12 \tvp4dpwssds 0x12345678(%rax,%rcx,8),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0x53, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7f 48 53 a4 c8 78 56 34 12 \tvp4dpwssds 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 08 54 d1    \tvpopcntb %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 28 54 d1    \tvpopcntb %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 48 54 d1    \tvpopcntb %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x54, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 54 94 c8 78 56 34 12 \tvpopcntb 0x12345678(%rax,%rcx,8),%zmm2",},
+{{0x67, 0x62, 0xf2, 0x7d, 0x48, 0x54, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7d 48 54 94 c8 78 56 34 12 \tvpopcntb 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 08 54 d1    \tvpopcntw %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 28 54 d1    \tvpopcntw %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x54, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 48 54 d1    \tvpopcntw %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x54, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 54 94 c8 78 56 34 12 \tvpopcntw 0x12345678(%rax,%rcx,8),%zmm2",},
+{{0x67, 0x62, 0xf2, 0xfd, 0x48, 0x54, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 fd 48 54 94 c8 78 56 34 12 \tvpopcntw 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 08 55 d1    \tvpopcntd %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 28 55 d1    \tvpopcntd %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 48 55 d1    \tvpopcntd %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x55, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 55 94 c8 78 56 34 12 \tvpopcntd 0x12345678(%rax,%rcx,8),%zmm2",},
+{{0x67, 0x62, 0xf2, 0x7d, 0x48, 0x55, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7d 48 55 94 c8 78 56 34 12 \tvpopcntd 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 08 55 d1    \tvpopcntq %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 28 55 d1    \tvpopcntq %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x55, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 48 55 d1    \tvpopcntq %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x55, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 55 94 c8 78 56 34 12 \tvpopcntq 0x12345678(%rax,%rcx,8),%zmm2",},
+{{0x67, 0x62, 0xf2, 0xfd, 0x48, 0x55, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 fd 48 55 94 c8 78 56 34 12 \tvpopcntq 0x12345678(%eax,%ecx,8),%zmm2",},
 {{0xc4, 0xe2, 0x79, 0x59, 0xf4, }, 5, 0, "", "",
 "c4 e2 79 59 f4       \tvpbroadcastq %xmm4,%xmm6",},
 {{0x62, 0x02, 0x7d, 0x48, 0x59, 0xd3, }, 6, 0, "", "",
 "62 62 7d 48 5b 21    \tvbroadcasti32x8 (%rcx),%zmm28",},
 {{0x62, 0x62, 0xfd, 0x48, 0x5b, 0x11, }, 6, 0, "", "",
 "62 62 fd 48 5b 11    \tvbroadcasti64x4 (%rcx),%zmm26",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 08 62 d1    \tvpexpandb %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 28 62 d1    \tvpexpandb %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 7d 48 62 d1    \tvpexpandb %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 62 94 c8 78 56 34 12 \tvpexpandb 0x12345678(%rax,%rcx,8),%zmm2",},
+{{0x67, 0x62, 0xf2, 0x7d, 0x48, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7d 48 62 94 c8 78 56 34 12 \tvpexpandb 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 08 62 d1    \tvpexpandw %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 28 62 d1    \tvpexpandw %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x62, 0xd1, }, 6, 0, "", "",
+"62 f2 fd 48 62 d1    \tvpexpandw %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 62 94 c8 78 56 34 12 \tvpexpandw 0x12345678(%rax,%rcx,8),%zmm2",},
+{{0x67, 0x62, 0xf2, 0xfd, 0x48, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 fd 48 62 94 c8 78 56 34 12 \tvpexpandw 0x12345678(%eax,%ecx,8),%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x08, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 7d 08 63 ca    \tvpcompressb %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7d, 0x28, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 7d 28 63 ca    \tvpcompressb %ymm1,%ymm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 7d 48 63 ca    \tvpcompressb %zmm1,%zmm2",},
+{{0x62, 0xf2, 0x7d, 0x48, 0x63, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7d 48 63 94 c8 78 56 34 12 \tvpcompressb %zmm2,0x12345678(%rax,%rcx,8)",},
+{{0x67, 0x62, 0xf2, 0x7d, 0x48, 0x63, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7d 48 63 94 c8 78 56 34 12 \tvpcompressb %zmm2,0x12345678(%eax,%ecx,8)",},
+{{0x62, 0xf2, 0xfd, 0x08, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 fd 08 63 ca    \tvpcompressw %xmm1,%xmm2",},
+{{0x62, 0xf2, 0xfd, 0x28, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 fd 28 63 ca    \tvpcompressw %ymm1,%ymm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x63, 0xca, }, 6, 0, "", "",
+"62 f2 fd 48 63 ca    \tvpcompressw %zmm1,%zmm2",},
+{{0x62, 0xf2, 0xfd, 0x48, 0x63, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 fd 48 63 94 c8 78 56 34 12 \tvpcompressw %zmm2,0x12345678(%rax,%rcx,8)",},
+{{0x67, 0x62, 0xf2, 0xfd, 0x48, 0x63, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 fd 48 63 94 c8 78 56 34 12 \tvpcompressw %zmm2,0x12345678(%eax,%ecx,8)",},
 {{0x62, 0x02, 0x25, 0x40, 0x64, 0xe2, }, 6, 0, "", "",
 "62 02 25 40 64 e2    \tvpblendmd %zmm26,%zmm27,%zmm28",},
 {{0x62, 0x02, 0xa5, 0x40, 0x64, 0xe2, }, 6, 0, "", "",
 "62 02 25 40 66 e2    \tvpblendmb %zmm26,%zmm27,%zmm28",},
 {{0x62, 0x02, 0xa5, 0x40, 0x66, 0xe2, }, 6, 0, "", "",
 "62 02 a5 40 66 e2    \tvpblendmw %zmm26,%zmm27,%zmm28",},
+{{0x62, 0xf2, 0x6f, 0x08, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 08 68 d9    \tvp2intersectd %xmm1,%xmm2,%k3",},
+{{0x62, 0xf2, 0x6f, 0x28, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 28 68 d9    \tvp2intersectd %ymm1,%ymm2,%k3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 48 68 d9    \tvp2intersectd %zmm1,%zmm2,%k3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x68, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6f 48 68 9c c8 78 56 34 12 \tvp2intersectd 0x12345678(%rax,%rcx,8),%zmm2,%k3",},
+{{0x67, 0x62, 0xf2, 0x6f, 0x48, 0x68, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6f 48 68 9c c8 78 56 34 12 \tvp2intersectd 0x12345678(%eax,%ecx,8),%zmm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x08, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 ef 08 68 d9    \tvp2intersectq %xmm1,%xmm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x28, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 ef 28 68 d9    \tvp2intersectq %ymm1,%ymm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x48, 0x68, 0xd9, }, 6, 0, "", "",
+"62 f2 ef 48 68 d9    \tvp2intersectq %zmm1,%zmm2,%k3",},
+{{0x62, 0xf2, 0xef, 0x48, 0x68, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ef 48 68 9c c8 78 56 34 12 \tvp2intersectq 0x12345678(%rax,%rcx,8),%zmm2,%k3",},
+{{0x67, 0x62, 0xf2, 0xef, 0x48, 0x68, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ef 48 68 9c c8 78 56 34 12 \tvp2intersectq 0x12345678(%eax,%ecx,8),%zmm2,%k3",},
+{{0x62, 0xf2, 0xed, 0x08, 0x70, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 70 d9    \tvpshldvw %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x70, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 70 d9    \tvpshldvw %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x70, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 70 d9    \tvpshldvw %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x70, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 70 9c c8 78 56 34 12 \tvpshldvw 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0xed, 0x48, 0x70, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ed 48 70 9c c8 78 56 34 12 \tvpshldvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 71 d9    \tvpshldvd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 71 d9    \tvpshldvd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 71 d9    \tvpshldvd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x71, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 71 9c c8 78 56 34 12 \tvpshldvd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x71, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 71 9c c8 78 56 34 12 \tvpshldvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x08, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 71 d9    \tvpshldvq %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 71 d9    \tvpshldvq %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x71, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 71 d9    \tvpshldvq %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x71, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 71 9c c8 78 56 34 12 \tvpshldvq 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0xed, 0x48, 0x71, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ed 48 71 9c c8 78 56 34 12 \tvpshldvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6f, 0x08, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 08 72 d9    \tvcvtne2ps2bf16 %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6f, 0x28, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 28 72 d9    \tvcvtne2ps2bf16 %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 6f 48 72 d9    \tvcvtne2ps2bf16 %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6f, 0x48, 0x72, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6f 48 72 9c c8 78 56 34 12 \tvcvtne2ps2bf16 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6f, 0x48, 0x72, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6f 48 72 9c c8 78 56 34 12 \tvcvtne2ps2bf16 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7e, 0x08, 0x72, 0xd1, }, 6, 0, "", "",
+"62 f2 7e 08 72 d1    \tvcvtneps2bf16 %xmm1,%xmm2",},
+{{0x62, 0xf2, 0x7e, 0x28, 0x72, 0xd1, }, 6, 0, "", "",
+"62 f2 7e 28 72 d1    \tvcvtneps2bf16 %ymm1,%xmm2",},
+{{0x62, 0xf2, 0x7e, 0x48, 0x72, 0xd1, }, 6, 0, "", "",
+"62 f2 7e 48 72 d1    \tvcvtneps2bf16 %zmm1,%ymm2",},
+{{0x62, 0xf2, 0x7e, 0x48, 0x72, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7e 48 72 94 c8 78 56 34 12 \tvcvtneps2bf16 0x12345678(%rax,%rcx,8),%ymm2",},
+{{0x67, 0x62, 0xf2, 0x7e, 0x48, 0x72, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7e 48 72 94 c8 78 56 34 12 \tvcvtneps2bf16 0x12345678(%eax,%ecx,8),%ymm2",},
+{{0x62, 0xf2, 0xed, 0x08, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 72 d9    \tvpshrdvw %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 72 d9    \tvpshrdvw %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x72, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 72 d9    \tvpshrdvw %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x72, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 72 9c c8 78 56 34 12 \tvpshrdvw 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0xed, 0x48, 0x72, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ed 48 72 9c c8 78 56 34 12 \tvpshrdvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 73 d9    \tvpshrdvd %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 73 d9    \tvpshrdvd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 73 d9    \tvpshrdvd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x73, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 73 9c c8 78 56 34 12 \tvpshrdvd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x73, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 73 9c c8 78 56 34 12 \tvpshrdvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x08, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 08 73 d9    \tvpshrdvq %xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf2, 0xed, 0x28, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 28 73 d9    \tvpshrdvq %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x73, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 73 d9    \tvpshrdvq %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x73, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 73 9c c8 78 56 34 12 \tvpshrdvq 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0xed, 0x48, 0x73, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ed 48 73 9c c8 78 56 34 12 \tvpshrdvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
 {{0x62, 0x02, 0x35, 0x40, 0x75, 0xd0, }, 6, 0, "", "",
 "62 02 35 40 75 d0    \tvpermi2b %zmm24,%zmm25,%zmm26",},
 {{0x62, 0x02, 0xa5, 0x40, 0x75, 0xe2, }, 6, 0, "", "",
 "62 02 25 40 8d e2    \tvpermb %zmm26,%zmm27,%zmm28",},
 {{0x62, 0x02, 0xa5, 0x40, 0x8d, 0xe2, }, 6, 0, "", "",
 "62 02 a5 40 8d e2    \tvpermw %zmm26,%zmm27,%zmm28",},
+{{0x62, 0xf2, 0x6d, 0x08, 0x8f, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 08 8f d9    \tvpshufbitqmb %xmm1,%xmm2,%k3",},
+{{0x62, 0xf2, 0x6d, 0x28, 0x8f, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 28 8f d9    \tvpshufbitqmb %ymm1,%ymm2,%k3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x8f, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 8f d9    \tvpshufbitqmb %zmm1,%zmm2,%k3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x8f, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 8f 9c c8 78 56 34 12 \tvpshufbitqmb 0x12345678(%rax,%rcx,8),%zmm2,%k3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x8f, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 8f 9c c8 78 56 34 12 \tvpshufbitqmb 0x12345678(%eax,%ecx,8),%zmm2,%k3",},
 {{0xc4, 0xe2, 0x69, 0x90, 0x4c, 0x7d, 0x02, }, 7, 0, "", "",
 "c4 e2 69 90 4c 7d 02 \tvpgatherdd %xmm2,0x2(%rbp,%xmm7,2),%xmm1",},
 {{0xc4, 0xe2, 0xe9, 0x90, 0x4c, 0x7d, 0x04, }, 7, 0, "", "",
 "62 22 7d 41 91 94 dd 7b 00 00 00 \tvpgatherqd 0x7b(%rbp,%zmm27,8),%ymm26{%k1}",},
 {{0x62, 0x22, 0xfd, 0x41, 0x91, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 22 fd 41 91 94 dd 7b 00 00 00 \tvpgatherqq 0x7b(%rbp,%zmm27,8),%zmm26{%k1}",},
+{{0xc4, 0xe2, 0x69, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 9a d9       \tvfmsub132ps %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d 9a d9       \tvfmsub132ps %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x9a, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 9a d9    \tvfmsub132ps %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0x9a, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 9a 9c c8 78 56 34 12 \tvfmsub132ps 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0x9a, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 9a 9c c8 78 56 34 12 \tvfmsub132ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0xe9, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 9a d9       \tvfmsub132pd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xed, 0x9a, 0xd9, }, 5, 0, "", "",
+"c4 e2 ed 9a d9       \tvfmsub132pd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x9a, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 9a d9    \tvfmsub132pd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0x9a, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 9a 9c c8 78 56 34 12 \tvfmsub132pd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0xed, 0x48, 0x9a, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ed 48 9a 9c c8 78 56 34 12 \tvfmsub132pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x9a, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 9a 20    \tv4fmaddps (%rax),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0x9a, 0x20, }, 7, 0, "", "",
+"67 62 f2 7f 48 9a 20 \tv4fmaddps (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0x9a, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 9a a4 c8 78 56 34 12 \tv4fmaddps 0x12345678(%rax,%rcx,8),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0x9a, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7f 48 9a a4 c8 78 56 34 12 \tv4fmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0xc4, 0xe2, 0x69, 0x9b, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 9b d9       \tvfmsub132ss %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x69, 0x9b, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 69 9b 9c c8 78 56 34 12 \tvfmsub132ss 0x12345678(%rax,%rcx,8),%xmm2,%xmm3",},
+{{0x67, 0xc4, 0xe2, 0x69, 0x9b, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"67 c4 e2 69 9b 9c c8 78 56 34 12 \tvfmsub132ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0x9b, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 9b d9       \tvfmsub132sd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0x9b, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 e9 9b 9c c8 78 56 34 12 \tvfmsub132sd 0x12345678(%rax,%rcx,8),%xmm2,%xmm3",},
+{{0x67, 0xc4, 0xe2, 0xe9, 0x9b, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"67 c4 e2 e9 9b 9c c8 78 56 34 12 \tvfmsub132sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x7f, 0x08, 0x9b, 0x20, }, 6, 0, "", "",
+"62 f2 7f 08 9b 20    \tv4fmaddss (%rax),%xmm0,%xmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x08, 0x9b, 0x20, }, 7, 0, "", "",
+"67 62 f2 7f 08 9b 20 \tv4fmaddss (%eax),%xmm0,%xmm4",},
+{{0x62, 0xf2, 0x7f, 0x08, 0x9b, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 08 9b a4 c8 78 56 34 12 \tv4fmaddss 0x12345678(%rax,%rcx,8),%xmm0,%xmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x08, 0x9b, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7f 08 9b a4 c8 78 56 34 12 \tv4fmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4",},
 {{0x62, 0x22, 0x7d, 0x41, 0xa0, 0xa4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 22 7d 41 a0 a4 ed 7b 00 00 00 \tvpscatterdd %zmm28,0x7b(%rbp,%zmm29,8){%k1}",},
 {{0x62, 0x22, 0xfd, 0x41, 0xa0, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 b2 7d 41 a3 b4 ed 7b 00 00 00 \tvscatterqps %ymm6,0x7b(%rbp,%zmm29,8){%k1}",},
 {{0x62, 0x22, 0xfd, 0x41, 0xa3, 0xa4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "",
 "62 22 fd 41 a3 a4 ed 7b 00 00 00 \tvscatterqpd %zmm28,0x7b(%rbp,%zmm29,8){%k1}",},
+{{0xc4, 0xe2, 0x69, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 aa d9       \tvfmsub213ps %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d aa d9       \tvfmsub213ps %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xaa, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 aa d9    \tvfmsub213ps %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xaa, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 aa 9c c8 78 56 34 12 \tvfmsub213ps 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0xaa, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 aa 9c c8 78 56 34 12 \tvfmsub213ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0xe9, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 aa d9       \tvfmsub213pd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xed, 0xaa, 0xd9, }, 5, 0, "", "",
+"c4 e2 ed aa d9       \tvfmsub213pd %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0xaa, 0xd9, }, 6, 0, "", "",
+"62 f2 ed 48 aa d9    \tvfmsub213pd %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0xed, 0x48, 0xaa, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 ed 48 aa 9c c8 78 56 34 12 \tvfmsub213pd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0xed, 0x48, 0xaa, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 ed 48 aa 9c c8 78 56 34 12 \tvfmsub213pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x7f, 0x48, 0xaa, 0x20, }, 6, 0, "", "",
+"62 f2 7f 48 aa 20    \tv4fnmaddps (%rax),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0xaa, 0x20, }, 7, 0, "", "",
+"67 62 f2 7f 48 aa 20 \tv4fnmaddps (%eax),%zmm0,%zmm4",},
+{{0x62, 0xf2, 0x7f, 0x48, 0xaa, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 48 aa a4 c8 78 56 34 12 \tv4fnmaddps 0x12345678(%rax,%rcx,8),%zmm0,%zmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x48, 0xaa, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7f 48 aa a4 c8 78 56 34 12 \tv4fnmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4",},
+{{0xc4, 0xe2, 0x69, 0xab, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 ab d9       \tvfmsub213ss %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x69, 0xab, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 69 ab 9c c8 78 56 34 12 \tvfmsub213ss 0x12345678(%rax,%rcx,8),%xmm2,%xmm3",},
+{{0x67, 0xc4, 0xe2, 0x69, 0xab, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"67 c4 e2 69 ab 9c c8 78 56 34 12 \tvfmsub213ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0xab, 0xd9, }, 5, 0, "", "",
+"c4 e2 e9 ab d9       \tvfmsub213sd %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0xe9, 0xab, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"c4 e2 e9 ab 9c c8 78 56 34 12 \tvfmsub213sd 0x12345678(%rax,%rcx,8),%xmm2,%xmm3",},
+{{0x67, 0xc4, 0xe2, 0xe9, 0xab, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"67 c4 e2 e9 ab 9c c8 78 56 34 12 \tvfmsub213sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3",},
+{{0x62, 0xf2, 0x7f, 0x08, 0xab, 0x20, }, 6, 0, "", "",
+"62 f2 7f 08 ab 20    \tv4fnmaddss (%rax),%xmm0,%xmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x08, 0xab, 0x20, }, 7, 0, "", "",
+"67 62 f2 7f 08 ab 20 \tv4fnmaddss (%eax),%xmm0,%xmm4",},
+{{0x62, 0xf2, 0x7f, 0x08, 0xab, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 7f 08 ab a4 c8 78 56 34 12 \tv4fnmaddss 0x12345678(%rax,%rcx,8),%xmm0,%xmm4",},
+{{0x67, 0x62, 0xf2, 0x7f, 0x08, 0xab, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 7f 08 ab a4 c8 78 56 34 12 \tv4fnmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4",},
 {{0x62, 0x02, 0xa5, 0x40, 0xb4, 0xe2, }, 6, 0, "", "",
 "62 02 a5 40 b4 e2    \tvpmadd52luq %zmm26,%zmm27,%zmm28",},
 {{0x62, 0x02, 0xa5, 0x40, 0xb5, 0xe2, }, 6, 0, "", "",
 "62 02 15 07 cd f4    \tvrsqrt28ss %xmm28,%xmm29,%xmm30{%k7}",},
 {{0x62, 0x02, 0xad, 0x07, 0xcd, 0xd9, }, 6, 0, "", "",
 "62 02 ad 07 cd d9    \tvrsqrt28sd %xmm25,%xmm26,%xmm27{%k7}",},
+{{0x66, 0x0f, 0x38, 0xcf, 0xd9, }, 5, 0, "", "",
+"66 0f 38 cf d9       \tgf2p8mulb %xmm1,%xmm3",},
+{{0x66, 0x0f, 0x38, 0xcf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "",
+"66 0f 38 cf 9c c8 78 56 34 12 \tgf2p8mulb 0x12345678(%rax,%rcx,8),%xmm3",},
+{{0x67, 0x66, 0x0f, 0x38, 0xcf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"67 66 0f 38 cf 9c c8 78 56 34 12 \tgf2p8mulb 0x12345678(%eax,%ecx,8),%xmm3",},
+{{0xc4, 0xe2, 0x69, 0xcf, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 cf d9       \tvgf2p8mulb %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xcf, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d cf d9       \tvgf2p8mulb %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xcf, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 cf d9    \tvgf2p8mulb %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xcf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 cf 9c c8 78 56 34 12 \tvgf2p8mulb 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0xcf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 cf 9c c8 78 56 34 12 \tvgf2p8mulb 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xdc, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 dc d9       \tvaesenc %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xdc, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d dc d9       \tvaesenc %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdc, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 dc d9    \tvaesenc %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdc, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 dc 9c c8 78 56 34 12 \tvaesenc 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0xdc, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 dc 9c c8 78 56 34 12 \tvaesenc 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xdd, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 dd d9       \tvaesenclast %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xdd, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d dd d9       \tvaesenclast %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdd, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 dd d9    \tvaesenclast %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdd, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 dd 9c c8 78 56 34 12 \tvaesenclast 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0xdd, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 dd 9c c8 78 56 34 12 \tvaesenclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xde, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 de d9       \tvaesdec %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xde, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d de d9       \tvaesdec %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xde, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 de d9    \tvaesdec %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xde, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 de 9c c8 78 56 34 12 \tvaesdec 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0xde, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 de 9c c8 78 56 34 12 \tvaesdec 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
+{{0xc4, 0xe2, 0x69, 0xdf, 0xd9, }, 5, 0, "", "",
+"c4 e2 69 df d9       \tvaesdeclast %xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe2, 0x6d, 0xdf, 0xd9, }, 5, 0, "", "",
+"c4 e2 6d df d9       \tvaesdeclast %ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdf, 0xd9, }, 6, 0, "", "",
+"62 f2 6d 48 df d9    \tvaesdeclast %zmm1,%zmm2,%zmm3",},
+{{0x62, 0xf2, 0x6d, 0x48, 0xdf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 11, 0, "", "",
+"62 f2 6d 48 df 9c c8 78 56 34 12 \tvaesdeclast 0x12345678(%rax,%rcx,8),%zmm2,%zmm3",},
+{{0x67, 0x62, 0xf2, 0x6d, 0x48, 0xdf, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 12, 0, "", "",
+"67 62 f2 6d 48 df 9c c8 78 56 34 12 \tvaesdeclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3",},
 {{0x62, 0x03, 0x15, 0x40, 0x03, 0xf4, 0x12, }, 7, 0, "", "",
 "62 03 15 40 03 f4 12 \tvalignd $0x12,%zmm28,%zmm29,%zmm30",},
 {{0x62, 0x03, 0xad, 0x40, 0x03, 0xd9, 0x12, }, 7, 0, "", "",
 "62 03 2d 40 43 d9 12 \tvshufi32x4 $0x12,%zmm25,%zmm26,%zmm27",},
 {{0x62, 0x03, 0x95, 0x40, 0x43, 0xf4, 0x12, }, 7, 0, "", "",
 "62 03 95 40 43 f4 12 \tvshufi64x2 $0x12,%zmm28,%zmm29,%zmm30",},
+{{0xc4, 0xe3, 0x69, 0x44, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 69 44 d9 12    \tvpclmulqdq $0x12,%xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe3, 0x6d, 0x44, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 6d 44 d9 12    \tvpclmulqdq $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0x6d, 0x48, 0x44, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 48 44 d9 12 \tvpclmulqdq $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0x2d, 0x40, 0x44, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 2d 40 44 d9 12 \tvpclmulqdq $0x12,%zmm25,%zmm26,%zmm27",},
 {{0x62, 0x03, 0x2d, 0x40, 0x50, 0xd9, 0x12, }, 7, 0, "", "",
 "62 03 2d 40 50 d9 12 \tvrangeps $0x12,%zmm25,%zmm26,%zmm27",},
 {{0x62, 0x03, 0x95, 0x40, 0x50, 0xf4, 0x12, }, 7, 0, "", "",
 "62 93 7d 08 67 eb 12 \tvfpclassss $0x12,%xmm27,%k5",},
 {{0x62, 0x93, 0xfd, 0x08, 0x67, 0xee, 0x12, }, 7, 0, "", "",
 "62 93 fd 08 67 ee 12 \tvfpclasssd $0x12,%xmm30,%k5",},
+{{0x62, 0xf3, 0xed, 0x08, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 70 d9 12 \tvpshldw $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 70 d9 12 \tvpshldw $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 70 d9 12 \tvpshldw $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0xad, 0x40, 0x70, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 ad 40 70 d9 12 \tvpshldw $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x62, 0xf3, 0x6d, 0x08, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 08 71 d9 12 \tvpshldd $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0x6d, 0x28, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 28 71 d9 12 \tvpshldd $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0x6d, 0x48, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 48 71 d9 12 \tvpshldd $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0x2d, 0x40, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 2d 40 71 d9 12 \tvpshldd $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x62, 0xf3, 0xed, 0x08, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 71 d9 12 \tvpshldq $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 71 d9 12 \tvpshldq $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 71 d9 12 \tvpshldq $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0xad, 0x40, 0x71, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 ad 40 71 d9 12 \tvpshldq $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x62, 0xf3, 0xed, 0x08, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 72 d9 12 \tvpshrdw $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 72 d9 12 \tvpshrdw $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 72 d9 12 \tvpshrdw $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0xad, 0x40, 0x72, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 ad 40 72 d9 12 \tvpshrdw $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x62, 0xf3, 0x6d, 0x08, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 08 73 d9 12 \tvpshrdd $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0x6d, 0x28, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 28 73 d9 12 \tvpshrdd $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0x6d, 0x48, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 6d 48 73 d9 12 \tvpshrdd $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0x2d, 0x40, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 2d 40 73 d9 12 \tvpshrdd $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x62, 0xf3, 0xed, 0x08, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 08 73 d9 12 \tvpshrdq $0x12,%xmm1,%xmm2,%xmm3",},
+{{0x62, 0xf3, 0xed, 0x28, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 28 73 d9 12 \tvpshrdq $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 73 d9 12 \tvpshrdq $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0xad, 0x40, 0x73, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 ad 40 73 d9 12 \tvpshrdq $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x66, 0x0f, 0x3a, 0xce, 0xd9, 0x12, }, 6, 0, "", "",
+"66 0f 3a ce d9 12    \tgf2p8affineqb $0x12,%xmm1,%xmm3",},
+{{0xc4, 0xe3, 0xe9, 0xce, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 e9 ce d9 12    \tvgf2p8affineqb $0x12,%xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe3, 0xed, 0xce, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 ed ce d9 12    \tvgf2p8affineqb $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0xce, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 ce d9 12 \tvgf2p8affineqb $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0xad, 0x40, 0xce, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 ad 40 ce d9 12 \tvgf2p8affineqb $0x12,%zmm25,%zmm26,%zmm27",},
+{{0x66, 0x0f, 0x3a, 0xcf, 0xd9, 0x12, }, 6, 0, "", "",
+"66 0f 3a cf d9 12    \tgf2p8affineinvqb $0x12,%xmm1,%xmm3",},
+{{0xc4, 0xe3, 0xe9, 0xcf, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 e9 cf d9 12    \tvgf2p8affineinvqb $0x12,%xmm1,%xmm2,%xmm3",},
+{{0xc4, 0xe3, 0xed, 0xcf, 0xd9, 0x12, }, 6, 0, "", "",
+"c4 e3 ed cf d9 12    \tvgf2p8affineinvqb $0x12,%ymm1,%ymm2,%ymm3",},
+{{0x62, 0xf3, 0xed, 0x48, 0xcf, 0xd9, 0x12, }, 7, 0, "", "",
+"62 f3 ed 48 cf d9 12 \tvgf2p8affineinvqb $0x12,%zmm1,%zmm2,%zmm3",},
+{{0x62, 0x03, 0xad, 0x40, 0xcf, 0xd9, 0x12, }, 7, 0, "", "",
+"62 03 ad 40 cf d9 12 \tvgf2p8affineinvqb $0x12,%zmm25,%zmm26,%zmm27",},
 {{0x62, 0x91, 0x2d, 0x40, 0x72, 0xc1, 0x12, }, 7, 0, "", "",
 "62 91 2d 40 72 c1 12 \tvprord $0x12,%zmm25,%zmm26",},
 {{0x62, 0x91, 0xad, 0x40, 0x72, 0xc1, 0x12, }, 7, 0, "", "",
index dd85a3a..ddbf07c 100644 (file)
@@ -510,6 +510,82 @@ int main(void)
        asm volatile("vrsqrt14ss %xmm24,%xmm25,%xmm26{%k7}");
        asm volatile("vrsqrt14sd %xmm24,%xmm25,%xmm26{%k7}");
 
+       /* AVX-512: Op code 0f 38 50 */
+
+       asm volatile("vpdpbusd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpbusd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpbusd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpbusd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpdpbusd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 51 */
+
+       asm volatile("vpdpbusds %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpbusds %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpbusds %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpbusds 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpdpbusds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 52 */
+
+       asm volatile("vdpbf16ps %xmm1, %xmm2, %xmm3");
+       asm volatile("vdpbf16ps %ymm1, %ymm2, %ymm3");
+       asm volatile("vdpbf16ps %zmm1, %zmm2, %zmm3");
+       asm volatile("vdpbf16ps 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vdpbf16ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vpdpwssd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpwssd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpwssd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpwssd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpdpwssd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vp4dpwssd (%rax), %zmm0, %zmm4");
+       asm volatile("vp4dpwssd (%eax), %zmm0, %zmm4");
+       asm volatile("vp4dpwssd 0x12345678(%rax,%rcx,8),%zmm0,%zmm4");
+       asm volatile("vp4dpwssd 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 53 */
+
+       asm volatile("vpdpwssds %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpwssds %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpwssds %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpwssds 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpdpwssds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vp4dpwssds (%rax), %zmm0, %zmm4");
+       asm volatile("vp4dpwssds (%eax), %zmm0, %zmm4");
+       asm volatile("vp4dpwssds 0x12345678(%rax,%rcx,8),%zmm0,%zmm4");
+       asm volatile("vp4dpwssds 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 54 */
+
+       asm volatile("vpopcntb %xmm1, %xmm2");
+       asm volatile("vpopcntb %ymm1, %ymm2");
+       asm volatile("vpopcntb %zmm1, %zmm2");
+       asm volatile("vpopcntb 0x12345678(%rax,%rcx,8),%zmm2");
+       asm volatile("vpopcntb 0x12345678(%eax,%ecx,8),%zmm2");
+
+       asm volatile("vpopcntw %xmm1, %xmm2");
+       asm volatile("vpopcntw %ymm1, %ymm2");
+       asm volatile("vpopcntw %zmm1, %zmm2");
+       asm volatile("vpopcntw 0x12345678(%rax,%rcx,8),%zmm2");
+       asm volatile("vpopcntw 0x12345678(%eax,%ecx,8),%zmm2");
+
+       /* AVX-512: Op code 0f 38 55 */
+
+       asm volatile("vpopcntd %xmm1, %xmm2");
+       asm volatile("vpopcntd %ymm1, %ymm2");
+       asm volatile("vpopcntd %zmm1, %zmm2");
+       asm volatile("vpopcntd 0x12345678(%rax,%rcx,8),%zmm2");
+       asm volatile("vpopcntd 0x12345678(%eax,%ecx,8),%zmm2");
+
+       asm volatile("vpopcntq %xmm1, %xmm2");
+       asm volatile("vpopcntq %ymm1, %ymm2");
+       asm volatile("vpopcntq %zmm1, %zmm2");
+       asm volatile("vpopcntq 0x12345678(%rax,%rcx,8),%zmm2");
+       asm volatile("vpopcntq 0x12345678(%eax,%ecx,8),%zmm2");
+
        /* AVX-512: Op code 0f 38 59 */
 
        asm volatile("vpbroadcastq %xmm4,%xmm6");
@@ -526,6 +602,34 @@ int main(void)
        asm volatile("vbroadcasti32x8 (%rcx),%zmm28");
        asm volatile("vbroadcasti64x4 (%rcx),%zmm26");
 
+       /* AVX-512: Op code 0f 38 62 */
+
+       asm volatile("vpexpandb %xmm1, %xmm2");
+       asm volatile("vpexpandb %ymm1, %ymm2");
+       asm volatile("vpexpandb %zmm1, %zmm2");
+       asm volatile("vpexpandb 0x12345678(%rax,%rcx,8),%zmm2");
+       asm volatile("vpexpandb 0x12345678(%eax,%ecx,8),%zmm2");
+
+       asm volatile("vpexpandw %xmm1, %xmm2");
+       asm volatile("vpexpandw %ymm1, %ymm2");
+       asm volatile("vpexpandw %zmm1, %zmm2");
+       asm volatile("vpexpandw 0x12345678(%rax,%rcx,8),%zmm2");
+       asm volatile("vpexpandw 0x12345678(%eax,%ecx,8),%zmm2");
+
+       /* AVX-512: Op code 0f 38 63 */
+
+       asm volatile("vpcompressb %xmm1, %xmm2");
+       asm volatile("vpcompressb %ymm1, %ymm2");
+       asm volatile("vpcompressb %zmm1, %zmm2");
+       asm volatile("vpcompressb %zmm2,0x12345678(%rax,%rcx,8)");
+       asm volatile("vpcompressb %zmm2,0x12345678(%eax,%ecx,8)");
+
+       asm volatile("vpcompressw %xmm1, %xmm2");
+       asm volatile("vpcompressw %ymm1, %ymm2");
+       asm volatile("vpcompressw %zmm1, %zmm2");
+       asm volatile("vpcompressw %zmm2,0x12345678(%rax,%rcx,8)");
+       asm volatile("vpcompressw %zmm2,0x12345678(%eax,%ecx,8)");
+
        /* AVX-512: Op code 0f 38 64 */
 
        asm volatile("vpblendmd %zmm26,%zmm27,%zmm28");
@@ -541,6 +645,76 @@ int main(void)
        asm volatile("vpblendmb %zmm26,%zmm27,%zmm28");
        asm volatile("vpblendmw %zmm26,%zmm27,%zmm28");
 
+       /* AVX-512: Op code 0f 38 68 */
+
+       asm volatile("vp2intersectd %xmm1, %xmm2, %k3");
+       asm volatile("vp2intersectd %ymm1, %ymm2, %k3");
+       asm volatile("vp2intersectd %zmm1, %zmm2, %k3");
+       asm volatile("vp2intersectd 0x12345678(%rax,%rcx,8),%zmm2,%k3");
+       asm volatile("vp2intersectd 0x12345678(%eax,%ecx,8),%zmm2,%k3");
+
+       asm volatile("vp2intersectq %xmm1, %xmm2, %k3");
+       asm volatile("vp2intersectq %ymm1, %ymm2, %k3");
+       asm volatile("vp2intersectq %zmm1, %zmm2, %k3");
+       asm volatile("vp2intersectq 0x12345678(%rax,%rcx,8),%zmm2,%k3");
+       asm volatile("vp2intersectq 0x12345678(%eax,%ecx,8),%zmm2,%k3");
+
+       /* AVX-512: Op code 0f 38 70 */
+
+       asm volatile("vpshldvw %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshldvw %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshldvw %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshldvw 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpshldvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 71 */
+
+       asm volatile("vpshldvd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshldvd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshldvd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshldvd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpshldvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vpshldvq %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshldvq %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshldvq %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshldvq 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpshldvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 72 */
+
+       asm volatile("vcvtne2ps2bf16 %xmm1, %xmm2, %xmm3");
+       asm volatile("vcvtne2ps2bf16 %ymm1, %ymm2, %ymm3");
+       asm volatile("vcvtne2ps2bf16 %zmm1, %zmm2, %zmm3");
+       asm volatile("vcvtne2ps2bf16 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vcvtne2ps2bf16 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vcvtneps2bf16 %xmm1, %xmm2");
+       asm volatile("vcvtneps2bf16 %ymm1, %xmm2");
+       asm volatile("vcvtneps2bf16 %zmm1, %ymm2");
+       asm volatile("vcvtneps2bf16 0x12345678(%rax,%rcx,8),%ymm2");
+       asm volatile("vcvtneps2bf16 0x12345678(%eax,%ecx,8),%ymm2");
+
+       asm volatile("vpshrdvw %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshrdvw %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshrdvw %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshrdvw 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpshrdvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 73 */
+
+       asm volatile("vpshrdvd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshrdvd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshrdvd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshrdvd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpshrdvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vpshrdvq %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshrdvq %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshrdvq %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshrdvq 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vpshrdvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
        /* AVX-512: Op code 0f 38 75 */
 
        asm volatile("vpermi2b %zmm24,%zmm25,%zmm26");
@@ -613,6 +787,14 @@ int main(void)
        asm volatile("vpermb %zmm26,%zmm27,%zmm28");
        asm volatile("vpermw %zmm26,%zmm27,%zmm28");
 
+       /* AVX-512: Op code 0f 38 8f */
+
+       asm volatile("vpshufbitqmb %xmm1, %xmm2, %k3");
+       asm volatile("vpshufbitqmb %ymm1, %ymm2, %k3");
+       asm volatile("vpshufbitqmb %zmm1, %zmm2, %k3");
+       asm volatile("vpshufbitqmb 0x12345678(%rax,%rcx,8),%zmm2,%k3");
+       asm volatile("vpshufbitqmb 0x12345678(%eax,%ecx,8),%zmm2,%k3");
+
        /* AVX-512: Op code 0f 38 90 */
 
        asm volatile("vpgatherdd %xmm2,0x02(%rbp,%xmm7,2),%xmm1");
@@ -627,6 +809,40 @@ int main(void)
        asm volatile("vpgatherqd 0x7b(%rbp,%zmm27,8),%ymm26{%k1}");
        asm volatile("vpgatherqq 0x7b(%rbp,%zmm27,8),%zmm26{%k1}");
 
+       /* AVX-512: Op code 0f 38 9a */
+
+       asm volatile("vfmsub132ps %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132ps %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub132ps %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub132ps 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vfmsub132ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vfmsub132pd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132pd %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub132pd %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub132pd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vfmsub132pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("v4fmaddps (%rax), %zmm0, %zmm4");
+       asm volatile("v4fmaddps (%eax), %zmm0, %zmm4");
+       asm volatile("v4fmaddps 0x12345678(%rax,%rcx,8),%zmm0,%zmm4");
+       asm volatile("v4fmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 9b */
+
+       asm volatile("vfmsub132ss %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132ss 0x12345678(%rax,%rcx,8),%xmm2,%xmm3");
+       asm volatile("vfmsub132ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("vfmsub132sd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132sd 0x12345678(%rax,%rcx,8),%xmm2,%xmm3");
+       asm volatile("vfmsub132sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("v4fmaddss (%rax), %xmm0, %xmm4");
+       asm volatile("v4fmaddss (%eax), %xmm0, %xmm4");
+       asm volatile("v4fmaddss 0x12345678(%rax,%rcx,8),%xmm0,%xmm4");
+       asm volatile("v4fmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4");
+
        /* AVX-512: Op code 0f 38 a0 */
 
        asm volatile("vpscatterdd %zmm28,0x7b(%rbp,%zmm29,8){%k1}");
@@ -647,6 +863,40 @@ int main(void)
        asm volatile("vscatterqps %ymm6,0x7b(%rbp,%zmm29,8){%k1}");
        asm volatile("vscatterqpd %zmm28,0x7b(%rbp,%zmm29,8){%k1}");
 
+       /* AVX-512: Op code 0f 38 aa */
+
+       asm volatile("vfmsub213ps %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213ps %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub213ps %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub213ps 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vfmsub213ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vfmsub213pd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213pd %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub213pd %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub213pd 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vfmsub213pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("v4fnmaddps (%rax), %zmm0, %zmm4");
+       asm volatile("v4fnmaddps (%eax), %zmm0, %zmm4");
+       asm volatile("v4fnmaddps 0x12345678(%rax,%rcx,8),%zmm0,%zmm4");
+       asm volatile("v4fnmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 ab */
+
+       asm volatile("vfmsub213ss %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213ss 0x12345678(%rax,%rcx,8),%xmm2,%xmm3");
+       asm volatile("vfmsub213ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("vfmsub213sd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213sd 0x12345678(%rax,%rcx,8),%xmm2,%xmm3");
+       asm volatile("vfmsub213sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("v4fnmaddss (%rax), %xmm0, %xmm4");
+       asm volatile("v4fnmaddss (%eax), %xmm0, %xmm4");
+       asm volatile("v4fnmaddss 0x12345678(%rax,%rcx,8),%xmm0,%xmm4");
+       asm volatile("v4fnmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4");
+
        /* AVX-512: Op code 0f 38 b4 */
 
        asm volatile("vpmadd52luq %zmm26,%zmm27,%zmm28");
@@ -685,6 +935,50 @@ int main(void)
        asm volatile("vrsqrt28ss %xmm28,%xmm29,%xmm30{%k7}");
        asm volatile("vrsqrt28sd %xmm25,%xmm26,%xmm27{%k7}");
 
+       /* AVX-512: Op code 0f 38 cf */
+
+       asm volatile("gf2p8mulb %xmm1, %xmm3");
+       asm volatile("gf2p8mulb 0x12345678(%rax,%rcx,8),%xmm3");
+       asm volatile("gf2p8mulb 0x12345678(%eax,%ecx,8),%xmm3");
+
+       asm volatile("vgf2p8mulb %xmm1, %xmm2, %xmm3");
+       asm volatile("vgf2p8mulb %ymm1, %ymm2, %ymm3");
+       asm volatile("vgf2p8mulb %zmm1, %zmm2, %zmm3");
+       asm volatile("vgf2p8mulb 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vgf2p8mulb 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 dc */
+
+       asm volatile("vaesenc %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesenc %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesenc %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesenc 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vaesenc 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 dd */
+
+       asm volatile("vaesenclast %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesenclast %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesenclast %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesenclast 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vaesenclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 de */
+
+       asm volatile("vaesdec %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesdec %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesdec %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesdec 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vaesdec 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 df */
+
+       asm volatile("vaesdeclast %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesdeclast %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesdeclast %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesdeclast 0x12345678(%rax,%rcx,8),%zmm2,%zmm3");
+       asm volatile("vaesdeclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
        /* AVX-512: Op code 0f 3a 03 */
 
        asm volatile("valignd $0x12,%zmm28,%zmm29,%zmm30");
@@ -804,6 +1098,13 @@ int main(void)
        asm volatile("vshufi32x4 $0x12,%zmm25,%zmm26,%zmm27");
        asm volatile("vshufi64x2 $0x12,%zmm28,%zmm29,%zmm30");
 
+       /* AVX-512: Op code 0f 3a 44 */
+
+       asm volatile("vpclmulqdq $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpclmulqdq $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpclmulqdq $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpclmulqdq $0x12,%zmm25,%zmm26,%zmm27");
+
        /* AVX-512: Op code 0f 3a 50 */
 
        asm volatile("vrangeps $0x12,%zmm25,%zmm26,%zmm27");
@@ -844,6 +1145,62 @@ int main(void)
        asm volatile("vfpclassss $0x12,%xmm27,%k5");
        asm volatile("vfpclasssd $0x12,%xmm30,%k5");
 
+       /* AVX-512: Op code 0f 3a 70 */
+
+       asm volatile("vpshldw $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshldw $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshldw $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpshldw $0x12,%zmm25,%zmm26,%zmm27");
+
+       /* AVX-512: Op code 0f 3a 71 */
+
+       asm volatile("vpshldd $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshldd $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshldd $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpshldd $0x12,%zmm25,%zmm26,%zmm27");
+
+       asm volatile("vpshldq $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshldq $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshldq $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpshldq $0x12,%zmm25,%zmm26,%zmm27");
+
+       /* AVX-512: Op code 0f 3a 72 */
+
+       asm volatile("vpshrdw $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshrdw $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshrdw $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpshrdw $0x12,%zmm25,%zmm26,%zmm27");
+
+       /* AVX-512: Op code 0f 3a 73 */
+
+       asm volatile("vpshrdd $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshrdd $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshrdd $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpshrdd $0x12,%zmm25,%zmm26,%zmm27");
+
+       asm volatile("vpshrdq $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshrdq $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshrdq $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vpshrdq $0x12,%zmm25,%zmm26,%zmm27");
+
+       /* AVX-512: Op code 0f 3a ce */
+
+       asm volatile("gf2p8affineqb $0x12,%xmm1,%xmm3");
+
+       asm volatile("vgf2p8affineqb $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vgf2p8affineqb $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vgf2p8affineqb $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vgf2p8affineqb $0x12,%zmm25,%zmm26,%zmm27");
+
+       /* AVX-512: Op code 0f 3a cf */
+
+       asm volatile("gf2p8affineinvqb $0x12,%xmm1,%xmm3");
+
+       asm volatile("vgf2p8affineinvqb $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vgf2p8affineinvqb $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vgf2p8affineinvqb $0x12,%zmm1,%zmm2,%zmm3");
+       asm volatile("vgf2p8affineinvqb $0x12,%zmm25,%zmm26,%zmm27");
+
        /* AVX-512: Op code 0f 72 (Grp13) */
 
        asm volatile("vprord $0x12,%zmm25,%zmm26");
@@ -1946,6 +2303,69 @@ int main(void)
        asm volatile("vrsqrt14ss %xmm4,%xmm5,%xmm6{%k7}");
        asm volatile("vrsqrt14sd %xmm4,%xmm5,%xmm6{%k7}");
 
+       /* AVX-512: Op code 0f 38 50 */
+
+       asm volatile("vpdpbusd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpbusd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpbusd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpbusd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 51 */
+
+       asm volatile("vpdpbusds %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpbusds %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpbusds %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpbusds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 52 */
+
+       asm volatile("vdpbf16ps %xmm1, %xmm2, %xmm3");
+       asm volatile("vdpbf16ps %ymm1, %ymm2, %ymm3");
+       asm volatile("vdpbf16ps %zmm1, %zmm2, %zmm3");
+       asm volatile("vdpbf16ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vpdpwssd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpwssd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpwssd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpwssd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vp4dpwssd (%eax), %zmm0, %zmm4");
+       asm volatile("vp4dpwssd 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 53 */
+
+       asm volatile("vpdpwssds %xmm1, %xmm2, %xmm3");
+       asm volatile("vpdpwssds %ymm1, %ymm2, %ymm3");
+       asm volatile("vpdpwssds %zmm1, %zmm2, %zmm3");
+       asm volatile("vpdpwssds 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vp4dpwssds (%eax), %zmm0, %zmm4");
+       asm volatile("vp4dpwssds 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 54 */
+
+       asm volatile("vpopcntb %xmm1, %xmm2");
+       asm volatile("vpopcntb %ymm1, %ymm2");
+       asm volatile("vpopcntb %zmm1, %zmm2");
+       asm volatile("vpopcntb 0x12345678(%eax,%ecx,8),%zmm2");
+
+       asm volatile("vpopcntw %xmm1, %xmm2");
+       asm volatile("vpopcntw %ymm1, %ymm2");
+       asm volatile("vpopcntw %zmm1, %zmm2");
+       asm volatile("vpopcntw 0x12345678(%eax,%ecx,8),%zmm2");
+
+       /* AVX-512: Op code 0f 38 55 */
+
+       asm volatile("vpopcntd %xmm1, %xmm2");
+       asm volatile("vpopcntd %ymm1, %ymm2");
+       asm volatile("vpopcntd %zmm1, %zmm2");
+       asm volatile("vpopcntd 0x12345678(%eax,%ecx,8),%zmm2");
+
+       asm volatile("vpopcntq %xmm1, %xmm2");
+       asm volatile("vpopcntq %ymm1, %ymm2");
+       asm volatile("vpopcntq %zmm1, %zmm2");
+       asm volatile("vpopcntq 0x12345678(%eax,%ecx,8),%zmm2");
+
        /* AVX-512: Op code 0f 38 59 */
 
        asm volatile("vpbroadcastq %xmm4,%xmm6");
@@ -1962,6 +2382,30 @@ int main(void)
        asm volatile("vbroadcasti32x8 (%ecx),%zmm6");
        asm volatile("vbroadcasti64x4 (%ecx),%zmm6");
 
+       /* AVX-512: Op code 0f 38 62 */
+
+       asm volatile("vpexpandb %xmm1, %xmm2");
+       asm volatile("vpexpandb %ymm1, %ymm2");
+       asm volatile("vpexpandb %zmm1, %zmm2");
+       asm volatile("vpexpandb 0x12345678(%eax,%ecx,8),%zmm2");
+
+       asm volatile("vpexpandw %xmm1, %xmm2");
+       asm volatile("vpexpandw %ymm1, %ymm2");
+       asm volatile("vpexpandw %zmm1, %zmm2");
+       asm volatile("vpexpandw 0x12345678(%eax,%ecx,8),%zmm2");
+
+       /* AVX-512: Op code 0f 38 63 */
+
+       asm volatile("vpcompressb %xmm1, %xmm2");
+       asm volatile("vpcompressb %ymm1, %ymm2");
+       asm volatile("vpcompressb %zmm1, %zmm2");
+       asm volatile("vpcompressb %zmm2,0x12345678(%eax,%ecx,8)");
+
+       asm volatile("vpcompressw %xmm1, %xmm2");
+       asm volatile("vpcompressw %ymm1, %ymm2");
+       asm volatile("vpcompressw %zmm1, %zmm2");
+       asm volatile("vpcompressw %zmm2,0x12345678(%eax,%ecx,8)");
+
        /* AVX-512: Op code 0f 38 64 */
 
        asm volatile("vpblendmd %zmm4,%zmm5,%zmm6");
@@ -1977,6 +2421,66 @@ int main(void)
        asm volatile("vpblendmb %zmm4,%zmm5,%zmm6");
        asm volatile("vpblendmw %zmm4,%zmm5,%zmm6");
 
+       /* AVX-512: Op code 0f 38 68 */
+
+       asm volatile("vp2intersectd %xmm1, %xmm2, %k3");
+       asm volatile("vp2intersectd %ymm1, %ymm2, %k3");
+       asm volatile("vp2intersectd %zmm1, %zmm2, %k3");
+       asm volatile("vp2intersectd 0x12345678(%eax,%ecx,8),%zmm2,%k3");
+
+       asm volatile("vp2intersectq %xmm1, %xmm2, %k3");
+       asm volatile("vp2intersectq %ymm1, %ymm2, %k3");
+       asm volatile("vp2intersectq %zmm1, %zmm2, %k3");
+       asm volatile("vp2intersectq 0x12345678(%eax,%ecx,8),%zmm2,%k3");
+
+       /* AVX-512: Op code 0f 38 70 */
+
+       asm volatile("vpshldvw %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshldvw %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshldvw %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshldvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 71 */
+
+       asm volatile("vpshldvd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshldvd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshldvd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshldvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vpshldvq %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshldvq %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshldvq %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshldvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 72 */
+
+       asm volatile("vcvtne2ps2bf16 %xmm1, %xmm2, %xmm3");
+       asm volatile("vcvtne2ps2bf16 %ymm1, %ymm2, %ymm3");
+       asm volatile("vcvtne2ps2bf16 %zmm1, %zmm2, %zmm3");
+       asm volatile("vcvtne2ps2bf16 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vcvtneps2bf16 %xmm1, %xmm2");
+       asm volatile("vcvtneps2bf16 %ymm1, %xmm2");
+       asm volatile("vcvtneps2bf16 %zmm1, %ymm2");
+       asm volatile("vcvtneps2bf16 0x12345678(%eax,%ecx,8),%ymm2");
+
+       asm volatile("vpshrdvw %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshrdvw %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshrdvw %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshrdvw 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 73 */
+
+       asm volatile("vpshrdvd %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshrdvd %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshrdvd %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshrdvd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vpshrdvq %xmm1, %xmm2, %xmm3");
+       asm volatile("vpshrdvq %ymm1, %ymm2, %ymm3");
+       asm volatile("vpshrdvq %zmm1, %zmm2, %zmm3");
+       asm volatile("vpshrdvq 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
        /* AVX-512: Op code 0f 38 75 */
 
        asm volatile("vpermi2b %zmm4,%zmm5,%zmm6");
@@ -2048,6 +2552,13 @@ int main(void)
        asm volatile("vpermb %zmm4,%zmm5,%zmm6");
        asm volatile("vpermw %zmm4,%zmm5,%zmm6");
 
+       /* AVX-512: Op code 0f 38 8f */
+
+       asm volatile("vpshufbitqmb %xmm1, %xmm2, %k3");
+       asm volatile("vpshufbitqmb %ymm1, %ymm2, %k3");
+       asm volatile("vpshufbitqmb %zmm1, %zmm2, %k3");
+       asm volatile("vpshufbitqmb 0x12345678(%eax,%ecx,8),%zmm2,%k3");
+
        /* AVX-512: Op code 0f 38 90 */
 
        asm volatile("vpgatherdd %xmm2,0x02(%ebp,%xmm7,2),%xmm1");
@@ -2062,6 +2573,32 @@ int main(void)
        asm volatile("vpgatherqd 0x7b(%ebp,%zmm7,8),%ymm6{%k1}");
        asm volatile("vpgatherqq 0x7b(%ebp,%zmm7,8),%zmm6{%k1}");
 
+       /* AVX-512: Op code 0f 38 9a */
+
+       asm volatile("vfmsub132ps %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132ps %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub132ps %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub132ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vfmsub132pd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132pd %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub132pd %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub132pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("v4fmaddps (%eax), %zmm0, %zmm4");
+       asm volatile("v4fmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 9b */
+
+       asm volatile("vfmsub132ss %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("vfmsub132sd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub132sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("v4fmaddss (%eax), %xmm0, %xmm4");
+       asm volatile("v4fmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4");
+
        /* AVX-512: Op code 0f 38 a0 */
 
        asm volatile("vpscatterdd %zmm6,0x7b(%ebp,%zmm7,8){%k1}");
@@ -2082,6 +2619,32 @@ int main(void)
        asm volatile("vscatterqps %ymm6,0x7b(%ebp,%zmm7,8){%k1}");
        asm volatile("vscatterqpd %zmm6,0x7b(%ebp,%zmm7,8){%k1}");
 
+       /* AVX-512: Op code 0f 38 aa */
+
+       asm volatile("vfmsub213ps %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213ps %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub213ps %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub213ps 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("vfmsub213pd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213pd %ymm1, %ymm2, %ymm3");
+       asm volatile("vfmsub213pd %zmm1, %zmm2, %zmm3");
+       asm volatile("vfmsub213pd 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       asm volatile("v4fnmaddps (%eax), %zmm0, %zmm4");
+       asm volatile("v4fnmaddps 0x12345678(%eax,%ecx,8),%zmm0,%zmm4");
+
+       /* AVX-512: Op code 0f 38 ab */
+
+       asm volatile("vfmsub213ss %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213ss 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("vfmsub213sd %xmm1, %xmm2, %xmm3");
+       asm volatile("vfmsub213sd 0x12345678(%eax,%ecx,8),%xmm2,%xmm3");
+
+       asm volatile("v4fnmaddss (%eax), %xmm0, %xmm4");
+       asm volatile("v4fnmaddss 0x12345678(%eax,%ecx,8),%xmm0,%xmm4");
+
        /* AVX-512: Op code 0f 38 b4 */
 
        asm volatile("vpmadd52luq %zmm4,%zmm5,%zmm6");
@@ -2120,6 +2683,44 @@ int main(void)
        asm volatile("vrsqrt28ss %xmm5,%xmm6,%xmm7{%k7}");
        asm volatile("vrsqrt28sd %xmm5,%xmm6,%xmm7{%k7}");
 
+       /* AVX-512: Op code 0f 38 cf */
+
+       asm volatile("gf2p8mulb %xmm1, %xmm3");
+       asm volatile("gf2p8mulb 0x12345678(%eax,%ecx,8),%xmm3");
+
+       asm volatile("vgf2p8mulb %xmm1, %xmm2, %xmm3");
+       asm volatile("vgf2p8mulb %ymm1, %ymm2, %ymm3");
+       asm volatile("vgf2p8mulb %zmm1, %zmm2, %zmm3");
+       asm volatile("vgf2p8mulb 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 dc */
+
+       asm volatile("vaesenc %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesenc %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesenc %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesenc 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 dd */
+
+       asm volatile("vaesenclast %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesenclast %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesenclast %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesenclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 de */
+
+       asm volatile("vaesdec %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesdec %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesdec %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesdec 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 38 df */
+
+       asm volatile("vaesdeclast %xmm1, %xmm2, %xmm3");
+       asm volatile("vaesdeclast %ymm1, %ymm2, %ymm3");
+       asm volatile("vaesdeclast %zmm1, %zmm2, %zmm3");
+       asm volatile("vaesdeclast 0x12345678(%eax,%ecx,8),%zmm2,%zmm3");
+
        /* AVX-512: Op code 0f 3a 03 */
 
        asm volatile("valignd $0x12,%zmm5,%zmm6,%zmm7");
@@ -2239,6 +2840,12 @@ int main(void)
        asm volatile("vshufi32x4 $0x12,%zmm5,%zmm6,%zmm7");
        asm volatile("vshufi64x2 $0x12,%zmm5,%zmm6,%zmm7");
 
+       /* AVX-512: Op code 0f 3a 44 */
+
+       asm volatile("vpclmulqdq $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpclmulqdq $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpclmulqdq $0x12,%zmm1,%zmm2,%zmm3");
+
        /* AVX-512: Op code 0f 3a 50 */
 
        asm volatile("vrangeps $0x12,%zmm5,%zmm6,%zmm7");
@@ -2279,6 +2886,54 @@ int main(void)
        asm volatile("vfpclassss $0x12,%xmm7,%k5");
        asm volatile("vfpclasssd $0x12,%xmm7,%k5");
 
+       /* AVX-512: Op code 0f 3a 70 */
+
+       asm volatile("vpshldw $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshldw $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshldw $0x12,%zmm1,%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 3a 71 */
+
+       asm volatile("vpshldd $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshldd $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshldd $0x12,%zmm1,%zmm2,%zmm3");
+
+       asm volatile("vpshldq $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshldq $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshldq $0x12,%zmm1,%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 3a 72 */
+
+       asm volatile("vpshrdw $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshrdw $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshrdw $0x12,%zmm1,%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 3a 73 */
+
+       asm volatile("vpshrdd $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshrdd $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshrdd $0x12,%zmm1,%zmm2,%zmm3");
+
+       asm volatile("vpshrdq $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vpshrdq $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vpshrdq $0x12,%zmm1,%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 3a ce */
+
+       asm volatile("gf2p8affineqb $0x12,%xmm1,%xmm3");
+
+       asm volatile("vgf2p8affineqb $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vgf2p8affineqb $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vgf2p8affineqb $0x12,%zmm1,%zmm2,%zmm3");
+
+       /* AVX-512: Op code 0f 3a cf */
+
+       asm volatile("gf2p8affineinvqb $0x12,%xmm1,%xmm3");
+
+       asm volatile("vgf2p8affineinvqb $0x12,%xmm1,%xmm2,%xmm3");
+       asm volatile("vgf2p8affineinvqb $0x12,%ymm1,%ymm2,%ymm3");
+       asm volatile("vgf2p8affineinvqb $0x12,%zmm1,%zmm2,%zmm3");
+
        /* AVX-512: Op code 0f 72 (Grp13) */
 
        asm volatile("vprord $0x12,%zmm5,%zmm6");
index d1044df..ac45015 100644 (file)
@@ -18,8 +18,7 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
 {
        int rc = 0;
        struct map *pos;
-       struct map_groups *kmaps = &machine->kmaps;
-       struct maps *maps = &kmaps->maps;
+       struct maps *kmaps = &machine->kmaps;
        union perf_event *event = zalloc(sizeof(event->mmap) +
                                         machine->id_hdr_size);
 
@@ -29,7 +28,7 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
                return -1;
        }
 
-       maps__for_each_entry(maps, pos) {
+       maps__for_each_entry(kmaps, pos) {
                struct kmap *kmap;
                size_t size;
 
index 376dbf1..f8b6ae5 100644 (file)
@@ -547,8 +547,8 @@ static int64_t block_cycles_diff_cmp(struct hist_entry *left,
        if (!pairs_left && !pairs_right)
                return 0;
 
-       l = labs(left->diff.cycles);
-       r = labs(right->diff.cycles);
+       l = llabs(left->diff.cycles);
+       r = llabs(right->diff.cycles);
        return r - l;
 }
 
@@ -646,7 +646,7 @@ static void compute_cycles_diff(struct hist_entry *he,
                        if (i >= he->block_info->num || i >= NUM_SPARKS)
                                break;
 
-                       val = labs(pair->block_info->cycles_spark[i] -
+                       val = llabs(pair->block_info->cycles_spark[i] -
                                     he->block_info->cycles_spark[i]);
 
                        update_spark_value(pair->diff.svals, NUM_SPARKS,
index ab0f6e5..830d563 100644 (file)
@@ -780,11 +780,6 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
        return printed;
 }
 
-static int map_groups__fprintf_task(struct map_groups *mg, int indent, FILE *fp)
-{
-       return maps__fprintf_task(&mg->maps, indent, fp);
-}
-
 static void task__print_level(struct task *task, FILE *fp, int level)
 {
        struct thread *thread = task->thread;
@@ -795,7 +790,7 @@ static void task__print_level(struct task *task, FILE *fp, int level)
 
        fprintf(fp, "%s\n", thread__comm_str(thread));
 
-       map_groups__fprintf_task(thread->mg, comm_indent, fp);
+       maps__fprintf_task(thread->maps, comm_indent, fp);
 
        if (!list_empty(&task->children)) {
                list_for_each_entry(child, &task->children, list)
index f86c5cc..e2406b2 100644 (file)
@@ -448,7 +448,7 @@ static int perf_evsel__check_attr(struct evsel *evsel,
                       "selected. Hence, no address to lookup the source line number.\n");
                return -EINVAL;
        }
-       if (PRINT_FIELD(BRSTACKINSN) &&
+       if (PRINT_FIELD(BRSTACKINSN) && !allow_user_set &&
            !(perf_evlist__combined_branch_type(session->evlist) &
              PERF_SAMPLE_BRANCH_ANY)) {
                pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"
@@ -932,6 +932,48 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
        return len;
 }
 
+static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srccode_state *state)
+{
+       char *srcfile;
+       int ret = 0;
+       unsigned line;
+       int len;
+       char *srccode;
+
+       if (!map || !map->dso)
+               return 0;
+       srcfile = get_srcline_split(map->dso,
+                                   map__rip_2objdump(map, addr),
+                                   &line);
+       if (!srcfile)
+               return 0;
+
+       /* Avoid redundant printing */
+       if (state &&
+           state->srcfile &&
+           !strcmp(state->srcfile, srcfile) &&
+           state->line == line) {
+               free(srcfile);
+               return 0;
+       }
+
+       srccode = find_sourceline(srcfile, line, &len);
+       if (!srccode)
+               goto out_free_line;
+
+       ret = fprintf(fp, "|%-8d %.*s", line, len, srccode);
+
+       if (state) {
+               state->srcfile = srcfile;
+               state->line = line;
+       }
+       return ret;
+
+out_free_line:
+       free(srcfile);
+       return ret;
+}
+
 static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr)
 {
        struct addr_location al;
@@ -1084,7 +1126,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
                                insn++;
                        }
                }
-               if (off != (unsigned)len)
+               if (off != end - start)
                        printed += fprintf(fp, "\tmismatch of LBR data and executable\n");
        }
 
index e72acce..a3c595f 100644 (file)
@@ -27,7 +27,7 @@ perf-y += wp.o
 perf-y += task-exit.o
 perf-y += sw-clock.o
 perf-y += mmap-thread-lookup.o
-perf-y += thread-mg-share.o
+perf-y += thread-maps-share.o
 perf-y += switch-tracking.o
 perf-y += keep-tracking.o
 perf-y += code-reading.o
@@ -52,7 +52,7 @@ perf-y += perf-hooks.o
 perf-y += clang.o
 perf-y += unit_number__scnprintf.o
 perf-y += mem2node.o
-perf-y += map_groups.o
+perf-y += maps.o
 perf-y += time-utils-test.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
index 8b286e9..7115aa3 100644 (file)
@@ -166,8 +166,8 @@ static struct test generic_tests[] = {
                .func = test__mmap_thread_lookup,
        },
        {
-               .desc = "Share thread mg",
-               .func = test__thread_mg_share,
+               .desc = "Share thread maps",
+               .func = test__thread_maps_share,
        },
        {
                .desc = "Sort output of hist entries",
@@ -297,8 +297,8 @@ static struct test generic_tests[] = {
                .func = test__time_utils,
        },
        {
-               .desc = "map_groups__merge_in",
-               .func = test__map_groups__merge_in,
+               .desc = "maps__merge_in",
+               .func = test__maps__merge_in,
        },
        {
                .func = NULL,
index 1f017e1..6fe221d 100644 (file)
@@ -276,7 +276,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
                len = al.map->end - addr;
 
        /* Read the object code using perf */
-       ret_len = dso__data_read_offset(al.map->dso, thread->mg->machine,
+       ret_len = dso__data_read_offset(al.map->dso, thread->maps->machine,
                                        al.addr, buf1, len);
        if (ret_len != len) {
                pr_debug("dso__data_read_offset failed\n");
diff --git a/tools/perf/tests/map_groups.c b/tools/perf/tests/map_groups.c
deleted file mode 100644 (file)
index 6b9f1cd..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include "tests.h"
-#include "map.h"
-#include "map_groups.h"
-#include "dso.h"
-#include "debug.h"
-
-struct map_def {
-       const char *name;
-       u64 start;
-       u64 end;
-};
-
-static int check_maps(struct map_def *merged, unsigned int size, struct map_groups *mg)
-{
-       struct map *map;
-       unsigned int i = 0;
-
-       map_groups__for_each_entry(mg, map) {
-               if (i > 0)
-                       TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size));
-
-               TEST_ASSERT_VAL("wrong map start",  map->start == merged[i].start);
-               TEST_ASSERT_VAL("wrong map end",    map->end == merged[i].end);
-               TEST_ASSERT_VAL("wrong map name",  !strcmp(map->dso->name, merged[i].name));
-               TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 1);
-
-               i++;
-       }
-
-       return TEST_OK;
-}
-
-int test__map_groups__merge_in(struct test *t __maybe_unused, int subtest __maybe_unused)
-{
-       struct map_groups mg;
-       unsigned int i;
-       struct map_def bpf_progs[] = {
-               { "bpf_prog_1", 200, 300 },
-               { "bpf_prog_2", 500, 600 },
-               { "bpf_prog_3", 800, 900 },
-       };
-       struct map_def merged12[] = {
-               { "kcore1",     100,  200 },
-               { "bpf_prog_1", 200,  300 },
-               { "kcore1",     300,  500 },
-               { "bpf_prog_2", 500,  600 },
-               { "kcore1",     600,  800 },
-               { "bpf_prog_3", 800,  900 },
-               { "kcore1",     900, 1000 },
-       };
-       struct map_def merged3[] = {
-               { "kcore1",      100,  200 },
-               { "bpf_prog_1",  200,  300 },
-               { "kcore1",      300,  500 },
-               { "bpf_prog_2",  500,  600 },
-               { "kcore1",      600,  800 },
-               { "bpf_prog_3",  800,  900 },
-               { "kcore1",      900, 1000 },
-               { "kcore3",     1000, 1100 },
-       };
-       struct map *map_kcore1, *map_kcore2, *map_kcore3;
-       int ret;
-
-       map_groups__init(&mg, NULL);
-
-       for (i = 0; i < ARRAY_SIZE(bpf_progs); i++) {
-               struct map *map;
-
-               map = dso__new_map(bpf_progs[i].name);
-               TEST_ASSERT_VAL("failed to create map", map);
-
-               map->start = bpf_progs[i].start;
-               map->end   = bpf_progs[i].end;
-               map_groups__insert(&mg, map);
-               map__put(map);
-       }
-
-       map_kcore1 = dso__new_map("kcore1");
-       TEST_ASSERT_VAL("failed to create map", map_kcore1);
-
-       map_kcore2 = dso__new_map("kcore2");
-       TEST_ASSERT_VAL("failed to create map", map_kcore2);
-
-       map_kcore3 = dso__new_map("kcore3");
-       TEST_ASSERT_VAL("failed to create map", map_kcore3);
-
-       /* kcore1 map overlaps over all bpf maps */
-       map_kcore1->start = 100;
-       map_kcore1->end   = 1000;
-
-       /* kcore2 map hides behind bpf_prog_2 */
-       map_kcore2->start = 550;
-       map_kcore2->end   = 570;
-
-       /* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */
-       map_kcore3->start = 880;
-       map_kcore3->end   = 1100;
-
-       ret = map_groups__merge_in(&mg, map_kcore1);
-       TEST_ASSERT_VAL("failed to merge map", !ret);
-
-       ret = check_maps(merged12, ARRAY_SIZE(merged12), &mg);
-       TEST_ASSERT_VAL("merge check failed", !ret);
-
-       ret = map_groups__merge_in(&mg, map_kcore2);
-       TEST_ASSERT_VAL("failed to merge map", !ret);
-
-       ret = check_maps(merged12, ARRAY_SIZE(merged12), &mg);
-       TEST_ASSERT_VAL("merge check failed", !ret);
-
-       ret = map_groups__merge_in(&mg, map_kcore3);
-       TEST_ASSERT_VAL("failed to merge map", !ret);
-
-       ret = check_maps(merged3, ARRAY_SIZE(merged3), &mg);
-       TEST_ASSERT_VAL("merge check failed", !ret);
-       return TEST_OK;
-}
diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c
new file mode 100644 (file)
index 0000000..edcbc70
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include "tests.h"
+#include "map.h"
+#include "maps.h"
+#include "dso.h"
+#include "debug.h"
+
+struct map_def {
+       const char *name;
+       u64 start;
+       u64 end;
+};
+
+static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps)
+{
+       struct map *map;
+       unsigned int i = 0;
+
+       maps__for_each_entry(maps, map) {
+               if (i > 0)
+                       TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size));
+
+               TEST_ASSERT_VAL("wrong map start",  map->start == merged[i].start);
+               TEST_ASSERT_VAL("wrong map end",    map->end == merged[i].end);
+               TEST_ASSERT_VAL("wrong map name",  !strcmp(map->dso->name, merged[i].name));
+               TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 1);
+
+               i++;
+       }
+
+       return TEST_OK;
+}
+
+int test__maps__merge_in(struct test *t __maybe_unused, int subtest __maybe_unused)
+{
+       struct maps maps;
+       unsigned int i;
+       struct map_def bpf_progs[] = {
+               { "bpf_prog_1", 200, 300 },
+               { "bpf_prog_2", 500, 600 },
+               { "bpf_prog_3", 800, 900 },
+       };
+       struct map_def merged12[] = {
+               { "kcore1",     100,  200 },
+               { "bpf_prog_1", 200,  300 },
+               { "kcore1",     300,  500 },
+               { "bpf_prog_2", 500,  600 },
+               { "kcore1",     600,  800 },
+               { "bpf_prog_3", 800,  900 },
+               { "kcore1",     900, 1000 },
+       };
+       struct map_def merged3[] = {
+               { "kcore1",      100,  200 },
+               { "bpf_prog_1",  200,  300 },
+               { "kcore1",      300,  500 },
+               { "bpf_prog_2",  500,  600 },
+               { "kcore1",      600,  800 },
+               { "bpf_prog_3",  800,  900 },
+               { "kcore1",      900, 1000 },
+               { "kcore3",     1000, 1100 },
+       };
+       struct map *map_kcore1, *map_kcore2, *map_kcore3;
+       int ret;
+
+       maps__init(&maps, NULL);
+
+       for (i = 0; i < ARRAY_SIZE(bpf_progs); i++) {
+               struct map *map;
+
+               map = dso__new_map(bpf_progs[i].name);
+               TEST_ASSERT_VAL("failed to create map", map);
+
+               map->start = bpf_progs[i].start;
+               map->end   = bpf_progs[i].end;
+               maps__insert(&maps, map);
+               map__put(map);
+       }
+
+       map_kcore1 = dso__new_map("kcore1");
+       TEST_ASSERT_VAL("failed to create map", map_kcore1);
+
+       map_kcore2 = dso__new_map("kcore2");
+       TEST_ASSERT_VAL("failed to create map", map_kcore2);
+
+       map_kcore3 = dso__new_map("kcore3");
+       TEST_ASSERT_VAL("failed to create map", map_kcore3);
+
+       /* kcore1 map overlaps over all bpf maps */
+       map_kcore1->start = 100;
+       map_kcore1->end   = 1000;
+
+       /* kcore2 map hides behind bpf_prog_2 */
+       map_kcore2->start = 550;
+       map_kcore2->end   = 570;
+
+       /* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */
+       map_kcore3->start = 880;
+       map_kcore3->end   = 1100;
+
+       ret = maps__merge_in(&maps, map_kcore1);
+       TEST_ASSERT_VAL("failed to merge map", !ret);
+
+       ret = check_maps(merged12, ARRAY_SIZE(merged12), &maps);
+       TEST_ASSERT_VAL("merge check failed", !ret);
+
+       ret = maps__merge_in(&maps, map_kcore2);
+       TEST_ASSERT_VAL("failed to merge map", !ret);
+
+       ret = check_maps(merged12, ARRAY_SIZE(merged12), &maps);
+       TEST_ASSERT_VAL("merge check failed", !ret);
+
+       ret = maps__merge_in(&maps, map_kcore3);
+       TEST_ASSERT_VAL("failed to merge map", !ret);
+
+       ret = check_maps(merged3, ARRAY_SIZE(merged3), &maps);
+       TEST_ASSERT_VAL("merge check failed", !ret);
+       return TEST_OK;
+}
index 9837b6e..25aea38 100644 (file)
@@ -73,7 +73,7 @@ int test__dwarf_unwind(struct test *test, int subtest);
 int test__expr(struct test *test, int subtest);
 int test__hists_filter(struct test *test, int subtest);
 int test__mmap_thread_lookup(struct test *test, int subtest);
-int test__thread_mg_share(struct test *test, int subtest);
+int test__thread_maps_share(struct test *test, int subtest);
 int test__hists_output(struct test *test, int subtest);
 int test__hists_cumulate(struct test *test, int subtest);
 int test__switch_tracking(struct test *test, int subtest);
@@ -107,7 +107,7 @@ const char *test__clang_subtest_get_desc(int subtest);
 int test__clang_subtest_get_nr(void);
 int test__unit_number__scnprint(struct test *test, int subtest);
 int test__mem2node(struct test *t, int subtest);
-int test__map_groups__merge_in(struct test *t, int subtest);
+int test__maps__merge_in(struct test *t, int subtest);
 int test__time_utils(struct test *t, int subtest);
 
 bool test__bp_signal_is_supported(void);
diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread-maps-share.c
new file mode 100644 (file)
index 0000000..9371484
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "tests.h"
+#include "machine.h"
+#include "thread.h"
+#include "debug.h"
+
+int test__thread_maps_share(struct test *test __maybe_unused, int subtest __maybe_unused)
+{
+       struct machines machines;
+       struct machine *machine;
+
+       /* thread group */
+       struct thread *leader;
+       struct thread *t1, *t2, *t3;
+       struct maps *maps;
+
+       /* other process */
+       struct thread *other, *other_leader;
+       struct maps *other_maps;
+
+       /*
+        * This test create 2 processes abstractions (struct thread)
+        * with several threads and checks they properly share and
+        * maintain maps info (struct maps).
+        *
+        * thread group (pid: 0, tids: 0, 1, 2, 3)
+        * other  group (pid: 4, tids: 4, 5)
+       */
+
+       machines__init(&machines);
+       machine = &machines.host;
+
+       /* create process with 4 threads */
+       leader = machine__findnew_thread(machine, 0, 0);
+       t1     = machine__findnew_thread(machine, 0, 1);
+       t2     = machine__findnew_thread(machine, 0, 2);
+       t3     = machine__findnew_thread(machine, 0, 3);
+
+       /* and create 1 separated process, without thread leader */
+       other  = machine__findnew_thread(machine, 4, 5);
+
+       TEST_ASSERT_VAL("failed to create threads",
+                       leader && t1 && t2 && t3 && other);
+
+       maps = leader->maps;
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 4);
+
+       /* test the maps pointer is shared */
+       TEST_ASSERT_VAL("maps don't match", maps == t1->maps);
+       TEST_ASSERT_VAL("maps don't match", maps == t2->maps);
+       TEST_ASSERT_VAL("maps don't match", maps == t3->maps);
+
+       /*
+        * Verify the other leader was created by previous call.
+        * It should have shared maps with no change in
+        * refcnt.
+        */
+       other_leader = machine__find_thread(machine, 4, 4);
+       TEST_ASSERT_VAL("failed to find other leader", other_leader);
+
+       /*
+        * Ok, now that all the rbtree related operations were done,
+        * lets remove all of them from there so that we can do the
+        * refcounting tests.
+        */
+       machine__remove_thread(machine, leader);
+       machine__remove_thread(machine, t1);
+       machine__remove_thread(machine, t2);
+       machine__remove_thread(machine, t3);
+       machine__remove_thread(machine, other);
+       machine__remove_thread(machine, other_leader);
+
+       other_maps = other->maps;
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 2);
+
+       TEST_ASSERT_VAL("maps don't match", other_maps == other_leader->maps);
+
+       /* release thread group */
+       thread__put(leader);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 3);
+
+       thread__put(t1);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 2);
+
+       thread__put(t2);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 1);
+
+       thread__put(t3);
+
+       /* release other group  */
+       thread__put(other_leader);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 1);
+
+       thread__put(other);
+
+       machines__exit(&machines);
+       return 0;
+}
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
deleted file mode 100644 (file)
index cbac717..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "tests.h"
-#include "machine.h"
-#include "thread.h"
-#include "debug.h"
-
-int test__thread_mg_share(struct test *test __maybe_unused, int subtest __maybe_unused)
-{
-       struct machines machines;
-       struct machine *machine;
-
-       /* thread group */
-       struct thread *leader;
-       struct thread *t1, *t2, *t3;
-       struct map_groups *mg;
-
-       /* other process */
-       struct thread *other, *other_leader;
-       struct map_groups *other_mg;
-
-       /*
-        * This test create 2 processes abstractions (struct thread)
-        * with several threads and checks they properly share and
-        * maintain map groups info (struct map_groups).
-        *
-        * thread group (pid: 0, tids: 0, 1, 2, 3)
-        * other  group (pid: 4, tids: 4, 5)
-       */
-
-       machines__init(&machines);
-       machine = &machines.host;
-
-       /* create process with 4 threads */
-       leader = machine__findnew_thread(machine, 0, 0);
-       t1     = machine__findnew_thread(machine, 0, 1);
-       t2     = machine__findnew_thread(machine, 0, 2);
-       t3     = machine__findnew_thread(machine, 0, 3);
-
-       /* and create 1 separated process, without thread leader */
-       other  = machine__findnew_thread(machine, 4, 5);
-
-       TEST_ASSERT_VAL("failed to create threads",
-                       leader && t1 && t2 && t3 && other);
-
-       mg = leader->mg;
-       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 4);
-
-       /* test the map groups pointer is shared */
-       TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
-       TEST_ASSERT_VAL("map groups don't match", mg == t2->mg);
-       TEST_ASSERT_VAL("map groups don't match", mg == t3->mg);
-
-       /*
-        * Verify the other leader was created by previous call.
-        * It should have shared map groups with no change in
-        * refcnt.
-        */
-       other_leader = machine__find_thread(machine, 4, 4);
-       TEST_ASSERT_VAL("failed to find other leader", other_leader);
-
-       /*
-        * Ok, now that all the rbtree related operations were done,
-        * lets remove all of them from there so that we can do the
-        * refcounting tests.
-        */
-       machine__remove_thread(machine, leader);
-       machine__remove_thread(machine, t1);
-       machine__remove_thread(machine, t2);
-       machine__remove_thread(machine, t3);
-       machine__remove_thread(machine, other);
-       machine__remove_thread(machine, other_leader);
-
-       other_mg = other->mg;
-       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 2);
-
-       TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
-
-       /* release thread group */
-       thread__put(leader);
-       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 3);
-
-       thread__put(t1);
-       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 2);
-
-       thread__put(t2);
-       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 1);
-
-       thread__put(t3);
-
-       /* release other group  */
-       thread__put(other_leader);
-       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 1);
-
-       thread__put(other);
-
-       machines__exit(&machines);
-       return 0;
-}
index ff64907..193b7c9 100644 (file)
@@ -190,10 +190,9 @@ next_pair:
                 * so use the short name, less descriptive but the same ("[kernel]" in
                 * both cases.
                 */
-               pair = map_groups__find_by_name(&kallsyms.kmaps,
-                                               (map->dso->kernel ?
-                                                       map->dso->short_name :
-                                                       map->dso->name));
+               pair = maps__find_by_name(&kallsyms.kmaps, (map->dso->kernel ?
+                                                               map->dso->short_name :
+                                                               map->dso->name));
                if (pair) {
                        pair->priv = 1;
                } else {
@@ -213,7 +212,7 @@ next_pair:
                mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start);
                mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end);
 
-               pair = map_groups__find(&kallsyms.kmaps, mem_start);
+               pair = maps__find(&kallsyms.kmaps, mem_start);
                if (pair == NULL || pair->priv)
                        continue;
 
index 992705c..badbddb 100644 (file)
@@ -430,7 +430,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
                return true;
        }
 
-       target_ms.mg  = ms->mg;
+       target_ms.maps = ms->maps;
        target_ms.map = ms->map;
        target_ms.sym = dl->ops.target.sym;
        pthread_mutex_unlock(&notes->lock);
index 132056c..2ab2af4 100644 (file)
@@ -8,7 +8,7 @@
 #include "../../util/event.h"
 #include "../../util/hist.h"
 #include "../../util/map.h"
-#include "../../util/map_groups.h"
+#include "../../util/maps.h"
 #include "../../util/symbol.h"
 #include "../../util/sort.h"
 #include "../../util/evsel.h"
@@ -885,7 +885,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                }
 
                if (h->ms.map == NULL && verbose > 1) {
-                       map_groups__fprintf(h->thread->mg, fp);
+                       maps__fprintf(h->thread->maps, fp);
                        fprintf(fp, "%.10s end\n", graph_dotted_line);
                }
        }
index b8e05a1..07da6c7 100644 (file)
@@ -49,6 +49,7 @@ perf-y += header.o
 perf-y += callchain.o
 perf-y += values.o
 perf-y += debug.o
+perf-y += fncache.o
 perf-y += machine.o
 perf-y += map.o
 perf-y += pstack.o
@@ -76,6 +77,7 @@ perf-y += sort.o
 perf-y += hist.o
 perf-y += util.o
 perf-y += cpumap.o
+perf-y += affinity.o
 perf-y += cputopo.o
 perf-y += cgroup.o
 perf-y += target.o
diff --git a/tools/perf/util/affinity.c b/tools/perf/util/affinity.c
new file mode 100644 (file)
index 0000000..a5e31f8
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Manage affinity to optimize IPIs inside the kernel perf API. */
+#define _GNU_SOURCE 1
+#include <sched.h>
+#include <stdlib.h>
+#include <linux/bitmap.h>
+#include <linux/zalloc.h>
+#include "perf.h"
+#include "cpumap.h"
+#include "affinity.h"
+
+static int get_cpu_set_size(void)
+{
+       int sz = cpu__max_cpu() + 8 - 1;
+       /*
+        * sched_getaffinity doesn't like masks smaller than the kernel.
+        * Hopefully that's big enough.
+        */
+       if (sz < 4096)
+               sz = 4096;
+       return sz / 8;
+}
+
+int affinity__setup(struct affinity *a)
+{
+       int cpu_set_size = get_cpu_set_size();
+
+       a->orig_cpus = bitmap_alloc(cpu_set_size * 8);
+       if (!a->orig_cpus)
+               return -1;
+       sched_getaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
+       a->sched_cpus = bitmap_alloc(cpu_set_size * 8);
+       if (!a->sched_cpus) {
+               zfree(&a->orig_cpus);
+               return -1;
+       }
+       bitmap_zero((unsigned long *)a->sched_cpus, cpu_set_size);
+       a->changed = false;
+       return 0;
+}
+
+/*
+ * perf_event_open does an IPI internally to the target CPU.
+ * It is more efficient to change perf's affinity to the target
+ * CPU and then set up all events on that CPU, so we amortize
+ * CPU communication.
+ */
+void affinity__set(struct affinity *a, int cpu)
+{
+       int cpu_set_size = get_cpu_set_size();
+
+       if (cpu == -1)
+               return;
+       a->changed = true;
+       set_bit(cpu, a->sched_cpus);
+       /*
+        * We ignore errors because affinity is just an optimization.
+        * This could happen for example with isolated CPUs or cpusets.
+        * In this case the IPIs inside the kernel's perf API still work.
+        */
+       sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus);
+       clear_bit(cpu, a->sched_cpus);
+}
+
+void affinity__cleanup(struct affinity *a)
+{
+       int cpu_set_size = get_cpu_set_size();
+
+       if (a->changed)
+               sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
+       zfree(&a->sched_cpus);
+       zfree(&a->orig_cpus);
+}
diff --git a/tools/perf/util/affinity.h b/tools/perf/util/affinity.h
new file mode 100644 (file)
index 0000000..0ad6a18
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef PERF_AFFINITY_H
+#define PERF_AFFINITY_H 1
+
+#include <stdbool.h>
+
+struct affinity {
+       unsigned long *orig_cpus;
+       unsigned long *sched_cpus;
+       bool changed;
+};
+
+void affinity__cleanup(struct affinity *a);
+void affinity__set(struct affinity *a, int cpu);
+int affinity__setup(struct affinity *a);
+
+#endif // PERF_AFFINITY_H
index 5ea9a45..f5e77ed 100644 (file)
@@ -23,7 +23,7 @@
 #include "dso.h"
 #include "env.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "symbol.h"
 #include "srcline.h"
 #include "units.h"
@@ -271,7 +271,7 @@ static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_s
 find_target:
        target.addr = map__objdump_2mem(map, ops->target.addr);
 
-       if (map_groups__find_ams(ms->mg, &target) == 0 &&
+       if (maps__find_ams(ms->maps, &target) == 0 &&
            map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr)
                ops->target.sym = target.ms.sym;
 
@@ -391,7 +391,7 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s
         * Actual navigation will come next, with further understanding of how
         * the symbol searching and disassembly should be done.
         */
-       if (map_groups__find_ams(ms->mg, &target) == 0 &&
+       if (maps__find_ams(ms->maps, &target) == 0 &&
            map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr)
                ops->target.sym = target.ms.sym;
 
@@ -1545,7 +1545,7 @@ static int symbol__parse_objdump_line(struct symbol *sym,
                        .ms = { .map = map, },
                };
 
-               if (!map_groups__find_ams(args->ms.mg, &target) &&
+               if (!maps__find_ams(args->ms.maps, &target) &&
                    target.ms.sym->start == target.al_addr)
                        dl->ops.target.sym = target.ms.sym;
        }
index f7ed5d1..a3207d9 100644 (file)
@@ -52,9 +52,7 @@ static int machine__process_bpf_event_load(struct machine *machine,
        for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
                u64 *addrs = (u64 *)(uintptr_t)(info_linear->info.jited_ksyms);
                u64 addr = addrs[i];
-               struct map *map;
-
-               map = map_groups__find(&machine->kmaps, addr);
+               struct map *map = maps__find(&machine->kmaps, addr);
 
                if (map) {
                        map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO;
index 5cefce3..818aa4e 100644 (file)
@@ -1106,7 +1106,7 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
 int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
                        bool hide_unresolved)
 {
-       al->mg  = node->ms.mg;
+       al->maps = node->ms.maps;
        al->map = node->ms.map;
        al->sym = node->ms.sym;
        al->srcline = node->srcline;
@@ -1119,8 +1119,8 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
                        goto out;
        }
 
-       if (al->mg == &al->mg->machine->kmaps) {
-               if (machine__is_host(al->mg->machine)) {
+       if (al->maps == &al->maps->machine->kmaps) {
+               if (machine__is_host(al->maps->machine)) {
                        al->cpumode = PERF_RECORD_MISC_KERNEL;
                        al->level = 'k';
                } else {
@@ -1128,7 +1128,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
                        al->level = 'g';
                }
        } else {
-               if (machine__is_host(al->mg->machine)) {
+               if (machine__is_host(al->maps->machine)) {
                        al->cpumode = PERF_RECORD_MISC_USER;
                        al->level = '.';
                } else if (perf_guest) {
index f5f855f..5471045 100644 (file)
@@ -2569,7 +2569,7 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
        if (err)
                goto err_delete_thread;
 
-       if (thread__init_map_groups(etm->unknown_thread, etm->machine)) {
+       if (thread__init_maps(etm->unknown_thread, etm->machine)) {
                err = -ENOMEM;
                goto err_delete_thread;
        }
index d029faf..db74471 100644 (file)
@@ -181,7 +181,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
        if (al->map) {
                struct dso *dso = al->map->dso;
 
-               err = db_export__dso(dbe, dso, al->mg->machine);
+               err = db_export__dso(dbe, dso, al->maps->machine);
                if (err)
                        return err;
                *dso_db_id = dso->db_id;
@@ -251,7 +251,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
                 */
                al.sym = node->ms.sym;
                al.map = node->ms.map;
-               al.mg  = thread->mg;
+               al.maps = thread->maps;
                al.addr = node->ip;
 
                if (al.map && !al.sym)
@@ -360,13 +360,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
        if (err)
                return err;
 
-       err = db_export__machine(dbe, al->mg->machine);
+       err = db_export__machine(dbe, al->maps->machine);
        if (err)
                return err;
 
-       main_thread = thread__main_thread(al->mg->machine, thread);
+       main_thread = thread__main_thread(al->maps->machine, thread);
 
-       err = db_export__threads(dbe, thread, main_thread, al->mg->machine, &comm);
+       err = db_export__threads(dbe, thread, main_thread, al->maps->machine, &comm);
        if (err)
                goto out_put;
 
@@ -380,7 +380,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
                goto out_put;
 
        if (dbe->cpr) {
-               struct call_path *cp = call_path_from_sample(dbe, al->mg->machine,
+               struct call_path *cp = call_path_from_sample(dbe, al->maps->machine,
                                                             thread, sample,
                                                             evsel);
                if (cp) {
index 0141b26..c5447ff 100644 (file)
@@ -457,11 +457,11 @@ int perf_event__process(struct perf_tool *tool __maybe_unused,
 struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
                             struct addr_location *al)
 {
-       struct map_groups *mg = thread->mg;
-       struct machine *machine = mg->machine;
+       struct maps *maps = thread->maps;
+       struct machine *machine = maps->machine;
        bool load_map = false;
 
-       al->mg = mg;
+       al->maps = maps;
        al->thread = thread;
        al->addr = addr;
        al->cpumode = cpumode;
@@ -474,13 +474,13 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
 
        if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
                al->level = 'k';
-               al->mg = mg = &machine->kmaps;
+               al->maps = maps = &machine->kmaps;
                load_map = true;
        } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
                al->level = '.';
        } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
                al->level = 'g';
-               al->mg = mg = &machine->kmaps;
+               al->maps = maps = &machine->kmaps;
                load_map = true;
        } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
                al->level = 'u';
@@ -500,7 +500,7 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
                return NULL;
        }
 
-       al->map = map_groups__find(mg, al->addr);
+       al->map = maps__find(maps, al->addr);
        if (al->map != NULL) {
                /*
                 * Kernel maps might be changed when loading symbols so loading
@@ -523,7 +523,7 @@ struct map *thread__find_map_fb(struct thread *thread, u8 cpumode, u64 addr,
                                struct addr_location *al)
 {
        struct map *map = thread__find_map(thread, cpumode, addr, al);
-       struct machine *machine = thread->mg->machine;
+       struct machine *machine = thread->maps->machine;
        u8 addr_cpumode = machine__addr_cpumode(machine, cpumode, addr);
 
        if (map || addr_cpumode == cpumode)
diff --git a/tools/perf/util/fncache.c b/tools/perf/util/fncache.c
new file mode 100644 (file)
index 0000000..6225cbc
--- /dev/null
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Manage a cache of file names' existence */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <linux/list.h>
+#include "fncache.h"
+
+struct fncache {
+       struct hlist_node nd;
+       bool res;
+       char name[];
+};
+
+#define FNHSIZE 61
+
+static struct hlist_head fncache_hash[FNHSIZE];
+
+unsigned shash(const unsigned char *s)
+{
+       unsigned h = 0;
+       while (*s)
+               h = 65599 * h + *s++;
+       return h ^ (h >> 16);
+}
+
+static bool lookup_fncache(const char *name, bool *res)
+{
+       int h = shash((const unsigned char *)name) % FNHSIZE;
+       struct fncache *n;
+
+       hlist_for_each_entry(n, &fncache_hash[h], nd) {
+               if (!strcmp(n->name, name)) {
+                       *res = n->res;
+                       return true;
+               }
+       }
+       return false;
+}
+
+static void update_fncache(const char *name, bool res)
+{
+       struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1);
+       int h = shash((const unsigned char *)name) % FNHSIZE;
+
+       if (!n)
+               return;
+       strcpy(n->name, name);
+       n->res = res;
+       hlist_add_head(&n->nd, &fncache_hash[h]);
+}
+
+/* No LRU, only use when bounded in some other way. */
+bool file_available(const char *name)
+{
+       bool res;
+
+       if (lookup_fncache(name, &res))
+               return res;
+       res = access(name, R_OK) == 0;
+       update_fncache(name, res);
+       return res;
+}
diff --git a/tools/perf/util/fncache.h b/tools/perf/util/fncache.h
new file mode 100644 (file)
index 0000000..fe020be
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _FCACHE_H
+#define _FCACHE_H 1
+
+unsigned shash(const unsigned char *s);
+bool file_available(const char *name);
+
+#endif
index 0a8d72a..ca5a8f4 100644 (file)
@@ -692,7 +692,7 @@ __hists__add_entry(struct hists *hists,
                        .ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
                },
                .ms = {
-                       .mg     = al->mg,
+                       .maps   = al->maps,
                        .map    = al->map,
                        .sym    = al->sym,
                },
@@ -760,7 +760,7 @@ struct hist_entry *hists__add_entry_block(struct hists *hists,
                .block_info = block_info,
                .hists = hists,
                .ms = {
-                       .mg  = al->mg,
+                       .maps = al->maps,
                        .map = al->map,
                        .sym = al->sym,
                },
@@ -895,7 +895,7 @@ iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
        if (iter->curr >= iter->total)
                return 0;
 
-       al->mg  = bi[i].to.ms.mg;
+       al->maps = bi[i].to.ms.maps;
        al->map = bi[i].to.ms.map;
        al->sym = bi[i].to.ms.sym;
        al->addr = bi[i].to.addr;
@@ -1072,7 +1072,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
                .comm = thread__comm(al->thread),
                .ip = al->addr,
                .ms = {
-                       .mg  = al->mg,
+                       .maps = al->maps,
                        .map = al->map,
                        .sym = al->sym,
                },
index 409afc6..33cf892 100644 (file)
@@ -3296,7 +3296,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
        err = thread__set_comm(pt->unknown_thread, "unknown", 0);
        if (err)
                goto err_delete_thread;
-       if (thread__init_map_groups(pt->unknown_thread, pt->machine)) {
+       if (thread__init_maps(pt->unknown_thread, pt->machine)) {
                err = -ENOMEM;
                goto err_delete_thread;
        }
index e2a312c..416d174 100644 (file)
@@ -86,7 +86,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
        int err = -ENOMEM;
 
        memset(machine, 0, sizeof(*machine));
-       map_groups__init(&machine->kmaps, machine);
+       maps__init(&machine->kmaps, machine);
        RB_CLEAR_NODE(&machine->rb_node);
        dsos__init(&machine->dsos);
 
@@ -217,7 +217,7 @@ void machine__exit(struct machine *machine)
                return;
 
        machine__destroy_kernel_maps(machine);
-       map_groups__exit(&machine->kmaps);
+       maps__exit(&machine->kmaps);
        dsos__exit(&machine->dsos);
        machine__exit_vdso(machine);
        zfree(&machine->root_dir);
@@ -412,28 +412,28 @@ static void machine__update_thread_pid(struct machine *machine,
        if (!leader)
                goto out_err;
 
-       if (!leader->mg)
-               leader->mg = map_groups__new(machine);
+       if (!leader->maps)
+               leader->maps = maps__new(machine);
 
-       if (!leader->mg)
+       if (!leader->maps)
                goto out_err;
 
-       if (th->mg == leader->mg)
+       if (th->maps == leader->maps)
                return;
 
-       if (th->mg) {
+       if (th->maps) {
                /*
                 * Maps are created from MMAP events which provide the pid and
                 * tid.  Consequently there never should be any maps on a thread
                 * with an unknown pid.  Just print an error if there are.
                 */
-               if (!map_groups__empty(th->mg))
+               if (!maps__empty(th->maps))
                        pr_err("Discarding thread maps for %d:%d\n",
                               th->pid_, th->tid);
-               map_groups__put(th->mg);
+               maps__put(th->maps);
        }
 
-       th->mg = map_groups__get(leader->mg);
+       th->maps = maps__get(leader->maps);
 out_put:
        thread__put(leader);
        return;
@@ -536,14 +536,13 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
                rb_insert_color_cached(&th->rb_node, &threads->entries, leftmost);
 
                /*
-                * We have to initialize map_groups separately
-                * after rb tree is updated.
+                * We have to initialize maps separately after rb tree is updated.
                 *
                 * The reason is that we call machine__findnew_thread
-                * within thread__init_map_groups to find the thread
+                * within thread__init_maps to find the thread
                 * leader and that would screwed the rb tree.
                 */
-               if (thread__init_map_groups(th, machine)) {
+               if (thread__init_maps(th, machine)) {
                        rb_erase_cached(&th->rb_node, &threads->entries);
                        RB_CLEAR_NODE(&th->rb_node);
                        thread__put(th);
@@ -724,9 +723,8 @@ static int machine__process_ksymbol_register(struct machine *machine,
                                             struct perf_sample *sample __maybe_unused)
 {
        struct symbol *sym;
-       struct map *map;
+       struct map *map = maps__find(&machine->kmaps, event->ksymbol.addr);
 
-       map = map_groups__find(&machine->kmaps, event->ksymbol.addr);
        if (!map) {
                map = dso__new_map(event->ksymbol.name);
                if (!map)
@@ -734,7 +732,7 @@ static int machine__process_ksymbol_register(struct machine *machine,
 
                map->start = event->ksymbol.addr;
                map->end = map->start + event->ksymbol.len;
-               map_groups__insert(&machine->kmaps, map);
+               maps__insert(&machine->kmaps, map);
        }
 
        sym = symbol__new(map->map_ip(map, map->start),
@@ -752,9 +750,9 @@ static int machine__process_ksymbol_unregister(struct machine *machine,
 {
        struct map *map;
 
-       map = map_groups__find(&machine->kmaps, event->ksymbol.addr);
+       map = maps__find(&machine->kmaps, event->ksymbol.addr);
        if (map)
-               map_groups__remove(&machine->kmaps, map);
+               maps__remove(&machine->kmaps, map);
 
        return 0;
 }
@@ -790,9 +788,9 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 start
        if (map == NULL)
                goto out;
 
-       map_groups__insert(&machine->kmaps, map);
+       maps__insert(&machine->kmaps, map);
 
-       /* Put the map here because map_groups__insert alread got it */
+       /* Put the map here because maps__insert alread got it */
        map__put(map);
 out:
        /* put the dso here, corresponding to  machine__findnew_module_dso */
@@ -977,7 +975,7 @@ int machine__create_extra_kernel_map(struct machine *machine,
        kmap->kmaps = &machine->kmaps;
        strlcpy(kmap->name, xm->name, KMAP_NAME_LEN);
 
-       map_groups__insert(&machine->kmaps, map);
+       maps__insert(&machine->kmaps, map);
 
        pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n",
                  kmap->name, map->start, map->end);
@@ -1022,8 +1020,7 @@ static u64 find_entry_trampoline(struct dso *dso)
 int machine__map_x86_64_entry_trampolines(struct machine *machine,
                                          struct dso *kernel)
 {
-       struct map_groups *kmaps = &machine->kmaps;
-       struct maps *maps = &kmaps->maps;
+       struct maps *kmaps = &machine->kmaps;
        int nr_cpus_avail, cpu;
        bool found = false;
        struct map *map;
@@ -1033,14 +1030,14 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine,
         * In the vmlinux case, pgoff is a virtual address which must now be
         * mapped to a vmlinux offset.
         */
-       maps__for_each_entry(maps, map) {
+       maps__for_each_entry(kmaps, map) {
                struct kmap *kmap = __map__kmap(map);
                struct map *dest_map;
 
                if (!kmap || !is_entry_trampoline(kmap->name))
                        continue;
 
-               dest_map = map_groups__find(kmaps, map->pgoff);
+               dest_map = maps__find(kmaps, map->pgoff);
                if (dest_map != map)
                        map->pgoff = dest_map->map_ip(dest_map, map->pgoff);
                found = true;
@@ -1102,7 +1099,7 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
                return -1;
 
        kmap->kmaps = &machine->kmaps;
-       map_groups__insert(&machine->kmaps, map);
+       maps__insert(&machine->kmaps, map);
 
        return 0;
 }
@@ -1116,7 +1113,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
                return;
 
        kmap = map__kmap(map);
-       map_groups__remove(&machine->kmaps, map);
+       maps__remove(&machine->kmaps, map);
        if (kmap && kmap->ref_reloc_sym) {
                zfree((char **)&kmap->ref_reloc_sym->name);
                zfree(&kmap->ref_reloc_sym);
@@ -1211,7 +1208,7 @@ int machine__load_kallsyms(struct machine *machine, const char *filename)
                 * kernel, with modules between them, fixup the end of all
                 * sections.
                 */
-               map_groups__fixup_end(&machine->kmaps);
+               maps__fixup_end(&machine->kmaps);
        }
 
        return ret;
@@ -1262,11 +1259,10 @@ static bool is_kmod_dso(struct dso *dso)
               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
 }
 
-static int map_groups__set_module_path(struct map_groups *mg, const char *path,
-                                      struct kmod_path *m)
+static int maps__set_module_path(struct maps *maps, const char *path, struct kmod_path *m)
 {
        char *long_name;
-       struct map *map = map_groups__find_by_name(mg, m->name);
+       struct map *map = maps__find_by_name(maps, m->name);
 
        if (map == NULL)
                return 0;
@@ -1290,8 +1286,7 @@ static int map_groups__set_module_path(struct map_groups *mg, const char *path,
        return 0;
 }
 
-static int map_groups__set_modules_path_dir(struct map_groups *mg,
-                               const char *dir_name, int depth)
+static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, int depth)
 {
        struct dirent *dent;
        DIR *dir = opendir(dir_name);
@@ -1323,8 +1318,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
                                        continue;
                        }
 
-                       ret = map_groups__set_modules_path_dir(mg, path,
-                                                              depth + 1);
+                       ret = maps__set_modules_path_dir(maps, path, depth + 1);
                        if (ret < 0)
                                goto out;
                } else {
@@ -1335,7 +1329,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
                                goto out;
 
                        if (m.kmod)
-                               ret = map_groups__set_module_path(mg, path, &m);
+                               ret = maps__set_module_path(maps, path, &m);
 
                        zfree(&m.name);
 
@@ -1362,7 +1356,7 @@ static int machine__set_modules_path(struct machine *machine)
                 machine->root_dir, version);
        free(version);
 
-       return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
+       return maps__set_modules_path_dir(&machine->kmaps, modules_path, 0);
 }
 int __weak arch__fix_module_text_start(u64 *start __maybe_unused,
                                u64 *size __maybe_unused,
@@ -1435,11 +1429,11 @@ static void machine__update_kernel_mmap(struct machine *machine,
        struct map *map = machine__kernel_map(machine);
 
        map__get(map);
-       map_groups__remove(&machine->kmaps, map);
+       maps__remove(&machine->kmaps, map);
 
        machine__set_kernel_mmap(machine, start, end);
 
-       map_groups__insert(&machine->kmaps, map);
+       maps__insert(&machine->kmaps, map);
        map__put(map);
 }
 
@@ -1940,7 +1934,7 @@ static void ip__resolve_ams(struct thread *thread,
 
        ams->addr = ip;
        ams->al_addr = al.addr;
-       ams->ms.mg  = al.mg;
+       ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
        ams->phys_addr = 0;
@@ -1958,7 +1952,7 @@ static void ip__resolve_data(struct thread *thread,
 
        ams->addr = addr;
        ams->al_addr = al.addr;
-       ams->ms.mg  = al.mg;
+       ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
        ams->phys_addr = phys_addr;
@@ -2075,7 +2069,7 @@ static int add_callchain_ip(struct thread *thread,
                iter_cycles = iter->cycles;
        }
 
-       ms.mg  = al.mg;
+       ms.maps = al.maps;
        ms.map = al.map;
        ms.sym = al.sym;
        srcline = callchain_srcline(&ms, al.addr);
index 499be20..be0a930 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <sys/types.h>
 #include <linux/rbtree.h>
-#include "map_groups.h"
+#include "maps.h"
 #include "dsos.h"
 #include "rwsem.h"
 
@@ -51,7 +51,7 @@ struct machine {
        struct vdso_info  *vdso_info;
        struct perf_env   *env;
        struct dsos       dsos;
-       struct map_groups kmaps;
+       struct maps       kmaps;
        struct map        *vmlinux_map;
        u64               kernel_start;
        pid_t             *current_tid;
@@ -83,7 +83,7 @@ struct map *machine__kernel_map(struct machine *machine)
 static inline
 struct maps *machine__kernel_maps(struct machine *machine)
 {
-       return &machine->kmaps.maps;
+       return &machine->kmaps;
 }
 
 int machine__get_kernel_start(struct machine *machine);
@@ -212,7 +212,7 @@ static inline
 struct symbol *machine__find_kernel_symbol(struct machine *machine, u64 addr,
                                           struct map **mapp)
 {
-       return map_groups__find_symbol(&machine->kmaps, addr, mapp);
+       return maps__find_symbol(&machine->kmaps, addr, mapp);
 }
 
 static inline
@@ -220,7 +220,7 @@ struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
                                                   const char *name,
                                                   struct map **mapp)
 {
-       return map_groups__find_symbol_by_name(&machine->kmaps, name, mapp);
+       return maps__find_symbol_by_name(&machine->kmaps, name, mapp);
 }
 
 int arch__fix_module_text_start(u64 *start, u64 *size, const char *name);
index 744bfba..fdd5bdd 100644 (file)
@@ -433,51 +433,6 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
        return ret;
 }
 
-int map__fprintf_srccode(struct map *map, u64 addr,
-                        FILE *fp,
-                        struct srccode_state *state)
-{
-       char *srcfile;
-       int ret = 0;
-       unsigned line;
-       int len;
-       char *srccode;
-
-       if (!map || !map->dso)
-               return 0;
-       srcfile = get_srcline_split(map->dso,
-                                   map__rip_2objdump(map, addr),
-                                   &line);
-       if (!srcfile)
-               return 0;
-
-       /* Avoid redundant printing */
-       if (state &&
-           state->srcfile &&
-           !strcmp(state->srcfile, srcfile) &&
-           state->line == line) {
-               free(srcfile);
-               return 0;
-       }
-
-       srccode = find_sourceline(srcfile, line, &len);
-       if (!srccode)
-               goto out_free_line;
-
-       ret = fprintf(fp, "|%-8d %.*s", line, len, srccode);
-
-       if (state) {
-               state->srcfile = srcfile;
-               state->line = line;
-       }
-       return ret;
-
-out_free_line:
-       free(srcfile);
-       return ret;
-}
-
-
 void srccode_state_free(struct srccode_state *state)
 {
        zfree(&state->srcfile);
@@ -557,73 +512,71 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
        return ip + map->reloc;
 }
 
-static void maps__init(struct maps *maps)
+void maps__init(struct maps *maps, struct machine *machine)
 {
        maps->entries = RB_ROOT;
        init_rwsem(&maps->lock);
+       maps->machine = machine;
+       maps->last_search_by_name = NULL;
+       maps->nr_maps = 0;
+       maps->maps_by_name = NULL;
+       refcount_set(&maps->refcnt, 1);
 }
 
-void map_groups__init(struct map_groups *mg, struct machine *machine)
-{
-       maps__init(&mg->maps);
-       mg->machine = machine;
-       mg->last_search_by_name = NULL;
-       mg->nr_maps = 0;
-       mg->maps_by_name = NULL;
-       refcount_set(&mg->refcnt, 1);
-}
-
-static void __map_groups__free_maps_by_name(struct map_groups *mg)
+static void __maps__free_maps_by_name(struct maps *maps)
 {
        /*
         * Free everything to try to do it from the rbtree in the next search
         */
-       zfree(&mg->maps_by_name);
-       mg->nr_maps_allocated = 0;
+       zfree(&maps->maps_by_name);
+       maps->nr_maps_allocated = 0;
 }
 
-void map_groups__insert(struct map_groups *mg, struct map *map)
+void maps__insert(struct maps *maps, struct map *map)
 {
-       struct maps *maps = &mg->maps;
-
        down_write(&maps->lock);
        __maps__insert(maps, map);
-       ++mg->nr_maps;
+       ++maps->nr_maps;
 
        /*
         * If we already performed some search by name, then we need to add the just
         * inserted map and resort.
         */
-       if (mg->maps_by_name) {
-               if (mg->nr_maps > mg->nr_maps_allocated) {
-                       int nr_allocate = mg->nr_maps * 2;
-                       struct map **maps_by_name = realloc(mg->maps_by_name, nr_allocate * sizeof(map));
+       if (maps->maps_by_name) {
+               if (maps->nr_maps > maps->nr_maps_allocated) {
+                       int nr_allocate = maps->nr_maps * 2;
+                       struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map));
 
                        if (maps_by_name == NULL) {
-                               __map_groups__free_maps_by_name(mg);
+                               __maps__free_maps_by_name(maps);
                                return;
                        }
 
-                       mg->maps_by_name = maps_by_name;
-                       mg->nr_maps_allocated = nr_allocate;
+                       maps->maps_by_name = maps_by_name;
+                       maps->nr_maps_allocated = nr_allocate;
                }
-               mg->maps_by_name[mg->nr_maps - 1] = map;
-               __map_groups__sort_by_name(mg);
+               maps->maps_by_name[maps->nr_maps - 1] = map;
+               __maps__sort_by_name(maps);
        }
        up_write(&maps->lock);
 }
 
-void map_groups__remove(struct map_groups *mg, struct map *map)
+static void __maps__remove(struct maps *maps, struct map *map)
+{
+       rb_erase_init(&map->rb_node, &maps->entries);
+       map__put(map);
+}
+
+void maps__remove(struct maps *maps, struct map *map)
 {
-       struct maps *maps = &mg->maps;
        down_write(&maps->lock);
-       if (mg->last_search_by_name == map)
-               mg->last_search_by_name = NULL;
+       if (maps->last_search_by_name == map)
+               maps->last_search_by_name = NULL;
 
        __maps__remove(maps, map);
-       --mg->nr_maps;
-       if (mg->maps_by_name)
-               __map_groups__free_maps_by_name(mg);
+       --maps->nr_maps;
+       if (maps->maps_by_name)
+               __maps__free_maps_by_name(maps);
        up_write(&maps->lock);
 }
 
@@ -637,50 +590,44 @@ static void __maps__purge(struct maps *maps)
        }
 }
 
-static void maps__exit(struct maps *maps)
+void maps__exit(struct maps *maps)
 {
        down_write(&maps->lock);
        __maps__purge(maps);
        up_write(&maps->lock);
 }
 
-void map_groups__exit(struct map_groups *mg)
-{
-       maps__exit(&mg->maps);
-}
-
-bool map_groups__empty(struct map_groups *mg)
+bool maps__empty(struct maps *maps)
 {
-       return !maps__first(&mg->maps);
+       return !maps__first(maps);
 }
 
-struct map_groups *map_groups__new(struct machine *machine)
+struct maps *maps__new(struct machine *machine)
 {
-       struct map_groups *mg = zalloc(sizeof(*mg));
+       struct maps *maps = zalloc(sizeof(*maps));
 
-       if (mg != NULL)
-               map_groups__init(mg, machine);
+       if (maps != NULL)
+               maps__init(maps, machine);
 
-       return mg;
+       return maps;
 }
 
-void map_groups__delete(struct map_groups *mg)
+void maps__delete(struct maps *maps)
 {
-       map_groups__exit(mg);
-       unwind__finish_access(mg);
-       free(mg);
+       maps__exit(maps);
+       unwind__finish_access(maps);
+       free(maps);
 }
 
-void map_groups__put(struct map_groups *mg)
+void maps__put(struct maps *maps)
 {
-       if (mg && refcount_dec_and_test(&mg->refcnt))
-               map_groups__delete(mg);
+       if (maps && refcount_dec_and_test(&maps->refcnt))
+               maps__delete(maps);
 }
 
-struct symbol *map_groups__find_symbol(struct map_groups *mg,
-                                      u64 addr, struct map **mapp)
+struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
 {
-       struct map *map = map_groups__find(mg, addr);
+       struct map *map = maps__find(maps, addr);
 
        /* Ensure map is loaded before using map->map_ip */
        if (map != NULL && map__load(map) >= 0) {
@@ -699,8 +646,7 @@ static bool map__contains_symbol(struct map *map, struct symbol *sym)
        return ip >= map->start && ip < map->end;
 }
 
-struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
-                                        struct map **mapp)
+struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp)
 {
        struct symbol *sym;
        struct map *pos;
@@ -727,19 +673,12 @@ out:
        return sym;
 }
 
-struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
-                                              const char *name,
-                                              struct map **mapp)
-{
-       return maps__find_symbol_by_name(&mg->maps, name, mapp);
-}
-
-int map_groups__find_ams(struct map_groups *mg, struct addr_map_symbol *ams)
+int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
 {
        if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) {
-               if (mg == NULL)
+               if (maps == NULL)
                        return -1;
-               ams->ms.map = map_groups__find(mg, ams->addr);
+               ams->ms.map = maps__find(maps, ams->addr);
                if (ams->ms.map == NULL)
                        return -1;
        }
@@ -750,7 +689,7 @@ int map_groups__find_ams(struct map_groups *mg, struct addr_map_symbol *ams)
        return ams->ms.sym ? 0 : -1;
 }
 
-static size_t maps__fprintf(struct maps *maps, FILE *fp)
+size_t maps__fprintf(struct maps *maps, FILE *fp)
 {
        size_t printed = 0;
        struct map *pos;
@@ -771,19 +710,8 @@ static size_t maps__fprintf(struct maps *maps, FILE *fp)
        return printed;
 }
 
-size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
-{
-       return maps__fprintf(&mg->maps, fp);
-}
-
-static void __map_groups__insert(struct map_groups *mg, struct map *map)
-{
-       __maps__insert(&mg->maps, map);
-}
-
-int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, FILE *fp)
+int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
 {
-       struct maps *maps = &mg->maps;
        struct rb_root *root;
        struct rb_node *next, *first;
        int err = 0;
@@ -848,7 +776,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, FILE
                        }
 
                        before->end = map->start;
-                       __map_groups__insert(mg, before);
+                       __maps__insert(maps, before);
                        if (verbose >= 2 && !use_browser)
                                map__fprintf(before, fp);
                        map__put(before);
@@ -865,7 +793,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, FILE
                        after->start = map->end;
                        after->pgoff += map->end - pos->start;
                        assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end));
-                       __map_groups__insert(mg, after);
+                       __maps__insert(maps, after);
                        if (verbose >= 2 && !use_browser)
                                map__fprintf(after, fp);
                        map__put(after);
@@ -886,31 +814,30 @@ out:
 /*
  * XXX This should not really _copy_ te maps, but refcount them.
  */
-int map_groups__clone(struct thread *thread, struct map_groups *parent)
+int maps__clone(struct thread *thread, struct maps *parent)
 {
-       struct map_groups *mg = thread->mg;
+       struct maps *maps = thread->maps;
        int err = -ENOMEM;
        struct map *map;
-       struct maps *maps = &parent->maps;
 
-       down_read(&maps->lock);
+       down_read(&parent->lock);
 
-       maps__for_each_entry(maps, map) {
+       maps__for_each_entry(parent, map) {
                struct map *new = map__clone(map);
                if (new == NULL)
                        goto out_unlock;
 
-               err = unwind__prepare_access(mg, new, NULL);
+               err = unwind__prepare_access(maps, new, NULL);
                if (err)
                        goto out_unlock;
 
-               map_groups__insert(mg, new);
+               maps__insert(maps, new);
                map__put(new);
        }
 
        err = 0;
 out_unlock:
-       up_read(&maps->lock);
+       up_read(&parent->lock);
        return err;
 }
 
@@ -935,26 +862,6 @@ static void __maps__insert(struct maps *maps, struct map *map)
        map__get(map);
 }
 
-void maps__insert(struct maps *maps, struct map *map)
-{
-       down_write(&maps->lock);
-       __maps__insert(maps, map);
-       up_write(&maps->lock);
-}
-
-void __maps__remove(struct maps *maps, struct map *map)
-{
-       rb_erase_init(&map->rb_node, &maps->entries);
-       map__put(map);
-}
-
-void maps__remove(struct maps *maps, struct map *map)
-{
-       down_write(&maps->lock);
-       __maps__remove(maps, map);
-       up_write(&maps->lock);
-}
-
 struct map *maps__find(struct maps *maps, u64 ip)
 {
        struct rb_node *p;
@@ -1018,7 +925,7 @@ struct kmap *map__kmap(struct map *map)
        return kmap;
 }
 
-struct map_groups *map__kmaps(struct map *map)
+struct maps *map__kmaps(struct map *map)
 {
        struct kmap *kmap = map__kmap(map);
 
index 5e88998..067036e 100644 (file)
 #include <linux/types.h>
 
 struct dso;
-struct ip_callchain;
-struct ref_reloc_sym;
-struct map_groups;
+struct maps;
 struct machine;
-struct evsel;
 
 struct map {
        union {
@@ -45,7 +42,7 @@ struct kmap;
 
 struct kmap *__map__kmap(struct map *map);
 struct kmap *map__kmap(struct map *map);
-struct map_groups *map__kmaps(struct map *map);
+struct maps *map__kmaps(struct map *map);
 
 static inline u64 map__map_ip(struct map *map, u64 ip)
 {
@@ -138,19 +135,12 @@ char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
 int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
                         FILE *fp);
 
-struct srccode_state;
-
-int map__fprintf_srccode(struct map *map, u64 addr,
-                        FILE *fp, struct srccode_state *state);
-
 int map__load(struct map *map);
 struct symbol *map__find_symbol(struct map *map, u64 addr);
 struct symbol *map__find_symbol_by_name(struct map *map, const char *name);
 void map__fixup_start(struct map *map);
 void map__fixup_end(struct map *map);
 
-void map__reloc_vmlinux(struct map *map);
-
 int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name,
                                    u64 addr);
 
diff --git a/tools/perf/util/map_groups.h b/tools/perf/util/map_groups.h
deleted file mode 100644 (file)
index 63ed211..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __PERF_MAP_GROUPS_H
-#define __PERF_MAP_GROUPS_H
-
-#include <linux/refcount.h>
-#include <linux/rbtree.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <linux/types.h>
-#include "rwsem.h"
-
-struct ref_reloc_sym;
-struct machine;
-struct map;
-struct thread;
-
-struct maps {
-       struct rb_root      entries;
-       struct rw_semaphore lock;
-};
-
-void maps__insert(struct maps *maps, struct map *map);
-void maps__remove(struct maps *maps, struct map *map);
-void __maps__remove(struct maps *maps, struct map *map);
-struct map *maps__find(struct maps *maps, u64 addr);
-struct map *maps__first(struct maps *maps);
-struct map *map__next(struct map *map);
-
-#define maps__for_each_entry(maps, map) \
-       for (map = maps__first(maps); map; map = map__next(map))
-
-#define maps__for_each_entry_safe(maps, map, next) \
-       for (map = maps__first(maps), next = map__next(map); map; map = next, next = map__next(map))
-
-struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp);
-
-struct map_groups {
-       struct maps      maps;
-       struct machine   *machine;
-       struct map       *last_search_by_name;
-       struct map       **maps_by_name;
-       refcount_t       refcnt;
-       unsigned int     nr_maps;
-       unsigned int     nr_maps_allocated;
-#ifdef HAVE_LIBUNWIND_SUPPORT
-       void                            *addr_space;
-       struct unwind_libunwind_ops     *unwind_libunwind_ops;
-#endif
-};
-
-#define KMAP_NAME_LEN 256
-
-struct kmap {
-       struct ref_reloc_sym *ref_reloc_sym;
-       struct map_groups    *kmaps;
-       char                 name[KMAP_NAME_LEN];
-};
-
-struct map_groups *map_groups__new(struct machine *machine);
-void map_groups__delete(struct map_groups *mg);
-bool map_groups__empty(struct map_groups *mg);
-
-static inline struct map_groups *map_groups__get(struct map_groups *mg)
-{
-       if (mg)
-               refcount_inc(&mg->refcnt);
-       return mg;
-}
-
-void map_groups__put(struct map_groups *mg);
-void map_groups__init(struct map_groups *mg, struct machine *machine);
-void map_groups__exit(struct map_groups *mg);
-int map_groups__clone(struct thread *thread, struct map_groups *parent);
-size_t map_groups__fprintf(struct map_groups *mg, FILE *fp);
-
-void map_groups__insert(struct map_groups *mg, struct map *map);
-
-void map_groups__remove(struct map_groups *mg, struct map *map);
-
-static inline struct map *map_groups__find(struct map_groups *mg, u64 addr)
-{
-       return maps__find(&mg->maps, addr);
-}
-
-#define map_groups__for_each_entry(mg, map) \
-       for (map = maps__first(&mg->maps); map; map = map__next(map))
-
-#define map_groups__for_each_entry_safe(mg, map, next) \
-       for (map = maps__first(&mg->maps), next = map__next(map); map; map = next, next = map__next(map))
-
-struct symbol *map_groups__find_symbol(struct map_groups *mg, u64 addr, struct map **mapp);
-struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, const char *name, struct map **mapp);
-
-struct addr_map_symbol;
-
-int map_groups__find_ams(struct map_groups *mg, struct addr_map_symbol *ams);
-
-int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, FILE *fp);
-
-struct map *map_groups__find_by_name(struct map_groups *mg, const char *name);
-
-int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map);
-
-void __map_groups__sort_by_name(struct map_groups *mg);
-
-#endif // __PERF_MAP_GROUPS_H
index 2964d97..5b8ca93 100644 (file)
@@ -4,12 +4,12 @@
 
 #include <linux/types.h>
 
-struct map_groups;
+struct maps;
 struct map;
 struct symbol;
 
 struct map_symbol {
-       struct map_groups *mg;
+       struct maps   *maps;
        struct map    *map;
        struct symbol *sym;
 };
diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h
new file mode 100644 (file)
index 0000000..3dd000d
--- /dev/null
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PERF_MAPS_H
+#define __PERF_MAPS_H
+
+#include <linux/refcount.h>
+#include <linux/rbtree.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <linux/types.h>
+#include "rwsem.h"
+
+struct ref_reloc_sym;
+struct machine;
+struct map;
+struct maps;
+struct thread;
+
+struct map *maps__find(struct maps *maps, u64 addr);
+struct map *maps__first(struct maps *maps);
+struct map *map__next(struct map *map);
+
+#define maps__for_each_entry(maps, map) \
+       for (map = maps__first(maps); map; map = map__next(map))
+
+#define maps__for_each_entry_safe(maps, map, next) \
+       for (map = maps__first(maps), next = map__next(map); map; map = next, next = map__next(map))
+
+struct maps {
+       struct rb_root      entries;
+       struct rw_semaphore lock;
+       struct machine   *machine;
+       struct map       *last_search_by_name;
+       struct map       **maps_by_name;
+       refcount_t       refcnt;
+       unsigned int     nr_maps;
+       unsigned int     nr_maps_allocated;
+#ifdef HAVE_LIBUNWIND_SUPPORT
+       void                            *addr_space;
+       struct unwind_libunwind_ops     *unwind_libunwind_ops;
+#endif
+};
+
+#define KMAP_NAME_LEN 256
+
+struct kmap {
+       struct ref_reloc_sym *ref_reloc_sym;
+       struct maps          *kmaps;
+       char                 name[KMAP_NAME_LEN];
+};
+
+struct maps *maps__new(struct machine *machine);
+void maps__delete(struct maps *maps);
+bool maps__empty(struct maps *maps);
+
+static inline struct maps *maps__get(struct maps *maps)
+{
+       if (maps)
+               refcount_inc(&maps->refcnt);
+       return maps;
+}
+
+void maps__put(struct maps *maps);
+void maps__init(struct maps *maps, struct machine *machine);
+void maps__exit(struct maps *maps);
+int maps__clone(struct thread *thread, struct maps *parent);
+size_t maps__fprintf(struct maps *maps, FILE *fp);
+
+void maps__insert(struct maps *maps, struct map *map);
+
+void maps__remove(struct maps *maps, struct map *map);
+
+struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp);
+struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp);
+
+struct addr_map_symbol;
+
+int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams);
+
+int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp);
+
+struct map *maps__find_by_name(struct maps *maps, const char *name);
+
+int maps__merge_in(struct maps *kmaps, struct map *new_map);
+
+void __maps__sort_by_name(struct maps *maps);
+
+#endif // __PERF_MAPS_H
index e014c2c..a454991 100644 (file)
@@ -41,7 +41,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
 
 static inline const char *perf_reg_name(int id __maybe_unused)
 {
-       return NULL;
+       return "unknown";
 }
 
 static inline int perf_reg_value(u64 *valp __maybe_unused,
index e8d3489..8b99fd3 100644 (file)
@@ -24,6 +24,7 @@
 #include "pmu-events/pmu-events.h"
 #include "string2.h"
 #include "strbuf.h"
+#include "fncache.h"
 
 struct perf_pmu_format {
        char *name;
@@ -82,7 +83,6 @@ int perf_pmu__format_parse(char *dir, struct list_head *head)
  */
 static int pmu_format(const char *name, struct list_head *format)
 {
-       struct stat st;
        char path[PATH_MAX];
        const char *sysfs = sysfs__mountpoint();
 
@@ -92,8 +92,8 @@ static int pmu_format(const char *name, struct list_head *format)
        snprintf(path, PATH_MAX,
                 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
 
-       if (stat(path, &st) < 0)
-               return 0;       /* no error if format does not exist */
+       if (!file_available(path))
+               return 0;
 
        if (perf_pmu__format_parse(path, format))
                return -1;
@@ -475,7 +475,6 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
  */
 static int pmu_aliases(const char *name, struct list_head *head)
 {
-       struct stat st;
        char path[PATH_MAX];
        const char *sysfs = sysfs__mountpoint();
 
@@ -485,8 +484,8 @@ static int pmu_aliases(const char *name, struct list_head *head)
        snprintf(path, PATH_MAX,
                 "%s/bus/event_source/devices/%s/events", sysfs, name);
 
-       if (stat(path, &st) < 0)
-               return 0;        /* no error if 'events' does not exist */
+       if (!file_available(path))
+               return 0;
 
        if (pmu_aliases_parse(path, head))
                return -1;
@@ -525,7 +524,6 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
  */
 static int pmu_type(const char *name, __u32 *type)
 {
-       struct stat st;
        char path[PATH_MAX];
        FILE *file;
        int ret = 0;
@@ -537,7 +535,7 @@ static int pmu_type(const char *name, __u32 *type)
        snprintf(path, PATH_MAX,
                 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
 
-       if (stat(path, &st) < 0)
+       if (access(path, R_OK) < 0)
                return -1;
 
        file = fopen(path, "r");
@@ -628,14 +626,11 @@ static struct perf_cpu_map *pmu_cpumask(const char *name)
 static bool pmu_is_uncore(const char *name)
 {
        char path[PATH_MAX];
-       struct perf_cpu_map *cpus;
-       const char *sysfs = sysfs__mountpoint();
+       const char *sysfs;
 
+       sysfs = sysfs__mountpoint();
        snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
-       cpus = __pmu_cpumask(path);
-       perf_cpu_map__put(cpus);
-
-       return !!cpus;
+       return file_available(path);
 }
 
 /*
@@ -645,7 +640,6 @@ static bool pmu_is_uncore(const char *name)
  */
 static int is_arm_pmu_core(const char *name)
 {
-       struct stat st;
        char path[PATH_MAX];
        const char *sysfs = sysfs__mountpoint();
 
@@ -655,10 +649,7 @@ static int is_arm_pmu_core(const char *name)
        /* Look for cpu sysfs (specific to arm) */
        scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus",
                                sysfs, name);
-       if (stat(path, &st) == 0)
-               return 1;
-
-       return 0;
+       return file_available(path);
 }
 
 static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
@@ -1544,7 +1535,6 @@ bool pmu_have_event(const char *pname, const char *name)
 
 static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
 {
-       struct stat st;
        char path[PATH_MAX];
        const char *sysfs;
 
@@ -1554,10 +1544,8 @@ static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
 
        snprintf(path, PATH_MAX,
                 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
-
-       if (stat(path, &st) < 0)
+       if (!file_available(path))
                return NULL;
-
        return fopen(path, "r");
 }
 
index 52b2d16..eea132f 100644 (file)
@@ -28,7 +28,7 @@
 #include "dso.h"
 #include "color.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "symbol.h"
 #include <api/fs/fs.h>
 #include "trace-event.h"       /* For __maybe_unused */
@@ -321,7 +321,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso)
                char module_name[128];
 
                snprintf(module_name, sizeof(module_name), "[%s]", module);
-               map = map_groups__find_by_name(&host_machine->kmaps, module_name);
+               map = maps__find_by_name(&host_machine->kmaps, module_name);
                if (map) {
                        dso = map->dso;
                        goto found;
index 9af1838..e7279ea 100644 (file)
@@ -33,3 +33,4 @@ util/trace-event.c
 util/string.c
 util/symbol_fprintf.c
 util/units.c
+util/affinity.c
index 9581a90..80ca5d0 100644 (file)
@@ -1127,7 +1127,7 @@ static void python_export_sample_table(struct db_export *dbe,
 
        tuple_set_u64(t, 0, es->db_id);
        tuple_set_u64(t, 1, es->evsel->db_id);
-       tuple_set_u64(t, 2, es->al->mg->machine->db_id);
+       tuple_set_u64(t, 2, es->al->maps->machine->db_id);
        tuple_set_u64(t, 3, es->al->thread->db_id);
        tuple_set_u64(t, 4, es->comm_db_id);
        tuple_set_u64(t, 5, es->dso_db_id);
index d84ed8b..c29edaa 100644 (file)
@@ -16,6 +16,7 @@
 #include "srccode.h"
 #include "debug.h"
 #include <internal/lib.h> // page_size
+#include "fncache.h"
 
 #define MAXSRCCACHE (32*1024*1024)
 #define MAXSRCFILES     64
@@ -36,14 +37,6 @@ static LIST_HEAD(srcfile_list);
 static long map_total_sz;
 static int num_srcfiles;
 
-static unsigned shash(unsigned char *s)
-{
-       unsigned h = 0;
-       while (*s)
-               h = 65599 * h + *s++;
-       return h ^ (h >> 16);
-}
-
 static int countlines(char *map, int maplen)
 {
        int numl;
index 16776d5..6658fbf 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "dso.h"
 #include "map.h"
-#include "map_groups.h"
+#include "maps.h"
 #include "symbol.h"
 #include "symsrc.h"
 #include "demangle-java.h"
@@ -844,7 +844,7 @@ void __weak arch__sym_update(struct symbol *s __maybe_unused,
 
 static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
                                      GElf_Sym *sym, GElf_Shdr *shdr,
-                                     struct map_groups *kmaps, struct kmap *kmap,
+                                     struct maps *kmaps, struct kmap *kmap,
                                      struct dso **curr_dsop, struct map **curr_mapp,
                                      const char *section_name,
                                      bool adjust_kernel_syms, bool kmodule, bool *remap_kernel)
@@ -876,8 +876,8 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
                        /* Ensure maps are correctly ordered */
                        if (kmaps) {
                                map__get(map);
-                               map_groups__remove(kmaps, map);
-                               map_groups__insert(kmaps, map);
+                               maps__remove(kmaps, map);
+                               maps__insert(kmaps, map);
                                map__put(map);
                        }
                }
@@ -902,7 +902,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
 
        snprintf(dso_name, sizeof(dso_name), "%s%s", dso->short_name, section_name);
 
-       curr_map = map_groups__find_by_name(kmaps, dso_name);
+       curr_map = maps__find_by_name(kmaps, dso_name);
        if (curr_map == NULL) {
                u64 start = sym->st_value;
 
@@ -928,7 +928,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
                        curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
                }
                curr_dso->symtab_type = dso->symtab_type;
-               map_groups__insert(kmaps, curr_map);
+               maps__insert(kmaps, curr_map);
                /*
                 * Add it before we drop the referece to curr_map, i.e. while
                 * we still are sure to have a reference to this DSO via
@@ -950,7 +950,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
                  struct symsrc *runtime_ss, int kmodule)
 {
        struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
-       struct map_groups *kmaps = kmap ? map__kmaps(map) : NULL;
+       struct maps *kmaps = kmap ? map__kmaps(map) : NULL;
        struct map *curr_map = map;
        struct dso *curr_dso = dso;
        Elf_Data *symstrs, *secstrs;
@@ -1162,7 +1162,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
                         * We need to fixup this here too because we create new
                         * maps here, for things like vsyscall sections.
                         */
-                       map_groups__fixup_end(kmaps);
+                       maps__fixup_end(kmaps);
                }
        }
        err = nr;
index db9667a..3b379b1 100644 (file)
@@ -239,9 +239,8 @@ void symbols__fixup_end(struct rb_root_cached *symbols)
                curr->end = roundup(curr->start, 4096) + 4096;
 }
 
-void map_groups__fixup_end(struct map_groups *mg)
+void maps__fixup_end(struct maps *maps)
 {
-       struct maps *maps = &mg->maps;
        struct map *prev = NULL, *curr;
 
        down_write(&maps->lock);
@@ -698,7 +697,7 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename)
        return kallsyms__parse(filename, dso, map__process_kallsym_symbol);
 }
 
-static int map_groups__split_kallsyms_for_kcore(struct map_groups *kmaps, struct dso *dso)
+static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
 {
        struct map *curr_map;
        struct symbol *pos;
@@ -724,7 +723,7 @@ static int map_groups__split_kallsyms_for_kcore(struct map_groups *kmaps, struct
                if (module)
                        *module = '\0';
 
-               curr_map = map_groups__find(kmaps, pos->start);
+               curr_map = maps__find(kmaps, pos->start);
 
                if (!curr_map) {
                        symbol__delete(pos);
@@ -751,8 +750,8 @@ static int map_groups__split_kallsyms_for_kcore(struct map_groups *kmaps, struct
  * kernel range is broken in several maps, named [kernel].N, as we don't have
  * the original ELF section names vmlinux have.
  */
-static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso, u64 delta,
-                                     struct map *initial_map)
+static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
+                               struct map *initial_map)
 {
        struct machine *machine;
        struct map *curr_map = initial_map;
@@ -797,7 +796,7 @@ static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso,
                                        dso__set_loaded(curr_map->dso);
                                }
 
-                               curr_map = map_groups__find_by_name(kmaps, module);
+                               curr_map = maps__find_by_name(kmaps, module);
                                if (curr_map == NULL) {
                                        pr_debug("%s/proc/{kallsyms,modules} "
                                                 "inconsistency while looking "
@@ -864,7 +863,7 @@ static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso,
                        }
 
                        curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
-                       map_groups__insert(kmaps, curr_map);
+                       maps__insert(kmaps, curr_map);
                        ++kernel_range;
                } else if (delta) {
                        /* Kernel was relocated at boot time */
@@ -1049,8 +1048,7 @@ out_delete_from:
        return ret;
 }
 
-static int do_validate_kcore_modules(const char *filename,
-                                 struct map_groups *kmaps)
+static int do_validate_kcore_modules(const char *filename, struct maps *kmaps)
 {
        struct rb_root modules = RB_ROOT;
        struct map *old_map;
@@ -1060,7 +1058,7 @@ static int do_validate_kcore_modules(const char *filename,
        if (err)
                return err;
 
-       map_groups__for_each_entry(kmaps, old_map) {
+       maps__for_each_entry(kmaps, old_map) {
                struct module_info *mi;
 
                if (!__map__is_kmodule(old_map)) {
@@ -1107,7 +1105,7 @@ static bool filename_from_kallsyms_filename(char *filename,
 static int validate_kcore_modules(const char *kallsyms_filename,
                                  struct map *map)
 {
-       struct map_groups *kmaps = map__kmaps(map);
+       struct maps *kmaps = map__kmaps(map);
        char modules_filename[PATH_MAX];
 
        if (!kmaps)
@@ -1167,15 +1165,15 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
 }
 
 /*
- * Merges map into map_groups by splitting the new map
- * within the existing map regions.
+ * Merges map into maps by splitting the new map within the existing map
+ * regions.
  */
-int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map)
+int maps__merge_in(struct maps *kmaps, struct map *new_map)
 {
        struct map *old_map;
        LIST_HEAD(merged);
 
-       map_groups__for_each_entry(kmaps, old_map) {
+       maps__for_each_entry(kmaps, old_map) {
                /* no overload with this one */
                if (new_map->end < old_map->start ||
                    new_map->start >= old_map->end)
@@ -1232,12 +1230,12 @@ int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map)
        while (!list_empty(&merged)) {
                old_map = list_entry(merged.next, struct map, node);
                list_del_init(&old_map->node);
-               map_groups__insert(kmaps, old_map);
+               maps__insert(kmaps, old_map);
                map__put(old_map);
        }
 
        if (new_map) {
-               map_groups__insert(kmaps, new_map);
+               maps__insert(kmaps, new_map);
                map__put(new_map);
        }
        return 0;
@@ -1246,7 +1244,7 @@ int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map)
 static int dso__load_kcore(struct dso *dso, struct map *map,
                           const char *kallsyms_filename)
 {
-       struct map_groups *kmaps = map__kmaps(map);
+       struct maps *kmaps = map__kmaps(map);
        struct kcore_mapfn_data md;
        struct map *old_map, *new_map, *replacement_map = NULL, *next;
        struct machine *machine;
@@ -1295,14 +1293,14 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
        }
 
        /* Remove old maps */
-       map_groups__for_each_entry_safe(kmaps, old_map, next) {
+       maps__for_each_entry_safe(kmaps, old_map, next) {
                /*
                 * We need to preserve eBPF maps even if they are
                 * covered by kcore, because we need to access
                 * eBPF dso for source data.
                 */
                if (old_map != map && !__map__is_bpf_prog(old_map))
-                       map_groups__remove(kmaps, old_map);
+                       maps__remove(kmaps, old_map);
        }
        machine->trampolines_mapped = false;
 
@@ -1331,8 +1329,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
                        map->unmap_ip   = new_map->unmap_ip;
                        /* Ensure maps are correctly ordered */
                        map__get(map);
-                       map_groups__remove(kmaps, map);
-                       map_groups__insert(kmaps, map);
+                       maps__remove(kmaps, map);
+                       maps__insert(kmaps, map);
                        map__put(map);
                        map__put(new_map);
                } else {
@@ -1341,7 +1339,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
                         * and ensure that current maps (eBPF)
                         * stay intact.
                         */
-                       if (map_groups__merge_in(kmaps, new_map))
+                       if (maps__merge_in(kmaps, new_map))
                                goto out_err;
                }
        }
@@ -1433,9 +1431,9 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename,
                dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
 
        if (!no_kcore && !dso__load_kcore(dso, map, filename))
-               return map_groups__split_kallsyms_for_kcore(kmap->kmaps, dso);
+               return maps__split_kallsyms_for_kcore(kmap->kmaps, dso);
        else
-               return map_groups__split_kallsyms(kmap->kmaps, dso, delta, map);
+               return maps__split_kallsyms(kmap->kmaps, dso, delta, map);
 }
 
 int dso__load_kallsyms(struct dso *dso, const char *filename,
@@ -1772,68 +1770,67 @@ static int map__strcmp_name(const void *name, const void *b)
        return strcmp(name, map->dso->short_name);
 }
 
-void __map_groups__sort_by_name(struct map_groups *mg)
+void __maps__sort_by_name(struct maps *maps)
 {
-       qsort(mg->maps_by_name, mg->nr_maps, sizeof(struct map *), map__strcmp);
+       qsort(maps->maps_by_name, maps->nr_maps, sizeof(struct map *), map__strcmp);
 }
 
-static int map__groups__sort_by_name_from_rbtree(struct map_groups *mg)
+static int map__groups__sort_by_name_from_rbtree(struct maps *maps)
 {
        struct map *map;
-       struct map **maps_by_name = realloc(mg->maps_by_name, mg->nr_maps * sizeof(map));
+       struct map **maps_by_name = realloc(maps->maps_by_name, maps->nr_maps * sizeof(map));
        int i = 0;
 
        if (maps_by_name == NULL)
                return -1;
 
-       mg->maps_by_name = maps_by_name;
-       mg->nr_maps_allocated = mg->nr_maps;
+       maps->maps_by_name = maps_by_name;
+       maps->nr_maps_allocated = maps->nr_maps;
 
-       maps__for_each_entry(&mg->maps, map)
+       maps__for_each_entry(maps, map)
                maps_by_name[i++] = map;
 
-       __map_groups__sort_by_name(mg);
+       __maps__sort_by_name(maps);
        return 0;
 }
 
-static struct map *__map_groups__find_by_name(struct map_groups *mg, const char *name)
+static struct map *__maps__find_by_name(struct maps *maps, const char *name)
 {
        struct map **mapp;
 
-       if (mg->maps_by_name == NULL &&
-           map__groups__sort_by_name_from_rbtree(mg))
+       if (maps->maps_by_name == NULL &&
+           map__groups__sort_by_name_from_rbtree(maps))
                return NULL;
 
-       mapp = bsearch(name, mg->maps_by_name, mg->nr_maps, sizeof(*mapp), map__strcmp_name);
+       mapp = bsearch(name, maps->maps_by_name, maps->nr_maps, sizeof(*mapp), map__strcmp_name);
        if (mapp)
                return *mapp;
        return NULL;
 }
 
-struct map *map_groups__find_by_name(struct map_groups *mg, const char *name)
+struct map *maps__find_by_name(struct maps *maps, const char *name)
 {
-       struct maps *maps = &mg->maps;
        struct map *map;
 
        down_read(&maps->lock);
 
-       if (mg->last_search_by_name && strcmp(mg->last_search_by_name->dso->short_name, name) == 0) {
-               map = mg->last_search_by_name;
+       if (maps->last_search_by_name && strcmp(maps->last_search_by_name->dso->short_name, name) == 0) {
+               map = maps->last_search_by_name;
                goto out_unlock;
        }
        /*
-        * If we have mg->maps_by_name, then the name isn't in the rbtree,
-        * as mg->maps_by_name mirrors the rbtree when lookups by name are
+        * If we have maps->maps_by_name, then the name isn't in the rbtree,
+        * as maps->maps_by_name mirrors the rbtree when lookups by name are
         * made.
         */
-       map = __map_groups__find_by_name(mg, name);
-       if (map || mg->maps_by_name != NULL)
+       map = __maps__find_by_name(maps, name);
+       if (map || maps->maps_by_name != NULL)
                goto out_unlock;
 
        /* Fallback to traversing the rbtree... */
        maps__for_each_entry(maps, map)
                if (strcmp(map->dso->short_name, name) == 0) {
-                       mg->last_search_by_name = map;
+                       maps->last_search_by_name = map;
                        goto out_unlock;
                }
 
index 0b718cc..93fc43d 100644 (file)
@@ -21,7 +21,7 @@
 
 struct dso;
 struct map;
-struct map_groups;
+struct maps;
 struct option;
 
 /*
@@ -108,7 +108,7 @@ struct ref_reloc_sym {
 
 struct addr_location {
        struct thread *thread;
-       struct map_groups *mg;
+       struct maps   *maps;
        struct map    *map;
        struct symbol *sym;
        const char    *srcline;
@@ -186,7 +186,7 @@ void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym,
 void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym);
 void symbols__fixup_duplicate(struct rb_root_cached *symbols);
 void symbols__fixup_end(struct rb_root_cached *symbols);
-void map_groups__fixup_end(struct map_groups *mg);
+void maps__fixup_end(struct maps *maps);
 
 typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
 int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
index 48c3f8b..c423298 100644 (file)
@@ -493,7 +493,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
 
                /*
                 * send mmap only for thread group leader
-                * see thread__init_map_groups
+                * see thread__init_maps()
                 */
                if (pid == tgid &&
                    perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
index cd8a948..0885967 100644 (file)
@@ -134,8 +134,8 @@ static int thread_stack__init(struct thread_stack *ts, struct thread *thread,
        if (err)
                return err;
 
-       if (thread->mg && thread->mg->machine) {
-               struct machine *machine = thread->mg->machine;
+       if (thread->maps && thread->maps->machine) {
+               struct machine *machine = thread->maps->machine;
                const char *arch = perf_env__arch(machine->env);
 
                ts->kernel_start = machine__kernel_start(machine);
index 0a277a9..28b7193 100644 (file)
 
 #include <api/fs/fs.h>
 
-int thread__init_map_groups(struct thread *thread, struct machine *machine)
+int thread__init_maps(struct thread *thread, struct machine *machine)
 {
        pid_t pid = thread->pid_;
 
        if (pid == thread->tid || pid == -1) {
-               thread->mg = map_groups__new(machine);
+               thread->maps = maps__new(machine);
        } else {
                struct thread *leader = __machine__findnew_thread(machine, pid, pid);
                if (leader) {
-                       thread->mg = map_groups__get(leader->mg);
+                       thread->maps = maps__get(leader->maps);
                        thread__put(leader);
                }
        }
 
-       return thread->mg ? 0 : -1;
+       return thread->maps ? 0 : -1;
 }
 
 struct thread *thread__new(pid_t pid, pid_t tid)
@@ -86,9 +86,9 @@ void thread__delete(struct thread *thread)
 
        thread_stack__free(thread);
 
-       if (thread->mg) {
-               map_groups__put(thread->mg);
-               thread->mg = NULL;
+       if (thread->maps) {
+               maps__put(thread->maps);
+               thread->maps = NULL;
        }
        down_write(&thread->namespaces_lock);
        list_for_each_entry_safe(namespaces, tmp_namespaces,
@@ -251,7 +251,7 @@ static int ____thread__set_comm(struct thread *thread, const char *str,
                list_add(&new->list, &thread->comm_list);
 
                if (exec)
-                       unwind__flush_access(thread->mg);
+                       unwind__flush_access(thread->maps);
        }
 
        thread->comm_set = true;
@@ -324,19 +324,19 @@ int thread__comm_len(struct thread *thread)
 size_t thread__fprintf(struct thread *thread, FILE *fp)
 {
        return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
-              map_groups__fprintf(thread->mg, fp);
+              maps__fprintf(thread->maps, fp);
 }
 
 int thread__insert_map(struct thread *thread, struct map *map)
 {
        int ret;
 
-       ret = unwind__prepare_access(thread->mg, map, NULL);
+       ret = unwind__prepare_access(thread->maps, map, NULL);
        if (ret)
                return ret;
 
-       map_groups__fixup_overlappings(thread->mg, map, stderr);
-       map_groups__insert(thread->mg, map);
+       maps__fixup_overlappings(thread->maps, map, stderr);
+       maps__insert(thread->maps, map);
 
        return 0;
 }
@@ -345,13 +345,13 @@ static int __thread__prepare_access(struct thread *thread)
 {
        bool initialized = false;
        int err = 0;
-       struct maps *maps = &thread->mg->maps;
+       struct maps *maps = thread->maps;
        struct map *map;
 
        down_read(&maps->lock);
 
        maps__for_each_entry(maps, map) {
-               err = unwind__prepare_access(thread->mg, map, &initialized);
+               err = unwind__prepare_access(thread->maps, map, &initialized);
                if (err || initialized)
                        break;
        }
@@ -371,21 +371,19 @@ static int thread__prepare_access(struct thread *thread)
        return err;
 }
 
-static int thread__clone_map_groups(struct thread *thread,
-                                   struct thread *parent,
-                                   bool do_maps_clone)
+static int thread__clone_maps(struct thread *thread, struct thread *parent, bool do_maps_clone)
 {
        /* This is new thread, we share map groups for process. */
        if (thread->pid_ == parent->pid_)
                return thread__prepare_access(thread);
 
-       if (thread->mg == parent->mg) {
+       if (thread->maps == parent->maps) {
                pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
                         thread->pid_, thread->tid, parent->pid_, parent->tid);
                return 0;
        }
        /* But this one is new process, copy maps. */
-       return do_maps_clone ? map_groups__clone(thread, parent->mg) : 0;
+       return do_maps_clone ? maps__clone(thread, parent->maps) : 0;
 }
 
 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone)
@@ -401,7 +399,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bo
        }
 
        thread->ppid = parent->tid;
-       return thread__clone_map_groups(thread, parent, do_maps_clone);
+       return thread__clone_maps(thread, parent, do_maps_clone);
 }
 
 void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
index 51bdb9a..20b96b5 100644 (file)
@@ -25,7 +25,7 @@ struct thread {
                struct rb_node   rb_node;
                struct list_head node;
        };
-       struct map_groups       *mg;
+       struct maps             *maps;
        pid_t                   pid_; /* Not all tools update this */
        pid_t                   tid;
        pid_t                   ppid;
@@ -53,7 +53,7 @@ struct namespaces;
 struct comm;
 
 struct thread *thread__new(pid_t pid, pid_t tid);
-int thread__init_map_groups(struct thread *thread, struct machine *machine);
+int thread__init_maps(struct thread *thread, struct machine *machine);
 void thread__delete(struct thread *thread);
 
 struct thread *thread__get(struct thread *thread);
index d2a8df0..7a3dbc2 100644 (file)
@@ -81,7 +81,7 @@ static int entry(u64 ip, struct unwind_info *ui)
                return -1;
 
        e->ip     = ip;
-       e->ms.mg  = al.mg;
+       e->ms.maps = al.maps;
        e->ms.map = al.map;
        e->ms.sym = al.sym;
 
@@ -200,7 +200,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
        struct unwind_info *ui, ui_buf = {
                .sample         = data,
                .thread         = thread,
-               .machine        = thread->mg->machine,
+               .machine        = thread->maps->machine,
                .cb             = cb,
                .arg            = arg,
                .max_stack      = max_stack,
index 6d53347..b4649f5 100644 (file)
@@ -578,7 +578,7 @@ static int entry(u64 ip, struct thread *thread,
        e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
        e.ip     = ip;
        e.ms.map = al.map;
-       e.ms.mg  = al.mg;
+       e.ms.maps = al.maps;
 
        pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
                 al.sym ? al.sym->name : "''",
@@ -616,26 +616,26 @@ static unw_accessors_t accessors = {
        .get_proc_name          = get_proc_name,
 };
 
-static int _unwind__prepare_access(struct map_groups *mg)
+static int _unwind__prepare_access(struct maps *maps)
 {
-       mg->addr_space = unw_create_addr_space(&accessors, 0);
-       if (!mg->addr_space) {
+       maps->addr_space = unw_create_addr_space(&accessors, 0);
+       if (!maps->addr_space) {
                pr_err("unwind: Can't create unwind address space.\n");
                return -ENOMEM;
        }
 
-       unw_set_caching_policy(mg->addr_space, UNW_CACHE_GLOBAL);
+       unw_set_caching_policy(maps->addr_space, UNW_CACHE_GLOBAL);
        return 0;
 }
 
-static void _unwind__flush_access(struct map_groups *mg)
+static void _unwind__flush_access(struct maps *maps)
 {
-       unw_flush_cache(mg->addr_space, 0, 0);
+       unw_flush_cache(maps->addr_space, 0, 0);
 }
 
-static void _unwind__finish_access(struct map_groups *mg)
+static void _unwind__finish_access(struct maps *maps)
 {
-       unw_destroy_addr_space(mg->addr_space);
+       unw_destroy_addr_space(maps->addr_space);
 }
 
 static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
@@ -660,7 +660,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
         */
        if (max_stack - 1 > 0) {
                WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL");
-               addr_space = ui->thread->mg->addr_space;
+               addr_space = ui->thread->maps->addr_space;
 
                if (addr_space == NULL)
                        return -1;
@@ -709,7 +709,7 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
        struct unwind_info ui = {
                .sample       = data,
                .thread       = thread,
-               .machine      = thread->mg->machine,
+               .machine      = thread->maps->machine,
        };
 
        if (!data->user_regs.regs)
index a24fb57..e89a547 100644 (file)
@@ -12,14 +12,12 @@ struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops;
 struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops;
 struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops;
 
-static void unwind__register_ops(struct map_groups *mg,
-                         struct unwind_libunwind_ops *ops)
+static void unwind__register_ops(struct maps *maps, struct unwind_libunwind_ops *ops)
 {
-       mg->unwind_libunwind_ops = ops;
+       maps->unwind_libunwind_ops = ops;
 }
 
-int unwind__prepare_access(struct map_groups *mg, struct map *map,
-                          bool *initialized)
+int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized)
 {
        const char *arch;
        enum dso_type dso_type;
@@ -29,7 +27,7 @@ int unwind__prepare_access(struct map_groups *mg, struct map *map,
        if (!dwarf_callchain_users)
                return 0;
 
-       if (mg->addr_space) {
+       if (maps->addr_space) {
                pr_debug("unwind: thread map already set, dso=%s\n",
                         map->dso->name);
                if (initialized)
@@ -38,14 +36,14 @@ int unwind__prepare_access(struct map_groups *mg, struct map *map,
        }
 
        /* env->arch is NULL for live-mode (i.e. perf top) */
-       if (!mg->machine->env || !mg->machine->env->arch)
+       if (!maps->machine->env || !maps->machine->env->arch)
                goto out_register;
 
-       dso_type = dso__type(map->dso, mg->machine);
+       dso_type = dso__type(map->dso, maps->machine);
        if (dso_type == DSO__TYPE_UNKNOWN)
                return 0;
 
-       arch = perf_env__arch(mg->machine->env);
+       arch = perf_env__arch(maps->machine->env);
 
        if (!strcmp(arch, "x86")) {
                if (dso_type != DSO__TYPE_64BIT)
@@ -60,31 +58,31 @@ int unwind__prepare_access(struct map_groups *mg, struct map *map,
                return 0;
        }
 out_register:
-       unwind__register_ops(mg, ops);
+       unwind__register_ops(maps, ops);
 
-       err = mg->unwind_libunwind_ops->prepare_access(mg);
+       err = maps->unwind_libunwind_ops->prepare_access(maps);
        if (initialized)
                *initialized = err ? false : true;
        return err;
 }
 
-void unwind__flush_access(struct map_groups *mg)
+void unwind__flush_access(struct maps *maps)
 {
-       if (mg->unwind_libunwind_ops)
-               mg->unwind_libunwind_ops->flush_access(mg);
+       if (maps->unwind_libunwind_ops)
+               maps->unwind_libunwind_ops->flush_access(maps);
 }
 
-void unwind__finish_access(struct map_groups *mg)
+void unwind__finish_access(struct maps *maps)
 {
-       if (mg->unwind_libunwind_ops)
-               mg->unwind_libunwind_ops->finish_access(mg);
+       if (maps->unwind_libunwind_ops)
+               maps->unwind_libunwind_ops->finish_access(maps);
 }
 
 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                         struct thread *thread,
                         struct perf_sample *data, int max_stack)
 {
-       if (thread->mg->unwind_libunwind_ops)
-               return thread->mg->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack);
+       if (thread->maps->unwind_libunwind_ops)
+               return thread->maps->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack);
        return 0;
 }
index 50337c9..ab8ad46 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/types.h>
 #include "util/map_symbol.h"
 
-struct map_groups;
+struct maps;
 struct perf_sample;
 struct thread;
 
@@ -18,9 +18,9 @@ struct unwind_entry {
 typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
 
 struct unwind_libunwind_ops {
-       int (*prepare_access)(struct map_groups *mg);
-       void (*flush_access)(struct map_groups *mg);
-       void (*finish_access)(struct map_groups *mg);
+       int (*prepare_access)(struct maps *maps);
+       void (*flush_access)(struct maps *maps);
+       void (*finish_access)(struct maps *maps);
        int (*get_entries)(unwind_entry_cb_t cb, void *arg,
                           struct thread *thread,
                           struct perf_sample *data, int max_stack);
@@ -45,20 +45,19 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 #endif
 
 int LIBUNWIND__ARCH_REG_ID(int regnum);
-int unwind__prepare_access(struct map_groups *mg, struct map *map,
-                          bool *initialized);
-void unwind__flush_access(struct map_groups *mg);
-void unwind__finish_access(struct map_groups *mg);
+int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized);
+void unwind__flush_access(struct maps *maps);
+void unwind__finish_access(struct maps *maps);
 #else
-static inline int unwind__prepare_access(struct map_groups *mg __maybe_unused,
+static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
                                         struct map *map __maybe_unused,
                                         bool *initialized __maybe_unused)
 {
        return 0;
 }
 
-static inline void unwind__flush_access(struct map_groups *mg __maybe_unused) {}
-static inline void unwind__finish_access(struct map_groups *mg __maybe_unused) {}
+static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
+static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
 #endif
 #else
 static inline int
@@ -71,14 +70,14 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
        return 0;
 }
 
-static inline int unwind__prepare_access(struct map_groups *mg __maybe_unused,
+static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
                                         struct map *map __maybe_unused,
                                         bool *initialized __maybe_unused)
 {
        return 0;
 }
 
-static inline void unwind__flush_access(struct map_groups *mg __maybe_unused) {}
-static inline void unwind__finish_access(struct map_groups *mg __maybe_unused) {}
+static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
+static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
index 6e00793..3cc91ad 100644 (file)
@@ -144,7 +144,7 @@ static enum dso_type machine__thread_dso_type(struct machine *machine,
        enum dso_type dso_type = DSO__TYPE_UNKNOWN;
        struct map *map;
 
-       map_groups__for_each_entry(thread->mg, map) {
+       maps__for_each_entry(thread->maps, map) {
                struct dso *dso = map->dso;
                if (!dso || dso->long_name[0] != '/')
                        continue;
index 0fb95f2..b001c60 100644 (file)
@@ -13,6 +13,7 @@ TARGETS += efivarfs
 TARGETS += exec
 TARGETS += filesystems
 TARGETS += filesystems/binderfs
+TARGETS += filesystems/epoll
 TARGETS += firmware
 TARGETS += ftrace
 TARGETS += futex
@@ -88,10 +89,10 @@ override LDFLAGS =
 endif
 
 ifneq ($(O),)
-       BUILD := $(abs_objtree)
+       BUILD := $(O)
 else
        ifneq ($(KBUILD_OUTPUT),)
-               BUILD := $(abs_objtree)/kselftest
+               BUILD := $(KBUILD_OUTPUT)/kselftest
        else
                BUILD := $(shell pwd)
                DEFAULT_INSTALL_HDR_PATH := 1
@@ -104,7 +105,6 @@ include $(top_srcdir)/scripts/subarch.include
 ARCH           ?= $(SUBARCH)
 export KSFT_KHDR_INSTALL_DONE := 1
 export BUILD
-#$(info abd_objtree = $(abs_objtree) BUILD = $(BUILD))
 
 # build and run gpio when output directory is the src dir.
 # gpio has dependency on tools/gpio and builds tools/gpio
index 3845144..4a85151 100644 (file)
@@ -240,14 +240,14 @@ static int sockmap_init_sockets(int verbose)
        addr.sin_port = htons(S1_PORT);
        err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
        if (err < 0) {
-               perror("bind s1 failed()\n");
+               perror("bind s1 failed()");
                return errno;
        }
 
        addr.sin_port = htons(S2_PORT);
        err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
        if (err < 0) {
-               perror("bind s2 failed()\n");
+               perror("bind s2 failed()");
                return errno;
        }
 
@@ -255,14 +255,14 @@ static int sockmap_init_sockets(int verbose)
        addr.sin_port = htons(S1_PORT);
        err = listen(s1, 32);
        if (err < 0) {
-               perror("listen s1 failed()\n");
+               perror("listen s1 failed()");
                return errno;
        }
 
        addr.sin_port = htons(S2_PORT);
        err = listen(s2, 32);
        if (err < 0) {
-               perror("listen s1 failed()\n");
+               perror("listen s1 failed()");
                return errno;
        }
 
@@ -270,14 +270,14 @@ static int sockmap_init_sockets(int verbose)
        addr.sin_port = htons(S1_PORT);
        err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
        if (err < 0 && errno != EINPROGRESS) {
-               perror("connect c1 failed()\n");
+               perror("connect c1 failed()");
                return errno;
        }
 
        addr.sin_port = htons(S2_PORT);
        err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
        if (err < 0 && errno != EINPROGRESS) {
-               perror("connect c2 failed()\n");
+               perror("connect c2 failed()");
                return errno;
        } else if (err < 0) {
                err = 0;
@@ -286,13 +286,13 @@ static int sockmap_init_sockets(int verbose)
        /* Accept Connecrtions */
        p1 = accept(s1, NULL, NULL);
        if (p1 < 0) {
-               perror("accept s1 failed()\n");
+               perror("accept s1 failed()");
                return errno;
        }
 
        p2 = accept(s2, NULL, NULL);
        if (p2 < 0) {
-               perror("accept s1 failed()\n");
+               perror("accept s1 failed()");
                return errno;
        }
 
@@ -332,6 +332,10 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
        int i, fp;
 
        file = fopen(".sendpage_tst.tmp", "w+");
+       if (!file) {
+               perror("create file for sendpage");
+               return 1;
+       }
        for (i = 0; i < iov_length * cnt; i++, k++)
                fwrite(&k, sizeof(char), 1, file);
        fflush(file);
@@ -339,12 +343,17 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
        fclose(file);
 
        fp = open(".sendpage_tst.tmp", O_RDONLY);
+       if (fp < 0) {
+               perror("reopen file for sendpage");
+               return 1;
+       }
+
        clock_gettime(CLOCK_MONOTONIC, &s->start);
        for (i = 0; i < cnt; i++) {
                int sent = sendfile(fd, fp, NULL, iov_length);
 
                if (!drop && sent < 0) {
-                       perror("send loop error:");
+                       perror("send loop error");
                        close(fp);
                        return sent;
                } else if (drop && sent >= 0) {
@@ -463,7 +472,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
                        int sent = sendmsg(fd, &msg, flags);
 
                        if (!drop && sent < 0) {
-                               perror("send loop error:");
+                               perror("send loop error");
                                goto out_errno;
                        } else if (drop && sent >= 0) {
                                printf("send loop error expected: %i\n", sent);
@@ -499,7 +508,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
                total_bytes -= txmsg_pop_total;
                err = clock_gettime(CLOCK_MONOTONIC, &s->start);
                if (err < 0)
-                       perror("recv start time");
+                       perror("recv start time");
                while (s->bytes_recvd < total_bytes) {
                        if (txmsg_cork) {
                                timeout.tv_sec = 0;
@@ -543,7 +552,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
                        if (recv < 0) {
                                if (errno != EWOULDBLOCK) {
                                        clock_gettime(CLOCK_MONOTONIC, &s->end);
-                                       perror("recv failed()\n");
+                                       perror("recv failed()");
                                        goto out_errno;
                                }
                        }
@@ -557,7 +566,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
 
                                errno = msg_verify_data(&msg, recv, chunk_sz);
                                if (errno) {
-                                       perror("data verify msg failed\n");
+                                       perror("data verify msg failed");
                                        goto out_errno;
                                }
                                if (recvp) {
@@ -565,7 +574,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
                                                                recvp,
                                                                chunk_sz);
                                        if (errno) {
-                                               perror("data verify msg_peek failed\n");
+                                               perror("data verify msg_peek failed");
                                                goto out_errno;
                                        }
                                }
@@ -654,7 +663,7 @@ static int sendmsg_test(struct sockmap_options *opt)
                        err = 0;
                exit(err ? 1 : 0);
        } else if (rxpid == -1) {
-               perror("msg_loop_rx");
+               perror("msg_loop_rx");
                return errno;
        }
 
@@ -681,7 +690,7 @@ static int sendmsg_test(struct sockmap_options *opt)
                                s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
                exit(err ? 1 : 0);
        } else if (txpid == -1) {
-               perror("msg_loop_tx");
+               perror("msg_loop_tx");
                return errno;
        }
 
@@ -715,7 +724,7 @@ static int forever_ping_pong(int rate, struct sockmap_options *opt)
        /* Ping/Pong data from client to server */
        sc = send(c1, buf, sizeof(buf), 0);
        if (sc < 0) {
-               perror("send failed()\n");
+               perror("send failed()");
                return sc;
        }
 
@@ -748,7 +757,7 @@ static int forever_ping_pong(int rate, struct sockmap_options *opt)
                        rc = recv(i, buf, sizeof(buf), 0);
                        if (rc < 0) {
                                if (errno != EWOULDBLOCK) {
-                                       perror("recv failed()\n");
+                                       perror("recv failed()");
                                        return rc;
                                }
                        }
@@ -760,7 +769,7 @@ static int forever_ping_pong(int rate, struct sockmap_options *opt)
 
                        sc = send(i, buf, rc, 0);
                        if (sc < 0) {
-                               perror("send failed()\n");
+                               perror("send failed()");
                                return sc;
                        }
                }
index d60a343..842d915 100644 (file)
@@ -45,7 +45,7 @@ static int get_stats(int fd, __u16 count, __u32 raddr)
        printf("\nXDP RTT data:\n");
 
        if (bpf_map_lookup_elem(fd, &raddr, &pinginfo)) {
-               perror("bpf_map_lookup elem");
+               perror("bpf_map_lookup elem");
                return 1;
        }
 
diff --git a/tools/testing/selftests/filesystems/epoll/.gitignore b/tools/testing/selftests/filesystems/epoll/.gitignore
new file mode 100644 (file)
index 0000000..9ae8db4
--- /dev/null
@@ -0,0 +1 @@
+epoll_wakeup_test
diff --git a/tools/testing/selftests/filesystems/epoll/Makefile b/tools/testing/selftests/filesystems/epoll/Makefile
new file mode 100644 (file)
index 0000000..e62f3d4
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CFLAGS += -I../../../../../usr/include/
+LDFLAGS += -lpthread
+TEST_GEN_PROGS := epoll_wakeup_test
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c
new file mode 100644 (file)
index 0000000..37a04da
--- /dev/null
@@ -0,0 +1,3074 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <poll.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include "../../kselftest_harness.h"
+
+struct epoll_mtcontext
+{
+       int efd[3];
+       int sfd[4];
+       int count;
+
+       pthread_t main;
+       pthread_t waiter;
+};
+
+static void signal_handler(int signum)
+{
+}
+
+static void kill_timeout(struct epoll_mtcontext *ctx)
+{
+       usleep(1000000);
+       pthread_kill(ctx->main, SIGUSR1);
+       pthread_kill(ctx->waiter, SIGUSR1);
+}
+
+static void *waiter_entry1a(void *data)
+{
+       struct epoll_event e;
+       struct epoll_mtcontext *ctx = data;
+
+       if (epoll_wait(ctx->efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx->count, 1);
+
+       return NULL;
+}
+
+static void *waiter_entry1ap(void *data)
+{
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext *ctx = data;
+
+       pfd.fd = ctx->efd[0];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx->efd[0], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx->count, 1);
+       }
+
+       return NULL;
+}
+
+static void *waiter_entry1o(void *data)
+{
+       struct epoll_event e;
+       struct epoll_mtcontext *ctx = data;
+
+       if (epoll_wait(ctx->efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx->count, 1);
+
+       return NULL;
+}
+
+static void *waiter_entry1op(void *data)
+{
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext *ctx = data;
+
+       pfd.fd = ctx->efd[0];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx->efd[0], &e, 1, 0) > 0)
+                       __sync_fetch_and_or(&ctx->count, 1);
+       }
+
+       return NULL;
+}
+
+static void *waiter_entry2a(void *data)
+{
+       struct epoll_event events[2];
+       struct epoll_mtcontext *ctx = data;
+
+       if (epoll_wait(ctx->efd[0], events, 2, -1) > 0)
+               __sync_fetch_and_add(&ctx->count, 1);
+
+       return NULL;
+}
+
+static void *waiter_entry2ap(void *data)
+{
+       struct pollfd pfd;
+       struct epoll_event events[2];
+       struct epoll_mtcontext *ctx = data;
+
+       pfd.fd = ctx->efd[0];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx->efd[0], events, 2, 0) > 0)
+                       __sync_fetch_and_add(&ctx->count, 1);
+       }
+
+       return NULL;
+}
+
+static void *emitter_entry1(void *data)
+{
+       struct epoll_mtcontext *ctx = data;
+
+       usleep(100000);
+       write(ctx->sfd[1], "w", 1);
+
+       kill_timeout(ctx);
+
+       return NULL;
+}
+
+static void *emitter_entry2(void *data)
+{
+       struct epoll_mtcontext *ctx = data;
+
+       usleep(100000);
+       write(ctx->sfd[1], "w", 1);
+       write(ctx->sfd[3], "w", 1);
+
+       kill_timeout(ctx);
+
+       return NULL;
+}
+
+/*
+ *          t0
+ *           | (ew)
+ *          e0
+ *           | (lt)
+ *          s0
+ */
+TEST(epoll1)
+{
+       int efd;
+       int sfd[2];
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 1);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (ew)
+ *          e0
+ *           | (et)
+ *          s0
+ */
+TEST(epoll2)
+{
+       int efd;
+       int sfd[2];
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 0);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *           t0
+ *            | (ew)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        s0    s2
+ */
+TEST(epoll3)
+{
+       int efd;
+       int sfd[4];
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *           t0
+ *            | (ew)
+ *           e0
+ *     (et) /  \ (et)
+ *        s0    s2
+ */
+TEST(epoll4)
+{
+       int efd;
+       int sfd[4];
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 0);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *          t0
+ *           | (p)
+ *          e0
+ *           | (lt)
+ *          s0
+ */
+TEST(epoll5)
+{
+       int efd;
+       int sfd[2];
+       struct pollfd pfd;
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       ASSERT_EQ(poll(&pfd, 1, 0), 1);
+       ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 1);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       ASSERT_EQ(poll(&pfd, 1, 0), 1);
+       ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 1);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (p)
+ *          e0
+ *           | (et)
+ *          s0
+ */
+TEST(epoll6)
+{
+       int efd;
+       int sfd[2];
+       struct pollfd pfd;
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       ASSERT_EQ(poll(&pfd, 1, 0), 1);
+       ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 1);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       ASSERT_EQ(poll(&pfd, 1, 0), 0);
+       ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 0);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *           t0
+ *            | (p)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        s0    s2
+ */
+
+TEST(epoll7)
+{
+       int efd;
+       int sfd[4];
+       struct pollfd pfd;
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *           t0
+ *            | (p)
+ *           e0
+ *     (et) /  \ (et)
+ *        s0    s2
+ */
+TEST(epoll8)
+{
+       int efd;
+       int sfd[4];
+       struct pollfd pfd;
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd = epoll_create(1);
+       ASSERT_GE(efd, 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
+
+       pfd.fd = efd;
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 0);
+       EXPECT_EQ(epoll_wait(efd, events, 2, 0), 0);
+
+       close(efd);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll9)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *            | (et)
+ *           s0
+ */
+TEST(epoll10)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 1);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        s0    s2
+ */
+TEST(epoll11)
+{
+       pthread_t emitter;
+       struct epoll_event events[2];
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry2a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], events, 2, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *     (et) /  \ (et)
+ *        s0    s2
+ */
+TEST(epoll12)
+{
+       pthread_t emitter;
+       struct epoll_event events[2];
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], events, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll13)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *            | (et)
+ *           s0
+ */
+TEST(epoll14)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 1);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        s0    s2
+ */
+TEST(epoll15)
+{
+       pthread_t emitter;
+       struct epoll_event events[2];
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry2ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], events, 2, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *     (et) /  \ (et)
+ *        s0    s2
+ */
+TEST(epoll16)
+{
+       pthread_t emitter;
+       struct epoll_event events[2];
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], events, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *          t0
+ *           | (ew)
+ *          e0
+ *           | (lt)
+ *          e1
+ *           | (lt)
+ *          s0
+ */
+TEST(epoll17)
+{
+       int efd[2];
+       int sfd[2];
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (ew)
+ *          e0
+ *           | (lt)
+ *          e1
+ *           | (et)
+ *          s0
+ */
+TEST(epoll18)
+{
+       int efd[2];
+       int sfd[2];
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *           t0
+ *            | (ew)
+ *           e0
+ *            | (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll19)
+{
+       int efd[2];
+       int sfd[2];
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *           t0
+ *            | (ew)
+ *           e0
+ *            | (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll20)
+{
+       int efd[2];
+       int sfd[2];
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (p)
+ *          e0
+ *           | (lt)
+ *          e1
+ *           | (lt)
+ *          s0
+ */
+TEST(epoll21)
+{
+       int efd[2];
+       int sfd[2];
+       struct pollfd pfd;
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (p)
+ *          e0
+ *           | (lt)
+ *          e1
+ *           | (et)
+ *          s0
+ */
+TEST(epoll22)
+{
+       int efd[2];
+       int sfd[2];
+       struct pollfd pfd;
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (p)
+ *          e0
+ *           | (et)
+ *          e1
+ *           | (lt)
+ *          s0
+ */
+TEST(epoll23)
+{
+       int efd[2];
+       int sfd[2];
+       struct pollfd pfd;
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 0);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *          t0
+ *           | (p)
+ *          e0
+ *           | (et)
+ *          e1
+ *           | (et)
+ *          s0
+ */
+TEST(epoll24)
+{
+       int efd[2];
+       int sfd[2];
+       struct pollfd pfd;
+       struct epoll_event e;
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 0);
+       EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(sfd[0]);
+       close(sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *            | (lt)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll25)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *            | (lt)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll26)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *            | (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll27)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 1);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *            | (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll28)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 1);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *            | (lt)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll29)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *            | (lt)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll30)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *            | (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll31)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 1);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *            | (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll32)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 1);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (ew)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll33)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (ew)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll34)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx.count, 2);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (ew)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll35)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (ew)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll36)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx.count, 2);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (ew)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll37)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       pfd.fd = ctx.efd[1];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx.count, 1);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (ew)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll38)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       pfd.fd = ctx.efd[1];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
+                       __sync_fetch_and_or(&ctx.count, 2);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (ew)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll39)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       pfd.fd = ctx.efd[1];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx.count, 1);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (ew)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll40)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       pfd.fd = ctx.efd[1];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
+                       __sync_fetch_and_or(&ctx.count, 2);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (p)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll41)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (p)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll42)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx.count, 2);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (p)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll43)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *    (ew) |    | (p)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll44)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx.count, 2);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (p)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll45)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       pfd.fd = ctx.efd[1];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx.count, 1);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (p)
+ *         |   e0
+ *          \  / (lt)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll46)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx.count, 2);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (p)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (lt)
+ *           s0
+ */
+TEST(epoll47)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       pfd.fd = ctx.efd[1];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx.count, 1);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *        t0   t1
+ *     (p) |    | (p)
+ *         |   e0
+ *          \  / (et)
+ *           e1
+ *            | (et)
+ *           s0
+ */
+TEST(epoll48)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
+               __sync_fetch_and_or(&ctx.count, 2);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+}
+
+/*
+ *           t0
+ *            | (ew)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll49)
+{
+       int efd[3];
+       int sfd[4];
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       efd[2] = epoll_create(1);
+       ASSERT_GE(efd[2], 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(efd[2]);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *           t0
+ *            | (ew)
+ *           e0
+ *     (et) /  \ (et)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll50)
+{
+       int efd[3];
+       int sfd[4];
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       efd[2] = epoll_create(1);
+       ASSERT_GE(efd[2], 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 0);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(efd[2]);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *           t0
+ *            | (p)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll51)
+{
+       int efd[3];
+       int sfd[4];
+       struct pollfd pfd;
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       efd[2] = epoll_create(1);
+       ASSERT_GE(efd[2], 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(efd[2]);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *           t0
+ *            | (p)
+ *           e0
+ *     (et) /  \ (et)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll52)
+{
+       int efd[3];
+       int sfd[4];
+       struct pollfd pfd;
+       struct epoll_event events[2];
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
+
+       efd[0] = epoll_create(1);
+       ASSERT_GE(efd[0], 0);
+
+       efd[1] = epoll_create(1);
+       ASSERT_GE(efd[1], 0);
+
+       efd[2] = epoll_create(1);
+       ASSERT_GE(efd[2], 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
+
+       events[0].events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
+
+       events[0].events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
+
+       ASSERT_EQ(write(sfd[1], "w", 1), 1);
+       ASSERT_EQ(write(sfd[3], "w", 1), 1);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 1);
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
+
+       pfd.fd = efd[0];
+       pfd.events = POLLIN;
+       EXPECT_EQ(poll(&pfd, 1, 0), 0);
+       EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 0);
+
+       close(efd[0]);
+       close(efd[1]);
+       close(efd[2]);
+       close(sfd[0]);
+       close(sfd[1]);
+       close(sfd[2]);
+       close(sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll53)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       ctx.efd[2] = epoll_create(1);
+       ASSERT_GE(ctx.efd[2], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.efd[2]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (ew)
+ *           e0
+ *     (et) /  \ (et)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll54)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       ctx.efd[2] = epoll_create(1);
+       ASSERT_GE(ctx.efd[2], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.efd[2]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll55)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       ctx.efd[2] = epoll_create(1);
+       ASSERT_GE(ctx.efd[2], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.efd[2]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *     (ew) \  / (p)
+ *           e0
+ *     (et) /  \ (et)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll56)
+{
+       pthread_t emitter;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       ctx.efd[2] = epoll_create(1);
+       ASSERT_GE(ctx.efd[2], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
+               __sync_fetch_and_add(&ctx.count, 1);
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.efd[2]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *      (p) \  / (p)
+ *           e0
+ *     (lt) /  \ (lt)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll57)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       ctx.efd[2] = epoll_create(1);
+       ASSERT_GE(ctx.efd[2], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       pfd.fd = ctx.efd[0];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[0], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx.count, 1);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.efd[2]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+/*
+ *        t0    t1
+ *      (p) \  / (p)
+ *           e0
+ *     (et) /  \ (et)
+ *        e1    e2
+ *    (lt) |     | (lt)
+ *        s0    s2
+ */
+TEST(epoll58)
+{
+       pthread_t emitter;
+       struct pollfd pfd;
+       struct epoll_event e;
+       struct epoll_mtcontext ctx = { 0 };
+
+       signal(SIGUSR1, signal_handler);
+
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
+
+       ctx.efd[0] = epoll_create(1);
+       ASSERT_GE(ctx.efd[0], 0);
+
+       ctx.efd[1] = epoll_create(1);
+       ASSERT_GE(ctx.efd[1], 0);
+
+       ctx.efd[2] = epoll_create(1);
+       ASSERT_GE(ctx.efd[2], 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
+
+       e.events = EPOLLIN;
+       ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
+
+       e.events = EPOLLIN | EPOLLET;
+       ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
+
+       ctx.main = pthread_self();
+       ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
+       ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
+
+       pfd.fd = ctx.efd[0];
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, -1) > 0) {
+               if (epoll_wait(ctx.efd[0], &e, 1, 0) > 0)
+                       __sync_fetch_and_add(&ctx.count, 1);
+       }
+
+       ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
+       EXPECT_EQ(ctx.count, 2);
+
+       if (pthread_tryjoin_np(emitter, NULL) < 0) {
+               pthread_kill(emitter, SIGUSR1);
+               pthread_join(emitter, NULL);
+       }
+
+       close(ctx.efd[0]);
+       close(ctx.efd[1]);
+       close(ctx.efd[2]);
+       close(ctx.sfd[0]);
+       close(ctx.sfd[1]);
+       close(ctx.sfd[2]);
+       close(ctx.sfd[3]);
+}
+
+TEST_HARNESS_MAIN
index c67d32e..334a7ee 100644 (file)
@@ -290,6 +290,40 @@ static void mfd_assert_read_shared(int fd)
        munmap(p, mfd_def_size);
 }
 
+static void mfd_assert_fork_private_write(int fd)
+{
+       int *p;
+       pid_t pid;
+
+       p = mmap(NULL,
+                mfd_def_size,
+                PROT_READ | PROT_WRITE,
+                MAP_PRIVATE,
+                fd,
+                0);
+       if (p == MAP_FAILED) {
+               printf("mmap() failed: %m\n");
+               abort();
+       }
+
+       p[0] = 22;
+
+       pid = fork();
+       if (pid == 0) {
+               p[0] = 33;
+               exit(0);
+       } else {
+               waitpid(pid, NULL, 0);
+
+               if (p[0] != 22) {
+                       printf("MAP_PRIVATE copy-on-write failed: %m\n");
+                       abort();
+               }
+       }
+
+       munmap(p, mfd_def_size);
+}
+
 static void mfd_assert_write(int fd)
 {
        ssize_t l;
@@ -760,6 +794,8 @@ static void test_seal_future_write(void)
        mfd_assert_read_shared(fd2);
        mfd_fail_write(fd2);
 
+       mfd_assert_fork_private_write(fd);
+
        munmap(p, mfd_def_size);
        close(fd2);
        close(fd);
index d93589b..64f6526 100644 (file)
@@ -3,16 +3,42 @@
 
 CHECK_TC="yes"
 
+# Can be overridden by the configuration file. See lib.sh
+TC_HIT_TIMEOUT=${TC_HIT_TIMEOUT:=1000} # ms
+
+__tc_check_packets()
+{
+       local id=$1
+       local handle=$2
+       local count=$3
+       local operator=$4
+
+       start_time="$(date -u +%s%3N)"
+       while true
+       do
+               cmd_jq "tc -j -s filter show $id" \
+                      ".[] | select(.options.handle == $handle) | \
+                           select(.options.actions[0].stats.packets $operator $count)" \
+                   &> /dev/null
+               ret=$?
+               if [[ $ret -eq 0 ]]; then
+                       return $ret
+               fi
+               current_time="$(date -u +%s%3N)"
+               diff=$(expr $current_time - $start_time)
+               if [ "$diff" -gt "$TC_HIT_TIMEOUT" ]; then
+                       return 1
+               fi
+       done
+}
+
 tc_check_packets()
 {
        local id=$1
        local handle=$2
        local count=$3
 
-       cmd_jq "tc -j -s filter show $id" \
-              ".[] | select(.options.handle == $handle) | \
-                     select(.options.actions[0].stats.packets == $count)" \
-              &> /dev/null
+       __tc_check_packets "$id" "$handle" "$count" "=="
 }
 
 tc_check_packets_hitting()
@@ -20,8 +46,5 @@ tc_check_packets_hitting()
        local id=$1
        local handle=$2
 
-       cmd_jq "tc -j -s filter show $id" \
-              ".[] | select(.options.handle == $handle) | \
-                     select(.options.actions[0].stats.packets > 0)" \
-              &> /dev/null
+       __tc_check_packets "$id" "$handle" 0 ">"
 }
index ab367e7..d697815 100755 (executable)
@@ -1249,8 +1249,7 @@ test_list_flush_ipv4_exception() {
        done
        run_cmd ${ns_a} ping -q -M want -i 0.1 -c 2 -s 1800 "${dst2}"
 
-       # Each exception is printed as two lines
-       if [ "$(${ns_a} ip route list cache | wc -l)" -ne 202 ]; then
+       if [ "$(${ns_a} ip -oneline route list cache | wc -l)" -ne 101 ]; then
                err "  can't list cached exceptions"
                fail=1
        fi
@@ -1300,7 +1299,7 @@ test_list_flush_ipv6_exception() {
                run_cmd ${ns_a} ping -q -M want -i 0.1 -w 1 -s 1800 "${dst_prefix1}${i}"
        done
        run_cmd ${ns_a} ping -q -M want -i 0.1 -w 1 -s 1800 "${dst2}"
-       if [ "$(${ns_a} ip -6 route list cache | wc -l)" -ne 101 ]; then
+       if [ "$(${ns_a} ip -oneline -6 route list cache | wc -l)" -ne 101 ]; then
                err "  can't list cached exceptions"
                fail=1
        fi
index 1c8f194..46abcae 100644 (file)
@@ -268,6 +268,38 @@ TEST_F(tls, sendmsg_single)
        EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
 }
 
+#define MAX_FRAGS      64
+#define SEND_LEN       13
+TEST_F(tls, sendmsg_fragmented)
+{
+       char const *test_str = "test_sendmsg";
+       char buf[SEND_LEN * MAX_FRAGS];
+       struct iovec vec[MAX_FRAGS];
+       struct msghdr msg;
+       int i, frags;
+
+       for (frags = 1; frags <= MAX_FRAGS; frags++) {
+               for (i = 0; i < frags; i++) {
+                       vec[i].iov_base = (char *)test_str;
+                       vec[i].iov_len = SEND_LEN;
+               }
+
+               memset(&msg, 0, sizeof(struct msghdr));
+               msg.msg_iov = vec;
+               msg.msg_iovlen = frags;
+
+               EXPECT_EQ(sendmsg(self->fd, &msg, 0), SEND_LEN * frags);
+               EXPECT_EQ(recv(self->cfd, buf, SEND_LEN * frags, MSG_WAITALL),
+                         SEND_LEN * frags);
+
+               for (i = 0; i < frags; i++)
+                       EXPECT_EQ(memcmp(buf + SEND_LEN * i,
+                                        test_str, SEND_LEN), 0);
+       }
+}
+#undef MAX_FRAGS
+#undef SEND_LEN
+
 TEST_F(tls, sendmsg_large)
 {
        void *mem = malloc(16384);
@@ -694,6 +726,34 @@ TEST_F(tls, recv_lowat)
        EXPECT_EQ(memcmp(send_mem, recv_mem + 10, 5), 0);
 }
 
+TEST_F(tls, recv_rcvbuf)
+{
+       char send_mem[4096];
+       char recv_mem[4096];
+       int rcv_buf = 1024;
+
+       memset(send_mem, 0x1c, sizeof(send_mem));
+
+       EXPECT_EQ(setsockopt(self->cfd, SOL_SOCKET, SO_RCVBUF,
+                            &rcv_buf, sizeof(rcv_buf)), 0);
+
+       EXPECT_EQ(send(self->fd, send_mem, 512, 0), 512);
+       memset(recv_mem, 0, sizeof(recv_mem));
+       EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), 0), 512);
+       EXPECT_EQ(memcmp(send_mem, recv_mem, 512), 0);
+
+       if (self->notls)
+               return;
+
+       EXPECT_EQ(send(self->fd, send_mem, 4096, 0), 4096);
+       memset(recv_mem, 0, sizeof(recv_mem));
+       EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), 0), -1);
+       EXPECT_EQ(errno, EMSGSIZE);
+
+       EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), 0), -1);
+       EXPECT_EQ(errno, EMSGSIZE);
+}
+
 TEST_F(tls, bidir)
 {
        char const *test_str = "test_read";
index 1c0d76c..93b90a9 100644 (file)
@@ -1,2 +1,3 @@
 CONFIG_SYSVIPC=y
 CONFIG_USERFAULTFD=y
+CONFIG_TEST_VMALLOC=m
index 50ce6c3..1063328 100644 (file)
@@ -43,7 +43,19 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
                err(1, "sigaction");
 }
 
-static volatile sig_atomic_t sig_traps;
+static void clearhandler(int sig)
+{
+       struct sigaction sa;
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = SIG_DFL;
+       sigemptyset(&sa.sa_mask);
+       if (sigaction(sig, &sa, 0))
+               err(1, "sigaction");
+}
+
+static volatile sig_atomic_t sig_traps, sig_eflags;
+sigjmp_buf jmpbuf;
+static unsigned char altstack_data[SIGSTKSZ];
 
 #ifdef __x86_64__
 # define REG_IP REG_RIP
@@ -90,6 +102,25 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
        }
 }
 
+static char const * const signames[] = {
+       [SIGSEGV] = "SIGSEGV",
+       [SIGBUS] = "SIBGUS",
+       [SIGTRAP] = "SIGTRAP",
+       [SIGILL] = "SIGILL",
+};
+
+static void print_and_longjmp(int sig, siginfo_t *si, void *ctx_void)
+{
+       ucontext_t *ctx = ctx_void;
+
+       printf("\tGot %s with RIP=%lx, TF=%ld\n", signames[sig],
+              (unsigned long)ctx->uc_mcontext.gregs[REG_IP],
+              (unsigned long)ctx->uc_mcontext.gregs[REG_EFL] & X86_EFLAGS_TF);
+
+       sig_eflags = (unsigned long)ctx->uc_mcontext.gregs[REG_EFL];
+       siglongjmp(jmpbuf, 1);
+}
+
 static void check_result(void)
 {
        unsigned long new_eflags = get_eflags();
@@ -109,6 +140,22 @@ static void check_result(void)
        sig_traps = 0;
 }
 
+static void fast_syscall_no_tf(void)
+{
+       sig_traps = 0;
+       printf("[RUN]\tFast syscall with TF cleared\n");
+       fflush(stdout);  /* Force a syscall */
+       if (get_eflags() & X86_EFLAGS_TF) {
+               printf("[FAIL]\tTF is now set\n");
+               exit(1);
+       }
+       if (sig_traps) {
+               printf("[FAIL]\tGot SIGTRAP\n");
+               exit(1);
+       }
+       printf("[OK]\tNothing unexpected happened\n");
+}
+
 int main()
 {
 #ifdef CAN_BUILD_32
@@ -163,17 +210,46 @@ int main()
        check_result();
 
        /* Now make sure that another fast syscall doesn't set TF again. */
-       printf("[RUN]\tFast syscall with TF cleared\n");
-       fflush(stdout);  /* Force a syscall */
-       if (get_eflags() & X86_EFLAGS_TF) {
-               printf("[FAIL]\tTF is now set\n");
-               exit(1);
+       fast_syscall_no_tf();
+
+       /*
+        * And do a forced SYSENTER to make sure that this works even if
+        * fast syscalls don't use SYSENTER.
+        *
+        * Invoking SYSENTER directly breaks all the rules.  Just handle
+        * the SIGSEGV.
+        */
+       if (sigsetjmp(jmpbuf, 1) == 0) {
+               unsigned long nr = SYS_getpid;
+               printf("[RUN]\tSet TF and check SYSENTER\n");
+               stack_t stack = {
+                       .ss_sp = altstack_data,
+                       .ss_size = SIGSTKSZ,
+               };
+               if (sigaltstack(&stack, NULL) != 0)
+                       err(1, "sigaltstack");
+               sethandler(SIGSEGV, print_and_longjmp,
+                          SA_RESETHAND | SA_ONSTACK);
+               sethandler(SIGILL, print_and_longjmp, SA_RESETHAND);
+               set_eflags(get_eflags() | X86_EFLAGS_TF);
+               /* Clear EBP first to make sure we segfault cleanly. */
+               asm volatile ("xorl %%ebp, %%ebp; SYSENTER" : "+a" (nr) :: "flags", "rcx"
+#ifdef __x86_64__
+                               , "r11"
+#endif
+                       );
+
+               /* We're unreachable here.  SYSENTER forgets RIP. */
        }
-       if (sig_traps) {
-               printf("[FAIL]\tGot SIGTRAP\n");
+       clearhandler(SIGSEGV);
+       clearhandler(SIGILL);
+       if (!(sig_eflags & X86_EFLAGS_TF)) {
+               printf("[FAIL]\tTF was cleared\n");
                exit(1);
        }
-       printf("[OK]\tNothing unexpected happened\n");
+
+       /* Now make sure that another fast syscall doesn't set TF again. */
+       fast_syscall_no_tf();
 
        return 0;
 }
index 57b20f7..4a753a4 100644 (file)
@@ -16,9 +16,6 @@ override c_flags = $(UAPI_CFLAGS) -Wp,-MD,$(depfile) -I$(objtree)/usr/include
 # Please consider to fix the header first.
 #
 # Sorted alphabetically.
-header-test- += asm/ipcbuf.h
-header-test- += asm/msgbuf.h
-header-test- += asm/sembuf.h
 header-test- += asm/shmbuf.h
 header-test- += asm/signal.h
 header-test- += asm/ucontext.h
@@ -26,8 +23,6 @@ header-test- += drm/vmwgfx_drm.h
 header-test- += linux/am437x-vpfe.h
 header-test- += linux/android/binder.h
 header-test- += linux/android/binderfs.h
-header-test-$(CONFIG_CPU_BIG_ENDIAN) += linux/byteorder/big_endian.h
-header-test-$(CONFIG_CPU_LITTLE_ENDIAN) += linux/byteorder/little_endian.h
 header-test- += linux/coda.h
 header-test- += linux/elfcore.h
 header-test- += linux/errqueue.h
@@ -36,15 +31,12 @@ header-test- += linux/hdlc/ioctl.h
 header-test- += linux/ivtv.h
 header-test- += linux/kexec.h
 header-test- += linux/matroxfb.h
-header-test- += linux/netfilter_ipv4/ipt_LOG.h
-header-test- += linux/netfilter_ipv6/ip6t_LOG.h
 header-test- += linux/nfc.h
 header-test- += linux/omap3isp.h
 header-test- += linux/omapfb.h
 header-test- += linux/patchkey.h
 header-test- += linux/phonet.h
 header-test- += linux/reiserfs_xattr.h
-header-test- += linux/scc.h
 header-test- += linux/sctp.h
 header-test- += linux/signal.h
 header-test- += linux/sysctl.h
@@ -99,9 +91,16 @@ endif
 # asm-generic/*.h is used by asm/*.h, and should not be included directly
 header-test- += asm-generic/%
 
-# The rest are compile-tested
-header-test-y += $(filter-out $(header-test-), \
-                       $(patsubst $(obj)/%,%, $(wildcard \
-                       $(addprefix $(obj)/, *.h */*.h */*/*.h */*/*/*.h))))
+extra-y := $(patsubst $(obj)/%.h,%.hdrtest, $(shell find $(obj) -name '*.h'))
+
+quiet_cmd_hdrtest = HDRTEST $<
+      cmd_hdrtest = \
+               $(CC) $(c_flags) -S -o /dev/null -x c /dev/null \
+                       $(if $(filter-out $(header-test-), $*.h), -include $<); \
+               $(PERL) $(srctree)/scripts/headers_check.pl $(obj) $(SRCARCH) $<; \
+               touch $@
+
+$(obj)/%.hdrtest: $(obj)/%.h FORCE
+       $(call if_changed_dep,hdrtest)
 
 clean-files += $(filter-out Makefile, $(notdir $(wildcard $(obj)/*)))